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);
		
	}
}