STM32实现三个串口同时开启发送接收数据

avatar
作者
筋斗云
阅读量:0

程序目的:

        实现STM32开通三个串口,每个串口都可以实现接收和发送数据。

注意事项:

        编程时,严禁在中断函数中写入发送串口数据代码,否则会出错,具体原因不清楚(有大佬知道的话帮我指出),可能原因是DR寄存器冲突导致。

开始编程:

Serial.c

#include "stm32f10x.h"                  // Device header #include <stdio.h> //#include "OLED.h" //#include "Delay.h" #include <stdarg.h> char Serial_RxPacket1[100]; char Serial_RxPacket2[100]; uint8_t Serial_RxFlag1; uint8_t Serial_RxFlag2; uint8_t Serial_RxFlag3; void Serial_Init(USART_TypeDef *USARTx) { 	 	GPIO_InitTypeDef GPIO_Init_Structure;                            //定义GPIO结构体     USART_InitTypeDef USART_Init_Structure;                          //定义串口结构体 	NVIC_InitTypeDef  NVIC_Init_Structure;							 //定义中断结构体  	if(USARTx == USART1){ 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,  ENABLE);              //开启GPIOA时钟 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);            	//开启APB2总线复用时钟 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,  ENABLE);         	//开启USART1时钟 		 		GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_AF_PP;				//复用推挽输出 		GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_9; 		GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz; 		GPIO_Init(GPIOA, &GPIO_Init_Structure); 		 		GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_IPU;					//浮空输入或者上拉输入,使用上拉输入抗干扰能力更强 		GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_10; 		GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz; 		 		USART_Init_Structure.USART_BaudRate = 115200;					//波特率 		USART_Init_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(不使用,CTS,CTS&RTS) 		USART_Init_Structure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;	//串口模式 可以使用(或)|符号实现Tx和Rx同时设置 		USART_Init_Structure.USART_Parity = USART_Parity_No;				//校验位,无需校验 		USART_Init_Structure.USART_StopBits = USART_StopBits_1;				//停止位,选择1位 		USART_Init_Structure.USART_WordLength = USART_WordLength_8b;		//字长 		USART_Init(USART1, &USART_Init_Structure); 		 		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);						//开启RXNE到NVIC的输出,开启中断 		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 		 		NVIC_Init_Structure.NVIC_IRQChannel = USART1_IRQn; 		NVIC_Init_Structure.NVIC_IRQChannelCmd = ENABLE; 		NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority = 1; 		NVIC_Init_Structure.NVIC_IRQChannelSubPriority = 1; 		NVIC_Init(&NVIC_Init_Structure); 	} 	if(USARTx == USART2) { 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,  ENABLE);           //开启GPIOA时钟 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);            //开启APB2总线复用时钟 		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,  ENABLE);          //开启USART1时钟 		 		//配置PA2 TX 		GPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_AF_PP;                //复用推挽 		GPIO_Init_Structure.GPIO_Pin   = GPIO_Pin_2; 		GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_10MHz; 		 		GPIO_Init(GPIOA, &GPIO_Init_Structure); 		 		//配置PA3 RX 		GPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_IPU;          		GPIO_Init_Structure.GPIO_Pin   = GPIO_Pin_3; 		GPIO_Init(GPIOA, &GPIO_Init_Structure); 			 		USART_Init_Structure.USART_BaudRate = 115200;                                          //波特率设置为115200 		USART_Init_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;       //硬件流控制为无 		USART_Init_Structure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                       //模式设为收和发 		USART_Init_Structure.USART_Parity = USART_Parity_No;                                   //无校验位 		USART_Init_Structure.USART_StopBits = USART_StopBits_1;                                //一位停止位 		USART_Init_Structure.USART_WordLength = USART_WordLength_8b;                           //字长为8位   		USART_Init(USART2, &USART_Init_Structure);   		USART_Cmd(USART2, ENABLE); 			 		USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); 		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 		 		NVIC_Init_Structure.NVIC_IRQChannel 			=   USART2_IRQn; 		NVIC_Init_Structure.NVIC_IRQChannelCmd   	=   ENABLE; 		NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority  =  1; 		NVIC_Init_Structure.NVIC_IRQChannelSubPriority         =  1; 		NVIC_Init(&NVIC_Init_Structure); 	} 	if(USARTx == USART3) { 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,  ENABLE);                 //开启GPIOA时钟 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);            	   //开启APB2总线复用时钟 		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,  ENABLE);          	   //开启USART1时钟 		 		//配置PB10 TX 		GPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_AF_PP;                	   //复用推挽 		GPIO_Init_Structure.GPIO_Pin   = GPIO_Pin_10; 		GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_10MHz; 		GPIO_Init( GPIOB, &GPIO_Init_Structure); 		//配置PB11 RX 		GPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; 		GPIO_Init_Structure.GPIO_Pin   = GPIO_Pin_11; 		GPIO_Init( GPIOB, &GPIO_Init_Structure); 		 		USART_Init_Structure.USART_BaudRate = 115200;                                          //波特率设置为115200 		USART_Init_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;       //硬件流控制为无 		USART_Init_Structure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                       //模式设为收和发 		USART_Init_Structure.USART_Parity = USART_Parity_No;                                   //无校验位 		USART_Init_Structure.USART_StopBits = USART_StopBits_1;                                //一位停止位 		USART_Init_Structure.USART_WordLength = USART_WordLength_8b;                           //字长为8位    		USART_Init(USART3, &USART_Init_Structure);    		USART_Cmd(USART3, ENABLE); 			 		USART_ITConfig(USART3,USART_IT_RXNE,ENABLE); 		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 		 		NVIC_Init_Structure.NVIC_IRQChannel 				   = USART3_IRQn; 		NVIC_Init_Structure.NVIC_IRQChannelCmd				   = ENABLE; 		NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority  = 1; 		NVIC_Init_Structure.NVIC_IRQChannelSubPriority         = 1; 		NVIC_Init(&NVIC_Init_Structure); 	} } void Serial_SendByte(USART_TypeDef *USARTx,uint8_t Byte) { 	USART_SendData(USARTx, Byte);//发送数据 	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET) {//等待发送寄存器空, 		//TXE就是发送寄存器空的标志位,不需要手动清零,下一次发送数据时候会自动清零 	} } void Serial_SendArray(USART_TypeDef *USARTx, uint8_t *Array, uint16_t Length){ 	uint16_t i; 	for(int i = 0; i < Length; i++) { 		Serial_SendByte(USARTx, Array[i]); 	}  } void Serial_SendString(USART_TypeDef *USARTx, char *Str) {//字符串自带结束标志位 	uint8_t i; 	for(int i = 0; Str[i] != '\0'; i++) { 		Serial_SendByte(USARTx, Str[i]); 	} }  //*****************************************发送数字 uint32_t Serial_Pow(uint32_t X, uint32_t y) { 	uint32_t Result = 1; 	while(y--) { 		Result *= X; 	} 	return Result; } void Serial_SendNumber(USART_TypeDef *USARTx, uint32_t Number, uint8_t Length) { 	uint8_t i; 	for(int i = 0; i < Length; i++){ 		Serial_SendByte(USARTx, (Number / Serial_Pow(10, Length - i - 1)) % 10 + '0'); 	}  } //*****************************************发送数字  int fputc(int ch, FILE* f){ 	Serial_SendByte(USART1, ch);//重定向到串口1,使得Printf打印到串口 	return ch;  } //使用sprintf让其他的串口也能使用,sprintf可以把格式化字符输出到一个字符串里 void Serial_Printf(USART_TypeDef *USARTx, char* format,...){ 	char String[100]; 	va_list arg; 	va_start(arg, format); 	vsprintf(String, format, arg); 	va_end(arg); 	Serial_SendString(USARTx,String); }  uint8_t Serial_GetRxFlag(USART_TypeDef *USARTx) { 	if(USARTx == USART1) { 		if(Serial_RxFlag1 == 1){ 			Serial_RxFlag1 = 0; 			return 1; 		} 	} 	else if(USARTx == USART2) { 		if(Serial_RxFlag2 == 1){ 			Serial_RxFlag2 = 0; 			return 1; 		} 	} 	else if(USARTx == USART3) { 		if(Serial_RxFlag3 == 1){ 			Serial_RxFlag3 = 0; 			return 1; 		} 	} 	return 0; } void Serial_SendPacket(USART_TypeDef *USARTx){  }  void USART1_IRQHandler() { 	static uint8_t RxState = 0;//类似全局变量,函数进入只会初始化一次0,函数退出仍然有效,与全局函数不同,静态变量只能在本函数中使用 	static uint8_t pRxPacket = 0; 	char temp; 	//Serial_SendString(USART1,"Led Open Successful\r\n"); 	//Delay_ms(1000); 	if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET) 	{ 		uint8_t RxData = USART_ReceiveData(USART1); 		if(RxState == 0){ 		//若在这里将RxState置为1,那么下面就会立马执行,因此要加上else,也可用switch case语句 			if(RxData == '@') { 				RxState = 1; 				pRxPacket = 0; 			} 		} 		else if(RxState == 1) { 			if(RxData == '\r'){ 				RxState = 2; 			} 			else { 				Serial_RxPacket1[pRxPacket] = RxData; 				pRxPacket ++; 			} 		} 		else if(RxState ==  2){ 			if(RxData == '\n') { 				RxState = 0; 				Serial_RxFlag1 = 1; 				Serial_RxPacket1[pRxPacket] = '\0';//不加不能使用OLED_ShowString 			} 		} 		USART_ClearITPendingBit(USART1, USART_IT_RXNE); 	} } void USART2_IRQHandler() { 	static uint8_t RxState = 0;//类似全局变量,函数进入只会初始化一次0,函数退出仍然有效,与全局函数不同,静态变量只能在本函数中使用 	static uint8_t pRxPacket = 0; 	char temp; 	//Serial_SendString(USART2,"Led Open Successful\r\n"); 	//Delay_ms(10); 	if(USART_GetITStatus(USART2,USART_IT_RXNE)!= RESET) 	{ 		uint8_t RxData = USART_ReceiveData(USART2); 		if(RxState == 0){ 		//若在这里将RxState置为1,那么下面就会立马执行,因此要加上else,也可用switch case语句 			if(RxData == '@') { 				RxState = 1; 				pRxPacket = 0; 			} 		} 		else if(RxState == 1) { 			if(RxData == '\r'){ 				RxState = 2; 			} 			else { 				Serial_RxPacket2[pRxPacket] = RxData; 				pRxPacket ++; 			} 		} 		else if(RxState ==  2){ 			if(RxData == '\n') { 				RxState = 0; 				Serial_RxFlag2 = 1; 				Serial_RxPacket2[pRxPacket] = '\0';//不加不能使用OLED_ShowString 			} 		} 		USART_ClearITPendingBit(USART2, USART_IT_RXNE); 	} } void USART3_IRQHandler(void) { 	char temp; 	if(USART_GetITStatus(USART3,USART_IT_RXNE)!= RESET) 	{ 		temp = USART_ReceiveData(USART3); 		if(temp == 'O') 		{ 			GPIO_ResetBits(GPIOC,GPIO_Pin_13); 			Serial_SendString(USART3,"Led Open Successful\r\n");		 		} 		if(temp == 'C') 		{ 			GPIO_SetBits(GPIOC,GPIO_Pin_13); 			Serial_SendString(USART3,"Led Close Successful\r\n"); 		} 	} }

