STM32——串口通信(发送/接收数据与中断函数应用)

文章目录

  • 通信:
    • 串口通信简介:
    • 1.双工/单工:
    • 2.同步/异步:
    • 3.电平:
        • 电平标准:
  • 串口参数以及数据帧时序:
    • 数据帧:
    • 1.波特率和比特率:
      • 例:无校验,1位停止位
    • 2.校验位:
      • 例:有校验,1位停止位
      • 例:无校验,2位停止
    • 输入电路的数据采样:
      • 注意:只有在输入电路,并且是检测到潜在下降沿(起始位)的时候才开始的以16倍的波特率进行数据采样,并且第二次的连续三次采样是对应在起始位的中间部分,之后的数据位也会跟着对齐,注意只有输入电路这个情况下才以波特率的16倍进行工作,其他电路例如移位仍然是以正常的波特率进行。
      • 起始位检测:
      • 数据采样:
    • 波特率发生器:
  • CH340模块原理图:
  • USART简介:
    • STM32的USART结构:
      • 1——发送数据和接收数据:
      • 2——硬件流控制:
      • 3——多设备通信:
      • 4——时钟控制(波特率发生器,也是分频器):
  • 程序编写:
    • 一、简单发送数据:
      • 总代码:
      • 步骤:
        • 第一步:肯定要先打开时钟
        • 第二步:配置好GPIO口的模式,还有通信配置
        • 第三步:各种发送函数,之后只需要在主函数进行初始化然后调用下列函数
    • 二、接收数据并产生中断,如果数据为1则点亮led灯:
      • 总代码:
      • 步骤:
        • 第一步:和发送时一样,打开时钟,配置好GPIO口,还有通信配置
        • 第二步:打开中断使能,通过misc文件中的NVIC函数配置好USART的中断优先级和中断通道
        • 第三步:在中断程序里检测RXNE位是否 = 1,读取接收数据寄存器,判断接收的数据是否 = 1,等于1则点亮LED灯,同时将接收到的数据回传到电脑串口助手,也就是发送部分

通信:

串口通信简介:

定义: 串口通信是指通过串口进行的数据传输方式,是通信双方根据比特遵循时间顺序的一种通信方式。在串口通信中,数据是按位顺序传输的,每一位数据占用固定的时间长度。
在这里插入图片描述

在这里插入图片描述

1.双工/单工:

全双工:两条通信线,A与B能够同时进行收、发数据,收、发互不影响,如打电话。

半双工:A与B同一时间任何一端只能进行发送或者接收,A发送,则B只能接收,如对讲机。

单工:只能进行单向通信,即A只能发送,B只能接收,如广播。

2.同步/异步:

同步:通信两端会有一根时钟线,两端时钟信号同步,根据时钟信号确认通信开始和结束时间。

异步:通信两端没有时钟同步,通过特定协议决定何时开始通信,何时结束。

3.电平:

单端:就是数据1和数据0代表的电压信号都是以GND为基准,通信两端需要共地,也就是GND引脚要接在同一处。

差分:根据两引脚的电压差来表示数据和信号,这种信号的抗干扰能力强,一般情况下,如果受到干扰两条通信线都会同时发生变化,变化产生的影响因此就会变小,因此可以长距离通信。
在这里插入图片描述
在这里插入图片描述

电平标准:

在这里插入图片描述
RS485电平是差分信号,大概能传输几千米,另外两种大概只有几十米。

串口参数以及数据帧时序:

下图红圈部分即为数据帧时序图:
在这里插入图片描述

数据帧:

这里根据时钟,在每一次时钟的上升沿就会进行一次数据采集
在这里插入图片描述

数据帧(Data Frame)是网络通信和数据处理中的一个基本概念,它指的是在网络传输中或数据处理系统中,由起始标志和结束标志限定的一段数据单元。数据帧是数据链路层的数据传输单元,封装了网络层传下来的数据包(Packet)。在不同的协议和上下文中,数据帧的具体结构和内容可能有所不同,但通常都包含了以下几个关键部分:

1.帧头(Frame Header): 包含了控制信息,如帧的起始标志、目的地址、源地址、数据长度等。这些控制信息对于数据的正确传输和接收至关重要。

2.数据字段(Data Field): 即实际传输的数据部分,可以是用户数据,也可以是控制信息。这部分是帧的主要负载。

