type
slug
status
summary
icon
category
date
tags
password
两个程序:
  • 串口发送:串口的模块,通过串口通信,把一些数据发送到电脑上的串口助手来显示。
  • 串口发送+接收:判断是否收到数据,如果收到数据,则读取数据。将数据回传到电脑。在OLED显示。
注意:在串口中,只能发送二进制数/十六进制数。发送字符,就需要一个数据到字符的映射表。ASCII码表。
eg:发送41。 以HEX模式显示,显示41;以文本模式显示,就会去查找映射表(0x41=65,对应ASCII码表的A)

通信接口

notion image
  • 通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统
    • STM32芯片中集成了很多功能模块,eg:定时器计数、PWM输出、AD采集……即读写操作芯片内部的寄存器。
    • 很多芯片没有的功能eg:蓝牙无线遥控功能、陀螺仪加速计测量姿态……只能外挂芯片来实现。
    • 外挂的芯片都在STM32外面。STM32如何获得这些数据呢?在设备之间连接一根/多根通信线路发送和接收数据,完成数据交换,从而实现控制外挂模块和读取外挂模块数据的目的。
  • 通信协议:制定通信的规则,通信双方按照协议规则进行数据收发
💡
USART:
  • 引脚TX、RX(TXD、RXD)
  • TX(Transmit Exchange):数据发送脚。RX(Receive Exchange):数据接收脚
I2C:
  • 引脚:SCL、SDA
  • SCL(Serial Clock):时钟。SDA:(Serial Data):数据
SPI:
  • 引脚:SCLK、MOSI、MISO、CS
  • SCLK(Serial Clock)时钟、MOSI(Master Output Slave Input)主机输出数据脚、MISO、CS(Chip Select)片选:指定通信的对象
CAN:
  • 引脚:CAN_H、CAN_L
  • 差分数据脚,用两个引脚代表一个差分数据
USB:
  • 引脚:DP、DM
  • DP(Data Positive)(D+),DM(Data Minus)(D-)。差分数据脚
💡
双工
全双工通信:两根通信线,发送线路和接受线路互不影响。
  • eg:串口:一根TX发送,一根RX接收。SPI:一根MOSI发送,一根MISO接收。
半双工通信:一根通信线。
  • (I2C\CAN\USB,CAN和USB的两根差分线也是组合成一根数据线的。)
单工通信:数据只能从一个设备到另一个设备,不能反过来。
  • 串口的RX去掉,就变成单工了。
 
💡
时钟
eg:当发送方发送一个高低电平,接收方不知道发送的是(1和0)还是(1100)还是……
所以需要时钟信号让接收方知道:什么时候需要采集数据
同步通信:
  • I2C和SPI有单独的时钟线,所以他们是同步的,接收方可以在时钟信号的指引下进行采样。
异步通信:
  • 剩下的串口\CAN\USB没有时钟线,需要双方约定一个采样频率。并且需要加一些帧头帧尾等,进行采样位置的对齐。
💡
电平特性
单端:
  • 引脚的高低电平都是对GND的电压差。单端通信的双方必须要共地(把GND接在一起)。(USART\I2C\SPI引脚里面还需要接一个GND引脚)
差分:
  • 靠两个差分引脚的电压差来传输信号的。通信的时候可以不需要GND。使用差分信号可以极大地提高抗干扰性,所以常被用来实现高速度和远距离通信。
💡
设备
点对点通信:
  • 双方直接传输数据就好
多设备通信:可以在总线上挂载多个设备
  • 需要寻址以确定通信对象
 
 
 
 

串口通信

notion image
单片机和电脑通信是串口通信的优势,常用于接电脑屏幕,调试打印信息。(I2C和SPI等是芯片之间的通信,不会接在电脑上)
USB转串口模块:芯片CH340,将串口协议转化成USB协议。一口接电脑,一口接支持串口通信的芯片的引脚。
陀螺仪传感器模块,可以测量角速度、加速度等姿态参数。
蓝牙串口模块:下面引脚是串口通信的引脚,上面的芯片和手机互联。
 

硬件电路

notion image
  • VCC和GND是供电,TX和RX是单端信号,即高低电平是相对于GND
  • TX\RX\GND必须要接,如果两个设备都有独立供电,VCC可以不接。如果设备1为STM32有独立供电,设备2为蓝牙模块,没有独立供电。那么需要把STM32的VCC和蓝牙模块的VCC接在一起。STM32通过VCC线向设备2供电,注意电压。
  • 如果只需要单向通信eg:设备1到设备2,那么只用接设备1的TX到设备2的RX即可。
  • 一般为TTL电平,不同电平信号需要加电平转换芯片,转接一下。
  • 协议规定:一个设备使用TX发送高低电平,一个设备用RX接受高低电平。3.3vTTL电平,相对GND为逻辑1。0v为逻辑0。

电平标准

电压和数据的对应关系。
notion image
逻辑1代表VCC,逻辑0代表GND。
 

串口参数及时序

notion image
  • 时序图:串口发送一个字节的格式。
  • 串口中每一个字节都装载在一个数据帧里面,每一个数据帧都由起始位、数据位、停止位组成。
    • 数据位8位(即一个字节),数据位9位(8位有效载荷(1字节)+1位奇偶校验位)
  • 波特率:串口通信的速率。串口使用异步通信,需要双方约定一个通信速率。eg:我每隔1s发送一位,你每隔1s接收一位。
    • 比特率:每秒传输比特数,bit/s,bps,在二进制调制下:一个码元为一个bit,高电平为1,低电平为0,波特率=比特率
    • eg:约定波特率为1000bps,1s要发1000位,每一位就是1ms。
  • 起始位:表示一个数据帧的开始,固定为低电平。
    • 串口空闲状态,引脚为高电平。需要传输时,必须要发送一个起始位(低电平),产生下降沿,告诉接收设备,这个数据帧要开始了。
  • 停止位:表示数据帧间隔,固定为高电平。同时为下一个起始位做准备。如果没有数据了,空闲状态也是高电平。
    • 如果没有停止位,当我数据的最后一位是0的时候,就无法产生下降沿。
  • 数据位:低位先行。
    • 发送0x0F,转化成二进制为00001111,低位先传输。高高高高低低低低。形成波形如下图。如果需要发送0x0F,就需要设置定时翻转引脚电平,产生这样的波形。
    • notion image
  • 校验位:三种方式:无校验、奇校验、偶校验。判断数据传输是否出错,出错选择丢弃或重传。
    • 波形组成:起始位,数据位,校验位,停止位。
    • 奇校验:包括校验位在内的9位数据会出现奇数个1。
      • eg:00001111,那么校验位需要再补充一个1,实现奇数个1。
      • eg:00001110,那么校验位需要补充一个0。
      • 发送方在发送数据后会补充一个校验位,保证1的个数为奇数。接收方会验证数据中1的个数判断传输是否出错。如果在传输过程中,因为干扰,一位1变为0/0变为1,则数据出错,要求丢弃或重传。
    • 偶检验:包括校验位在内的9位数据会出现偶数个1。
    • 准确性更高的校验:CRC校验。
notion image
notion image
  • 0x55:01010101
  • 波特率:9600,即一秒发送9600位,每一位就是1/9600s,大概是104us
    • 波特率变为4800,波形时长就会变成原来的两倍。
  • 波形解析:
    • 空闲状态为高电平,数据帧开始,先发送起始位产生下降沿,表示数据开始。
    • 数据转化为01010101,低位先行。10101010
  • 8位数据1位停止无校验:8位数据之后引脚置为高电平。表示一个数据帧完成
    • 停止位的位数是可以发生变化的:
    • 连续发生两个0x55,停止位2位比1位数据分隔得更宽。
    • notion image
  • TX发送数据的两种方式:
    • 在STM32中,根据字节数翻转高低电平,是由USART外设自动翻转。
    • 也可以软件模拟产生波形。定时器定一个104us的时间,根据数据帧要求,调用GPIO_WriteBit设置高低电平,进行高低电平的翻转。
  • RX接收数据的两种方式:
    • USART外设自动
    • 软件模拟:定时调用GPIO_ReadInputDataBit来读取每一位。拼接为一个字节。
    • 接收时,需要一个外部中断,在起始位的下降沿触发,进入接收状态,对齐采样时钟,依次采样8次。
💡
总结:
TX定时输出高低电平。
RX定时接收高低电平。
 
 

USART外设

notion image
  • USART:通用同步/异步收发器,UART:通用异步收发器。
    • 同步模式多了个时钟输出。只支持时钟输出,不支持时钟输入。同步模式更多是为了兼容其他协议/特殊用途。并不支持两个USART之间同步通信。所以一般看来USART和UART没有区别。
  • 串口主要通过波形来收发信息,USART外设就是串口通信的硬件支持电路。
    • 当我们配置好USART电路,直接读写寄存器,就可以自动发送和接收数据了。
  • 波特率发生器:即一个分频器,eg:APB2总线72MHz的频率。然后波特率发生器进行一个分频,得到我们想要的波特率时钟,在这个时钟下进行收发,即我们指定的通信波特率。
  • 同步模式:多一个CLK时钟线。
  • 硬件流控制:防止B设备因为处理数据慢而导致的数据丢失问题。 硬件电路上多出一根线,A设备向B设备高速发送数据。如果B没准备好接收,就置高电平。如果准备好了就置低电平。A接收到B反馈的准备信号,就只会在B准备好的时候才发送数据。
  • STM32F103C8T6一共有三个USART外设资源,USART1是APB2总线上的设备,USART2和USART3是APB1总线上的设备。
 

USART框图

notion image
  • 程序上只表现为一个寄存器,数据寄存器:DR。实际硬件里面有两个寄存器:TDR/RDR(一个用于发送,一个用于接收。TDR只写,RDR只读。)
  • 发送移位寄存器/接收移位寄存器:将数据一位一位发送/接收,正好对应串口协议的波形数据位。
    • 发送移位寄存器
      • 工作原理:如果给TDR写入0x55数据,寄存器里为01010101。硬件检测到数据写入,就会检查当前移位寄存器是否有数据正在移位,如果没有:01010101就会全部移入发送移位寄存器准备发送。当数据从TDR移入发送移位寄存器时,会置一个标志位(TXE:TX Empty)。如果置1,那么就可以在TDR写入下一个数据了。
      • 发送移位寄存器就可以在下面的发生器控制的驱动下,一位一位将数据输入到TX引脚。向右移位和串口协议规定的低位先行一致。
      • 两个寄存器缓存,有利于连续接收。
    • 接收移位寄存器:
      • 在接收器控制的驱动下一位一位接收高低电平,向右移位。当接收8位后,将数据整体传给RDR。转移过程中也设置一个标志位RXNE(RX Not Empty)(接收数据寄存器非空)当我们检测到RXNE置1,就可以把数据读走了。
  • SCLK控制:配合发送移位寄存器输出。每移一位,同步时钟电平就跳变一个周期。
  • 中断控制:配置中断能不能通向NVIC
    • 中断控制位
    • notion image
  • 波特率发生器
    • fPCLKx:APB1/APB2
    • notion image
 

串口引脚(F103)

引脚复用以及重映射
notion image
notion image
notion image
notion image
 

USART基本结构

notion image
时钟来源:PCLK2/1,波特率发生器分频,产生必要的时钟(通信速率)发送给发送接收器和接收控制器。
软件层面只有一个DR寄存器供我们读写。
 

