当前位置: 首页 > news >正文

STM32串口通信—串口的接收和发送详解

目录

前言:

STM32串口通信基础知识:

1,STM32里的串口通信

2,串口的发送和接收

串口发送:

串口接收:

串口在STM32中的配置:

1. RCC开启USART、串口TX/RX所对应的GPIO口

2. 初始化GPIO口

3. 串口初始化

4. 串口使能

5. 串口发送数据

串口接收的两种实现方式:

1,轮询方式:

2,中断方式:

查询RXNE标志位

 使用中断

实战演练:

1. 初始化LED灯相应的GPIO口

2. 初始化USART3

3. 实现发送功能

4. 实现接收字符串功能

1,通过轮询的方式检查是否接收到了特定的字符串:

2,通过中断的方式实现USART3接收特定的字符串:

1. 配置NVIC以使能USART3中断

2. 在USART3初始化函数中开启接收中断

3. 编写USART3的中断服务函数来处理接收到的字节

5. 主函数

总结:


前言:

本文在于记录自己最近做项目过程中遇到的问题和总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重,本文主要对串口的发送和接受做了一个详细的总结和规划,同时也对串口通信做一个简要的总结。

STM32串口通信基础知识:

1,STM32里的串口通信

在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输并行数据,是全双工异步时钟控制,设备之间是点对点的传输。对应的STM32引脚分别是RX和TX端。STM32的串口资源有USART1、USART2、USART3.

串口的几个重要的参数:

  • 波特率,串口通信的速率
  • 空闲,一般为高电平
  • 起始位,标志一个数据帧的开始,固定为低电平。当数据开始发送时,产生一个下降沿。(空闲–>起始位)
  • 数据位,发送数据帧,1为高电平,0为低电平。低位先行。
    比如 发送数据帧0x0F 在数据帧里就是低位线性 即 1111 0000
  • 校验位,用于数据验证,根据数据位的计算得来。有奇校验,偶校验和无校验。
  • 停止位,用于数据的间隔,固定为高电平。数据帧发送完成后,产生一个上升沿。(数据传输–>停止位)

下方就是一个字节数据的传输过程,从图中可以看出,串口发送的数据一般都是以数据帧的形式进行传输,每个数据帧都由起始位,数据位,停止位组成, 且停止位可变。

2,串口的发送和接收

USART是STM32内部集成的硬件外设,可以根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可以自动接收RX引脚的数据帧时序,拼接成一个字节数据,存放在数据寄存器里。

当配置好USART的电路之后,直接读取数据寄存器,就可以自动发送数据和接收数据了。在发送和接收的模块有4个重要的寄存器

  • 发送数据寄存器TDR
  • 发送移位寄存器,把一个字节的数据一位一位的移出去
  • 接收数据寄存器RDR
  • 接收移位寄存器,把一个字节的数据

下方为串口的发送和接收图解:

串口发送:

在配置串口的各个参数时,可以选择发送数据帧的数据位的大小,可选8位或9位。

串口发送数据实际上就是对发送数据寄存器TDR进行写操作

1. 当串口发送数据时,会检测发送移位寄存器是不是有数据正在移位,如果没有移位,那么这个数据就会立刻转移到发送移位寄存器里。准备发送。

2. 当数据移动到移位寄存器时,会产生一个TXE发送寄存器空标志位,该位描述如下。当TXE被置1,那么就可以在TDR写入下一个数据了。即发送下一个数据。

3. 发送移位寄存器在发送器控制的控制下,向右移位,一位一位的把数据传输到TX引脚。

4. 数据移位完成后,新的数据就会再次从TDR转移到发送移位寄存器里来,依次重复1-3的过程。通过读取TXE标志位来判断是否发送下一个数据。

串口接收:
  1. 数据从RX引脚通向接收移位寄存器,在接收控制的控制下,一位一位的读取RX的电平,把第一位放在最高位,然后右移,移位八次之后就可以接收一个字节了。
  2. 当一个字节数据移位完成之后,这一个字节的数据就会整体的移到接收数据寄存器RDR里来。
  3. 在转移时会置RXNE接收标志位,即RDR寄存器非空,下方为该位的描述。当被置1后,就说明数据可以被读出

下图即为串口接收的工作流程

串口在STM32中的配置:

1. RCC开启USART、串口TX/RX所对应的GPIO口

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);  //开启USART2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //开启GPIOA的时钟

2. 初始化GPIO口

这里注意哈,根据自己的需求来配置GPIO口,发送和接收是都需要还是只需要其中一个。然后对应的根据引脚定义表来初始化对应的GPIO口。

USART3对应的引脚

USART2对应的引脚

USART1对应的引脚

这里根据手册来看,RX引脚模式配置成浮空输入或者上拉输入。TX引脚模式配置成复用推挽输出。

    GPIO_InitTypeDef GPIO_InitStructure;// USART3 TX -> PB10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);   // USART3 RX -> PB11GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);

3. 串口初始化

注意哈,USART_Init()这个函数,是用来配置串口的相关参数的。

  • USART_BaudRate 串口通信使用的波特率 一般是9600或者是115200,这里我们给9600
  • USART_HardwareFlowControl 是否选择硬件流触发,一般这个我们也不选,所以选择无硬件流触发。
  • USART_Mode 这个参数要注意了哈,串口的模式,发送模式还是接收模式,还是两者都有,这里使用收发模式
  • USART_Parity 校验位,可以选择奇偶校验和不校验。没有需求就直接无校验
  • USART_StopBits 停止位 有1、0.5、2位,我们这里选1位停止位
  • USART_WordLength 数据位 有8位和9位可以选择
 //串口初始化USART_InitTypeDef USART_InitStruct;USART_StructInit(&USART_InitStruct);  //初始默认值USART_InitStruct.USART_BaudRate=9600;USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;   //不使用硬件流触发USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;	//收发模式(TX 发送模式  RX 接收模式)   			USART_InitStruct.USART_Parity=USART_Parity_No;   		//不选择校验USART_InitStruct.USART_StopBits=USART_StopBits_1;  		//停止位1位USART_InitStruct.USART_WordLength=USART_WordLength_8b;	//数据位8位USART_Init(USART3,&USART_InitStruct);

4. 串口使能

//串口使能USART_Cmd(USART3,ENABLE);

5. 串口发送数据

注意哈,我们要判断TXE标志位的状态。0,数据还没有被转移到移位寄存器;1,数据已经被转移到移位寄存器。当TXE标志位为1时,就说明可以发送下一个数据了。详细过程可看上面串口发送的解释。

//串口3发送一个字节
void Usart3_SendByte(u8 val)
{USART_SendData(USART3, val);//0 表示数据还未转移到移位寄存器 循环等待 1 数据已经被转移到了移位寄存器可以发送数据while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);	//等待发送完成,不需要手动清零 再次写入TDR时会自动清零	
}

经过上述五步的配置,单片机就可以通过串口发送数据了。

串口接收的两种实现方式:

串口接收通常可以通过轮询(Polling)中断(Interrupt)两种方式来实现。

  • 轮询方式就是通过不断的查询RXNE标志位,通过判断RXNE位的状态来确定数据是否接收。
  • 中断方式就是通过配置接收输出控制通道,配置NVIC,在中断服务子函数里进行数据的接收。

1,轮询方式

在轮询方式中,程序通过不断地查询串口接收缓冲区是否有数据到达。当检测到数据到达时,程序立即读取接收缓冲区中的数据。

优点:

  • 实现简单,易于理解。
  • 可以直接在接收到数据后立即进行处理。
  • 适合于数据传输量不大且CPU负荷较轻的场合。

缺点:

  • 需要不断地轮询串口接收缓冲区,占用 CPU 资源。
  • 无法及时响应其他任务或事件。
  • 效率较低,可能会错过一些数据。

实现步骤:
配置串口:设置串口的波特率、数据位数、停止位等参数。
轮询状态寄存器:不断检查USART的状态寄存器,判断接收缓冲区是否有新数据。
读取数据:一旦发现有新数据,立即从数据寄存器读取数据。 

示例代码:

// 定义一个函数,用于轮询方式接收 USART 数据
void USART_Receive_Polling(void) {// 进入一个无限循环while(1) {// 检查接收缓冲区是否有数据if(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == SET) {// 如果接收缓冲区有数据// 从接收缓冲区读取数据uint8_t data = USART_ReceiveData(USART3);// 处理接收到的数据// 这里可以添加代码来解析和处理接收到的数据}// 如果接收缓冲区无数据,则继续轮询// 可以添加延时以降低 CPU 占用率// delay_ms(10);}
}

2,中断方式

在中断方式中,程序允许 MCU 在接收到数据时触发串口接收中断,并在中断服务函数中处理接收到的数据。当接收缓冲区有新数据时,硬件自动产生一个中断,CPU响应这个中断并执行中断服务程序来处理接收到的数据。

优点:

  • 采用了中断机制,不需要不断地轮询串口接收缓冲区,减少了 CPU 的占用率。
  • 效率高,可以及时响应其他任务或事件,提高了系统的实时性。
  • 适合于数据量大或实时性要求高的应用

缺点:

  • 实现相对复杂,需要编写中断服务函数。
  • 在中断服务函数中对数据的处理需要考虑中断嵌套、优先级等问题,需要谨慎设计。

实现步骤:
配置串口:同轮询方式。
使能中断:在串口初始化中,使能USART的接收中断。
编写中断服务程序:实现USART的中断服务函数,该函数会在接收到新数据时被调用。
数据处理:在中断服务程序中读取接收到的数据,并进行相应的处理。

示例代码:

// USART3中断处理函数
void USART3_IRQHandler(void) {// 检查 USART3 接收中断标志位是否被设置if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {// 如果接收缓冲区非空// 从接收缓冲区读取数据uint8_t data = USART_ReceiveData(USART3);// 处理接收到的数据// 在这里可以添加代码来处理接收到的数据}
}// 使 USART3 接收中断
void USART_Receive_Interrupt(void) {// 使能串口接收中断USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);// 配置 USART3 中断优先级NVIC_InitTypeDef NVIC_InitStructure;// 设置中断通道为 USART3NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;// 设置中断抢占优先级为0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 设置中断响应优先级为0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;// 使能中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;// 初始化 NVICNVIC_Init(&NVIC_InitStructure);// 进入一个无限循环,等待中断服务函数处理接收到的数据while(1) {// 在中断服务函数中处理接收到的数据}
}

查询RXNE标志位

这里我们还是来看一看RXNE标志位的描述


上图描述,为0时数据没有收到,为1时收到了数据,数据可以从RDR里读出

所以在主程序里不断读取RXNE标志位,如果为1,表示数据可以读出

uint8_t RX_Data; // 定义一个全局变量 RX_Data,用于存储接收到的数据int main() // 主函数入口
{ Serial_Init(); // 初始化串口Serial_SendByte(0x16); // 向串口发送一个字节数据 0x16while(1) // 进入一个无限循环{if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET) // 检查 USART2 接收缓冲区是否有数据,0=RESET 循环等待 ,1=SET 可以接收数据{RX_Data = USART_ReceiveData(USART2); // 如果接收缓冲区有数据,则从中读取数据并存储到 RX_Data 中Serial_SendByte(RX_Data); // 将接收到的数据发送回串口}}
}

if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET)

// 检查 USART2 接收缓冲区是否有数据,0=RESET 循环等待 ,1=SET 可以接收数据

下图为程序现象:pc向单片机发送数据0x15,单片机接收数据0x15,并且把接收到的数据作为数据发送到pc,在pc上显示0x15。

 使用中断

  • 通过配置串口的接收作为中断源,开启中断输出控制,配置NVIC。开启中断通道。
// 开启 USART2 接收中断
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);// 配置 NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)// 设置 NVIC 分组优先级,选择分组 2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 定义一个 NVIC_InitTypeDef 结构体变量,用于配置中断控制器
NVIC_InitTypeDef NVIC_InitStruct;// 设置中断通道为 USART2,即选择 USART2 的中断通道
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;// 使能中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;// 设置抢占优先级为 1
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;// 设置子优先级为 1
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;// 将配置好的 NVIC_InitStruct 结构体变量传入 NVIC_Init 函数中,对 NVIC 进行配置
NVIC_Init(&NVIC_InitStruct);
  • 中断服务子函数
    中断服务子函数写好后,就可以在中断里读取接收到的数据了。
    当接收到数据后,触发接收中断,主程序暂停执行。接收完数据后主程序回复执行。当接收到数据时,就触发中断。
void USART2_IRQHandler(void)
{// 检查 USART2 接收缓冲区是否有数据if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)   // RXNE 标志位为1 表示可以接收数据{// 从接收缓冲区读取数据并存储到 RX_Data 中RX_Data = USART_ReceiveData(USART2);// 设置标志位 Flag 为 1,表示已接收到数据Flag = 1;// 清除 USART2 接收中断标志位 RXNEUSART_ClearITPendingBit(USART2, USART_IT_RXNE);  // 清除 RXNE 标志位}
}
  • 主程序测试