3.帧尾(Frame Trailer): 包含了帧的结束标志和校验信息等,用于标识帧的结束和检测传输过程中可能发生的错误。

想象一下你正在寄送一个包裹给朋友,这个包裹就相当于网络中的数据帧。

1.包裹的封面(帧头):
包裹上会有收件人的地址(目的地址),这样快递员就知道要送到哪里。
也会有寄件人的地址(源地址),以便在需要时可以追溯包裹的来源。
还会标注包裹里面大概装的是什么东西(数据类型或长度),虽然不是详细清单,但给了一些基本信息。

2.包裹里的东西(数据字段):
这就是你要寄给朋友的实际物品,对应数据帧中的数据部分。它可以是任何东西,比如一封信、一份礼物或任何你想要分享的东西。

3.包裹的封口和标签(帧尾):
包裹会有一个封口,确保里面的东西不会掉出来。在数据帧中,这就像是一个结束标志,告诉接收方这个数据帧到此为止。
有时包裹上还会贴一个“已检查,无损坏”的标签,类似于数据帧中的校验信息。它帮助接收方检查包裹在运输过程中是否完好无损。

1.波特率和比特率:

  • 两者意义相似,数据发送方就是间隔多长时间发送一位数据,而接受方需要以相同的波特率或比特率接收,如此,如果A每间隔1秒发送一个数据,B就每间隔1秒接收一个数据,慢了会漏掉数据,快了会重复接收数据。

例:无校验,1位停止位

在这里插入图片描述
1.用单片机的TX引脚发送0X55Z这个数据,比特率是9600,就是1s内发送9600位的数据,

2.空闲状态TX引脚由内部上拉电阻上拉至并保持高电平,发送数据时起始位为低电平,因此电平翻转变成低电平,此时会产生下降沿表示数据开始传输,

3.然后之后发送8位数据,最后停止位为高电平,因此发送完数据位之后引脚会变成高电平表示发送数据结束,

4.如果之后又有新的数据要发送该引脚电平又会被拉低,没有则保持空闲状态高电平。

2.校验位:

例:有校验,1位停止位

  • 这里采用简单的奇偶检验,就是总发送的位数会多出一位校验位,如果是偶校验位,如下图,数据1的个数已经是偶数,那么校验位就为0低电平,如果数据1的个数是奇数,那么校验位就会置高电平保证数据1个数为偶数,如果设置为偶校验,而接收端接收到的数据1个数仍然为奇数,就可以舍弃该数据,申请重新发送。
    在这里插入图片描述

例:无校验,2位停止

下图为连续发送两个数据,中间没有空闲状态
在这里插入图片描述

输入电路的数据采样:

注意:只有在输入电路,并且是检测到潜在下降沿(起始位)的时候才开始的以16倍的波特率进行数据采样,并且第二次的连续三次采样是对应在起始位的中间部分,之后的数据位也会跟着对齐,注意只有输入电路这个情况下才以波特率的16倍进行工作,其他电路例如移位仍然是以正常的波特率进行。

起始位检测:

在这里插入图片描述

1.空闲状态下接收到的信号为高电平

2.当检测到一个下降沿时,就开始进行起始位检测,此时会以16倍的波特率进行采样,在第3,5,7和8,9,10进行采样,当前三位和后三位都被检测为0时才算检测到了起始位,这里每三位至少有两个0才算检测到0,如果有一个1两个0仍然算0但是会置一个噪声标志位NE。

3.如果此时这两个三位采样,有一个为1就不算检测到起始位,将会放弃1前的数据,中止侦测起始位的过程,重新开始侦测起始位。

如果侦测起始位成功,那么接收状态就从空闲状态转换为接收起始位,而8,9,10位正好位于起始位的中间,那么之后进行数据接收时,上升沿也会处于数据位的中间。
在这里插入图片描述

数据采样:

在一个数据位有16个采样时钟,由于在起始位侦测时已经对齐了数据位的中间,因此在第8,9,10的采样时钟对数据位进行三次连续采样,三个采样都为1则数据为1,为0同理,如果只有两个为1也将数据认为1但会置噪声标志位NE = 1。
在这里插入图片描述

波特率发生器:

输入电路的采样时钟 = 16倍的波特率
在这里插入图片描述

CH340模块原理图:

在这里插入图片描述

USART简介:

定义: USART是一种通用的串行通信接口,它支持同步和异步两种通信模式,并且具有很好的扩展性和可定制性。USART不仅包含了UART(通用异步收发器)的所有功能,还增加了同步通信的功能。串口是一个泛称,指的是一类通信接口;而USART是具体的一种串行通信接口标准。

当我们配置好USART电路后,直接读写数据寄存器就能进行数据的接收和发送。
在这里插入图片描述

STM32的USART结构:

在这里插入图片描述

1——发送数据和接收数据:

注意:发送和接收数据的帧头帧尾由硬件帮我们添加和提出了。
在这里插入图片描述

发送数据寄存器接收数据寄存器在软件上占用同一个地址,但是在硬件上它们是两个寄存器,只是软件上写入和读取地址的值时这两个地址都会被读取到,但是TDR是只写的,RDR是只读的,写数据时寻址该地址只会被写入TDR,反之同理。

发送数据时:
发送移位寄存器和接收移位寄存器,如果你要通过TX发送01010101数据,那么这个数据会先被保存在发送数据寄存器,然后由硬件检测发送移位数据寄存器是否正在进行数据移位操作,如果没有,则01010101这个要发送的数据就会被转移到发送移位寄存器,转移后会置一个标志位TXE表示发送数寄存器为空,这是我们可以通过查看TXE的值来确定是否写入下一个要发送的数据。但是此时刚转移的数据还没被发送,然后在下面的发送控制器的驱动下这个数据就会从低位开始被一位一位的移出去并通过TX发送。

接收数据时:
在这里插入图片描述
在接收器控制的驱动下,从RX进入的数据会被不断向右移进入接收移位寄存器,当数据完整的移位到接收移位寄存器后就会立刻整体转移到接收数据寄存器,此时也会置一个标志位RXNE表示接收数据寄存器非空,这时我们读取该寄存器的值就能够知道接收的数据是什么。

2——硬件流控制:

在这里插入图片描述

  • 硬件流控制指的是利用硬件线路的电气信号进行发送和接收的控制。它通过额外的信号线(如nRTS、nCTS等,n表示低电平有效,当接收端没准备好时,RTS就会置高电平,而发送方的CTS接收到该电平信号就会暂停发送数据,只有接收数据寄存器的数据被读取,RTS被置低电平,发送方才会继续发送,反之发送数据时也同样,需要判断对方的RTS)来实时监测数据传输的状态,并根据接收端的处理能力来控制发送端的数据发送速率,从而避免数据丢失和网络拥塞。其基本原理是在发送端和接收端之间通过预先设置的阈值或固定的时间间隔来控制数据的传输速率和数量。

例如:
A给B发送数据,但是B还没处理完上一段数据A就将下一段数据发送发送了过来,导致B只能要么舍去旧数据去处理新数据或者反过来,这样会导致数据丢失,而硬件流控制就是通信两端AB之间会多一根电路,当B处理好旧数据时这个电路会被置低电平表示接收端B做好准备接收新的数据了,那么此时发送端A才会发送新的数据,就避免了数据丢失。

3——多设备通信:

在这里插入图片描述

串口是点对点通信,但是在一条总线上可以挂多个设备,给USART地址单元填入某个设备的地址就能够唤醒该设备,此时就能够实现USART与该设备的通信。

4——时钟控制(波特率发生器,也是分频器):

在这里插入图片描述

时钟输入先由APB时钟fPCLKx(x = 1或2)(接在APB1总线x就等于1),进行两次分频,就能够得到发送和接收移位的时钟,这个USARTDIV分频就是右边的篮圈部分,他分有整数部分和小数部分,绿圈中当TE = 1就是发送器使能,发送器波特率有效,RE = 1同理

程序编写:

一、简单发送数据:

简易架构图:
在这里插入图片描述
完整结构图:
在这里插入图片描述
根据结构图,我们使用的是USART是APB2总线的外设,
1.肯定要先打开时钟,
2.当我们要发送数据时,首先把要发送的数据先写入TDR,如果发送移位寄
存器此时没有在转移数据,那么TDR的值就会直接被转移到发送移位寄存器,还需要配置一帧信号的配置
3.然后通过通过波特率发生器,设置DIV的值得到波特率,然后置TE = 1,使发送器波特率有效,
4.再通过发送器控制将发生移位寄存器的数据右移至TX线发送出去

总代码:

主函数中进行函数调用:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "COuntSensor.h"
#include "Usart.h"int main()
{OLED_Init();Usart_Init();USART1_SendDate('A');while(1){}
}   

下面是Usart文件:

#include "stm32f10x.h"  // Device header
#include "stdarg.h"
#include "stdio.h"uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Usart_Init(void)
{//打开GPIO和USART的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);/*配置好TX和RX引脚,对应PA9和PA10TX配置为复用推挽输出RX配置为上拉输入*/GPIO_InitTypeDef GPIOA9_InitStructure;GPIOA9_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA9_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIOA9_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA9_InitStructure);GPIO_InitTypeDef GPIOA10_InitStructure;GPIOA10_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIOA10_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIOA10_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA10_InitStructure);//配置通信设置(字长,停止位,波特率)USART_InitTypeDef USART1_InitSturcture;USART1_InitSturcture.USART_BaudRate = 9600;USART1_InitSturcture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitSturcture.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART1_InitSturcture.USART_Parity = USART_Parity_No;USART1_InitSturcture.USART_StopBits = USART_StopBits_1;USART1_InitSturcture.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitSturcture);USART_Cmd(USART1,ENABLE);
}
//发送8位数据
void USART1_SendDate(uint8_t Byte)
{USART_SendData(USART1,Byte);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
//发送一个数组
void USART1_SendArray(uint8_t *Array,uint8_t size)
{uint8_t i = 0;while(i < size){USART1_SendDate(Array[i]);i++;}
}
//发送一个字符串
void USART1_SendString(char *String)
{uint8_t i = 0;while(String[i] != '\0'){USART1_SendDate(String[i]);i++;}
}
//打印函数
void USART1_Printf(char *format,...)
{char String[100];va_list arg;va_start(arg,format);vsprintf(String,format,arg);va_end(arg);USART1_SendString(String);
}

步骤:

第一步:肯定要先打开时钟
//打开GPIO和USART的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
第二步:配置好GPIO口的模式,还有通信配置
/*配置好TX和RX引脚,对应PA9和PA10TX配置为复用推挽输出RX配置为上拉输入*/GPIO_InitTypeDef GPIOA9_InitStructure;GPIOA9_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA9_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIOA9_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA9_InitStructure);GPIO_InitTypeDef GPIOA10_InitStructure;GPIOA10_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIOA10_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIOA10_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA10_InitStructure);//配置通信设置(字长,停止位,波特率)USART_InitTypeDef USART1_InitSturcture;USART1_InitSturcture.USART_BaudRate = 9600;USART1_InitSturcture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitSturcture.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART1_InitSturcture.USART_Parity = USART_Parity_No;USART1_InitSturcture.USART_StopBits = USART_StopBits_1;USART1_InitSturcture.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitSturcture);//启动USART1USART_Cmd(USART1,ENABLE);
第三步:各种发送函数,之后只需要在主函数进行初始化然后调用下列函数
//以下函数都是在这个函数的基础上
void USART1_SendDate(uint8_t Byte)
{USART_SendData(USART1,Byte);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}void USART1_SendArray(uint8_t *Array,uint8_t size)
{uint8_t i = 0;while(i < size){USART1_SendDate(Array[i]);i++;}
}
void USART1_SendString(char *String)
{uint8_t i = 0;while(String[i] != '\0'){USART1_SendDate(String[i]);i++;}
}
void USART1_Printf(char *format,...)
{char String[100];va_list arg;va_start(arg,format);vsprintf(String,format,arg);va_end(arg);USART1_SendString(String);
}

二、接收数据并产生中断,如果数据为1则点亮led灯:

在USART的控制寄存器中有一个RXNEIE位,为中断使能位
首先需要配置好USART通向NVIC的中断路径
在这里插入图片描述
当我们接收到数据时RXNE会被置1表示数据读取寄存器非空,这时候如果我们已经将RXNEIE = 1开启中断,那么就会产生中断申请到NVIC,此时NVIC会根据当前的中断事件选择中断优先级最合适的通道给CPU,则CPU就会去执行对应的中断程序。那么我们的配置步骤就是:
在这里插入图片描述

总代码:

主函数只需要调用Usart_Init函数:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "COuntSensor.h"
#include "Usart.h"int main()
{OLED_Init();Usart_Init();while(1){}
}   

下面是Usart.c文件中的函数:

