ch573提供了 4 组全双工的异步串口,UART0/1/2/3。支持全双工和半双工串口通讯,其中 UART0提供发送状态引脚用于切换 RS485,并且支持 MODEM 调制解调器信号 CTS、DSR、DTR、RTS。对应的引脚分别为:
串口0:
复制并粘贴“CH573_01_led”工程,并重命名为“CH573_06_UART”。
将与串口无关的LED相关程序删除,如下所示:
首先配置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);
首先声明串口收发数据缓冲区:
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); //将接收的数据串口发送
//自行数据解析
}
}
while(1)
{
UART0_SendString(Tx0Buff, sizeof(Tx0Buff));
DelayMs(2000);
}
/********************************** (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); //将接收的数据串口发送
//自行数据解析
}
}
在使用串口时,首先需要保证相关的C文件是否参与编译,例如在使用串口2和串口3时需要手动添加编译,大家根据实际需要选择参与/排除:
由于沁恒官方为我们做好了相关的函数封装,我们可以对串口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);
我们也可以通过printf重定义实现使用printf完成串口数据发送,在完成串口1的初始化后,我们可以直接使用PRINT函数,例如:
PRINT("Debug %s\r\n",Tx1Buff);
/********************************** (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); //将接收的数据串口发送
//自行数据解析
}
}
程序烧录完成后需要手动复位一次或者重新上电,另外这里还需要额外注意的是,如果使用了串口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接收后会将接收到的数据返回发送,如下图: