华大单片机HC32L110、HC32F003和HC32F005系列MCU有相同的UART通讯模块,因此这三个系列UART模块的使用程序也相同,本文将介绍通过中断的方式进行UART的通讯。
此UART模块共有模式0~模式3四种通讯模式,其中模式0为半双工同步通讯模式,此模式为同步模式不在我们今天的讨论范围之内。此模块支持8bit、9bit的数据格式,因此异步通讯的数据格式为:1位起始位,8bit或9bit的数据位,1位结束位。模式1为8bit数据位的全双工异步模式;模式2和模式3为9bit数据位的全双工异步通讯模式。具体如下图:
由上图可知模式2和模式3中数据多了个TB8位。该位在多机通讯环境下使用时,当 TB8=1,表明所接收的是地址帧;当 TB8=0,表明所接收的是数据帧。当不需要多机通讯时,此位作为奇偶校验位来使用。大家在使用UART模块之前一定要注意确定自己要使用的模式,模式如果选错会直接导致通讯数据出现错误。
异步通讯时波特率有两种产生方式。Mode2为一种方式,Mode1和Mode3为一种方式。
Mode2:
当工作在 Mode2 时,波特率被固定在如下公式所得值:
其中,UARTx_SCON.DBAUD 表示双倍波特率,Freq 为 PCLK 时钟频率。
Mode1/3:
当工作在 Mode1 或者 Mode3 时,波特率由 TIMER 的溢出时间决定。具体公式如下图
所示:
其中,UARTx_SCON.DBAUD 表示双倍波特率,Freq 为 PCLK 时钟频率,TM 为TIMER 计数值。注意,TIMER 必须配置为 16 位自动重载入模式,计数寄存器和重载寄存器都得写入 TM 值。UART0对应使用的TIMER是TIM0,UART1对应使用的TIMER是TIM1。对于不同的PCLK产生的不同的波特率误差是有差别的,大家在使用的时候最好先查下误表,看下自己的配置所对应的误差是否在可接受的范围,如果误差不可接受,更改到自己可以接受的误差所对应的配置。不同配置波特率误差表在本文最后。
发送数据
发送数据时,与 UARTx_SCON.REN 的值无关,将所发送数据写入 UARTx_SBUF 寄存器中,数据就会从 TXD 移出(低位在先,高位在后)。
接收数据
接收数据时,需将 UARTx_SCON.REN 位置 1,并将 UARTx_ISR.RI 位清 0。开始接收 RXD 上数据(低位在先,高位在后),当接收完毕,可以从 UARTx_SBUF 寄存器读出。
接收缓存
通用 UART(UART0/1)接收端有一个帧长度(8/9bits)的接收缓存,也就是说当一帧数据接收完毕后,接收缓存中的数据会被一直保持,直到下一帧数据的 Stop 位接收完毕后,接收缓存才会更新为新一帧数据。
发送缓存
通用 UART(UART0/1)发送端不支持发送缓存。如果在发送数据过程中,填写UARTx_SBUF 寄存器,将会破坏当前正在发送数据。软件应该避免这种操作。
寄存器 | 位 | 符号 | 描述 | 说明 |
---|---|---|---|---|
UARTx_SBUF | 数据寄存器 | |||
7:0 | SBUF | 数据寄存器 | 发送数据时,待发送数据写入该寄存器; 接收数据时,从该寄存器中读出接收到的数据; 注意,对该寄存器读的值实际是 RxBuffer 中的值,对该寄存器写的值实际是写到了 TXShifter 中。 |
|
UARTx_SCON | 控制寄存器 | |||
9 | DBAUD | 波特率倍率设置 | 0:单倍波特率; 1:双倍波特率 |
|
7:6 | SM01 | 工作模式配置 | 00:mode0;01:mode1; 10:mode2;11:mode3 |
|
5 | SM2 | 多机通讯使能控制 | 0:关闭多机通信功能 1:使能多机通信功能 |
|
4 | REN | 接收使能 | mode0: 0:发送,1:接收 其他: 0:发送,1:接收/发送 |
|
3 | TB8 | 发送数据时待发送的TB8位 | ||
2 | RB8 | 接收数据时收到的RB8位 | ||
1 | TIEN | 发送完成中断使能 | 0:禁止发送完成中断 1:使能发送完成中断 |
|
0 | RIEN | 接收完成中断使能 | 0:禁止接收完成中断 1:使能接收完成中断 |
|
UARTx_ISR | 标志位寄存器 | |||
2 | FE | 接收帧错误标志位;硬件置位,软件清零 | 1:FE中断标志有效 0:FE中断标志无效 |
|
1 | TI | 发送完成中断标志位;硬件置位,软件清零 | 1:TI中断标志有效 0:TI中断标志无效 |
|
0 | RI | 接收完成中断标志位;硬件置位,软件清零 | 1:RI中断标志有效 0:RI中断标志无效 |
|
UARTx_ICR | 中断标志位清除寄存器 | |||
2 | FECLR | 清除接收帧错误标志位 | 写0清零,写1无效 | |
1 | TICLR | 清除发送完成中断标志位 | 写0清零,写1无效 | |
0 | RICLR | 清除接收完成中断标志位 | 写0清零,写1无效 |
stcUartIrqCb.pfnRxIrqCb = RxIntCallback; //配置接收中断回调函数
stcUartIrqCb.pfnTxIrqCb = NULL;
stcUartIrqCb.pfnRxErrIrqCb = ErrIntCallback; //配置错误中断回调函数
stcConfig.pstcIrqCb = &stcUartIrqCb; //配置中断服务函数
stcConfig.bTouchNvic = TRUE; //允许中断
stcConfig.enRunMode = UartMode3; //测试项,更改此处来转换4种模式测试
stcMulti.enMulti_mode = UartNormal; //测试项,更改此处来转换多主机模式,mode2/3才有多主机模//式,此处配置为正常工作模式
stcConfig.pstcMultiMode = &stcMulti; //配置正常或多机工作模式
stcBaud.bDbaud = 0u; //双倍波特率功能
stcBaud.u32Baud = 9600u; //更新波特率位置
stcBaud.u8Mode = UartMode3; //计算波特率需要模式参数
pclk = Clk_GetPClkFreq(); //获得PCLK
timer=Uart_SetBaudRate(UARTCH1,pclk,&stcBaud); //计算波特率所需TIMER值
stcBtConfig.enMD = BtMode2; //自动重装载16位计数器/定时器
stcBtConfig.enCT = BtTimer; //定时模式
Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
Bt_ARRSet(TIM1,timer); //配置重载值
Bt_Cnt16Set(TIM1,timer); //配置计数值
Bt_Run(TIM1); //启动定时
Uart_Init(UARTCH1, &stcConfig); //串口1初始化
Uart_EnableIrq(UARTCH1,UartRxIrq); //允许串口1接收中断
Uart_ClrStatus(UARTCH1,UartRxFull); //清串口1接收中断标志
Uart_EnableFunc(UARTCH1,UartRx); //串口1接收中断使能
void RxIntCallback(void)
{
u8RxData[1]=M0P_UART1->SBUF; //取出接收数据
u8RxFlg = 1; //接收标志置1
}
while(1)
{
CheckFlg = 0; //校验出错标志清零
if(u8RxFlg) //有接收数据进入,无数据跳过
{
u8RxFlg = 0; //接收标志清零
if(Uart_CheckEvenOrOdd(UARTCH1,Even,u8RxData[1])!=Ok) //检查偶检验是否成功
{
CheckFlg = 1; //偶校验出错
}
else
{
Uart_SetTb8(UARTCH1,Even,u8RxData[0]); //根据数据设置TB8位
Uart_SendData(UARTCH1,u8RxData[0]); //发送数据
Uart_SetTb8(UARTCH1,Even,u8RxData[1]);
Uart_SendData(UARTCH1,u8RxData[1]);
}
}
}
好多朋友在使用UART的时候因为没有掌握4种模式的差别,所示调试的时候总是接收数据不对,走了很多弯路,现在就把不同种的差别总结一下。
半双工同步模式
Mode0 波特率为固定的 PCLK 时钟的 1/12。不常用。
全双工异步模式
Mode1 数据位8位,不带检验位,不带多机通讯功能,波特率由TIMER产生,常用;
Mode2 数据位9位,带检验位,带多机通讯功能,波特率为与PCLK有关的固定值,不常用;
Mode3 数据位9位,带检验位,带多机通讯功能,波特率由TIMER产生,常用。
不同模式的总结可以参考下表:
关注微信公众号『芯缘意码』,查看更多内容,回复“加群”加入技术交流群。
淘宝 店铺 搜索 『芯缘意码』,购买开发学习板仿真器。