程序目的:
实现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字符同理。文章来源:https://www.toymoban.com/news/detail-850123.html
文章来源地址https://www.toymoban.com/news/detail-850123.html
到了这里,关于STM32实现三个串口同时开启发送接收数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!