uint8_t RX_Data; // 定义一个全局变量 RX_Data,用于存储接收到的数据
uint8_t Flag;    // 定义一个全局变量 Flag,用于表示是否接收到数据的标志位int main() // 主函数入口
{Serial_Init(); // 初始化串口Serial_SendByte(0x16); // 向串口发送一个字节数据 0x16while(1) // 进入一个无限循环{if(Flag == 1) // 如果接收到数据的标志位为 1{Serial_SendByte(RX_Data); // 向串口发送接收到的数据,这里可以改为自己需要的逻辑}}
}void USART2_IRQHandler(void) // USART2 中断服务函数
{if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET) // 如果 USART2 接收到数据{RX_Data = USART_ReceiveData(USART2); // 从接收缓冲区读取数据并存储到 RX_Data 中Flag = 1; // 设置接收到数据的标志位 Flag 为 1USART_ClearITPendingBit(USART2, USART_IT_RXNE); // 清除 USART2 的接收中断标志位 RXNE,准备接收下一次数据}
}

下图为程序现象:可以看到,串口确实收到了数据,只是我把接收到的数据0xFE放在了while循环里,这说明数据接收是成功的,使用中断是可行的。

实战演练:

要求:使用stm32f103C8T6,使用标准库,硬件方面使用到了一个LED灯,要求在PC端串口助手发送"led on",单片机的usart3接收到PC端发送的led on时,打开LED灯,同时向PC端发送“已打开”

为了实现提出的要求,你需要按照以下步骤进行编程和硬件配置:

  1. 硬件连接

    • LED 灯连接到单片机的一个 GPIO 端口(比如 PA0)。
    • USART3 需要连接到 PC 通过串口或者通过串口转USB模块。
  2. 软件实现(使用STM32标准库)

以下提供一个粗略的实现示例:

首先,确保你已经在项目中正确配置了 STM32F103 的标准库,以及正确设置系统时钟。

1. 初始化LED灯相应的GPIO口

void LED_Init(void) {GPIO_InitTypeDef GPIO_InitStructure; // 定义一个 GPIO_InitTypeDef 结构体变量,用于配置 GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 开启 GPIOA 时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 设置要初始化的引脚为 PA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚工作模式为推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的输出速度为 50MHzGPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 GPIOA 的 PA0 引脚GPIO_SetBits(GPIOA, GPIO_Pin_0); // 将 PA0 引脚输出高电平,默认关闭 LED
}

2. 初始化USART3

void USART3_Init(void) {GPIO_InitTypeDef GPIO_InitStructure; // 定义一个 GPIO_InitTypeDef 结构体变量,用于配置 GPIOUSART_InitTypeDef USART_InitStructure; // 定义一个 USART_InitTypeDef 结构体变量,用于配置 USARTRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 打开 GPIOB 的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); // 打开 USART3 的时钟// 配置 USART3 的 TX 引脚为复用推挽输出模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // 设置要初始化的引脚为 PB10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 设置引脚工作模式为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的输出速度为 50MHzGPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIOB 的 PB10 引脚// 配置 USART3 的 RX 引脚为浮空输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // 设置要初始化的引脚为 PB11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置引脚工作模式为浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIOB 的 PB11 引脚// 配置 USART3 的通信参数USART_InitStructure.USART_BaudRate = 9600; // 设置波特率为 9600USART_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_HardwareFlowControl = USART_HardwareFlowControl_None; // 设置硬件流控制为无流控USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 设置 USART 的工作模式为接收和发送都使能USART_Init(USART3, &USART_InitStructure); // 初始化 USART3USART_Cmd(USART3, ENABLE); // 使能 USART3
}

3. 实现发送功能

void USART3_SendChar(char ch) {// 发送字符数据 ch 到 USART3USART_SendData(USART3, (uint8_t) ch);// 等待发送完成while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
}

4. 实现接收字符串功能

此部分可以通过中断或者轮询的方式实现。

