1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
#define GPA0CON 0xE0200000
#define UCON0 0xE2900004
#define ULCON0 0xE2900000
#define UMCON0 0xE290000C
#define UFCON0 0xE2900008
#define UBRDIV0 0xE2900028
#define UDIVSLOT0 0xE290002C
#define UTRSTAT0 0xE2900010
#define UTXH0 0xE2900020
#define URXH0 0xE2900024
#define rGPA0CON (*(volatile unsigned int *)GPA0CON)
#define rUCON0 (*(volatile unsigned int *)UCON0)
#define rULCON0 (*(volatile unsigned int *)ULCON0)
#define rUMCON0 (*(volatile unsigned int *)UMCON0)
#define rUFCON0 (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0 (*(volatile unsigned int *)UTXH0)
#define rURXH0 (*(volatile unsigned int *)URXH0)
// 串口初始化程序
void uart_init( void )
{
// 初始化Tx Rx对应的GPIO引脚
rGPA0CON &= ~(0xff<<0); // 把寄存器的bit0~7全部清零
rGPA0CON |= 0x00000022; // 0b0010, Rx Tx bit[3:0] = 0b0010 bit[7:4] = 0b0010
// 几个关键寄存器的设置
rULCON0 = 0x3;
rUCON0 = 0x5;
rUMCON0 = 0;
rUFCON0 = 0;
// 波特率设置 DIV_VAL = (PCLK / (bps x 16))-1
// PCLK_PSYS用66MHz算 余数0.8
//rUBRDIV0 = 34;
//rUDIVSLOT0 = 0xdfdd;
// PCLK_PSYS用66.7MHz算 余数0.18
// DIV_VAL = (66700000/(115200*16)-1) = 35.18
rUBRDIV0 = 35;
// (rUDIVSLOT中的1的个数)/16=上一步计算的余数=0.18
// (rUDIVSLOT中的1的个数 = 16*0.18= 2.88 = 3
rUDIVSLOT0 = 0x0888; // 3个1,查官方推荐表得到这个数字
}
// 串口发送程序,发送一个字节
void uart_putc( char c)
{
// 串口发送一个字符,其实就是把一个字节丢到发送缓冲区中去
// 因为串口控制器发送1个字节的速度远远低于CPU的速度,所以CPU发送1个字节前必须
// 确认串口控制器当前缓冲区是空的(意思就是串口已经发完了上一个字节)
// 如果缓冲区非空则位为0,此时应该循环,直到位为1
while (!(rUTRSTAT0 & (1<<1)));
rUTXH0 = c;
}
// 串口接收程序,轮询方式,接收一个字节
char uart_getc( void )
{
while (!(rUTRSTAT0 & (1<<0)));
return (rURXH0 & 0x0f);
}
|
1
2
3
4
5
6
7
8
9
10
|
void main( void )
{
uart_init();
while (1)
{
uart_putc( 'a' );
delay();
}
}
|
CC = arm-linux-gcc
LD = arm-linux-ld
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
AR = arm-linux-ar
INCDIR := $(shell pwd)
# C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include //-nostdlib -nostdinc:不用标准库和标准头文件
# C编译器的flag
CFLAGS := -Wall -O2 -fno-builtin //-O2:编译器优化级别,数字越高,优化程度越高
#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS
objs := start.o led.o clock.o uart.o main.o
objs += lib/libc.a
uart.bin: $(objs)
$(LD) -Tlink.lds -o uart.elf $^
$(OBJCOPY) -O binary uart.elf uart.bin
$(OBJDUMP) -D uart.elf > uart_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 uart.bin 210.bin
lib/libc.a:
cd lib; make; cd ..
%.o : %.S
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
cd lib; make clean; cd ..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// putc函数真正和输出设备绑定,这个函数需要我们自己去实现,这就是移植的关键
int
printf
(
const
char
*fmt, ...)
//...可变参数
{
int
i;
int
len;
va_list
args;
va_start
(args, fmt);
len =
vsprintf
(g_pcOutBuf,fmt,args);
va_end
(args);
for
(i = 0; i <
strlen
(g_pcOutBuf); i++)
{
putc
(g_pcOutBuf[i]);
}
return
len;
}
|
参考:https://blog.csdn.net/wooin/article/details/697106
11.3、vsprintf函数详解