#include "stm32f10x.h"  // Device headeruint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Usart_Init(void)
{//打开GPIO和USART的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);/*配置好TX和RX引脚,对应PA9和PA10TX配置为复用推挽输出RX配置为上拉输入*/GPIO_InitTypeDef GPIOA9_InitStructure;GPIOA9_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA9_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIOA9_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA9_InitStructure);GPIO_InitTypeDef GPIOA10_InitStructure;GPIOA10_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIOA10_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIOA10_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA10_InitStructure);//配置GPIOA_0口用A0口点亮LED灯GPIO_InitTypeDef GPIOA0_InitStructure;GPIOA0_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIOA0_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIOA0_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA0_InitStructure);//配置通信设置(字长,停止位,波特率)USART_InitTypeDef USART1_InitSturcture;USART1_InitSturcture.USART_BaudRate = 9600;USART1_InitSturcture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitSturcture.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART1_InitSturcture.USART_Parity = USART_Parity_No;USART1_InitSturcture.USART_StopBits = USART_StopBits_1;USART1_InitSturcture.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitSturcture);//使用IT_Comfig函数开启RXNE的中断使能位USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//配置好中断优先级的分组,这个是所有中断一起用的只需配置一次NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//用NVIC给USART的中断进行中断优先级和通道配置NVIC_InitTypeDef NVIC_USART_InitStructyre;//启用这个通道只会USART1的中断都会通过这个通道进入到NVICNVIC_USART_InitStructyre.NVIC_IRQChannel = USART1_IRQn;NVIC_USART_InitStructyre.NVIC_IRQChannelCmd = ENABLE;NVIC_USART_InitStructyre.NVIC_IRQChannelPreemptionPriority = 1;NVIC_USART_InitStructyre.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_USART_InitStructyre);USART_Cmd(USART1,ENABLE);
}void USART1_SendDate(uint8_t Byte)
{USART_SendData(USART1,Byte);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}void USART1_SendArray(uint8_t *Array,uint8_t size)
{uint8_t i = 0;while(i < size){USART1_SendDate(Array[i]);i++;}
}
void USART1_SendString(char *String)
{uint8_t i = 0;while(String[i] != '\0'){USART1_SendDate(String[i]);i++;}
}
void USART1_Printf(char *format,...)
{char String[100];va_list arg;va_start(arg,format);vsprintf(String,format,arg);va_end(arg);USART1_SendString(String);
}
void LED1_ON(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}void LED1_OFF(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_0);
}
//到启动文件_md.s中查看中断向量表,确认中断程序名
void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}//数据回传USART1_SendDate(Serial_RxData);//注意这里的1并不是字符1,字符1还要看ascill码表switch(Serial_RxData){//事件1点灯:case 1:LED1_ON();break;//事件2灭灯:case 2:LED1_OFF();break;}
}

步骤:

第一步:和发送时一样,打开时钟,配置好GPIO口,还有通信配置
//打开GPIO和USART的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);/*配置好TX和RX引脚,对应PA9和PA10TX配置为复用推挽输出RX配置为上拉输入*/GPIO_InitTypeDef GPIOA9_InitStructure;GPIOA9_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA9_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIOA9_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA9_InitStructure);GPIO_InitTypeDef GPIOA10_InitStructure;GPIOA10_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIOA10_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIOA10_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA10_InitStructure);//配置GPIOA_0口用A0口点亮LED灯GPIO_InitTypeDef GPIOA0_InitStructure;GPIOA0_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIOA0_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIOA0_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOA0_InitStructure);//配置通信设置(字长,停止位,波特率)USART_InitTypeDef USART1_InitSturcture;USART1_InitSturcture.USART_BaudRate = 9600;USART1_InitSturcture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitSturcture.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART1_InitSturcture.USART_Parity = USART_Parity_No;USART1_InitSturcture.USART_StopBits = USART_StopBits_1;USART1_InitSturcture.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitSturcture);
第二步:打开中断使能,通过misc文件中的NVIC函数配置好USART的中断优先级和中断通道
//使用IT_Comfig函数开启RXNE的中断使能位USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//配置好中断优先级的分组,这个是所有中断一起用的只需配置一次NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//用NVIC给USART的中断进行中断优先级和通道配置NVIC_InitTypeDef NVIC_USART_InitStructyre;//启用这个通道只会USART1的中断都会通过这个通道进入到NVICNVIC_USART_InitStructyre.NVIC_IRQChannel = USART1_IRQn;NVIC_USART_InitStructyre.NVIC_IRQChannelCmd = ENABLE;NVIC_USART_InitStructyre.NVIC_IRQChannelPreemptionPriority = 1;NVIC_USART_InitStructyre.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_USART_InitStructyre);USART_Cmd(USART1,ENABLE);
第三步:在中断程序里检测RXNE位是否 = 1,读取接收数据寄存器,判断接收的数据是否 = 1,等于1则点亮LED灯,同时将接收到的数据回传到电脑串口助手,也就是发送部分
void LED1_ON(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}void LED1_OFF(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_0);
}
//到启动文件_md.s中查看中断向量表,确认中断程序名
void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}//数据回传USART1_SendDate(Serial_RxData);//注意这里的1并不是字符1,字符1还要看ascill码表switch(Serial_RxData){//事件1点灯:case 1:LED1_ON();break;//事件2灭灯:case 2:LED1_OFF();break;}
}

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

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