1,通过轮询的方式检查是否接收到了特定的字符串:
void checkReceive(void) {uint8_t data; // 定义一个无符号 8 位整数型变量 data,用于存储接收到的数据char buffer[8]; // 定义一个长度为 8 的字符数组 buffer,用于存储接收到的数据int i = 0; // 定义一个整型变量 i,用于索引 buffer 数组// 进入一个循环,循环条件是 i 小于 7while (i < 7) {// 检查 USART3 接收缓冲区是否非空,即是否有数据可读if (USART_GetFlagStatus(USART3, USART_FLAG_RXNE) != RESET) {// 如果接收缓冲区非空,则读取接收到的数据并存储到 data 变量中data = (uint8_t)USART_ReceiveData(USART3);// 将读取到的数据存储到 buffer 数组中,并将索引 i 自增buffer[i++] = data;}}// 在 buffer 数组末尾添加字符串结束标志 '\0'buffer[i] = '\0';// 比较 buffer 数组中的内容是否为 "led on"if (strcmp(buffer, "led on") == 0) {// 如果接收到的数据是 "led on",则执行以下操作// 打开 LED 灯,即将 GPIOA 的 PA0 引脚输出低电平GPIO_ResetBits(GPIOA, GPIO_Pin_0);// 定义一个指向字符串常量 "已打开" 的指针 msgchar *msg = "已打开";// 进入一个循环,循环条件是指针 msg 指向的字符不为空字符 '\0'while (*msg) {// 发送指针 msg 指向的字符到 USART3,然后指针 msg 自增USART3_SendChar(*msg++);}}
}

注意:这里并没有添加中断服务程序,也没有实现字符缓存区的溢出处理,此外,发送和接收字符的精确处理逻辑可能需要根据实际需求调整。实际项目中还可能需要考虑debounce(消抖)和更加复杂的串口命令解析。

务必确保单片机的时钟配置正确,并且USART3的引脚与你连接的外设相匹配。在进行硬件连线时也要确保正确连接。

2,通过中断的方式实现USART3接收特定的字符串:

要通过中断方式实现USART3接收字符串,我们需要做几件事情:

  1. 配置NVIC以使能USART3中断
  2. 在USART3初始化函数中开启接收中断
  3. 编写USART3的中断服务函数来处理接收到的字节

这种实现方式相比轮询,可以有效减少CPU的负担,特别是在数据不频繁接收时。

1. 配置NVIC以使能USART3中断

USART3_Init函数中,初始化USART3后,你应该使能中断:

NVIC_InitTypeDef NVIC_InitStructure; // 定义一个 NVIC_InitTypeDef 结构体变量,用于配置 NVIC 中断控制器// 设置 NVIC 优先级分组为 2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断源为 USART3
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
// 设置抢占优先级为 1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 设置子优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
// 使能中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 初始化 NVIC
NVIC_Init(&NVIC_InitStructure);// 使能 USART3 接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
2. 在USART3初始化函数中开启接收中断

已经在上面的步骤中通过调用USART_ITConfig来实现了。

3. 编写USART3的中断服务函数来处理接收到的字节

你要定义一个缓冲区来存储接收到的字符,并在接收到整个字符串后进行处理:

#define BUFFER_SIZE 100 // 定义缓冲区大小为 100
char buffer[BUFFER_SIZE]; // 声明一个大小为 BUFFER_SIZE 的字符数组作为接收缓冲区
volatile unsigned int buffer_index = 0; // 声明一个无符号整数变量,用于表示当前缓冲区的索引位置,使用 volatile 关键字声明,表示在中断中可能被改变,需要及时更新void USART3_IRQHandler(void) { // 定义 USART3 的中断服务函数// 检查是否接收到数据if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) { // 如果接收到 USART3 的接收中断标志位char data = (char)USART_ReceiveData(USART3); // 读取接收到的数据,并转换为字符类型// 简单的字符串终止判断(例如以换行结束)if (data != '\n' && buffer_index < BUFFER_SIZE - 1) { // 如果接收到的字符不是换行且缓冲区索引未超过最大长度减一buffer[buffer_index++] = data; // 将接收到的字符存入缓冲区中,并更新索引} else { buffer[buffer_index] = '\0'; // 确保字符串结束,即在缓冲区最后添加 '\0' 表示字符串结束// 检查接收到的命令if (strcmp(buffer, "led on") == 0) { // 如果接收到的命令是 "led on"GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 点亮 LEDchar *msg = "已打开\n"; // 定义一个指向字符串的指针,表示要发送的消息while (*msg) { // 循环发送消息中的每一个字符,直到遇到 '\0' 表示字符串结束USART3_SendChar(*msg++); // 发送字符并将指针移向下一个字符}}// 重置索引,准备下一次接收buffer_index = 0; // 将缓冲区索引重置为 0,准备接收下一条命令}USART_ClearITPendingBit(USART3, USART_IT_RXNE); // 清除接收中断标志位,准备下一次接收中断}
}

