硬件平台:jz2440
软件平台:Ubuntu16.04 arm-linux-gcc-3.4.5
源码位置: https://github.com/lian494362816/C/tree/master/2440/008_uart
串口算是各种芯片最基本的功能之一,串口配置好后程序就可以通过串口来打印各种信息,方便代码的调试。 串口最主要的参数有4个:波特率,数据宽度, 校验位,停止位
波特率 | 115200,38400 ,19200, 9600, 2440最高支持921.6Kb |
---|---|
数据宽度 | 5bit, 6bit, 7bit, 8bit |
校验位 | 奇校验,偶校验,无校验 |
停止位 | 1bit, 2bit |
常用的串口配置为:波特率115200,8bit数据宽度,无校验位,1bit停止位,通常缩写为115200 8N1
2440有3组UART, 每组UART都有2个64Bytes 的FIFO
jz2240使用的串口0与电脑通信,之间通过PL2303来转换电脑和开发板之间的逻辑电平。
串口需要用的Pin脚就3个:Tx,RX,GND, 因此首先需要把对应的Pin设置为TX,RD模式,除此外,还需要将上拉功能开启。因为UART在空闲时是高电平。
ULCON0 用来控制串口的基本属性,这里设置了115200 8N1中的8N1
ULCON 主要设置时钟源及工作的各种模式
如果时钟选择FLCK,在配置上有许多限制条件,所以这里选择PCLK会更加方便。
发送接收都选择polling mode,因此需要自己手动去查看状态寄存器。
状态寄存器,在polling mode下可以通过查询此寄存器的值来判断收发数据的情况
当发送数据时,需要先查看UTRSTAT0[2]是否empty, 逻辑代码为:
{
/* 等待trasnmitter为空,否则表示还有剩余数据未被发送 */
while (!(UTRSTAT0 & 0x4))
发送数据
}
当接收数据时,需要先查看UTRSTAT0[0]是否非empty,逻辑代码为:
{
/*需要等待Receive buffer非空,表示获取到了数据,否则一直等待 */
while (!(UTRSTAT0 & 0x1));
接收数据
}
波特率设置,公式为:UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
UART clock前面设置为PLCK=50M
期望的buad rate = 115200
代入公式 (50M / ( 115200 x 16) ) - 1 = 27.12 - 1 = 26
因为除法可能会有小数,所以实际的波特率会有误差,不过2440提供了误差的计算公式和最大的误差范围
误差的计算公式为:
tUPCLK = (UBRDIVn + 1) x 16 x 1Frame / PCLK
tUEXACT = 1Frame / baud-rate
UART error = (tUPCLK – tUEXACT) / tUEXACT x 100%
UBRDIVn = 26,
1Frame = start bit + data bit + parity bit + stop bit. 因为每次传输1个Byte都会有1bit start bit 所以
1Frame = 1 + 8 + 0 + 1 = 10,
tUPCLK = (26 + 1)* 16 * 10 / 50M = 432 / 5M
tUEXACT = 10 / 115200 = 1 / 11520
UART error = (432 / 5M - 1 / 11520) / (1 / 11520) * 100% = -0.446%
uart.c
int uart0_init(void)
{
/* 1 set gpio to uart mode
Tx GPH2 [5:4] b10
Rx GPH3 [7:6] b10
*/
GPHCON &= ~((0x3 << 4) | (0x3 << 6));
GPHCON |= (0x2 << 4) | (0x2 << 6);
/* 2 set pull up */
GPHUP |= (0x1 << 2) | (0x1 << 3);
/* 3 set formar 8N1 */
ULCON0 |= 0x3;
/* 4 set Soruce clock PCLK and poling mode*/
UCON0 = 0x5;
/* 5 set baud rate 115200
PCLK = 50M
UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
UBRDIVn = (50M / (115200 x 16))-1 = 26.1267 -> 26
*/
UBRDIV0 = 26;
return 0;
}
int getchar(void)
{
int chr = 0;
while (!(UTRSTAT0 & 0x1))
{
//nothing
}
chr = URXH0;
return chr;
}
int putchar(int c)
{
while (!(UTRSTAT0 & 0x4))
{
//nothing
}
UTXH0 = (unsigned char )c;
}
uart0_init, getchar, putchar的实现都很简单,不做过多介绍
唯一要注意的是,发送数据时,最好把数据强制转换成 unsigned char ,避免当字符的ascii 超过127时转变成负数而导致发送数据异常