CMT2380F32模块开发4-UART例程
Posted andylauren
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMT2380F32模块开发4-UART例程相关的知识,希望对你有一定的参考价值。
该模块带有 2 个通用 UART 模块(UART0/1),通用同步异步收发器(UART)能够灵活地与外部设备进行全双工数据交换,它支持同步单向通信以及多处理器通信。常用于短距离、低速的串行通信中。UART 通过可编程波特率发生器提供了多种波特率。UART0 的波特率由 TIMER0 产生,UART1 的波特率由 TIMER1 产生。UART 支持4种工作模式。
当工作在 Mode0 时,UART 工作在同步模式,其波特率为固定的 PCLK 时钟的 1/12。
当工作在 Mode1 时,波特率由定时器模块产生,并且是可编程的。UART0 的波特率由 TIMER0 产生,UART1 的波特率由 TIMER1 产生。
Mode2/3 具有多机通讯功能,为此在其帧格式中增加了 1 位 TB8/RB8。将 UARTx_SCON.SM2 置“1”,可开启多机通讯位。
当开启多机通讯位后,发送数据时,主机可以通过 UARTx_SCON.TB8 来区分当前帧是地址帧(UARTx_SCON.TB8=1)还是数据帧(UARTx_SCON.TB8=0)。接收数据时,从机会忽略 RB8 位(第 9 位)为“0”的当前接收帧。
总结:mode0,波特率与主频有关,不可改。mode1,波特率可调,就是普通的串口,一般用这个。mode2,mode3是实现多机通讯的,可以实现ID过滤,但是需要其他机器也是这个模块,而且不带有总线仲裁,也就是单主机总线模式。
Mode1/Mode3 波特率设置示例,在《AN220-CMT2380F32用户指南(微控制器部分)-CN-V1.0-20200107.pdf》P230.需要用什么波特率,误差可以使用这个表查看。太大这里就不粘了。
从上表看出,不同的主频对于不同的波特率误差是不同的,如果想稳定可靠的通信,建议误差在0.5%以内。因为这个模块没有外部晶振,只能使用内部晶振,如果你想使用115200波特率,需要将内部晶振设置为22.12M或者24M,否则串口接收的数据可能是乱码。
uart_int例程
这个例程效果是配置P35、P36为UART收发端口,配置波特率9600bps,配置BaseTime1自动重载周期,使能UART中断,使能UART收发功能。
然后在串口调试工具配置波特率9600bps、无校验、1stop,PC串口发送1字节数据XX,发送完成后,收到0X55+0xXX('U+ASCII(XX)')
Gpio_InitIOExt(3, 5, GpioDirOut, TRUE, FALSE, FALSE, FALSE);
Gpio_InitIOExt(3, 6, GpioDirOut, TRUE, FALSE, FALSE, FALSE);
//通道端口配置
Gpio_SetFunc_UART1TX_P35();
Gpio_SetFunc_UART1RX_P36();
//外设时钟使能
Clk_SetPeripheralGate(ClkPeripheralBt, TRUE); //模式0/2可以不使能
Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
stcUartIrqCb.pfnRxIrqCb = RxIntCallback;
stcUartIrqCb.pfnTxIrqCb = NULL;
stcUartIrqCb.pfnRxErrIrqCb = ErrIntCallback;
stcConfig.pstcIrqCb = &stcUartIrqCb;
stcConfig.bTouchNvic = TRUE;
// Mode0 同步模式 半双工 8bit Data(8bit) 波特率为固定的 PCLK 时钟的 1/12
// Mode1 异步模式 全双工 10bit Start (1bit)+Data(8bit)+Stop(1bit)
// UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
// Mode2 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit) 波特率可以独立产生
// Mode3 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit)
// UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
stcConfig.enRunMode = UartMode1; //测试项,更改此处来转换4种模式测试
stcMulti.enMulti_mode = UartNormal; //测试项,更改此处来转换多主机模式,mode2/3才有多主机模式
stcConfig.pstcMultiMode = &stcMulti;
stcBaud.bDbaud = 0u; //双倍波特率功能
stcBaud.u32Baud = 9600u; //更新波特率位置Page230
stcBaud.u8Mode = UartMode1; //计算波特率需要模式参数
pclk = Clk_GetPClkFreq();
timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
stcBtConfig.enMD = BtMode2;
stcBtConfig.enCT = BtTimer;
Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
Bt_ARRSet(TIM1, timer);
Bt_Cnt16Set(TIM1, timer);
Bt_Run(TIM1);
Uart_Init(UARTCH1, &stcConfig);
Uart_EnableIrq(UARTCH1, UartRxIrq);
Uart_ClrStatus(UARTCH1, UartRxFull);
Uart_EnableFunc(UARTCH1, UartRx);
while (1)
CheckFlg = 0;
if (u8RxFlg)
u8RxFlg = 0;
Uart_SendData(UARTCH1, u8RxData[0]);
Uart_SendData(UARTCH1, u8RxData[1]);
主要代码在上面,基本就是配置,设置,中断接收,循环发送。
uart_master和uart_slave例程
这两个例程是测试mode3的多机通讯程序,需要两块板子测试,其中一个板子下载uart_master作为主机,另一个下载uart_slave作为从机。
主机代码
//通道端口配置
Gpio_SetFunc_UART1TX_P35();
Gpio_SetFunc_UART1RX_P36();
//外设时钟使能
Clk_SetPeripheralGate(ClkPeripheralBt, TRUE);
Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
stcUartIrqCb.pfnRxIrqCb = NULL;
stcUartIrqCb.pfnTxIrqCb = NULL;
stcUartIrqCb.pfnRxErrIrqCb = NULL;
stcConfig.pstcIrqCb = &stcUartIrqCb;
stcConfig.bTouchNvic = FALSE;
#if 1 //多主机模式测试
// Mode3 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit)
// UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
stcConfig.enRunMode = UartMode3;
stcMulti.enMulti_mode = UartMulti;
enTb8 = Addr;
Uart_SetMMDOrCk(UARTCH1, enTb8);
stcConfig.pstcMultiMode = &stcMulti;
stcBaud.bDbaud = 0u;
stcBaud.u32Baud = 2400u;
stcBaud.u8Mode = UartMode3; //计算波特率需要模式参数
pclk = Clk_GetPClkFreq();
timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
stcBtConfig.enMD = BtMode2;
stcBtConfig.enCT = BtTimer;
Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
Bt_ARRSet(TIM1, timer);
Bt_Cnt16Set(TIM1, timer);
Bt_Run(TIM1);
#endif
Uart_Init(UARTCH1, &stcConfig);
Uart_ClrStatus(UARTCH1, UartTxEmpty); //清所有中断请求
Uart_EnableFunc(UARTCH1, UartRx);
#if 1
Uart_SendData(UARTCH1, 0xC0); // 发送地址0xC0
enTb8 = Data;
Uart_SetMMDOrCk(UARTCH1, enTb8);
Uart_ClrStatus(UARTCH1, UartTxEmpty);
Gpio_SetIO(2, 3, 0);
while (i < 10)
Uart_SendData(UARTCH1, u8TxData[i]);
i++;
Gpio_SetIO(2, 3, 1);
#endif
首先将P35,P36配置为串口,然后配置串口为mode3,波特率2400,然后进入从机设置,设置从机地址为0xC0,然后在发送前会点亮LED1,发送如下数据
uint8_t u8TxData[10] = 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00;
发送完成后关闭LED1,最后进入while 1。
从机代码
//通道端口配置
Gpio_SetFunc_UART1TX_P35();
Gpio_SetFunc_UART1RX_P36();
//外设时钟使能
Clk_SetPeripheralGate(ClkPeripheralBt, TRUE);
Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
stcUartIrqCb.pfnRxIrqCb = NULL;
stcUartIrqCb.pfnTxIrqCb = NULL;
stcUartIrqCb.pfnRxErrIrqCb = NULL;
stcConfig.pstcIrqCb = &stcUartIrqCb;
stcConfig.bTouchNvic = FALSE;
#if 1 //多主机模式测试
stcConfig.enRunMode = UartMode3;
stcMulti.enMulti_mode = UartMulti;
stcMulti.u8SlaveAddr = 0xc0; //从机地址配置
stcMulti.u8SaddEn = 0xff; // 0x7f;//
enTb8 = Addr;
Uart_SetMMDOrCk(UARTCH1, enTb8);
stcConfig.pstcMultiMode = &stcMulti;
stcBaud.bDbaud = 0u;
stcBaud.u32Baud = 2400u;
stcBaud.u8Mode = UartMode3; //计算波特率需要模式参数
pclk = Clk_GetPClkFreq();
timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
stcBtConfig.enMD = BtMode2;
stcBtConfig.enCT = BtTimer;
Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
Bt_ARRSet(TIM1, timer);
Bt_Cnt16Set(TIM1, timer);
Bt_Run(TIM1);
#endif
Uart_Init(UARTCH1, &stcConfig);
Uart_ClrStatus(UARTCH1, UartRxFull); //清所有接收完成标志
Uart_EnableFunc(UARTCH1, UartRx);
while (0 == Uart_GetStatus(UARTCH1, UartRxFull))
;
Uart_ClrStatus(UARTCH1, UartRxFull);
if (1 == Uart_GetRb8(UARTCH1)) //只有此处配置后,后续的数据方可正确接收
stcMulti.enMulti_mode = UartNormal;
Uart_SetMultiMode(UARTCH1, &stcMulti);
u8SlaveAddr = Uart_ReceiveData(UARTCH1);
while (i < 10)
while (0 == Uart_GetStatus(UARTCH1, UartRxFull))
;
Uart_ClrStatus(UARTCH1, UartRxFull);
u8RxData[i++] = Uart_ReceiveData(UARTCH1);
for (i = 0; i < 10; i++)
if (u8RxData[i] != u8TxData[i])
Gpio_SetIO(2, 3, 0);
Gpio_SetIO(1, 4, 1);
break;
else
Gpio_SetIO(2, 3, 1);
Gpio_SetIO(1, 4, 0);
首先将P35,P36配置为串口,然后配置串口为mode3,波特率2400,然后设置从机地址为0xC0,从机掩码为0xFF,从机掩码用法是UART 设备的 UARTx_SADDR 寄存器用来表示自己的设备给定地址,UARTx_SADEN 寄存器是地址掩码,可以用来定义地址中的无关位。当 UARTx_SADEN 的某一位为“0”,表示该位地址为无关位,也就是说在地址匹配过程中,该位地址不参与地址匹配。这些无关位增加了寻址的灵活性,使得主机可以同时寻址一个或者多个从机设备。也就是可以实现组播功能。
然后通过Uart_ReceiveData接收数据,这里注意接收到的第一个字节是从机地址,之后的才是数据,收到10个数据后进行比对,如果数据正确会点亮LED1,如果数据错误会点亮LED2。
也可以仿真在for循环处打断点,查看u8RxData数组值和u8SlaveAddr值。
两个板子链接需要将P35链接另一个板子的P36,将P36链接另一个板子的P35.
如果使用多机通讯时,在硬件设计上需要考虑带载能力,是否需要上拉电阻,和通讯速率高的时候需要阻抗匹配问题。
以上是关于CMT2380F32模块开发4-UART例程的主要内容,如果未能解决你的问题,请参考以下文章