STM32——USART
一、通信
1.1通信是什么;
通信是将一个设备的数据发送到另一个设备中,从而实现硬件的扩展;
1.2通信的目的是什么;
实现硬件的扩展-在STM32中集成了很多功能,例如PWM输出,AD采集,定时器等,在STM32中是通过内部硬件电路实现的,可以通过指针操作相应的寄存器,来控制硬件电路,通过读来获取电路状态,通过写来操控电路;而有一些功能是STM32内没有集成的例如蓝牙无线遥控,陀螺仪测姿态等,此时需要外挂模块,来实现这些功能,而这些功能的数据是保存在外挂模块的寄存器中的,STM32想要获取这些数据来控制外挂模块就需要与该设备进行通信,通过读写外挂模块相应的寄存器,实现对外挂模块的控制,从而达到硬件扩展的功能;
1.3设备间如何进行通信
通过在设备间连接一根或者多根通信线,实现数据的接收和数据的发送,从而达到主控模块控制外挂模块的功能;
1.4通信协议是什么;
通信协议是指通信双方规定的通信规则,双方按照协议进行数据的收发;
1.5有哪些通信协议;
主要的通信方式:串口通信(USART),I2C,SPI,CAN,USB通信;
1.6通信协议有哪些模式;
通信方式的特点主要由以下几种模式决定:双工模式,时钟模式,电平模式,设备模式;
1.7通信特性具体是什么;
1.7.1双工模式:
双工模式分为全双工,半双工,单工;
全双工:通信双方可以同时接收或者发送数据,一般有两根通信线,接收线路和发送线路互不干扰,全双工;
半双工:通信双方在指定时间,只能接收或者只能发送,一根通信线,半双工;
单工:数据只能由一个设备发送另一个设备接收,一根通信线(全双工撤去一根通信线可转换为单工);
1.7.2时钟模式
同步时钟:通信双方在时钟线的时钟脉冲驱动下,进行数据的收发;
异步时钟:通信双方没有时钟线,需要双方约定传输频率(波特率),根据传输频率来接收数据;
*波特率和比特率
波特率:单位时间内接收的码元个数,单位是码元/s,也称波特;在通信系统中,二进制的一位称为码元或者符号;波特率是指单位时间内传送二进制数据的位数,单位用bps(位/秒)表示,记作波特。
比特率:单位时间内接收的比特的个数,单位是bit/s,比特率来衡量异步串行通信的数据传输速率,即单位时间内传送二进制有效数据的位数,单位用bps表示。
在二进制下波特和比特是相同的,多进制下是不同的;
1.7.3电平模式
单端信号:通信线上的电平是对GND的电平,所以通信设备需要共地;
差分信号:俩根传输线上的电位差,差分信号具有很强的抗干扰性,所以差分信号一般可以传输很远的距离;
1.7.4设备模式
点对点设备:
多设备;
多设备分为一主多从模式和多主多从模式;
一主多从模式:指的是有一个主机,多个从机,主机对总线的时钟线有绝对的控制权,从机在任何时候都只能接收,不能发送;主机在数据线空闲时候,可以调用,从机只能在接收或者发送数据的时候才可以短暂的控制;
多主多从模式
一根总线上挂载了多个设备,这些设备既可以作为从机又可以作为主机;
又分为:固定多主机模式和可变多主机模式;
固定多主机模式:主机的数量是固定的,每个主机都可以掌握总线的控制权,当多个主机同时申请总线控制权时,总线进行仲裁,失败的让出总线控制权;
可变多主机模式:每一个挂载在总线的设备都可以作为主机,当需要作为主机与其他设备进行通信时,申请总线控制权,对从机设备进行寻址即可,通信完成后,让出总线控制权,变回从机;当多个主机同时申请总线控制权时,总线进行仲裁,失败的让出总线控制权;
1.8总结:
二、USART串口通信协议
2.1串口通信介绍:
串口是一种应用十分广泛的通讯接口,串口按位bit发送和接收字节,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力;
2.2串行通信和并行通信
1.通讯可分为串行通讯与并行通讯,串行通讯是指设备之间通过少量数据信号线(一般是 8 根以下),地线以及控制信号线,按数据位形式一位一位地传输数据的通讯方式。而并行通讯一般是指使用 8、16、32 及 64 根或更多的数据线进行传输的通讯方式,它们的通讯传输对比说明见下图:
很明显,因为一次可传输多个数据位的数据,在数据传输速率相同的情况下,并行通讯传输的数据量要大得多,而串行通讯则可以节省数据线的硬件成本(特别是远距离时)以及 PCB 的布线面积,串行通讯与并行通讯的特性对比见下表:
不过由于并行传输对同步要求较高,且随着通讯速率的提高,信号干扰的问题会显著影响通讯性能,现在随着技术的发展,越来越多的应用场合采用高速率的串行差分传输。
2.3UART协议
UART全称是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),它通常称作UART,是一种异步收发传输器,是设备间进行异步通信的关键模块。UART负责处理数据总线和串行口之间的串并转换,并规定了帧格式;通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(RX 和TX)就可以完成通信过程,因此也称为异步串行通信。
对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层(硬件规定)和协议层(软件规定)。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。
2.4USART串口硬件规定:
简单的双向串口通信需要两个通信线(TX数据发送端,RX数据接收端)
TX 数据发送引脚
RX 数据接受引脚
TX和RX需要交叉连接(一个设备的TX连接在另外一个设备的RX);
GND是单端信号,即所有的电平信号是相对于GND的,所以需要共地;
VCC当从设备没有单独供电时,需要接VCC;
当只需要单向数据传输时,可以只接一个通信线;
当电平标准不一样的时候需要接电平转换芯片;
全双工模式,发送端设置为复用推挽输出,接收端设置为浮空输入或上拉输入;
2.5USART的软件规定
2.3.1时序组成:
串口的参数:起始位,停止位,校验位,数据位,波特率;
波特率,单位时间接收二进制的位数,单位是bsp/s(位/s);
起始位:标志一个数据帧的开始,固定为低电平;
停止位: 用于数据帧的间隔,固定为高电平;
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行;
校验位:用于数据验证,根据数据位计算得来;
串口的时序:
1位起始位+8位有效数据位+1位停止位=1帧(10位);
1位起始位+8位有效数据位+1位停止位+1位校验位=1帧(11位);
过程:串口处于空闲状态时,为默认为高电平为1,串口需要传输的时候,必须要发送一个起始位,这个起始位必须是低电平,打破空闲状态的高电平,这个下降沿就是告诉接收设备,这一帧的数据要开始了,发送数据后,停止位固定为高电平,为下一帧发送做准备;
奇偶校验位:例如奇校验:就是如果数据中1的数为奇数则校验位为0,默认1为奇数,如果1为偶数,则校验位补1,使1为奇数个;
引脚高低电平反转是STM32USART外设自动完成,也可以通过软件模拟,就是设置一个对应波特率时间的定时器,然后定时调用GPIO完成引脚反转;
接收时候需要一个外部中断,在接收位下降沿触发,进入接收状态,对齐采样时钟,依次采样八次;
*停止位可以设置长度;
2.3.2时序图
总结:TX引脚发送高低电平,RX引脚读取高低电平,每个字节的数据加上起始位,停止位 ,可选的校验位打包成数据帧,依次输出在TX引脚,另一端RX引脚依次接收,完成数据传输,这就是串口通信;
三、电平标准
*电平标准:
电平标准是数据0和数据1的表达方式,在传输线缆中人为的规定电压和数据的对应关系,串口通信常见的三种电平标准:
TTL电平:0V表示0,3.3V~5V表示1;
RS232:-3.3V~-15V表示1,3.3V~15V表示0;
RS485:两线压差-2V~-6V表示0,2V~6V表示1;RS485是差分信号;
四、STM32的USART串口外设
4.1USART串口外设的介绍
通用同步/异步收发器;
*同步模式多加一个时钟输出,没有时钟输入,主要是为了兼容其他通信协议,不支持两个USART直接的同步;
USART是STM32内部集成的硬件外设,可以根据数据寄存器的一个字节数据,自动生成数据帧的时序,从TX引脚发送,也可以自动接收RX引脚的数据帧时序,拼接成一个字节数据,存放在数据寄存器中;
自带波特率发生器,最高可达4.5Mbits/S;(APB2总线给一个时钟频率72MKHZ,波特率发生器进行分频得到想要的时钟频率,作为采样频率)
可以配置数据位长度(8/9),停止位长度(0.5/1/2/2.5)
可选择校验位(无校验/奇校验/偶校验)
支持同步模式(多一个CLK时钟输出),硬件流控制(设备发送数据太块,会导致另外一个设备没有做好接收准备,通过实现一个设备准备好接收,另一个设备才继续发送,此时设置硬件流控制,就可以防止其中一个发送太块,导致另外一个没有接收导致数据丢失的问题),DMA(转运数据),智能卡,IRDA(红外光通信),LIN(局域网通信);
4.2USART串口外设的结构图
过程分析:TX,RX分别是接收和发送引脚,通过DR寄存器,硬件上分为两部分TDR发送寄存器和RDR数据接收寄存器组成;
剩下的三个引脚是智能卡和IrDA通信的引脚;
我们需要发送数据时候,操作TDR发送数据寄存器(只写),当我们读取数据时候,通过RDR接收数据寄存器(只读),我们进行写操作,此时数据会被写入TDR中,然后检测发送移位寄存器内是否有数据,如果没有,那么TRD中的数据会立刻转移到发送移位寄存器中,然后置标志位TXE(发送寄存器为空)为1,表示转运完成,然后新的数据会装载在TRD中,此时数据还没有发送出去,之后移位寄存器中的数据,在发送控制器的作用下,向右移位(低位先行),一位一位的对应数据帧的时序,把数据输出到TX引脚,通过TX发送出去,当数据移位完成后,新的数据就会再次自动从TDR发送到移位寄存器里来,如果当前移位还没有完成,TDR数据就会进行等待,直到移位完成;有了TRD和移位寄存器的双重缓存,可以保证连续发送数据,数据帧不会有空闲;
我们需要接收数据时候,数据从RX段输入,到接收移位寄存器中,在接收器控制下,一位一位的读取RX电平,先放在最高位,然后移位8次,接收一个字节(从高位到低位),当一个字节的移位完成后,这个字节的数据就会整体转移到RDR接收数据寄存器中,转移过程中也会置一个标志位RXNE(接收寄存器非空),之后可以通过读取寄存器获取值;
发送控制器,控制发送移位寄存器,硬件数据流控制,又称流空,防止数据丢失或覆盖,nRTS是请求发送,是输出脚,nCTS用于接收其他设备的nRTS(n低电平有效)
原理:发送设备的TX引脚接入接收设备的RX引脚,同时接收设备的nRTS接到发送设备的nCTS上,RTS输出一个能不能接收的反馈信号,如果可以接收时,RTX置低电平,表示可以接收,如果不能接收,则置高电平表示不能接收;直到置低电平重新发送;
同步模式:产生同步的时钟信号,配合发送移位寄存器使用,发送寄存器每移位依次,同步时钟电平跳变一个周期,时钟告诉对方,移出去一位,只支持输出,不指出输入;
用途:1.串口加时钟类似于SPI,可以于SPI兼容;
2.可以做自适应波特率;原理:当接收设备不知道发送设备的波特率,可以通过测量是时钟周期来计算波特率;
唤醒单元:一般串口只支持点对点通信,而对于多设备通信,即一根总线上挂在多个设备,想和某个设备通信,只需要进行寻址,确定通信对象后,在进行数据收发;
唤醒单元可以实现多设备通信,当发送指定地址时,唤醒单元开始工作;从而实现多设备通信
各种中断标志位;
其中中断控制就是控制中断是否能到NVIC;
波特率发生器:
APBx时钟
过程:TE为1发送器波特率控制,RE为1接收器波特率控制,然后再波特率控制器中分为整数部分和小数部分(因为有些波特率整数除不尽可能会有误差,所以有小数部分),然后将分频系数输出对输入进来的时钟频率进行分频,然后/16得到发送器时钟和接收器时钟 ,通向控制部分;
USART引脚复用GPIO参考引脚复用复用;
4.3USART串口外设实现过程
1.RCC开启GPIO和USART外设时钟;
2.初始化GPIO,配置GPIO的输出引脚为复用推挽输出,输入引脚为上拉输入或者浮空输入(最好是上拉输入,给引脚一个默认的电平,防止外部干扰,造成引脚跳变);
3.初始化USART,配置波特率发生器(预分频器,对输入的时钟进行分频),配置发送和接受控制器;
4.使能CMD;
4.4USART串口外设时序图分析
输入数据问题:第一就是要在输入数据中间进行采样,才能确保采样的准确性,否则可能电平还在翻转就采样,导致数据不准;
第二数据输入要对噪声有一定的判断能力,如果是噪声,置标志位判断;
STM32中,通过对输入的波特率进行16分进行采样
过程:空闲状态每一位进行16次采样,对应结果一直为1,如果某一个时刻采样为0,那么表示出现下降沿,那么继续在一位中采样16次,并且之后每三位进行一次判断,如果三位中至少有两个为0,则认为为起始位标志,但是出现了噪声,同时将噪声标志位NE置1,如果只有一个0那么默认为前面的标志位0为噪声影响,全部忽略不计重新开始计算;如果通过了起始位侦测,则接收状态由空闲位,变成接收起始位,同时第8、9、10次采样的位置为起始位的正中间,之后每次都在第8、9、10次采样,这样就能保证后续每次采样都在正中间进行采样;
数据采样流程:1-16,一个数据位有16个采样时钟对应16位,由于起始帧测已经对齐采样时钟,直接在第8、9、10次采样,为了保证数据的可靠,即三次采样,如果都为1则位1,如果都为0则为0,如果不全为1或者0,则根据2:1的原则判断1或者0;
Printf 打印到串口方法
1.重定向方法:
int fputc(int ch,FILE *f)
{
Serial_SendByte(ch);
return ch;
}
更改底层,但是只能应用一个串口;
2.sprintf指定打印位置;把格式化字符输出到一个字符串里;
Char string[100];
Sprint(string,“num=%d”,666);
Serial_SendString(String);
- 封装Sprintf(可变参数)
Include“stdarg.H”
Void Serial_print(char *format ,......)
{
Char String[100];
Va_list arg;
Va_start(arg,format);
Vsprintf(String,format,arg);
Va_end(arg);
Serial_SendString(String);
}
串口接收模式:使用查询或者中断两种方式;
查询:在主函数循环不断判断RXNE标志位,如果置1表示接收到数据;,在读取寄存器就可以了;
五、数据包
数据包作用:将一个个数据打包起来,方便进行多字节数据通信;
例如陀螺仪数据,发送X,Y,Z,共三个字节需要连续不断的发送,出现一个问题,接收方不知道那个数据对应X那个对应Y,会出现数据错位的情况,把数据分割,xyz当作一组数据,把同一批的数据分割成一个个数据包来接收;
额外添加包头包尾的方式,不改变原有的数据结构;
HEX数据包格式
文本数据包格式
数据包发送
HEX:传输直接,解析数据简单,适合模块发送数据,例如陀螺仪,湿度传感器等;
文本数据包:数据直观易理解,适合人机交换的场合;;蓝牙AT指令,CNC,三D打印机的G代码;
HEX数据包发送
定义一个缓冲数组
在发送输出的数据添加包头包尾,实现数据打包;
void Serial_SendPacket(void)
{
Serial_SendByte(0xFF);//发送包头
Serial_SendArray(Serial_TxPacket,4);//发送一个数组
Serial_SendByte(0xFE);//发送包尾;
}
如何构建状态机:
状态机方法,根据项目要求,定几个状态,然后考虑各个状态在什么情况下进行转移,如何转移;
方法:定义一个状态量,然后判断状态量的值确定处于那种状态,然后考虑转移;
状态机1:HEX数据包发送
void USART1_IRQHandler (void)
{
static uint8_t RxState=0;//状态变量S
static uint8_t PRxPacket=0;//指示接收到哪一个了
if(USART_GetFlagStatus( USART1, USART_IT_TXE)==SET)//发送寄存器TDR为空,置TXE标志位为1;
{
uint8_t RxData =USART_ReceiveData(USART1);//输入的数据给到RXData中;
if(RxState==0)//判断状态S选择不同的过程
{如果接收数据为0xff则是包头,切换状态变量为接收状态;同时清零PRxPacket
if(RxData==0xFF)//收到包头
{
RxState=1;//转移状态
PRxPacket=0;//从第0个开始接收
}
}
else if(RxState==1)//使用else if而不使用if防止状态转移过程中,两个同时成立
{
Serial_RxPacket[PRxPacket]=RxData;//第N个接收数据
PRxPacket++;//数据转存一次
if( PRxPacket>=4)//四个载荷数据接收完成
{
RxState=2;//进入下一个状态
}
}
else if(RxState==2)//等待包尾
{
if(RxData==0xFE)//接收到包尾
{
RxState=0;//回到最初的状态
Serial_RxFlag=1;//置一个接收标志位;
}
}
USART_ClearITPendingBit(USART1, USART_IT_TXE);
}
}
void Serial_SendPacket(void)
{
Serial_SendByte(0xFF);
Serial_SendArray(Serial_RxPacket,4);
Serial_SendByte(0xFE);
}
状态机2:文本数据包
void USART1_IRQHandler (void)
{
static uint8_t RxState=0;//状态变量S
static uint8_t PRxPacket=0;
if(USART_GetFlagStatus( USART1, USART_IT_TXE)==SET)
{
uint8_t RxData =USART_ReceiveData(USART1);
if(RxState==0)
{
if(RxData== '@')//判断包头
{
RxState=1;//进入下一个状态
PRxPacket=0;//此时为1
}
}
else if(RxState==1)//防止状态转移时候,两个同时成立
{
if( PRxPacket=='\r')//判断第一个包尾
{
RxState=2;//进入下一个状态
}
else
{
Serial_RxPacket[PRxPacket]=RxData;
PRxPacket++;
}
}
else if(RxState==2)
{
if(RxData=='\n')
{
RxState=0;
Serial_RxFlag=1;
Serial_RxPacket[PRxPacket]='\0';
}
}
USART_ClearITPendingBit(USART1, USART_IT_TXE);
}
}
五、API实现
5.1 API1:实现软串口接收或者发送一个数据;
5.1.1程序规划:
首先明确想实现的功能-实现发送一个字节,发送一个数组,发送一个字符串,发送数字(依次发送每一位);
5.1.1.1建立通信层模块(底层):
初始化串口后,对各部分进行封装;
5.1.1.2应用层
mian函数里调用驱动层函数,实现功能;
5.1.2库函数分析
库函数:
void USART_DeInit(USART_TypeDef* USARTx);//复位
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);//初始化
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);//初始化结构体
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);//配置同步时钟输出
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);//使能
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);//中断使能
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);//开启到DMA的通道
void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address);//设置 USART 节点的地址。
void USART_WakeUpConfig(USART_TypeDef* USARTx, uint16_t USART_WakeUp);//配置唤醒单元
void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState);//使能唤醒单元
void USART_LINBreakDetectLengthConfig(USART_TypeDef* USARTx, uint16_t USART_LINBreakDetectLength);//设置USART LIN模式下的断点检测长度
void USART_LINCmd(USART_TypeDef* USARTx, FunctionalState NewState);//LIN使能
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);//功能:通过USARTx外设传输单个字节数据
注释:DR数据寄存器只有DR[8:0]可用,一次发送1字节的数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);//功能:返回由USARTx外设接收的最新数据
注释:DR数据寄存器只有DR[8:0]可用,一次接收16位的数据
void USART_SendBreak(USART_TypeDef* USARTx);//功能:发送断开帧
注释:如果设置SBK=1,在完成当前数据发送后,将在TX线上发送一个断开符号
单独发送断开符号时:不能发送,波形无变化(持续高电平)
TC中断时发送断开符号:接收端接收,认为是数据0x00
结论是:断开符号对防止接收端把两包看做一包没什么用,无法起到真正的断开作用void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime);//功能:设置指定的USART保护时间
注释:以波特时钟为单位的保护时间。在智能卡模式下,需要这个功能,当保护时间过去后,才会设置发送完成标志
UART4和UART5上不存在这一位
void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler);//功能:设置对系统时钟预分频器的数值
注释:红外低功耗模式[7:0]位,红外正常模式数值确定,智能卡模式[4:0]位
位[7:5]在智能卡模式下没有意义;UART4和UART5上不存在这一位
例如:USART_SetPrescaler(USART1 , 00000001);
void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者失能USARTx的智能卡模式
注释:UART4和UART5上不存在这一位
例如:USART_SmartCardCmd(USART1 , ENABLE);
void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者失能NACK传输
注释:校验错误时,是否发送NACK位;UART4和UART5上不存在这一位
例如:USART_SmartCardNACKCmd(USART1 , ENABLE);
void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者失能USART半双工通信
注释:是否选择选择单线半双工模式
例如:USART_HalfDuplexCmd(USART1 , ENABLE);
void USART_OverSampling8Cmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者失能USART的8X过采样模式
void USART_OneBitMethodCmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者失能USART的one bit采样模式
void USART_IrDAConfig(USART_TypeDef* USARTx, uint16_t USART_IrDAMode);//功能:配置USART的IrDA(红外)接口
注释:低功耗与正常模式
void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState);//功能:使能或者红外模式失能
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);//标志位函数
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
5.1.3思路:
5.1.3.1初始化串口
1.RCC开启GPIO和USART的时钟;
2.初始化GPIO,配置GPIO的输出为复用推挽输出(片上外设输出控制引脚电平),输入为上拉输入或者浮空输入;
3.初始化USART,配置USART的模式(接收还是发送),是否需要流控,是否需要校验位和位长;
4.使能USARTcmd;
5.1.3.2输出一个字节:
1.输出一个字节;
2.判断是否发送至移位寄存器,不需要手动清0标志位;
5.1.3.3输出一个数组
1.通过for循环依次输出数组的每一位;
5.1.3.4输出一个字符串for循环依次发送字符串的每一位,直到标志位“\0”;
5.1.3.5发送数字
1.依次发送数字的每一位;
2.通过定义函数表达函数的每一位;
5.1.3.6将输出重定义至串口
5.1.4实现
1.RCC开启GPIO和USART的时钟;
2.初始化GPIO,配置GPIO的输出为复用推挽输出(片上外设输出控制引脚电平),输入为上拉输入或者浮空输入;
3.初始化USART,配置USART的模式(接收还是发送),是否需要流控,是否需要校验位和位长;
4.使能USARTcmd;
5.1.3.2输出一个字节:
1.输出一个字节;
2.判断是否发送至移位寄存器,不需要手动清0标志位;
5.1.3.3输出一个数组
1.通过for循环依次输出数组的每一位;
5.1.3.4输出一个字符串for循环依次发送字符串的每一位,直到标志位“\0”;
5.1.3.5发送数字
1.依次发送数字的每一位;
2.通过定义函数表达函数的每一位;
5.1.3.6将输出重定义至串口
应用层:
5.2API2实现串口接收一个数据:
基本于发送数据初始化基础上,开启中断控制输出,到NVIC,配置NVIC后,但是接收数据时候需要产生中断,在中断函数中判断标志位后,读取数据和标志位,清除标志位,最后用俩个函数返回读取的数据和标志位
应用层:
5.3API3串口收发HEX数据包(固定包长)
在串口发送和接收数据API1和API2基础上建立;
如何建立状态机:
状态机方法,根据项目要求,定几个状态,然后考虑各个状态在什么情况下进行转移,如何转移;
方法:定义一个状态量,然后判断状态量的值确定处于那种状态,然后考虑转移;
1.定义发送缓存区和接收缓存区;
2.封装数据包,在数据前后分别加上包头和包尾;
定义一个状态量用于判断状态,定义一个数据指示接收到哪一个了
状态机逻辑:根据分析得到几种状态:等待包头,接收数据,等到包尾
各个状态在什么样的情况下转变:等待包头在接收到包头后转移至接收数据,接收数据接收够数据后转移至等待包尾,等待包尾,收到包尾后,切换至等待包头模式;
首先静态变量初始值为0,是一个状态—等待包头,判断接收的数据是不是包头,如果是包头0xFF,切换至下一个状态为1,是第二个状态接收数据,判断接收的数据是否够4个,如果接收够4个,切换为下一个状态2,是第三个状态等待包尾,判断是否接收到包尾,如果接收到状态切换为0,第一个状态;
应用层:
5.4API4串口发送字节数据包 (随机包长)
在串口发送和接收数据API1和API2基础上建立;
逻辑结构:
根据分析得到几种状态:等待包头,接收数据,等到包尾
各个状态在什么样的情况下转变:等待包头在接收到包头后转移至接收数据,接收数据接收够数据后转移至等待包尾,等待包尾,收到包尾后,切换至等待包头模式;
首先静态变量初始值为0,是一个状态—等待包头,判断接收的数据是不是包头或者是不是第一次接收数据,如果是包头0xFF,切换至下一个状态为1,是第二个状态接收数据,判断接收的数据是否够4个,如果接收够4个,切换为下一个状态2,是第三个状态等待包尾,判断是否接收到包尾,如果接收到状态切换为0,第一个状态;
通过串口发送相应的数据,来操作LED;
通过Strcmp(par1,par2)(判断字符串1和2是否相等,相等为1,不相等为0),套用IF循环,如果相等,执行点亮LED并向串口回传一个数据LED点亮,并用OLED显示,否则反之;
如果连续发送数据包,程序处理不及时,可能会导致数据包错位 ,文本数据包,每个数据包是独立的,如果错位了问题就比较大了,所以在每次程序处理完成后,在接收下一个程序包;
在主循环里执行完程序后清0标志位;
判断等待包头的时候在加一个条件如果数据等于包头并且RXflag==0才执行接收;(如果不满足就跳过)
相关文章:

STM32——USART
一、通信 1.1通信是什么; 通信是将一个设备的数据发送到另一个设备中,从而实现硬件的扩展; 1.2通信的目的是什么; 实现硬件的扩展-在STM32中集成了很多功能,例如PWM输出,AD采集,定时器等&am…...

WebCopilot:一款功能强大的子域名枚举和安全漏洞扫描工具
关于WebCopilot WebCopilot是一款功能强大的子域名枚举和安全漏洞扫描工具,该工具能够枚举目标域名下的子域名,并使用不同的开源工具检测目标存在的安全漏洞。 工具运行机制 WebCopilot首先会使用assetsfinder、submaster、subfinder、accumt、finddom…...

HarmonyOS实战开发-如何实现一个支持加减乘除混合运算的计算器。
介绍 本篇Codelab基于基础组件、容器组件,实现一个支持加减乘除混合运算的计算器。 说明: 由于数字都是双精度浮点数,在计算机中是二进制存储数据的,因此小数和非安全整数(超过整数的安全范围[-Math.pow(2, 53)&#…...

每日OJ题_子序列dp⑥_力扣873. 最长的斐波那契子序列的长度
目录 力扣873. 最长的斐波那契子序列的长度 解析代码 力扣873. 最长的斐波那契子序列的长度 873. 最长的斐波那契子序列的长度 难度 中等 如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的: n > 3对于所有 i 2 < n&#x…...

病毒循环Viral Loop是什么?为何能实现指数增长
一、什么是病毒循环(Viral Loop)? 病毒循环(Viral Loop)是一种机制,它推动连续的推荐以实现持续增长。 它会促使你现有的客户推荐其他人,去认识你的品牌,然后让这些新客户进一步告诉…...

下载huggingface中数据集/模型(保存到本地指定路径)
一. snapshot_download # 1.安装huggingface_hub # pip install huggingface_hubimport osfrom huggingface_hub import snapshot_downloadprint(downloading entire files...) # 注意,这种方式仍然保存在cache_dir中 snapshot_download(repo_id"ibrahimhamam…...

HarmonyOS实战开发-使用List组件实现导航与内容联动的效果。
1 卡片介绍 使用ArkTS语言,实现一个导航与内容二级联动的效果。 2 标题 二级联动(ArkTS) 3 介绍 本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能: 切换左侧导航ÿ…...

ArcGIS二次开发(一)——搭建开发环境以及第一个简单的ArcGIS Engine 程序
Arcgis10.2、Arcgis Engine10.2与Microsoft Visual Studio 2012的版本进行安装 1、推荐教程与安装包2、安装顺序3、安装成功测试VS新建项目可以创建ArcGIS项目,并且在VS中拖拽ArcGIS工具 4、搭建第一个简单的ArcGIS Engine 程序 ArcEngine和VS版本是有对应的&#x…...

Oracle 19c 高可用部署实战系列之Data Guard理论与实战
课程介绍 Oracle Data Guard确保企业数据的高可用性、数据保护和灾难恢复。 Oracle Data Guard提供了一组全面的服务,用于创建、维护、管理和监视一个或多个备用数据库,使生产Oracle数据库能够在灾难和数据损坏中幸存下来。Oracle Data Guard将这些备用…...

ubuntu常用记录
常用命令 ps aux |grep ... pip show pkgname nvidia-smi -l du -sh * df -h head -n 10 file.txt htop sudo apt install package_name kill process_id 软链接 在 Linux 中,软连接(Symbolic Link,也称为符号链接或软链接)是一…...

顺序表专题
文章目录 目录1. 数据结构相关概念1.1 什么是数据结构1.2 为什么需要数据结构 2. 顺序表的概念及结构3. 顺序表分类4. 实现动态顺序表4.1 初始化4.2 顺序表的尾部插入4.3 打印顺序表4.4 顺序表的头部插入4.5 顺序表的尾部删除4.6 顺序表的头部删除4.7 指定位置之前插入数据4.8 …...

手写SpringBoot(三)之自动配置
系列文章目录 手写SpringBoot(一)之简易版SpringBoot 手写SpringBoot(二)之动态切换Servlet容器 手写SpringBoot(三)之自动配置 手写SpringBoot(四)之bean动态加载 手写SpringBoot…...

vitepress builld报错
问题:build时报错:document/window is not defined。 背景:使用vitepress展示自定义的组件,之前build是没有问题了,由于新增了qr-code以及quill富文本组件,导致打包时报错。 原因:vitepress官…...

redis分布式锁-----基于Redis的SETNX命令的简单分布式锁实现
Redis的SETNX命令的简单分布式锁实现的Java示例 首先,确保你已经引入了Jedis这个Java Redis客户端库。你可以通过Maven或Gradle来添加依赖。 1、Maven依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifact…...

HTTP请求头中的Host表示是什么?
表示处理请求的服务器地址,由于一台服务器可能部署多个网站,如果通过域名访问,host就是域名...

apk被play protect blocked的解决方案(ADB+Appium+webdriverio)
起因:公司有海外项目,需要推广apk ,数量多,但是由于被play protect阻止安装,初版解决方案 apk加固、换签名、垃圾代码、修改资源文件的MD5,但是由于原生代码标记过于严重,推广成本高,又换了一种…...

【BlossomRPC】手把手教你写一个RPC协议
文章目录 新的开始什么是RPC?设计一个RPC需要些什么? 新的开始 经常会遇到一些项目,看着看着就发现看不懂文档了,也就是会出现一些跳过讲解的文章,使得自己很难了解某种中间件的开发全貌,所以想着自己先设计一个比较…...

算法之美:堆排序原理剖析及应用案例分解实现
这段时间持续更新关于“二叉树”的专栏文章,关心的小伙伴们对于二叉树的基本原理已经有了初步的了解。接下来,我将会更深入地探究二叉树的原理,并且展示如何将这些原理应用到更广泛的场景中去。文章将延续前面文章的风格,尽量精炼…...

Net8 ABP VNext完美集成FreeSql、SqlSugar,实现聚合根增删改查,完全去掉EFCore
没有基础的,请参考上一篇 彩蛋到最后一张图里找 参考链接 结果直接上图,没有任何业务代码 启动后,已经有了基本的CRUD功能,还扩展了批量删除,与动态查询 动态查询截图,支持分页,排序 实现原理…...

yolov8直接调用zed相机实现三维测距(python)
yolov8直接调用zed相机实现三维测距(python) 1. 相关配置2. 版本一2.1 相关代码2.2 实验结果 3. 版本二3.1 相关代码3.2 实验结果 相关链接 此项目直接调用zed相机实现三维测距,无需标定,相关内容如下: 1.yolov5直接调…...

element跑马灯/轮播图,第一页隐藏左边按钮,最后一页隐藏右边按钮(vue 开箱即用)
图示: 第一步: <el-carousel :class"changeIndex0?leftBtnNone:changeIndeximgDataList.length-1? rightBtnNone:" height"546px" :autoplay"false" change"changeNext"><el-carousel-item v-for…...

下载及安装PHP,composer,phpstudy,thinkPHP6.0框架
文章目录 目录 文章目录 前言 一、下载PHP 二、下载composer 三、下载PHPstudy 四、下载think PHP 1.下载 2.多应用开发 前言 thinkPHP是一款开源的PHP框架,它是基于MVC(Model-View-Controller)设计模式构建的。thinkPHP提供了丰富的…...

volatile使用场景总结
volatile关键字在Java中用于确保变量的可见性以及防止指令重排序,特别是在没有使用锁定机制时对变量进行读写的多线程环境中。以下是需要使用volatile修饰的一些场景: 确保变量的可见性 当一个变量被多个线程访问,且至少有一个线程在写&…...

AcWing 1413. 矩形牛棚(每日一题)
原题链接:1413. 矩形牛棚 - AcWing题库 作为一个资本家,农夫约翰希望通过购买更多的奶牛来扩大他的牛奶业务。 因此,他需要找地方建立一个新的牛棚。 约翰购买了一大块土地,这个土地可以看作是一个 R 行(编号 1∼R&…...

macOS Sonoma 14.4.1 (23E224) 正式版发布,ISO、IPSW、PKG 下载
macOS Sonoma 14.4.1 (23E224) 正式版发布,ISO、IPSW、PKG 下载 2024 年 3 月 26 日凌晨,macOS Sonoma 14.4.1 更新修复了一个可能导致连接到外部显示器的 USB 集线器无法被识别的问题。它还解决了可能导致 Java 应用程序意外退出的问题,并修…...

WPF使用外部字体,思源黑体,为例子
1.在工程中新建文件夹,命名为“Font"。 2.将下载好的字体文件复制到Font文件夹。 3.在工程中,加入静态资源 <Window.Resources><FontFamily x:Key"SYBold">/AnalyzeImage;Component/Font/#思源黑体 CN Bold</FontFamily…...

9、jenkins微服务持续集成(一)
文章目录 一、流程说明二、源码概述三、本地部署3.1 SpringCloud微服务部署本地运行微服务本地部署微服务3.2 静态Web前端部署四、Docker快速入门一、流程说明 Jenkins+Docker+SpringCloud持续集成流程说明 大致流程说明: 开发人员每天把代码提交到Gitlab代码仓库Jenkins从G…...

VOC(客户之声)赋能智能家居:打造个性化、交互式的未来生活体验
随着科技的飞速发展,智能家居已成为现代家庭不可或缺的一部分。然而,如何让智能家居更好地满足用户需求,提供更贴心、更智能的服务,一直是行业关注的焦点。在这个背景下,VOC(客户之声)作为一种用…...

时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测
时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测 目录 时序预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-BP灰狼算法优化BP神经网络时间序列预测(完整源码和数据…...

node.js学习(2)
版权声明 以下文章为尚硅谷PDF资料,B站视频链接:【尚硅谷Node.js零基础视频教程,nodejs新手到高手】仅供个人学习交流使用。如涉及侵权问题,请立即与本人联系,本人将积极配合删除相关内容。感谢理解和支持,…...