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例程的主要内容,如果未能解决你的问题,请参考以下文章

CMT2380F32模块开发13-低功耗同步异步收发器例程

CMT2380F32模块开发13-低功耗同步异步收发器例程

CMT2380F32模块开发3-GPIO例程

CMT2380F32模块开发3-GPIO例程

CMT2380F32模块开发5-CLK例程

CMT2380F32模块开发5-CLK例程