相关文章

【WebGIS实例】(16)GeoServer 自定义样式 - 渲染矢量数据

1. 前言 本篇博客将会分享一系列的 GeoServer 样式&#xff0c;通过这些样式预先在服务端完成数据渲染&#xff0c;让前端应用更便捷的加载数据服务。 2. 面矢量 示例数据&#xff1a; {type: FeatureCollection,features: [{type: Feature,properties: {分类字段: 字段一…

数据权限的设计与实现系列6——前端筛选器组件Everright-filter使用探索

linear 功能探索 最终我们是需要使用 API 的方式&#xff0c;调用后端服务拉取数据填充筛选器组件&#xff0c;不过在探索阶段&#xff0c;直接用 API 方式&#xff0c;就需要构造 mock 数据&#xff0c;比较麻烦&#xff0c;因此先使用 Function 方式来进行功能验证。 组件初…

代理模式详解

1.基本介绍 代理模式&#xff1a;为一个对象提供一个替身&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能;被代理的对象可以是远程对象、创建开销大的对象或需要安全控制…

记录:uniapp直播的弹幕的样式修改与发送弹幕会自动滚动到底部两个技巧

1、在直播页面的弹幕评论中&#xff0c;我们希望的样式是&#xff1a; 观众名字&#xff1a;评论 而且颜色有所区分&#xff0c;并在同一行显示 2、我们希望在发弹幕的时候可以回自动滚动到自己发的内容那里 一&#xff1a;弹幕样式修改 因为是小白&#xff0c;前端对于样式这…

苹果手机照片被删除?如何通过不同的方法来恢复照片

手机已经成为我们生活中不可或缺的一部分&#xff0c;它不仅仅是通讯工具&#xff0c;更是我们记录生活点滴的重要工具之一。然而&#xff0c;正如其他任何设备一样&#xff0c;iPhone上存储的照片有时也会不小心被删除或丢失。 别担心&#xff0c;即使你误删了重要的照片&…

重头开始嵌入式第三十四天(数据库二)

sqlite3的一些补充 目录 sqlite3的一些补充 1.事物 2.连接&#xff0c;联合 3.触发器 4.子查询 1.事物 数据库事务是数据库管理系统执行过程中的一个逻辑单位&#xff0c;它由一系列对数据库的操作组成。 一、事务的特性 1. 原子性&#xff08;Atomicity&#xff09…

Linux:目录及文件管理

目录及文件管理 cd的命令使用 . 当前目录 .. 父目录&#xff08;上一层&#xff09; ~ 表示家目录 家目录&#xff1a;专门存放用户个性化信息的目录 ~user&#xff1a;用户user的家目录 /root: 是Linux管理员的家目录 /home: 存放所有普通用户的家目录]# cd ~root #去…

大模型LLM算法工程师技术面试指南

大模型LLM算法工程师技术面试指南 AI大模型全套学习资料 “最先掌握AI的人&#xff0c;将会比较晚掌握AI的人有竞争优势”。 这句话&#xff0c;放在计算机、互联网、移动互联网的开局时期&#xff0c;都是一样的道理。 我在一线互联网企业工作十余年里&#xff0c;指导过不少…

Java异常类

目录 Java异常类 Java中的异常体系 抛出异常 处理异常 处理异常的两种方式 try...catch和throws的区别 finally关键字 抛出异常注意事项 自定义异常类 Java异常类 Java中的异常体系 在Java中&#xff0c;异常类的父类为Throwable类&#xff0c;在Throwable下&#x…

