文章目录
一、UART串口协议简介;
串口协议(UART)是一种异步串行通信协议 ,仅需TX(发送)、RX(接收)和GND(地线)三根线即可实现全双工通信。通信连线示意图如下所示:

UART核心特征是"异步 ",即没有独立的时钟线 ,收发双方需事先约定相同的波特率(如9600、57600、115200)来同步每位数据 。数据传输以一帧为单位:空闲时总线为高电平,发一个低电平起始位通知对方开始,随后依次发送5-9位数据(通常最低位在前 ),可选添加一位校验位用于简单检错,最后以1或2位高电平停止位结束。由于协议简单、接线少,串口被广泛用于单片机与传感器、GPS模块、蓝牙模块及电脑调试之间的通信。UART时序图如下所示:

二、CS32ME10串口模块使用;
2.1.UART普通输出模式;
设置好串口在主循环里轮询发送数据,可以用逻辑分析仪抓取验证。
CS32ME10串口模块配置步骤:
1、打开IO端口和串口时钟;
2、配置IO口的输入输出方向;
3、使能IO复用为串口功能;
4、配置串口模块(CS32ME10芯片默认串口输出使能);
c
/* 普通串口输出测试*/
uint8_t uart_data[]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};
void uart_send_test(void)
{
uint8_t count = 0;
UART_InitTypeDef uart0_initstruct;
/*打开端口和外设时钟*/
Rcc_Periph_config(RCC_Periph_GPIOA|RCC_Periph_UART0, ENABLE);
/*配置TX,RX的方向*/
Gpio_out_config(GPIOA_MODULE, GPIO_PIN_7, ENABLE);//TX
Gpio_in_config(GPIOA_MODULE, GPIO_PIN_6, ENABLE);//RX
/*配置IO口的复用功能*/
Gpio_af_uart_config(GPIOA_MODULE, GPIO_PIN_6|GPIO_PIN_7, ENABLE);
/*配置串口*/
uart0_initstruct.UART_BaudRate = 115200;
uart0_initstruct.UART_Mode = UART_Mode_RXTX;
uart0_initstruct.UART_Parity = UART_Parity_Odd;
uart0_initstruct.UART_StopBits = UART_Stop_bit1;
uart0_initstruct.UART_WordLength= UART_WorldLength_bit8;
Uart_Init(UART0_MODULE, &uart0_initstruct);
/*发送数据*/
while(1)
{
for(count=0;count<10;count++)
{
while(Uart_Get_Status(UART0_MODULE,UART_FLAG_TFF)){} //等待发送完成
Uart_SendData(UART0_MODULE, uart_data[count]); //发送数据
}
delay_ms(50); //50ms发送一次
}
}
2.2.UART重定向至printf输出;
通过配置串口模块重定向至printf,可以直接使用c库函数的printf输出字符,可以通过串口助手验证。
CS32ME10串口模块配置步骤:
1、打开IO端口和串口时钟;
2、配置IO口的输入输出方向(;
3、使能IO复用为串口功能;
4、配置串口模块;
5、重定向printf函数;
7、记得使用keil自带的微库
c
/* printf打印测试*/
void uart_printf_test(void)
{
UART_InitTypeDef uart0_initstruct;
/*打开端口和外设时钟*/
Rcc_Periph_config(RCC_Periph_GPIOA|RCC_Periph_UART0, ENABLE);
/*配置TX,RX的方向*/
Gpio_out_config(GPIOA_MODULE, GPIO_PIN_7, ENABLE);//TX
Gpio_in_config(GPIOA_MODULE, GPIO_PIN_6, ENABLE);//RX
/*配置IO口的复用功能*/
Gpio_af_uart_config(GPIOA_MODULE, GPIO_PIN_6|GPIO_PIN_7, ENABLE);
/*配置串口*/
uart0_initstruct.UART_BaudRate = 115200;
uart0_initstruct.UART_Mode = UART_Mode_RXTX;
uart0_initstruct.UART_Parity = UART_Parity_Odd;
uart0_initstruct.UART_StopBits = UART_Stop_bit1;
uart0_initstruct.UART_WordLength= UART_WorldLength_bit8;
Uart_Init(UART0_MODULE, &uart0_initstruct);
while(1)
{
printf("hello world \r\n");
delay_ms(500);
}
}
/*串口重定向*/
int fputc(int ch,FILE *f)
{
Uart_SendData(UART0_MODULE,(unsigned char)ch);
while(Uart_Get_Status(UART0_MODULE,UART_FLAG_TFF)){} //等待发送完成
return (ch);
}
2.3.UART中断接收串口数据;
通过串口助手或者别的芯片发送数据到CS32ME10,ME10在中断接收后通过printf打印出来(在实际项目中最好不要在中断中使用printf)。
CS32ME10串口模块配置步骤:
1、打开IO端口和串口时钟;
2、配置IO口的输入输出方向(因为串口总是要输入输出);
3、使能IO复用为串口功能;
4、配置串口模块(华润的芯片默认就是串口输出使能);
5、开启串口接收中断并编程中断处理函数;
7、设置串口对应中断的优先级;
8、使能中断;
c
void uart_int_receive_XCOM_data(void)
{
UART_InitTypeDef uart0_initstruct;
/*打开端口和外设时钟*/
Rcc_Periph_config(RCC_Periph_GPIOA|RCC_Periph_UART0, ENABLE);
/*配置TX,RX的方向*/
Gpio_out_config(GPIOA_MODULE, GPIO_PIN_7, ENABLE);//TX
Gpio_in_config(GPIOA_MODULE, GPIO_PIN_6, ENABLE);//RX
/*配置IO口的复用功能*/
Gpio_af_uart_config(GPIOA_MODULE, GPIO_PIN_6|GPIO_PIN_7, ENABLE);
/*配置串口*/
uart0_initstruct.UART_BaudRate = 115200;
uart0_initstruct.UART_Mode = UART_Mode_RXTX;
uart0_initstruct.UART_Parity = UART_Parity_Odd;
uart0_initstruct.UART_StopBits = UART_Stop_bit1;
uart0_initstruct.UART_WordLength= UART_WorldLength_bit8;
Uart_Init(UART0_MODULE, &uart0_initstruct);
/*打开串口接收中断*/
Uart_interrupt_config(UART0_MODULE,UART_IT_RFNE,ENABLE);
/*设置串口中断优先级*/
NVIC_SetPriority(UART0_IRQn, 2);
/*使能串口中断*/
NVIC_EnableIRQ(UART0_IRQn);
//.....具体处理过程见中断处理函数
while(1)
{
}
}
/**
* @name :UART0_IRQHandler
* @功能 :UART0中断服务函数
* @param :无
* @retval: 无
*/
void UART0_IRQHandler(void)
{
uint8_t a;
if(Uart_Get_Status(UART0_MODULE, UART_IT_RFNE)!=UART_IT_RFNE)
{
a = Uart_ReadData(UART0_MODULE);
printf("a=%x \r\n",a);
}
}
三、UART模块重构版库函数;
c
#include "me10_uart.h"
/**
* @name Uart_config
* @功能 :串口模块配置
* @param uart_module 需要配置的UART模块
@arg UART0_MODULE
@arg UART1_MODULE
* @param uart_initstruct
* @retval: 无
*/
void Uart_Init(UART_REG * uart_module, UART_InitTypeDef* uart_initstruct)
{
uint32_t reg_value = uart_module->UART_CR;
uint32_t DIV;
/* 计算波特率分频系数*/
#if SYSCLK_48MHZ
DIV = 48000000/uart_initstruct->UART_BaudRate;
#elif SYSCLK_24MHZ
DIV = 24000000/uart_initstruct->UART_BaudRate;
#elif SYSCLK_12MHZ
DIV = 12000000/uart_initstruct->UART_BaudRate;
#elif SYSCLK_6MHZ
DIV = 6000000/uart_initstruct->UART_BaudRate;
#endif
/* 获取串口的基本配置*/
reg_value = (uint32_t)( uart_initstruct->UART_Mode|\
uart_initstruct->UART_Parity|\
uart_initstruct->UART_StopBits|\
uart_initstruct->UART_WordLength);
/* 最终要写入寄存器的值*/
reg_value |= (DIV<<8);
/* 将配置信息写入寄存器*/
uart_module->UART_CR |= reg_value;
}
/**
* @name Uart_SendData
* @功能 :串口发送数据接口
* @param uart_module 需要发送数据的UART模块
@arg UART0_MODULE
@arg UART1_MODULE
* @param data 需要发送的数据
* @retval: 无
*/
void Uart_SendData(UART_REG * uart_module, uint8_t data)
{
uart_module->UART_DO = data;
}
/**
* @name Uart_ReadData
* @功能 :串口读取数据接口
* @param uart_module 需要读取数据的UART模块
@arg UART0_MODULE
@arg UART1_MODULE
* @retval: ret_value 返回读出的数据
*/
uint8_t Uart_ReadData(UART_REG * uart_module)
{
uint8_t ret_value;
ret_value = uart_module->UART_DI;
return ret_value;
}
/**
* @name Uart_Get_Status
* @功能 :获取串口状态(由用户去判断何种状态是否发生)
* @param uart_module 需要获取状态的UART模块
@arg UART0_MODULE
@arg UART1_MODULE
* @param uart_flag 需要获取的状态
@arg UART_FLAG_RBSY ((uint32_t)0x00000001) //接收忙标识, 1 表示正在接收
@arg UART_FLAG_TBSY ((uint32_t)0x00000002) //发送忙标识, 1 表示正在发送
@arg UART_FLAG_RFF ((uint32_t)0x00000004) //接收 FIFO 满标识, 1 表示满
@arg UART_FLAG_TFF ((uint32_t)0x00000008) //发送 FIFO 满标识, 1 表示满
@arg UART_FLAG_TFE ((uint32_t)0x00000010) //发送 FIFO 空标识, 1 表示空
@arg UART_IT_PE ((uint32_t)0x01000000) //校验错中断标志位,1:表示校验出错 写"0"清零
@arg UART_IT_ROV ((uint32_t)0x02000000) //接收 FIFO 溢出中断标志位,1:表示接收 FIFO 溢出, 写"0"清零
@arg UART_IT_RFNE ((uint32_t)0x04000000) //接收到数据中断标志位,"1"表示空,"0"表示有接收到数据,数据读完自动恢复 1
@arg UART_IT_TC ((uint32_t)0x08000000) //数据发送完成 中断标志位 (每发送完一个 数据 产生中断),"1"表示 一个数据发送已经完成,写"0"清零
@arg UART_IT_TFE ((uint32_t)0x10000000) //TXFIFO空中断标志位,1:表示 TXFIFO 空 ,写入数据后自动清零
@arg UART_IT_RFF ((uint32_t)0x20000000) //RXFIFO满中断标志位,1:表
* @retval: ret_value 返回对应状态的bit值,由用户判断状态是否发生
*/
uint32_t Uart_Get_Status(UART_REG * uart_module, uint32_t uart_flag)
{
uint32_t ret_value;
ret_value = uart_module->UART_SR & uart_flag;
return ret_value;
}
/**
* @name Uart_interrupt_config
* @功能 :设置相应的串口中断是否开启
* @param uart_module 需要设置中断的UART模块
@arg UART0_MODULE
@arg UART1_MODULE
* @param uart_it 需要设屏蔽或者开启的中断
@arg UART_IT_PE ((uint32_t)0x01000000) //校验错中断标志位,1:表示校验出错 写"0"清零
@arg UART_IT_ROV ((uint32_t)0x02000000) //接收 FIFO 溢出中断标志位,1:表示接收 FIFO 溢出, 写"0"清零
@arg UART_IT_RFNE ((uint32_t)0x04000000) //接收到数据中断标志位,"1"表示空,"0"表示有接收到数据,数据读完自动恢复 1
@arg UART_IT_TC ((uint32_t)0x08000000) //数据发送完成 中断标志位 (每发送完一个 数据 产生中断),"1"表示 一个数据发送已经完成,写"0"清零
@arg UART_IT_TFE ((uint32_t)0x10000000) //TXFIFO空中断标志位,1:表示 TXFIFO 空 ,写入数据后自动清零
@arg UART_IT_RFF ((uint32_t)0x20000000) //RXFIFO满中断标志位,1:表
* @param: flag
@arg ENABLE 开启
@arg DISABLE 屏蔽
*/
void Uart_interrupt_config(UART_REG * uart_module, uint32_t uart_it , FunctionalState flag)
{
if(flag)
{
uart_module->UART_CR |= uart_it; //开启相应的中断
}
else
{
uart_module->UART_CR &= (~uart_it); //屏蔽相应的中断
}
}
*此教程仅记录个人使用过程,仅供参考学习,且本教程使用的库函数均为重构的版本,不代表官方文档,谢谢!