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

程序目的:

        实现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 TXGPIO_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 RXGPIO_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;                                          //波特率设置为115200USART_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 TXGPIO_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 RXGPIO_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;                                          //波特率设置为115200USART_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 headervoid 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_Hvoid 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字符同理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/575629.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云4核8G服务器价格,12M带宽一年646元,送3个月

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

快速上手Spring Cloud五:Spring Cloud与持续集成/持续部署(CI/CD)

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

前端的拖拽序列(drag)

html和css代码如下 <style>.item {width: 200px;height: 50px;background: rgb(15, 226, 219);margin: 10px 0;padding-left: 20px;border-radius: 10px;line-height: 50px;}.item.move {background: transparent;color: transparent;border: 1px dashed #ccc;}</sty…

如何创建纯净版Django项目并启动?——让Django更加简洁

目录 1. Django的基本目录结构 2. 创建APP 2.1 创建app 2.2 配置文件介绍 3. 迁移数据库文件 3.2 连接数据库 3.1 创建迁移文件 3.2 同步数据库 4. 纯净版Django创建 4.1 剔除APP 4.2 剔除中间件 4.3 剔除模板引擎 5. 最终 1. Django的基本目录结构 在我们创建Django项…

Web框架开发-Django中间件

一、中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。 Django的中间件的定义: Middleware is a framework of hooks into Dj…

实现DevOps需要什么?

实现DevOps需要什么&#xff1f; 硬性要求&#xff1a;工具上的准备 上文提到了工具链的打通&#xff0c;那么工具自然就需要做好准备。现将工具类型及对应的不完全列举整理如下&#xff1a; 代码管理&#xff08;SCM&#xff09;&#xff1a;GitHub、GitLab、BitBucket、SubV…

设计模式之外观模式解析

外观模式 1&#xff09;概述 1.问题 在软件开发中&#xff0c;为完成一项较为复杂的功能&#xff0c;一个客户类需要和多个业务类交互&#xff0c;而这些需要交互的业务类经常会作为一个整体出现&#xff0c;由于涉及到的类比较多&#xff0c;导致使用时代码较为复杂。 2.作…

【IntelliJ IDEA】运行测试报错解决方案(附图)

IntelliJ IDEA 版本 2023.3.4 (Ultimate Edition) 测试报错信息 命令行过长。 通过 JAR 清单或通过类路径文件缩短命令行&#xff0c;然后重新运行 解决方案 修改运行配置&#xff0c;里面如果没有缩短命令行&#xff0c;需要再修改选项里面勾选缩短命令行让其显示&#x…

springboot+vue在idea上面的使用小结

1.在mac上面删除java的jdk方法&#xff1a; sudo rm -rfjdk的路径 sudo rm -rf /Users/like/Library/Java/JavaVirtualMachines/corretto-17.0.10/Contents/Home 2.查询 Mac的jdk版本和路径&#xff1a; /usr/libexec/java_home -V 3.mac上面查询和关闭idea的网页端口&…

什么是RISC-V?开源 ISA 如何重塑未来的处理器设计

RISC-V代表了处理器架构的范式转变&#xff0c;特点是其开源模型简化了设计理念并促进了全球community-driven的开发。RISC-V导致了处理器技术发展前进方式的重大转变&#xff0c;提供了一个不受传统复杂性阻碍的全新视角。 RISC-V起源于加州大学伯克利分校的学术起点&#xff…

是德科技安捷伦 E5052B信号源分析仪

181/2461/8938产品概述&#xff1a; Keysight E5052B&#xff08;安捷伦&#xff09;信号源分析仪&#xff0c;10 MHz 至 7 GHz&#xff0c;具有许多增强的性能特性。它在表征 VCO 或其他类型的高频信号源以及高速数据通信系统中的时钟抖动评估方面提供了世界上最高的测量吞吐…

Github万星项目lobe-chat,连接GPT4GPTs,平替chatgpt-plus

简介 Lobe Chat - 一个开源、高性能的聊天机器人框架&#xff0c;支持语音合成、多模态和可扩展的函数调用插件系统。支持一键免费部署您的私人 ChatGPT/LLM Web 应用程序。 项目地址&#xff1a; GitHub - lobehub/lobe-chat: &#x1f92f; Lobe Chat - an open-source, mo…