CH573-06-串口通信——RISC-V内核BLE MCU快速开发教程

在这里插入图片描述

1.简介

  ch573提供了 4 组全双工的异步串口,UART0/1/2/3。支持全双工和半双工串口通讯,其中 UART0提供发送状态引脚用于切换 RS485,并且支持 MODEM 调制解调器信号 CTS、DSR、DTR、RTS。对应的引脚分别为:
  串口0:
在这里插入图片描述

  串口1:
在这里插入图片描述
在这里插入图片描述

  串口2:
在这里插入图片描述

  串口3:
在这里插入图片描述

2. 新建工程

复制并粘贴“CH573_01_led”工程,并重命名为“CH573_06_UART”。


3. 串口0初始化与串口收发

 1) 精简代码

将与串口无关的LED相关程序删除,如下所示:


 2) 串口初始化

  首先配置IO口模式:

    /* 配置串口0:先配置IO口模式,再配置串口 */
    GPIOB_SetBits(GPIO_Pin_7);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);      // RXD0-配置上拉输入
    GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA); // TXD0-配置推挽输出,注意先让IO口输出高电

  然后调用串口初始化:

    UART0_DefInit();  //初始化默认配置,波特率115200

  最后配置串口中断:

    //配置串口0中断接收模式
    UART0_ByteTrigCfg(UART_7BYTE_TRIG);
    UART0_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART0_IRQn);

  3) 串口接收中断函数

      首先声明串口收发数据缓冲区:

uint8_t Tx0Buff[] = "Hello by UART0 --- FUNIOT.XYZ!\r\n";
uint8_t Rx0Buff[100];

      在main.c的最后重写串口接收中断函数:

/*********************************************************************
 * @fn      UART0_IRQHandler
 *
 * @brief   UART0中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART0_IRQHandler(void)
{
    
    
    volatile uint8_t i;
    if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
    {
    
    
        i = UART0_RecvString(Rx0Buff);   //接收数据并记录长度
        UART0_SendString(Rx0Buff, i);    //将接收的数据串口发送
        //自行数据解析

    }
}

  4) 主函数中串口定时发送

    while(1)
    {
    
    
        UART0_SendString(Tx0Buff, sizeof(Tx0Buff));
        DelayMs(2000);
    }

  5) main.c完整内容

/********************************** (C) COPYRIGHT *******************************
 * File Name          : Main.c
 * Author             : FUNIOT.XYZ
 * Version            : V1.0
 * Date               : 2023/05/21
 * Description        : 实验06-UART
 * Copyright          : WeChat official accounts "IOT趣制作"
 * SPDX-License-Identifier: Apache-2.0
 *******************************************************************************/

#include "CH57x_common.h"
uint8_t Tx0Buff[] = "Hello by UART0 --- FUNIOT.XYZ!\r\n";
uint8_t Rx0Buff[100];

/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main()
{
    
    
    SetSysClock(CLK_SOURCE_PLL_60MHz);

    /********************************串口0初始化********************************/
    /* 配置串口0:先配置IO口模式,再配置串口 */
    GPIOB_SetBits(GPIO_Pin_7);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);      // RXD0-配置上拉输入
    GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA); // TXD0-配置推挽输出,注意先让IO口输出高电
    UART0_DefInit();  //初始化默认配置,波特率115200
    //配置串口0中断接收模式
    UART0_ByteTrigCfg(UART_7BYTE_TRIG);
    UART0_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART0_IRQn);

    while(1)
    {
    
    
        UART0_SendString(Tx0Buff, sizeof(Tx0Buff));
        DelayMs(2000);
    }
}
/*********************************************************************
 * @fn      UART0_IRQHandler
 *
 * @brief   UART0中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART0_IRQHandler(void)
{
    
    
    volatile uint8_t i;
    if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
    {
    
    
        i = UART0_RecvString(Rx0Buff);   //接收数据并记录长度
        UART0_SendString(Rx0Buff, i);    //将接收的数据串口发送
        //自行数据解析

    }
}

4. 其他串口初始化与串口收发

  1) 参与编译

      在使用串口时,首先需要保证相关的C文件是否参与编译,例如在使用串口2和串口3时需要手动添加编译,大家根据实际需要选择参与/排除:
在这里插入图片描述

  2) 串口1初始化与串口收发

      由于沁恒官方为我们做好了相关的函数封装,我们可以对串口0初始化相关的程序进行非常简单的修改,以实现其他串口的使用,例如串口1,具体得区别如下图所示:
在这里插入图片描述

    /********************************串口1初始化********************************/
    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD1-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD1-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();    //初始化默认配置,波特率115200
    //配置串口1中断接收模式
    UART1_ByteTrigCfg(UART_7BYTE_TRIG);
    UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART1_IRQn);

      中断函数区别:
在这里插入图片描述