记一次高版本view-design的组件迁移到自身项目的低版本

背景 npm i -S view-design当前老项目使用view-design这个组件库&#xff0c;但是当我们去官网查看该组件库最新版本&#xff0c;竟然发现没有博主想用的image/ImagePreivew这两个基础组件 说实话&#xff0c;有点离谱了哈&#xff01;&#xff01; 自己造轮子&#xff1f; …

数据结构基本知识

一、什么是数据结构 1.1、组织存储数据 ---------》内存&#xff08;存储&#xff09; 1.2、研究目的 如何存储数据&#xff08;变量&#xff0c;数组....)程序数据结构算法 1.3、常见保存数据的方法 数组&#xff1a;保存自己的数据指针&#xff1a;是间接访问已经存在的…

分库分表核心理念

文章目录 分库&#xff0c;分表&#xff0c;分库分表什么时候分库&#xff1f;什么时候分表&#xff1f;什么时候既分库又分表&#xff1f;横向拆分 & 纵向拆分 分表算法Range 范围Hash 取模一致性 Hash斐波那契散列 严格雪崩标准&#xff08;SAC&#xff09;订单分库分表实…

【880高数】高等数学一刷错题整理

第一章 函数、极限、连续 2024.8.11日 1. 2. 3. 4. 5. 2024.8.12日 1. 2. 3. 4. 5. 6. 7. 8. 2024.8.13日 1. 2. 3. 4. 2024.8.14日 1. 2. 3. 4. 5. 第二章 一元函数微分学及其应用 2024.8.15日 1. 2. 3. 4. 5. 6. 2024.8.16日 1. 2. 3. 4. 5. 2024.8.17日 1. 2. 3. 4…

个人简历 (自己设计的)

欢迎大家来观看。 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" co…

相亲交友系统背后的科技力量:智能匹配的秘密

随着互联网技术的发展&#xff0c;相亲交友系统已经成为许多人寻找另一半的重要工具。这些相亲交友系统不仅仅是一个简单的社交平台&#xff0c;它们背后隐藏着强大的科技力量&#xff0c;尤其是智能匹配技术&#xff0c;使得用户能够更加高效地找到适合自己的伴侣。 相亲交友…

信息学奥赛初赛天天练-87-NOIP2014普及组-完善程序-矩阵、子矩阵、最大子矩阵和、前缀和、打擂台求最大值

1 完善程序 最大子矩阵和 给出 m行 n列的整数矩阵&#xff0c;求最大的子矩阵和(子矩阵不能为空)。 输入第一行包含两个整数 m和 n&#xff0c;即矩阵的行数和列数。之后 m行&#xff0c;每行 n个整数&#xff0c;描述整个矩阵。程序最终输出最大的子矩阵和。 &#xff08;最…

C语言俄罗斯方块(VS2022版)

C语言俄罗斯方块 演示视频一、前置知识1.Win32 API 的使用2.宽字符的使用 二、封装核心数据与框架介绍三、核心操作介绍旋转操作检测操作水平检测竖直检测代码化简 四、源码展示在 tetris.h 中&#xff1a;在 tetris.c 中&#xff1a;在 test.c 中&#xff1a; 以下代码环境为 …

码上进阶_刷题模块测试_用例设计

码上进阶_刷题模块测试_用例设计 系统概述&#xff1a; 码上进阶是为程序员专门打造的交流平台&#xff0c;采用主流的微服务框架和C端技术栈作为技术基础。在这个平台上&#xff0c;程序员 可以通过刷题、练习和模拟面试来提升自己的面试能力。 功能测试&#xff1a; 登录…

SpringBoot OAuth2自定义登陆/授权页

背景 5 月份的时候&#xff0c;我实践并整理了一篇博客&#xff1a;SpringBoot搭建OAuth2&#xff0c;该博客完成之后&#xff0c;很长一段时间里我都有种意犹未尽的感觉。诚然&#xff0c;我把OAuth2搭起来了&#xff0c;各种场景的用例也跑通了&#xff0c;甚至源码也看了&am…

99.WEB渗透测试-信息收集-网络空间搜索引擎shodan(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;98.WEB渗透测试-信息收集-Google语法&#xff08;12&#xff09; 信息收集方向-网络空间…