实验八--uart

一。环境

  系统:ubuntu12.04

  开发板:jz2440

  编译器:gcc

二。说明

    有空补上

三。代码

      head.S

 1 @******************************************************************************
 2 @ File:head.S
 3 @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
 4 @******************************************************************************       
 5    
 6 .extern     main
 7 .text 
 8 .global _start 
 9 _start:
10 Reset:                  
11     ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
12     bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
13     bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
14 
15     ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行
16 on_sdram:
17     ldr sp, =0x34000000     @ 设置栈指针
18     ldr lr, =halt_loop      @ 设置返回地址
19     ldr pc, =main           @ 调用main函数
20 halt_loop:
21     b   halt_loop

Makefile

 1 objs := head.o init.o serial.o main.o
 2 
 3 uart.bin: $(objs)
 4     arm-linux-ld -Ttext 0x00000000 -o uart_elf $^
 5     arm-linux-objcopy -O binary -S uart_elf $@
 6     arm-linux-objdump -D -m arm uart_elf > uart.dis
 7     
 8 %.o:%.c
 9     arm-linux-gcc -Wall -O2 -c -o $@ $<
10 
11 %.o:%.S
12     arm-linux-gcc -Wall -O2 -c -o $@ $<
13 
14 clean:
15     rm -f uart.bin uart_elf uart.dis *.o        
16     

init.c

 1 /*
 2  * init.c: 进行一些初始化
 3  */ 
 4 
 5 #include "s3c24xx.h"
 6  
 7 void disable_watch_dog(void);
 8 void clock_init(void);
 9 
10 
11 /*
12  * 关闭WATCHDOG,否则CPU会不断重启
13  */
14 void disable_watch_dog(void)
15 {
16     WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
17 }
18 
19 #define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))
20 #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
21 /*
22  * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
23  * 有如下计算公式:
24  *  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
25  *  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
26  *  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
27  * 对于本开发板,Fin = 12MHz
28  * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
29  * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
30  */
31 void clock_init(void)
32 {
33     // LOCKTIME = 0x00ffffff;   // 使用默认值即可
34     CLKDIVN  = 0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
35 
36     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
37 __asm__(
38     "mrc    p15, 0, r1, c1, c0, 0
"        /* 读出控制寄存器 */ 
39     "orr    r1, r1, #0xc0000000
"          /* 设置为“asynchronous bus mode” */
40     "mcr    p15, 0, r1, c1, c0, 0
"        /* 写入控制寄存器 */
41     );
42 
43     /* 判断是S3C2410还是S3C2440 */
44     if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
45     {
46         MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
47     }
48     else
49     {
50         MPLLCON = S3C2440_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
51     }       
52 }

serial.c

 1 #include "s3c24xx.h"
 2 #include "serial.h"
 3 
 4 #define TXD0READY   (1<<2)
 5 #define RXD0READY   (1)
 6 
 7 #define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
 8 #define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
 9 #define UART_BAUD_RATE  115200      // 波特率
10 #define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)
11 
12 /*
13  * 初始化UART0
14  * 115200,8N1,无流控
15  */
16 void uart0_init(void)
17 {
18     GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
19     GPHUP   = 0x0c;     // GPH2,GPH3内部上拉
20 
21     ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
22     UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
23     UFCON0  = 0x00;     // 不使用FIFO
24     UMCON0  = 0x00;     // 不使用流控
25     UBRDIV0 = UART_BRD; // 波特率为115200
26 }
27 
28 /*
29  * 发送一个字符
30  */
31 void putc(unsigned char c)
32 {
33     /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
34     while (!(UTRSTAT0 & TXD0READY));
35     
36     /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
37     UTXH0 = c;
38 }
39 
40 /*
41  * 接收字符
42  */
43 unsigned char getc(void)
44 {
45     /* 等待,直到接收缓冲区中的有数据 */
46     while (!(UTRSTAT0 & RXD0READY));
47     
48     /* 直接读取URXH0寄存器,即可获得接收到的数据 */
49     return URXH0;
50 }
51 
52 /*
53  * 判断一个字符是否数字
54  */
55 int isDigit(unsigned char c)
56 {
57     if (c >= '0' && c <= '9')
58         return 1;
59     else
60         return 0;       
61 }
62 
63 /*
64  * 判断一个字符是否英文字母
65  */
66 int isLetter(unsigned char c)
67 {
68     if (c >= 'a' && c <= 'z')
69         return 1;
70     else if (c >= 'A' && c <= 'Z')
71         return 1;       
72     else
73         return 0;
74 }

main.c

 1 #include "serial.h"
 2 
 3 int main()
 4 {
 5     unsigned char c;
 6     uart0_init();   // 波特率115200,8N1(8个数据位,无校验位,1个停止位)
 7 
 8     while(1)
 9     {
10         // 从串口接收数据后,判断其是否数字或子母,若是则加1后输出
11         c = getc();
12         if (isDigit(c) || isLetter(c))
13             putc(c+1);
14     }
15 
16     return 0;
17 }

注:代码源自韦东山先生,简作修改。

删掉sdram部分内容

上面代码只是测试串口用,下面贴出实用的串口代码,可以输出打印信息,这点在uboot和内核很有用

而且这里不用硬件重定向

对于上面代码作修改如下

serial.c里面添加:

 1 void puts(unsigned char *str)
 2 {
 3     int i=0;
 4     while(str[i])
 5     {
 6       putc(str[i]);
 7       i++;    
 8     }    
 9 
10 
11 }

当然serial.h里面也相应的删减,去掉对输入字符判断函数

此外,mian函数可以作出一个菜单选项

 1 #include "serial.h"
 2 
 3 int main()
 4 {
 5     unsigned char c;
 6     uart0_init();   // 波特率115200,8N1(8个数据位,无校验位,1个停止位)
 7 
 8     while(1)
 9     {
10         // 从串口接收数据后,判断其是否数字或子母,若是则加1后输出
11         c = getc();
12     switch(c)
13     {
14       case '0':
15         {
16         puts("I

");
17         break;
18         }    
19       case '1':
20         {
21         puts("AM

");
22         break;    
23         }
24       case '2':
25         {
26         puts("HELLO

");
27         break;
28         }    
29       case '3':        
30         {
31         puts("WORLD

");
32         break;    
33         }
34       default:
35         {
36         puts("thanks!

");
37         break;    
38         }
39     }
40     }
41 
42     return 0;
43 }

输出会相对输入作出不同响应,在后面做菜单方面很有用。

韦东山老师用作菜单的串口函数是硬件重定向,没这个简练

经测试,可用。

原文地址:https://www.cnblogs.com/hulig7/p/4115273.html