数据帧

  • 字长设置
    • notion image
      最好选择9位字长有校验,8位字长无校验(保证一个字节的数据)。
  • 配置停止位
    • 一位停止位时长=一位数据位时长
    • notion image
  • 采样
    • 采样的高电平在每一位的正中间,使得读入的高低电平是稳定的。过前或过后会使得可能高低电平正在翻转导致采样误差。
    • 侦测到一个起始位后,就会以波特率的频率,连续采样一帧数据。起始位开始,采样位置就要对齐到位的正中间,后面就会都对齐正中间了。
    • notion image
      notion image
      一个数据位有16个采样时钟,起始位侦测对齐采样时钟。直接在8,9,10位采样数据(即在该位的正中间采样)连续采样三次,全为1,就为1;全为0,就为0。其他以2:1的标准来执行,同时噪声标志位NE置1.
      notion image
 

波特率发生器

notion image
  • DIV分为整数部分和小数部分
  • /16是因为还有一个16倍波特率的采样时钟,所以输入时钟/DIV=16倍的波特率。计算波特率就得/16
    • eg:USART1波特率为9600,9600=72M/(16*DIV),解得DIV=468.75,转化为二进制111010100.11数据写入寄存器。多出部分补0,
    • 库函数只用输入波特率,会自动帮我们转换。
    notion image
     

    USB转串口原理图

    notion image
    经过CH340转换,输出为TXD和RXD,串口协议。
    注意供电图:USB为5V供电,经过稳压电路也有3.3v。都引出。其中5号引脚为CH340VCC,是CH340的电源输入脚。
     
    notion image
    状态寄存器SR(存放状态)/数据寄存器DR(存放最关键的数据)/配置寄存器CR(存放各自配置参数)
     
     

    代码1:串口发送

    接线图

    notion image
    notion image
    • 跳线帽接VCC:3.3V和VCC,两个设备要把GND接在一起,进行共地。
    • TX和RX交叉连接:TXD接板子的RX即PA10,RXD接板子的TX即PA9
    • 串口模块和STLINK都要插在电脑上,保证两个模块都有独立供电。
    • 保证串口模块的驱动已安装
    notion image
     

    库函数

    (很多事增强功能的函数,需要这个功能再去了解相关的函数)
    notion image
    notion image
    notion image
    💡
    SendData:写DR寄存器,RecieveData:读DR寄存器
    如何发送和接收,软件一律不管。
    notion image
    标志位相关的函数。
     

    代码思路

    💡
    串口初始化:
    第一步:开启时钟,将USART和GPIO的时钟都打开。
    第二步:GPIO初始化,将TX配置成复用输出,将RX配置为输入。
    第三步:配置USART,直接使用一个结构体。
    第四步:如果只需要发送功能,直接开启USART。如果既需要发送又需要接收功能,就还得配置一下中断。
    接收数据:调用接收数据的函数
    发送数据:调用发送数据的函数
    获取发送和接收的状态:调用获取标志位的函数

    代码分析

    notion image
    • 第一步:开启时钟,将USART和GPIO的时钟都打开。
    • 第二步:GPIO初始化,将TX配置成复用输出,将RX配置为输入。
      • TX引脚是USART外设的数据输出脚,选用复用推挽输出。
      • RX引脚是USART外设的数据输入脚,选择输入模式。输入模式并不分普通/复用输入。一根线只能有一个输出,但可以有多个输入。所以输入脚外设和GPIO可以同时用。RX配置是浮空输入/上拉输入
    • 第三步:配置USART,直接使用一个结构体。
      • notion image
      • 当写入波特率后,该函数会自动帮我们算好分频系数等,写入BRR寄存器
      • 定义一个结构体,将所有参数引出,将结构体的地址传入初始化。
        • 复制名称,crtl+alt+空格选择
          • notion image
        • 选择模式,如果即想要发送又需要接收,那就USART_Mode_RX|USART_Mode_TX(或符号连接),和GPIO_Pin_2|GPIO_Pin_1用法相同
          • notion image
        • 选择校验位
          • notion image
        • 选择停止位
          • notion image
        • 选择字长(8位/9位)
          • notion image
     
    第四步:如果只需要发送功能,直接开启USART。
    notion image
     
    接收数据:调用接收数据的函数
    notion image
    发送到TXD后,等待TXE置1(即数据移动到移位寄存器后),才又写入数据(否则会发生数据覆盖)
    条件循环等待:TXE==RESET,等待。TXE=SET,循环结束,结束等待。
    标志位自动清0(标志位置1后不需要手动清0)
    notion image
    notion image
    notion image
    notion image
    notion image
    HEX模式:以原始数据的形式显示
    文本模式:显示字符串,41数据解析成A

    数据模式

    notion image
    HEX模式:只能显示一个个十六进制的数据,不能显示文本/符号
    显示文本,需要对一个个数据进行编码,查找字符集,。
    notion image
    空字符:对应原始数据是0x00,保留位,不映射任何字符。一般作为字符串的结束位,字符串遇到数据0x00后,就代表字符串结束了。
    想显示和存储汉字,也得制定汉字的字符集(GB2312\GBK\GB18030)
    将全球的字符收录到一个统一的字符集Unicode字符集,最常用的传输形式是UTF8
    notion image
    字符和数据在发送和接收的转换关系。线路中传输的必须是十六进制数,0x41。
     

    Serial_SendArray

    注意:
    • 第一个参数为数组的首地址,传递一个指针。第二个参数为length,可以根据长度定义为uint16_t,uint32_t。
    • 遍历数组(循环length次)。不断调用Serial_SendByte(Array[i])。
    main.c
    notion image
     
    • 一般使用HEX模式
     

    Serial_SendString

    注意:
    • char * == uint8_t *
    • 字符串自带一个结束标志位,所以就不需要传递长度参数了。这里的数据0,对应刚刚所说的空字符,是字符串结束的标志位。也可以写成字符的形式’\0’(空字符的转义字符)
    • 头文件声明
    main.c
    注意:
    • 字符串用双引号,写完这个字符串之后,编译器会自动补上结束标志位。所以字符串的存储空间=字符串长度+1;
    • 一般用文本模式
    • 想要换行:转义字符\r\n
    notion image
     

    Serial_SendNumber

    注意:
    • 在函数内我们需要把Number的位数按十进制分开。
      • eg:12345
        • 取万位:12345/10000%10=1%10=1
        • 取千位:12345/1000%10=12%10=2
        • 取百位:12345/100%10=123%10=3
        • 取十位:12345/10%10=1234%10=4
        • 取个位:12345/1%10=12345%10=5
        • 总结:取x位,即数字/10^x%10(/10^x即将右边x-1位去掉,%10将左边去掉,保留目标位)
          • 优先级位图法:prio/8去掉低三位。
        • 次方函数
    • Serial_SendByte(Number / Serial_Pow(10,i) % 10); i=0,即第一次取出来的是个位
      • 第一次取出来最高位,即Length-i-1
        • 因为10000=10^4(即4个0)
        • 注意临界情况:第五次循环,i=4,Length-i-1=0,10^0=1,取到个位。
        • 修改代码为:Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10);
    • 最终以字符的形式显示,则需要对照ASCII表加上偏移量:
      • 字符0对应的数据是0x30,所以+0x30/+’0’
      • Serial_SendByte(Number / Serial_Pow(10, Length - i -1) % 10 + 0x30);
     

    printf

    notion image
    MicroLIB:Keil精简库
    将printf进行重定向,将printf函数打印的东西输出到串口。(printf默认将输出到屏幕,单片机没有屏幕)
    在Serial.c里面加入#include <stdio.h> ,重写printf函数(fputc为printf的底层函数)
    • int ch:这个参数是你需要输出的字符,它是一个整数类型,但只占用 1 字节存储。字符是以 ASCII 码的形式传递给 fputc,比如字符 'A' 对应的 ASCII 值是 65,字符 'a' 对应的是 97。
    • FILE *f:这个参数是指向 FILE 类型的指针。FILE 是标准 I/O 库用来表示文件或设备的结构。在嵌入式开发中,我们不关心它的具体内容,通常传递的是一个 NULL 或者一个已经打开的文件句柄(如果你有文件输出的需求)。在重定向 printf 的输出时,这个参数实际上不会被用到,但它是标准 fputc 函数的一部分。
    • 例如,调用 printf("Hello") 后,实际上它会依次调用:
      • 而每次调用 fputc 时,它会将字符通过串口输出(或其他设备)。如果你没有做任何重定向,默认情况下,fputc 会将字符输出到标准输出(通常是屏幕)。
    • main.c:
    出现warning:printf隐式声明
    notion image
    解决方案:Serial.h中 #include <stdio.h>(其中有printf的声明,而main.c中又包含串口头文件)
     

    sprintf

    sprintf 是 C 标准库中的一个函数,用于将格式化的数据输出到字符串中。与 printf 不同,printf 是将格式化数据输出到标准输出(如终端或屏幕),而 sprintf 则是将格式化的数据写入到一个字符串(字符数组)中。 函数原型:
    • str:指向要写入格式化数据的字符数组的指针。
    • format:格式化字符串,包含普通字符和格式说明符(如 %d%s 等)。
    • ...:要格式化的参数,根据格式说明符的数量和类型提供相应的参数。
    • 返回值:sprintf 函数返回写入到字符串中的字符数,不包括字符串结束符 \0
    函数示例:
    输出:
    关于串口(不涉及重定向的问题,每个串口都可以用springf格式化打印)
    再次封装(可变参数)
    notion image

    发送汉字

    如果汉字以UTF8的方式编码发送,也要以UTF8的方式接收。同时在c/c++杂项控制栏写入:—no-multibyte-chars
    notion image
    Serial_printf(”你好,世界!”);才不会报错。
    Encoding选择GB2312(汉字的编码方式),接收处选择GBK编码
     

    代码2:串口接收

    USART_RX复用在了PA10引脚,需要初始化PA10(浮空输入/上拉输入)
    notion image
    同时开启发送和接收的部分
    notion image
    串口接收可以使用查询和中断两种方式

    查询方式:

    流程:在主函数里面不断判断RXNE标志位,如果置1,就说明收到数据。
    再调用RecieveData读取寄存器即可。
    notion image
    清除标志位的问题:
    notion image
     
     

    使用中断:

    开启中断,配置NVIC
    notion image
    当RXNE一旦置1,就会向NVIC申请中断。
    notion image
    对Serial_RxData和RXFlag封装/extern
    notion image
     
     

    串口数据包收发

    发送;文本数据包和HEX数据包

    HEX数据包

    notion image
    数据包:把一个个单独的数据打包和分割,进行多字节通信。
    eg:陀螺仪的X\Y\Z轴数据,需要连续不断的打包发送。出现问题,接收方接收数据时候的分割。X数据置一个标志位,最高位为1。检查标志位,得到X数据,接着的两个数据是Y和Z的数据。
    notion image
    串口数据包的分割方法:额外增添包头和包尾
    • 固定包长,含包头包尾:即每个数据包的长度是一样的。
      • 四个字节为一个数据包。0xFF为包头,0xFE为包尾。
    • 可变包长,含包头包尾:即每个数据包的长度不一样。
     
    Q1:包头包尾和数据载荷重复的问题。(即如果数据是0xFF和0xFE怎么办?)
    S1:对数据进行限幅。如XYZ3个数据,范围都在0~100.
    S2;尽量使用固定包长的数据。对齐几个数据包之后,之后的数据包也是对齐,只用判断包头包尾而不会判断数据内部。
    S3:增加包头包尾的数量,使得它尽量呈现出载荷数据表示不了的状态。
    Q2:包长可变性的选择。根据需求和是否会有严重的数据载荷重复问题。
    Q3:各种数据转化为字节流的问题。
    S:只需要一个uint8_t的指针指向它,当成字节数组发送就可以了。
    优点:传输简单,解析数据简单。比较适合一些模块发送原始数据。串口通信的陀螺仪/温湿度传感器。
    缺点:灵活性不足,载荷容易和包头包尾重复。
     

    文本数据包

    notion image
    在HEX数据包里,数据都是原始数据。文本数据包中,每个字节都经过了一层编码和译码。其实本质还是一个字节的HEX数据。由于字符作为包头包尾,可以有效避免包头包尾重复和数据载荷的问题。
    eg:@作为包头,\r\n换行的字符作为包尾。
    优点:数据清晰可见,适合人机交互。蓝牙模块常用的AT指令。有效避免重复和载荷问题。
    缺点:需要编码和译码,解析数据低。
     

    HEX数据包接收

    notion image
    发送HEX数据包:SendArray
    发送文本数据包:SendString
    上图是固定包长的HEX数据包的接收。
    每收到一个字节,程序都会进一遍中断。中断函数里,可以拿到一个字节。但是拿到字节后,就需要退出中断。所以具有独立性。但是数据包其实是有前后关联性的。包头之后是数据,数据之后为包尾。—>不同类型数据需要不同的处理方式,还要一个记住不同状态、操作、合理状态转移的机制。
    “状态机”
    notion image
    设计状态转换图如下:
    第一个状态:等待包头。第二个状态:接收数据。第三个状态:等待包尾。
    每个状态需要一个变量来标志。(S=0/S=1/S=2)
    流程如下:
    • 最开始S=0,收到一个数据进行中断。判断数据是不是包头0xFF。
      • 如果是包头0xFF,那么将S=1,退出中断结束。
      • 如果不是0xFF,那么数据包头没有对齐。继续等待包头(仍然在状态一,S=0)。下次仍然进中断,判断包头。
    • 下次再进入中断,就可以根据S=1,就可以进行第二个状态:数据接收。
      • 将数据存入数组。还有一个变量,记录数据的个数。
        • 如果没有收够4个数据,那么继续接收数据。
        • 收够4个数据,S=2。
    • 下次再进入中断,就可以根据S=2,就可以进行第三个状态:等待包尾。判断数据是不是0xFE
      • 如果是包尾0xFE,那么将S=0.
      • 如果不是,继续等待包尾。
    设计状态转换图:状态,转移条件。—>编程。
     

    文本数据包接收

    notion image
    可变包长的文本数据包的接收。
     

    串口收发数据包的代码

    HEX发送

    notion image
    notion image
    main.c中:
    notion image

    HEX接收

    接收数据包,将载荷数据存在RxPacket数组里面。然后设置标志位,进行状态变化。
    Serial.c
    Serial.h
    main.c
    第4行,1,4,7,10列显示数据
    即使出现重复问题时也不会报错,因为接收载荷数据的时候,并不会判断包头包尾。
    问题:RxPacket[]在中断函数里被写入,在主函数中被读出。如果数据收发频率出现问题,可能会导致数据混杂。(这个数据包的一部分和下一个数据包的一部分形成一个新的数据包)
    解决办法:加入判断。当每个数据包接收处理完毕之后再接收下一个数据包。/传感器的独立数据连续性,即使出现数据混杂那么还是可以分辨的。
     

    文本接收

    可变包长,含包头包尾
    Serial.c
    Serial.h
    main.c
    发送:@ABC+换行符
    屏幕显示ABC
     
    发送:@LED_ON+换行符
    回传:LED_ON_OK
    如果收发数据包的速度太快了,可以定义一个缓存区进行接收,来解决数据错误的问题。
     

    启动配置和存储器映像

    notion image
    notion image
    1-1-2 GPIO小记2-1 用Keil实现μC/OS-II工程搭建
    Loading...
    🐟🐟
    🐟🐟
    在坚冰还盖着北海的时候,我看到了怒放的梅花
    最新发布
    2-1 用Keil实现μC/OS-II工程搭建
    2025-5-10
    Chapter1:Introduction
    2025-5-7
    2-4 启动ARM STM32
    2025-5-6
    1-4-1 USART串口协议
    2025-5-6
    1-1-2 GPIO小记
    2025-5-6
    1-1-1 用Keil点亮一盏小灯
    2025-5-6
    公告
    🎉NotionNext 3.15已上线🎉
    -- 感谢您的支持 ---
    👏欢迎更新体验👏