/*********************************************************************
 * @fn      UART1_IRQHandler

 * @brief   UART1中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler(void)
{
    
    
    volatile uint8_t i;
    if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
    {
    
    
        i = UART1_RecvString(Rx1Buff);   //接收数据并记录长度
        UART1_SendString(Rx1Buff, i);    //将接收的数据串口发送
        //自行数据解析

    }
}

      另外在主函数中补充串口1的定时发送:

        UART1_SendString(Tx1Buff, sizeof(Tx1Buff));
        DelayMs(1500);

5. PRINT

   我们也可以通过printf重定义实现使用printf完成串口数据发送,在完成串口1的初始化后,我们可以直接使用PRINT函数,例如:

        PRINT("Debug %s\r\n",Tx1Buff);

6. main.c完整内容

/********************************** (C) COPYRIGHT *******************************
 * File Name          : Main.c
 * Author             : FUNIOT.XYZ
 * Version            : V1.0
 * Date               : 2023/05/26
 * Description        : 实验06-UART
 * Copyright          : WeChat official accounts "IOT趣制作"
 * SPDX-License-Identifier: Apache-2.0
 *******************************************************************************/

#include "CH57x_common.h"
uint8_t Tx0Buff[] = "Hello by UART0 --- FUNIOT.XYZ!\r\n";
uint8_t Rx0Buff[100];
uint8_t Tx1Buff[] = "Hello by UART1 --- FUNIOT.XYZ!\r\n";
uint8_t Rx1Buff[100];
/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main()
{
    
    
    SetSysClock(CLK_SOURCE_PLL_60MHz);

    /********************************串口0初始化********************************/
    /* 配置串口0:先配置IO口模式,再配置串口 */
    GPIOB_SetBits(GPIO_Pin_7);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);      // RXD0-配置上拉输入
    GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA); // TXD0-配置推挽输出,注意先让IO口输出高电
    UART0_DefInit();  //初始化默认配置,波特率115200
    //配置串口0中断接收模式
    UART0_ByteTrigCfg(UART_7BYTE_TRIG);
    UART0_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART0_IRQn);
    /*************************************************************************/

    /********************************串口1初始化********************************/
    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD1-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD1-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();    //初始化默认配置,波特率115200
    //配置串口1中断接收模式
    UART1_ByteTrigCfg(UART_7BYTE_TRIG);
    UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART1_IRQn);
    while(1)
    {
    
    
        UART0_SendString(Tx0Buff, sizeof(Tx0Buff));
        DelayMs(1500);
        UART1_SendString(Tx1Buff, sizeof(Tx1Buff));
        DelayMs(1500);
        PRINT("Debug %s\r\n",Tx1Buff);
        DelayMs(1500);
    }
}
/*********************************************************************
 * @fn      UART0_IRQHandler
 *
 * @brief   UART0中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART0_IRQHandler(void)
{
    
    
    volatile uint8_t i;
    if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
    {
    
    
        i = UART0_RecvString(Rx0Buff);   //接收数据并记录长度
        UART0_SendString(Rx0Buff, i);    //将接收的数据串口发送
        //自行数据解析

    }
}
/*********************************************************************
 * @fn      UART1_IRQHandler

 * @brief   UART1中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler(void)
{
    
    
    volatile uint8_t i;
    if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
    {
    
    
        i = UART1_RecvString(Rx1Buff);   //接收数据并记录长度
        UART1_SendString(Rx1Buff, i);    //将接收的数据串口发送
        //自行数据解析

    }
}

7. 编译烧录运行

   程序烧录完成后需要手动复位一次或者重新上电,另外这里还需要额外注意的是,如果使用了串口2,则在下载时,需要将RST引脚取消使能,因为RST引脚为PB23,也是TXD2引脚,如下图:
在这里插入图片描述

    现象1:使用USB-TTL连接串口0引脚PB7(TXD0)\PB4(RXD0),然后打开串口助手,波特率设置为115200,打开串口,复位ch573,可以在串口中发现ch573定时发送的数据,然后向ch573发送数据“hello,too”,ch573接收后会将接收到的数据返回发送,如下图:
在这里插入图片描述
   现象2:使用USB-TTL连接串口1引脚PA8(RXD1)\PA9(TXD1),然后打开串口助手,波特率设置为115200,打开串口,复位ch573,可以在串口中发现ch573定时发送的数据,一个是串口函数发送,一个是PRINT函数发送;然后向ch573发送数据“hello,too”,ch573接收后会将接收到的数据返回发送,如下图:

在这里插入图片描述


    如果串口0和串口1的数据收发如上面的最后两张截图所示,即达到本实验的目的,如果异常,请检查源代码,如有疑问可关注公众号 “IOT趣制作”,将您遇到的问题描述出来,平台收到您的留言后会第一时间进行解决。

猜你喜欢

转载自blog.csdn.net/weixin_43351158/article/details/131141669