这个示例代码会在接收到一串字符后处理这串字符。如果接收到的字符串是"led on"加上换行符'\n',它将点亮LED并通过USART3发送回"已打开\n"。

注意:实际上你可能需要添加更多的错误处理和缓冲区管理来处理可能出现的错误和异常情况(比如缓冲区溢出)。

此外,为了让上述代码正常工作,请确保你的USART3接收中断已经正确配置,并且你的系统时钟设置支持你的串口通信需求。你可能还需要根据你的具体硬件连接调整GPIO端口初始化和LED操作的代码。

5. 主函数

在主函数里初始化LED和USART3,然后不断检查串口接收:

int main(void) {SystemInit();  // 调用 SystemInit() 函数初始化系统时钟,这通常是启动代码中的一部分,用于初始化系统的时钟和基本的硬件设置。LED_Init();  // 调用 LED_Init() 函数初始化 LED,准备控制 LED 灯的状态。USART3_Init(); // 调用 USART3_Init() 函数初始化 USART3,配置 USART3 的通信参数和引脚连接等。while (1) {checkReceive(); // 循环调用 checkReceive() 函数,用于检查是否接收到特定命令,并根据接收到的命令执行相应的操作。}
}

总结:

本文大致总结了串口的发送和接收。

串口的配置,使用查询或者中断来接收数据。

串口的使用会很常用到,所以在这里对串口做一个总结,也算是对之前知识的一个回顾和总结,加强印象。

参考链接:

https://gitcode.csdn.net/65e6e6b81a836825ed787581.html?dp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MjgwNDA1NSwiZXhwIjoxNzEwNjEwNTI5LCJpYXQiOjE3MTAwMDU3MjksInVzZXJuYW1lIjoid2VpeGluXzUxMDI4NTg0In0.1Eac2jHw_Iz7Nc6l36BNEre9cCLz_gXA_Lz_OQnvtLc

相关文章:

STM32串口通信—串口的接收和发送详解

目录 前言&#xff1a; STM32串口通信基础知识&#xff1a; 1&#xff0c;STM32里的串口通信 2&#xff0c;串口的发送和接收 串口发送&#xff1a; 串口接收&#xff1a; 串口在STM32中的配置&#xff1a; 1. RCC开启USART、串口TX/RX所对应的GPIO口 2. 初始化GPIO口 …...

《汇编语言》第3版 (王爽) 第14章

第14章 端口 检测点14.1 &#xff08;1&#xff09;.编程&#xff0c;读取CMOS RAM的2号单元的内容。 mov al,2 ;向al写入2 out 70,al ;将2送入端口70h in al,71 ;从端口71h读取2号单元的内容在CMOS RAM中用6个字节存放当前时间&#xff08;以BCD码形式存放&#xff09;&…...

Axure原型设计项目效果 全国职业院校技能大赛物联网应用开发赛项项目原型设计题目

目录 前言 一、2022年任务书3效果图 二、2022年任务书5效果图 三、2022年国赛正式赛卷 四、2023年国赛第一套样题 五、2023年国赛第二套样题 六、2023年国赛第三套样题 七、2023年国赛第四套样题 八、2023年国赛第七套样题 九、2023年国赛正式赛题&#xff08;第八套…...

力扣串题:字符串中的第一个唯一字母

映射做法&#xff1a;将字母转为数字之类的转化必须在运算中实现如-a int firstUniqChar(char * s){int a[26] {0};int len strlen(s);int i;for (i 0; i < len; i)a[s[i] - a];for (i 0; i < len; i) {if (a[s[i] - a] 1)return i;}return -1; }...

【五、接口自动化测试】GET/POST 请求区别

大家好&#xff0c;我是山茶&#xff0c;一个探索AI 测试的程序员 在网上看到了许多关于post与get之间区别的帖子&#xff0c;也有很多帖子是直接粘贴复制的&#xff0c;甚至连标题、符号都没改&#xff0c;甚至还有很多争议 一、post、get 关于post与get之间区别&#xff0c;…...

HDOJ 2036

改革春风吹满地 Problem Description “ 改革春风吹满地, 不会AC没关系; 实在不行回老家&#xff0c; 还有一亩三分地。 谢谢!&#xff08;乐队奏乐&#xff09;” 话说部分学生心态极好&#xff0c;每天就知道游戏&#xff0c;这次考试如此简单的题目&#xff0c;也是云里雾…...