Serial.h

#ifndef __SERIAL_H #define __SERIAL_H #include <stdio.h> extern char Serial_RxPacket1[]; extern char Serial_RxPacket2[]; void Serial_Init(USART_TypeDef *USARTx); void Serial_SendByte(USART_TypeDef *USARTx,uint8_t Byte); void Serial_SendArray(USART_TypeDef *USARTx,uint8_t *Array, uint16_t Length); void Serial_SendString(USART_TypeDef *USARTx,char *String); void Serial_SendNumber(USART_TypeDef *USARTx,uint32_t Number, uint8_t Length); void Serial_Printf(USART_TypeDef *USARTx,char* format,...); uint8_t Serial_GetRxFlag(USART_TypeDef *USARTx);   #endif 

GpioControl.c

#include "stm32f10x.h"                  // Device header  void GpioInit(GPIO_TypeDef *GPIOx, uint16_t Pin, GPIOMode_TypeDef GpioMode){ 	uint32_t RCC_APB2Periph_GPIOx; 	if(GPIOx == GPIOA) { 		RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOA; 	} 	else if(GPIOx == GPIOB) { 		RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOB; 	} 	else if(GPIOx == GPIOC) { 		RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOC; 	} 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);//ctrl + Alt + 空格:可以出现代码提示 	GPIO_InitTypeDef GPIO_InitStructure; 	GPIO_InitStructure.GPIO_Mode = GpioMode;//推挽输出 	GPIO_InitStructure.GPIO_Pin = Pin; 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 	GPIO_Init(GPIOx, &GPIO_InitStructure); 	GPIO_ResetBits(GPIOx, Pin); } void GpioTurn(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN) {//反转当前引脚状态 	if(GPIO_ReadOutputDataBit(GPIOx,GPIO_PIN) == 0){ 		GPIO_SetBits(GPIOx,GPIO_PIN); 	} 	else{ 		GPIO_ResetBits(GPIOx, GPIO_PIN); 	} } void GpioControl(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN, uint8_t sign) {//控制引脚 	if(sign == ENABLE){ 		GPIO_SetBits(GPIOx, GPIO_PIN); 	} 	if(sign == DISABLE){ 		GPIO_ResetBits(GPIOx, GPIO_PIN); 	} } 

