串口时钟使用了PCLK,所以在初始化串口之前需要先将系统时钟初始化,(除非想一直使用默认时钟)。
一、代码
1. start.S 主要功能是:
a.关闭看门狗
b. 初始化系统时钟
c. 设置堆栈
d. 跳到main函数
2. main.c 主要功能是:
点击(此处)折叠或打开
- .text
- .global _start
- _start:
- /*disable watchdog*/
- ldr r0, =0x53000000
- mov r1, #0x0
- str r1, [r0]
-
- #define COCKTIME 0x4C000000
- #define MPLLCON 0x4C000004
- #define UPLLCON 0x4C000008
- #define CLKCON 0x4C00000C
- #define CLKSLOW 0x4C000010
- #define CLKDIVN 0x4C000014
- #define CAMDIVN 0x4C000018
- /*FCLK:HCLK:PCLK=1:4:8*/
- ldr r0, =CLKDIVN
- mov r1, #0x05
- str r1, [r0]
-
- mrc p15, 0, r0, c1, c0, 0
- orr r0, r0, #0xc0000000
- mcr p15, 0, r0, c1, c0,0
-
- /*MPLL=(2*m*Fin)/(P*(1<<S)), m=(MDIV+8), p=PDIV+2 s=SDIV*/
- ldr r0, =MPLLCON
- ldr r1, =((0x5C<<12)|(0x01<<4)|(0x01))
- str r1, [r0]
-
- ldr r0, =0x10000
- 1:
- sub r0, r0, #1
- bne 1b
-
- /*UPLL=(m*Fin)/(P*(1<<S)), m=(MDIV+8), p=(PDIV+2), s=SDIV*/
- ldr r0, =UPLLCON
- ldr r1, =((0x10<<12)|(0x01<<4)|(0x01))
- str r1, [r0]
-
- ldr r0, =0x10000
- 1:
- sub r0, r0, #1
- bne 1b
-
- /* set up the stack */
- ldr sp, =1024*4
- bl main
-
- loop:
- b loop
a. 初始化串口
b. 进入死循环,每次点亮一个led灯,顺便打印一个字母'a'
点击(此处)折叠或打开
- #include "uart.h"
- #define GPBCON (*(volatile unsigned int *) 0x56000010)
- #define GPBDAT (*(volatile unsigned int *) 0x56000014)
-
- static inline void delay (unsigned long loops)
- {
- __asm__ volatile ("1:\n"
- "subs %0, %1, #1\n"
- "bne 1b":"=r" (loops):"0" (loops));
- }
-
- void main()
- {
- int i = 1;
- GPBCON = 0x15400;
- init_uart();
- while(1)
- {
- GPBDAT = 0x7FF&(~i<<5);
- i *= 2;
- if(16==i)
- i = 1;
- delay(400000);
- putc('a');
- }
- return ;
- }
a. 初始化串口
b. 实现发送与接收函数getc与putc
点击(此处)折叠或打开
- #define GPHCON (* (volatile unsigned int *) 0x56000070)
- #define GPHUP (* (volatile unsigned int *) 0x56000078)
-
- #define ULCON0 (* (volatile unsigned int *) 0x50000000)
- #define UCON0 (* (volatile unsigned int *) 0x50000004)
- #define UFCON0 (* (volatile unsigned int *) 0x50000008)
- #define UMCON0 (* (volatile unsigned int *) 0x5000000C)
- #define UTRSTAT0 (* (volatile unsigned int *) 0x50000010)
- #define UERSTAT0 (* (volatile unsigned int *) 0x50000014)
- #define UFSTAT0 (* (volatile unsigned int *) 0x50000018)
- #define UMSTAT0 (* (volatile unsigned int *) 0x5000001C)
- #define UTXH0 (* (volatile unsigned char *) 0x50000020)
- #define URXH0 (* (volatile unsigned char *) 0x50000024)
- #define UBRDIV0 (* (volatile unsigned int *) 0x50000028)
-
- #define BAUD_RATE 115200
-
- void uart_init(void)
- {
- GPHCON = 0x000000A0;
- GPHUP = 0x000007FF;
- ULCON0 = (0x03); //8N1
- UCON0 = (0x01<<2)|(0x01);
- UFCON0 = 0;
- UMCON0 = 0;
- UBRDIV0 = (int)((50*1000*1000)/(BAUD_RATE*16))-1;
- }
-
- unsigned char uart_getc(void)
- {
- while(!(UTRSTAT0 & 0x01))
- ;
- return (URXH0 & 0xff);
- }
-
- void uart_putc(char c)
- {
- while (!(UTRSTAT0&0x02))
- ;
- UTXH0 = c;
- if('\n' == c)
- uart_putc('\r');
- }
-
- void uart_puts(char *s)
- {
- while (*s)
- {
- uart_putc(*s++);
- }
- }
注: uart.c中的uart_putc函数(
ascii中:
\n__换行__LF__0x10 \r__回车__CR__0x13
)
1. 当键盘敲下 Enter键时,从串口收到的按键是0x0d(即:\r 回车符:将光标移动到行首,而不换行)。
2. 当调用puts("hello\n");时putc收到\n后,将换行但光标的列不变,然后再输出\r,将光标移动到换行之后的行首,这样
效果
就跟平常的回车一样了。
4. uart.h
点击(此处)折叠或打开
- void uart_init(void);
- unsigned char uart_getc(void);
- void uart_putc(char c);
编译时只需要在Makefile的OBJS中添加uart.o就可以了。
2.1 将main中主循环改为接收一个字符然后打印
点击(此处)折叠或打开
- uart_init();
- while(1)
- {
- c=uart_getc();
- uart_putc(c);
- }