2.案例、鼠标时间类型、事件对象参数

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …...

OPENCV(0-1之0.0)

OPENCV 第1周&#xff1a;基础知识和安装目标内容 第2-3周&#xff1a;图像处理基础目标内容 第4-5周目标内容 第6-7周目标内容 第8周及以后目标内容 时间安排如下&#xff1a; 第1周&#xff1a;基础知识和安装 目标 了解计算机视觉的基本概念&#xff0c;安装OpenCV&#x…...

easyrecovery破解版百度云(含Mac/Win版)以及EasyRecovery可以恢复哪些设备

软件介绍 当不小心将回收站的文件删除了怎么办&#xff1f;想找回但是不知道怎么找回需要的数据文件&#xff1f;别担心今天小编就为大家介绍一款非常专业的电脑数据文件恢复工具&#xff0c;easyrecovery14是由Ontrack专为电脑用户推出的一款专业的数据恢复软件&…...

[2023年]-hadoop面试真题(一)

&#xff08;北京&#xff09;HDFS底层存储原理? (北京) HDFS读写数据流程? (北京) HDFS如何管理元数据或者checkpoint的理解 ? (北京) HDFS常用命令 ? (北京) hadoop调优 (北京) HDFS扩容原理 (北京) HDFS有哪些进程,分别是什么? (北京) HDFS中大量小文件对…...

Kubernetes kafka系列 | k8s部署kafka+zookeepe集群

一、kafka.zookeeper介绍 Kafka 简介&#xff1a; Apache Kafka 是一个开源的分布式流处理平台和消息队列系统。它最初由LinkedIn开发&#xff0c;并于2011年成为Apache软件基金会的顶级项目。 特点&#xff1a; 高吞吐量&#xff1a; Kafka 能够处理大规模的消息流&#xf…...

ip广播智慧工地广播喊话号角 IP网络号角在塔吊中应用 通过寻呼话筒预案广播

ip广播智慧工地广播喊话号角 IP网络号角在塔吊中应用 通过寻呼话筒预案广播 SV-704XT是深圳锐科达电子有限公司的一款壁挂式网络有源号角&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和号角喇叭输出播放&#xff0c;可达到功率50W。SV-704XT内置有…...

B端系统优化,可不是换个颜色和图标,看看与大厂系统的差距。

、不要被流于表面的需求描述迷惑。 很多人找我们优化系统界面&#xff0c;对需求总是轻描淡写&#xff0c;比如&#xff1a;换个颜色、换个图标、换个皮肤&#xff0c;甚至还有的说&#xff0c;随便改下就行。 这些需求都是听起来简单&#xff0c;实现起来难&#xff0c;你如…...

【LeetCode热题100】240. 搜索二维矩阵 II

一.题目要求 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 ‘每列的元素从上到下升序排列。 二.题目难度 中等 三.输入样例 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7…...

three.js 鼠标左右拖动改变玩家视角

这里主要用到了 一个方法 obj.getWorldDirection(); obj.getWorldDirection()表示的获取obj对象自身z轴正方向在世界坐标空间中的方向。 按下 W键前进运动&#xff1b; <template><div><el-container><el-main><div class"box-card-left…...

Pycharm jupyter server process exited with code 1

Pycharm jupyter server process exited with code 1 1. 问题描述2. 原因和解决方法 1. 问题描述 使用 Pycharm 启动 Jupyter 时&#xff0c;报错如下&#xff0c; jupyter server process exited with code 12. 原因和解决方法 Pycharm 启动 jupyter 时&#xff0c;默认的 …...

ubuntu 20.04 Python pip 配置 pip.conf

1. 状况描述 $ pip install timm WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connection broken by ProxyError(Cannot connect to proxy., RemoteDisconnected(Remote end closed connection without response)): /simple/t…...

GPT-4.5 Turbo意外曝光,最快明天发布?OpenAI终于要放大招了!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…...

Ubuntu 中 desktop-amd64 和 live-server-amd64 的区别

一、Ubuntu的操作系统镜像 Ubuntu的操作系统镜像主要有两种&#xff1a;desktop-amd64和live-server-amd64 这两者的主要区别在于使用场景和安装方式 1. Desktop-amd64: * 这是Ubuntu的桌面版本&#xff0c;用于安装具有图形用户界面的Ubuntu系统。 * 它包含了用于日常使…...

第10集《天台教观纲宗》