GpioControl.h

#ifndef __GPIOCONTROL_H #define __GPIOCONTROL_H  void GpioInit(GPIO_TypeDef *GPIOx, uint16_t Pin, GPIOMode_TypeDef GpioMode); void GpioTurn(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN); void GpioControl(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN, uint8_t sign);  #endif 

main.c

#include "stm32f10x.h"                  // Device header //#include "DELAY.h" //#include "OLED.h" #include "Serial.h" //#include "DigitalSwitch.h" #include "GpioControl.h" #include <string.h> uint8_t RxData; uint8_t KeyNum;  int main() { 	GpioInit(GPIOC, GPIO_Pin_13, GPIO_Mode_Out_PP); 	GPIO_SetBits(GPIOC,GPIO_Pin_13); //	DigitalSwitchInit(GPIOA, GPIO_Pin_1, GPIO_Mode_IPU); 	OLED_Init(); 	Serial_Init(USART1); 	Serial_Init(USART2); 	Serial_Init(USART3);  	//OLED_ShowString(1, 1, "TxData:"); 	//OLED_ShowString(3, 1, "RxData:");  	while(1){ 		 		if(Serial_GetRxFlag(USART1) == 1) { 			if(strcmp(Serial_RxPacket1, "LED_ON") == 0) { 				GPIO_ResetBits(GPIOC,GPIO_Pin_13); 				Serial_SendString(USART1,Serial_RxPacket1); 			} 			else if(strcmp(Serial_RxPacket1, "LED_OFF") == 0) { 				GPIO_SetBits(GPIOC,GPIO_Pin_13); 				Serial_SendString(USART1,Serial_RxPacket1); 			} 		} 		if(Serial_GetRxFlag(USART2) == 1) { 			if(strcmp(Serial_RxPacket2, "LED_ON") == 0) { 				GPIO_ResetBits(GPIOC,GPIO_Pin_13); 				Serial_SendString(USART2,Serial_RxPacket2); 			} 			else if(strcmp(Serial_RxPacket2, "LED_OFF") == 0) { 				GPIO_SetBits(GPIOC,GPIO_Pin_13); 				Serial_SendString(USART2,Serial_RxPacket2); 			} 		} 		 	} } 

程序现象:

        RX,TX连接到A9,A10使用串口1,使用串口工具发送@LED_ON指令(记得发送时候按下回车,将\n也发送出去),串口回传LED_ON,同时LED灯被打开,发送LED_OFF同理。

        RX,TX连接到A2,A3使用串口2,使用串口工具发送@LED_ON指令(记得发送时候按下回车,将\n也发送出去),串口回传LED_ON,同时LED灯被打开,发送LED_OFF同理。

        RX,TX连接到B10,B11使用串口3,使用串口工具发送O字符,串口回传Led Open Successful\r\n,同时LED灯被打开,发送C字符同理。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!