• 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)')

    1. Gpio_InitIOExt(3, 5, GpioDirOut, TRUE, FALSE, FALSE, FALSE);
    2. Gpio_InitIOExt(3, 6, GpioDirOut, TRUE, FALSE, FALSE, FALSE);
    3. //通道端口配置
    4. Gpio_SetFunc_UART1TX_P35();
    5. Gpio_SetFunc_UART1RX_P36();
    6. //外设时钟使能
    7. Clk_SetPeripheralGate(ClkPeripheralBt, TRUE); //模式0/2可以不使能
    8. Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
    9. stcUartIrqCb.pfnRxIrqCb = RxIntCallback;
    10. stcUartIrqCb.pfnTxIrqCb = NULL;
    11. stcUartIrqCb.pfnRxErrIrqCb = ErrIntCallback;
    12. stcConfig.pstcIrqCb = &stcUartIrqCb;
    13. stcConfig.bTouchNvic = TRUE;
    14. // Mode0 同步模式 半双工 8bit Data(8bit) 波特率为固定的 PCLK 时钟的 1/12
    15. // Mode1 异步模式 全双工 10bit Start (1bit)+Data(8bit)+Stop(1bit)
    16. // UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
    17. // Mode2 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit) 波特率可以独立产生
    18. // Mode3 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit)
    19. // UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
    20. stcConfig.enRunMode = UartMode1; //测试项,更改此处来转换4种模式测试
    21. stcMulti.enMulti_mode = UartNormal; //测试项,更改此处来转换多主机模式,mode2/3才有多主机模式
    22. stcConfig.pstcMultiMode = &stcMulti;
    23. stcBaud.bDbaud = 0u; //双倍波特率功能
    24. stcBaud.u32Baud = 9600u; //更新波特率位置Page230
    25. stcBaud.u8Mode = UartMode1; //计算波特率需要模式参数
    26. pclk = Clk_GetPClkFreq();
    27. timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
    28. stcBtConfig.enMD = BtMode2;
    29. stcBtConfig.enCT = BtTimer;
    30. Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
    31. Bt_ARRSet(TIM1, timer);
    32. Bt_Cnt16Set(TIM1, timer);
    33. Bt_Run(TIM1);
    34. Uart_Init(UARTCH1, &stcConfig);
    35. Uart_EnableIrq(UARTCH1, UartRxIrq);
    36. Uart_ClrStatus(UARTCH1, UartRxFull);
    37. Uart_EnableFunc(UARTCH1, UartRx);
    38. while (1) {
    39. CheckFlg = 0;
    40. if (u8RxFlg) {
    41. u8RxFlg = 0;
    42. Uart_SendData(UARTCH1, u8RxData[0]);
    43. Uart_SendData(UARTCH1, u8RxData[1]);
    44. }
    45. }

    主要代码在上面,基本就是配置,设置,中断接收,循环发送。

    uart_master和uart_slave例程

    这两个例程是测试mode3的多机通讯程序,需要两块板子测试,其中一个板子下载uart_master作为主机,另一个下载uart_slave作为从机。

    主机代码

    1. //通道端口配置
    2. Gpio_SetFunc_UART1TX_P35();
    3. Gpio_SetFunc_UART1RX_P36();
    4. //外设时钟使能
    5. Clk_SetPeripheralGate(ClkPeripheralBt, TRUE);
    6. Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
    7. stcUartIrqCb.pfnRxIrqCb = NULL;
    8. stcUartIrqCb.pfnTxIrqCb = NULL;
    9. stcUartIrqCb.pfnRxErrIrqCb = NULL;
    10. stcConfig.pstcIrqCb = &stcUartIrqCb;
    11. stcConfig.bTouchNvic = FALSE;
    12. #if 1 //多主机模式测试
    13. // Mode3 异步模式 全双工 11bit Start (1bit)+Data(8bit)+B8(1bit)+Stop(1bit)
    14. // UART0 的波特率由 TIMER0 产生, UART1 的波特率由 TIMER1 产生
    15. stcConfig.enRunMode = UartMode3;
    16. stcMulti.enMulti_mode = UartMulti;
    17. enTb8 = Addr;
    18. Uart_SetMMDOrCk(UARTCH1, enTb8);
    19. stcConfig.pstcMultiMode = &stcMulti;
    20. stcBaud.bDbaud = 0u;
    21. stcBaud.u32Baud = 2400u;
    22. stcBaud.u8Mode = UartMode3; //计算波特率需要模式参数
    23. pclk = Clk_GetPClkFreq();
    24. timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
    25. stcBtConfig.enMD = BtMode2;
    26. stcBtConfig.enCT = BtTimer;
    27. Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
    28. Bt_ARRSet(TIM1, timer);
    29. Bt_Cnt16Set(TIM1, timer);
    30. Bt_Run(TIM1);
    31. #endif
    32. Uart_Init(UARTCH1, &stcConfig);
    33. Uart_ClrStatus(UARTCH1, UartTxEmpty); //清所有中断请求
    34. Uart_EnableFunc(UARTCH1, UartRx);
    35. #if 1
    36. Uart_SendData(UARTCH1, 0xC0); // 发送地址0xC0
    37. enTb8 = Data;
    38. Uart_SetMMDOrCk(UARTCH1, enTb8);
    39. Uart_ClrStatus(UARTCH1, UartTxEmpty);
    40. Gpio_SetIO(2, 3, 0);
    41. while (i < 10) {
    42. Uart_SendData(UARTCH1, u8TxData[i]);
    43. i++;
    44. }
    45. Gpio_SetIO(2, 3, 1);
    46. #endif

    首先将P35,P36配置为串口,然后配置串口为mode3,波特率2400,然后进入从机设置,设置从机地址为0xC0,然后在发送前会点亮LED1,发送如下数据

    uint8_t u8TxData[10] = {0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};

    发送完成后关闭LED1,最后进入while 1。

    从机代码

    1. //通道端口配置
    2. Gpio_SetFunc_UART1TX_P35();
    3. Gpio_SetFunc_UART1RX_P36();
    4. //外设时钟使能
    5. Clk_SetPeripheralGate(ClkPeripheralBt, TRUE);
    6. Clk_SetPeripheralGate(ClkPeripheralUart1, TRUE);
    7. stcUartIrqCb.pfnRxIrqCb = NULL;
    8. stcUartIrqCb.pfnTxIrqCb = NULL;
    9. stcUartIrqCb.pfnRxErrIrqCb = NULL;
    10. stcConfig.pstcIrqCb = &stcUartIrqCb;
    11. stcConfig.bTouchNvic = FALSE;
    12. #if 1 //多主机模式测试
    13. stcConfig.enRunMode = UartMode3;
    14. stcMulti.enMulti_mode = UartMulti;
    15. stcMulti.u8SlaveAddr = 0xc0; //从机地址配置
    16. stcMulti.u8SaddEn = 0xff; // 0x7f;//
    17. enTb8 = Addr;
    18. Uart_SetMMDOrCk(UARTCH1, enTb8);
    19. stcConfig.pstcMultiMode = &stcMulti;
    20. stcBaud.bDbaud = 0u;
    21. stcBaud.u32Baud = 2400u;
    22. stcBaud.u8Mode = UartMode3; //计算波特率需要模式参数
    23. pclk = Clk_GetPClkFreq();
    24. timer = Uart_SetBaudRate(UARTCH1, pclk, &stcBaud);
    25. stcBtConfig.enMD = BtMode2;
    26. stcBtConfig.enCT = BtTimer;
    27. Bt_Init(TIM1, &stcBtConfig); //调用basetimer1设置函数产生波特率
    28. Bt_ARRSet(TIM1, timer);
    29. Bt_Cnt16Set(TIM1, timer);
    30. Bt_Run(TIM1);
    31. #endif
    32. Uart_Init(UARTCH1, &stcConfig);
    33. Uart_ClrStatus(UARTCH1, UartRxFull); //清所有接收完成标志
    34. Uart_EnableFunc(UARTCH1, UartRx);
    35. while (0 == Uart_GetStatus(UARTCH1, UartRxFull))
    36. ;
    37. Uart_ClrStatus(UARTCH1, UartRxFull);
    38. if (1 == Uart_GetRb8(UARTCH1)) //只有此处配置后,后续的数据方可正确接收
    39. {
    40. stcMulti.enMulti_mode = UartNormal;
    41. Uart_SetMultiMode(UARTCH1, &stcMulti);
    42. }
    43. u8SlaveAddr = Uart_ReceiveData(UARTCH1);
    44. while (i < 10) {
    45. while (0 == Uart_GetStatus(UARTCH1, UartRxFull))
    46. ;
    47. Uart_ClrStatus(UARTCH1, UartRxFull);
    48. u8RxData[i++] = Uart_ReceiveData(UARTCH1);
    49. }
    50. for (i = 0; i < 10; i++) {
    51. if (u8RxData[i] != u8TxData[i]) {
    52. Gpio_SetIO(2, 3, 0);
    53. Gpio_SetIO(1, 4, 1);
    54. break;
    55. } else {
    56. Gpio_SetIO(2, 3, 1);
    57. Gpio_SetIO(1, 4, 0);
    58. }
    59. }

    首先将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.

    如果使用多机通讯时,在硬件设计上需要考虑带载能力,是否需要上拉电阻,和通讯速率高的时候需要阻抗匹配问题。

  • 相关阅读:
    设计模式——建造者模式
    主机探测
    R语言编写用户自定义函数:处理可能出错的代码、遇到错误继续处理而不停止代码运行
    python+django社区医院诊所医疗管理系统_6t4o8
    三层交换机的工作原理
    华为机试真题 C++ 实现【We Are A Team】
    Redis 主从复制,哨兵,集群——(1)主从复制篇
    海格里斯HEGERLS工程项目案例|陕西西安某新能源电池制造集团企业三期自放电立体库工程项目安装过程
    1381:城市路(Dijkstra)
    ESP32网络开发实例-Web服务器RGB LED调光
  • 原文地址:https://blog.csdn.net/andylauren/article/details/126097019