请大家打开讲义第十七页。我们讲到己二、结申正义。 己二、结申正义 《法华经》把我们修行人修行的相貌&#xff0c;比喻作一个车乘。车乘就是一种交通工具&#xff0c;它能够让我们从此岸超越到彼岸去。所以修行它是可以超越的&#xff0c;你今天比昨天超越了&#xff0c;就好…...

ch12 课堂参考代码 及 题目参考思路

课堂参考代码 Bellman-Ford 主要思路&#xff1a;对所有的边进行 n-1 轮松弛操作 单源最短路算法&#xff0c; O ( n m ) O(nm) O(nm) using ll long long; const int maxn 5010, maxm 5010; struct Edge {int u, v, w; } E[maxm]; // d[u]: 当前 s 到 u 的最短路 ll d[m…...

数据结构:导论

目录 什么是“第一性原理”&#xff1f; 什么是“数据结构”&#xff1f; 数据结构解决的根本问题是什么&#xff1f; 数据结构的两大分类 数据结构的基本操作 数据结构与算法的关系 学习数据结构的底层目标 什么是“第一性原理”&#xff1f; 在正式进入数据结构之前&…...

Python 训练营打卡 Day 30-模块和库的导入

模块和库的导入 1.1标准导入 import mathprint("方式1: 使用 import math") print(f"圆周率π的值: {math.pi}") print(f"2的平方根: {math.sqrt(2)}\n") 1.2从库中导入特定项 from math import pi, sqrtprint("方式2&#xff1a;使用 f…...

早发现=早安心!超导心磁图如何捕捉早期病变信号?

随着生活节奏的加快&#xff0c;心血管疾病已成为威胁人们健康的“隐形杀手”。据国家心血管病中心发布的《中国心血管健康与疾病报告2022》显示&#xff0c;我国心血管病现患者人数已高达3.3亿&#xff0c;每5例死亡中就有2例死于心血管病。这一数据触目惊心&#xff0c;提醒我…...

单细胞注释前沿:CASSIA——无参考、可解释、自动化细胞注释的大语言模型

细胞类型注释是单细胞RNA-seq分析的重要步骤&#xff0c;目前有许多注释方法。大多数注释方法都需要计算和特定领域专业知识的结合&#xff0c;而且经常产生不一致的结果&#xff0c;难以解释。大语言模型有可能在减少人工输入和提高准确性的同时扩大可访问性&#xff0c;但现有…...

使用animation.css库快速实现CSS3旋转动画效果

CSS3旋转动画效果实现&#xff08;使用Animate.css&#xff09; 下面我将展示如何使用Animate.css库快速实现各种CSS3旋转动画效果&#xff0c;同时提供一个直观的演示界面。 思路分析 引入Animate.css库创建不同旋转动画的展示区域添加控制面板自定义动画效果实现实时预览功…...

Screen 连接远程服务器(Ubuntu)

连接 1. 安装screen 默认预安装&#xff0c;可以通过命令查看&#xff1a; screen --version 若未安装&#xff1a; # Ubuntu/Debian sudo apt-get install screen 2. 本机连接远程服务器 ssh root192.168.x.x 在远程服务器中打开screen&#xff1a; screen -S <nam…...

VR视角下,浙西南革命的热血重生​

VR 浙西南革命项目依托先进的 VR 技术&#xff0c;为浙西南革命历史的展示开辟了一条全新的道路 &#xff0c;打破了时间与空间的限制&#xff0c;使革命历史变得触手可及。​ &#xff08;一&#xff09;沉浸式体验革命场景​ 借助 VR 技术&#xff0c;在 VR 浙西南革命的展示…...

Prompt Engineering 提示工程介绍与使用/调试技巧

1. 介绍 Prompt Engineering 是一种人工智能&#xff08;AI&#xff09;技术&#xff0c;它通过设计和改进 AI 的 prompt 来提高 AI 的表现。Prompt Engineering 的目标是创建高度有效和可控的 AI 系统&#xff0c;使其能够准确、可靠地执行特定任务。 如果你从来没有使用过Pr…...

Linux——数据链路层

1. 认识以太网 认知&#xff1a;以太网是用于局域网数据通信的协议标准&#xff0c;定义了同一局域网内通过电缆/无线怎么在设备之间传输数据帧。 注&#xff1a;整个网络世界可以具象看出由许许多多的局域网组成&#xff0c; • 家庭中的设备A and 家庭中的设备B and 家庭路由…...