STM32F103VE共有5个串口功能,其中USART1,USART2,USART3为通用同步异步串口通信,UART4,UART5为通用异步串口通信
为了方便地初时化串口,定义一个串口初时化结构体变量,假定一些参数相同,简化结构里的成员个数,如有需要则要在结构体增加相应的参数,结构体定义如下:
typedef struct
{
uint16_t tx_pin; /*!< 串口TX脚*/
uint16_t rx_pin; /*!< 串口RX脚*/
uint32_t APB1_clock; /*!< APB1时钟,如为0xffffffff则不初时化此时钟*/
uint32_t APB2_clock; /*!< APB2时钟*/
uint32_t baudrate; /*!< 串口波特率*/
uint32_t NVIC_PriorityGroup; /*!< NVIC优先级分组*/
uint32_t NVIC_IRQChannelPreemptionPriority; /*!< 抢占优先级*/
uint32_t NVIC_IRQChannelSubPriority; /*!< 子优先级*/
GPIO_TypeDef * TX_PORT; /*!< 串口TX引脚IO指针*/
GPIO_TypeDef * RX_PORT; /*!< 串口RX引脚IO指针*/
USART_TypeDef *UART; /*!< 串口指针*/
IRQn_Type IRQn; /*!< 串口中断号*/
}USART_UART_INIT_T;
分别定义5组串口初时化变量
/*----------串口USART1-----------------------------*/
const USART_UART_INIT_T g_usart1 = {
.tx_pin = GPIO_Pin_9,
.rx_pin = GPIO_Pin_10,
.APB1_clock = 0xffffffff,
.APB2_clock = RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA,
.baudrate = 9600,
.NVIC_PriorityGroup = NVIC_PriorityGroup_2,
.NVIC_IRQChannelPreemptionPriority = 3,
.NVIC_IRQChannelSubPriority = 3,
.TX_PORT = GPIOA,
.RX_PORT = GPIOA,
.UART = USART1,
.IRQn = USART1_IRQn,
};
/*----------串口USART2-----------------------------*/
const USART_UART_INIT_T g_usart2 = {
.tx_pin = GPIO_Pin_2,
.rx_pin = GPIO_Pin_3,
.APB1_clock = RCC_APB1Periph_USART2,
.APB2_clock = RCC_APB2Periph_GPIOA,
.baudrate = 9600,
.NVIC_PriorityGroup = NVIC_PriorityGroup_2,
.NVIC_IRQChannelPreemptionPriority = 3,
.NVIC_IRQChannelSubPriority = 3,
.TX_PORT = GPIOA,
.RX_PORT = GPIOA,
.UART = USART2,
.IRQn = USART2_IRQn,
};
/*----------串口USART3-----------------------------*/
const USART_UART_INIT_T g_usart3 = {
.tx_pin = GPIO_Pin_10,
.rx_pin = GPIO_Pin_11,
.APB1_clock = RCC_APB1Periph_USART3,
.APB2_clock = RCC_APB2Periph_GPIOB,
.baudrate = 9600,
.NVIC_PriorityGroup = NVIC_PriorityGroup_2,
.NVIC_IRQChannelPreemptionPriority = 3,
.NVIC_IRQChannelSubPriority = 3,
.TX_PORT = GPIOB,
.UART = USART3,
.RX_PORT = GPIOB,
.IRQn = USART3_IRQn,
};
/*----------串口UART4-----------------------------*/
const USART_UART_INIT_T g_uart4 = {
.tx_pin = GPIO_Pin_10,
.rx_pin = GPIO_Pin_11,
.APB1_clock = RCC_APB1Periph_UART4,
.APB2_clock = RCC_APB2Periph_GPIOC,
.baudrate = 9600,
.NVIC_PriorityGroup = NVIC_PriorityGroup_2,
.NVIC_IRQChannelPreemptionPriority = 3,
.NVIC_IRQChannelSubPriority = 3,
.TX_PORT = GPIOC,
.RX_PORT = GPIOC,
.UART = UART4,
.IRQn = UART4_IRQn,
};
/*----------串口UART5-----------------------------*/
const USART_UART_INIT_T g_uart5 = {
.tx_pin = GPIO_Pin_12,
.rx_pin = GPIO_Pin_2,
.APB1_clock = RCC_APB1Periph_UART5,
.APB2_clock = RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,
.baudrate = 9600,
.NVIC_PriorityGroup = NVIC_PriorityGroup_2,
.NVIC_IRQChannelPreemptionPriority = 3,
.NVIC_IRQChannelSubPriority = 3,
.TX_PORT = GPIOC,
.RX_PORT = GPIOD,
.UART = UART5,
.IRQn = UART5_IRQn,
};
简单演示5个串口的通信功能,定义一个通用的数据结构
typedef struct
{
uint8_t rxBuf[23]; // RX接收数据缓冲
uint8_t rxLen; // RX接收娄据长度
}UART_DATA_INFO;
定义5个串个功能变量
UART_DATA_INFO uart1Data;
UART_DATA_INFO uart2Data;
UART_DATA_INFO uart3Data;
UART_DATA_INFO uart4Data;
UART_DATA_INFO uart5Data;
定义一个通能串口接收处理函数,在串口中断内调用
void receiveUartData(USART_TypeDef *uart,UART_DATA_INFO *dat)
{
/* 暂存接收结果 */
uint8_t result;
ITStatus status = USART_GetITStatus(uart,USART_IT_RXNE);
result = USART_ReceiveData(uart);
/* 检查是否为USART1接收中断 */
if(status != RESET)
{
if(dat->rxLen < 20)
{
dat->rxBuf[dat->rxLen] = result;
dat->rxLen++;
}
}
/* 溢出发生时,先读SR,再读DR,解决中断不进入问题*/
else if(USART_GetFlagStatus(uart,USART_IT_ORE) == SET)
{
USART_ReceiveData(uart);
}
}
为了演示收到的数据,定义一个通用将接收到的串口数据原样返回函数,每20个字符回传一次
void replyData(USART_TypeDef *uart,UART_DATA_INFO *dat)
{
if(dat->rxLen >= 20)
{
USART_Send_Data(uart,dat->rxBuf,20);
dat->rxLen = 0;
}
}
初时化串口通用函数
/**
* @brief USART1~3,UART4,UART5串口初时化
*
*
* @param USART_UART_INIT_T *uart_params[in]:串口相关参数
* @retval None
*/
void uart_init(const USART_UART_INIT_T * uart_params)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 初时化串口前,先将相应的时钟打开 */
RCC_APB2PeriphClockCmd(uart_params->APB2_clock,ENABLE);
if(uart_params->APB1_clock != 0xffffffff)
{
RCC_APB1PeriphClockCmd(uart_params->APB1_clock,ENABLE);
}
/* 初时化USART1 TX 引脚设为复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = uart_params->tx_pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(uart_params->TX_PORT,&GPIO_InitStructure);
/* 初时化USART1 RX 引脚为浮空输入 */
GPIO_InitStructure.GPIO_Pin = uart_params->rx_pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(uart_params->RX_PORT,&GPIO_InitStructure);
/* USART1 NVIC初时化 */
NVIC_PriorityGroupConfig(uart_params->NVIC_PriorityGroup); /*!< 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 0-3; */
NVIC_InitStructure.NVIC_IRQChannel = uart_params->IRQn; /*!< USART1中断通道USART1_IRQn */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = uart_params->NVIC_IRQChannelPreemptionPriority; /*!< 抢占优先级3 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = uart_params->NVIC_IRQChannelSubPriority; /*!< 子优先级3 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*!< IRQ使能通道 */
NVIC_Init(&NVIC_InitStructure); /*!< 初时化NVIC寄存器 */
/* USART1初时化设置 */
USART_InitStructure.USART_BaudRate = uart_params->baudrate; /*!< 设置波特率 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; /*!< 8位数据*/
USART_InitStructure.USART_StopBits = USART_StopBits_1; /*!< 1位停止位 */
USART_InitStructure.USART_Parity = USART_Parity_No; /*!< 无校验位 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /*!< 收发模式*/
USART_Init(uart_params->UART,&USART_InitStructure); /*!< 初时化串口1 */
/* 开启串口1接收中断 */
USART_ITConfig(uart_params->UART,USART_IT_RXNE,ENABLE);
/* 使能串口1 */
USART_Cmd(uart_params->UART,ENABLE);
}
串口发送函数
/**
* @brief USART串口发送函数
*
*
* @param uint8_t *buf[in]:待发送的数据buffer
* @param uint16_t len:发送的数据长度
* @retval None
*/
void USART_Send_Data(USART_TypeDef *usart, uint8_t *buf,uint16_t len)
{
for(uint16_t i = 0; i<len; i++)
{
while(USART_GetFlagStatus(usart,USART_FLAG_TXE)==RESET); /*!< 是否可以写数据到发送寄存器*/
USART_SendData(usart,buf[i]);
while(USART_GetFlagStatus(usart,USART_FLAG_TC)==RESET); /*!<发送是否完成*/
}
}
实现5个串口中断函数
/**
* @brief USART1串口中断函数
*
*
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
receiveUartData(USART1,&uart1Data);
}
/**
* @brief USART2串口中断函数
*
*
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
receiveUartData(USART2,&uart2Data);
}
/**
* @brief USART3串口中断函数
*
*
* @param None
* @retval None
*/
void USART3_IRQHandler(void)
{
receiveUartData(USART3,&uart3Data);
}
/**
* @brief UART4串口中断函数
*
*
* @param None
* @retval None
*/
void UART4_IRQHandler(void)
{
receiveUartData(UART4,&uart4Data);
}
/**
* @brief UART5串口中断函数
*
*
* @param None
* @retval None
*/
void UART5_IRQHandler(void)
{
receiveUartData(UART5,&uart5Data);
}
最后主函数中测试5个串口功能
/**
* @brief 主函数,程序的入口
*
*
* @param None
* @retval int:不用理会,对于嵌入式系统,永远都不会返回
*/
int main(void)
{
uart_init(&g_usart1);
uart_init(&g_usart2);
uart_init(&g_usart3);
uart_init(&g_uart4);
uart_init(&g_uart5);
USART_Send_Data(USART1,(uint8_t *)"usart 1\n",8);
USART_Send_Data(USART2,(uint8_t *)"usart 2\n",8);
USART_Send_Data(USART3,(uint8_t *)"usart 3\n",8);
USART_Send_Data(UART4,(uint8_t *)"usart 4\n",8);
USART_Send_Data(UART5,(uint8_t *)"usart 5\n",8);
// assert_param(0);
for(;;)
{
replyData(USART1,&uart1Data);
replyData(USART2,&uart2Data);
replyData(USART3,&uart3Data);
replyData(UART4,&uart4Data);
replyData(UART5,&uart5Data);
}
}