• 09:STM32-------USART串口通信+串口数据包


    目录

    一:串口协议

    1:通信接口

    2:串口通信

    3:硬件电路

    4:电平标准

    5:串口参数及其时序

    二:USART介绍

    1:简历

    2:USART框图

    3:USART的基本结构

    4:数据帧

    5: 波特率发生器

    6:数据模式

    三:案例

    A:串口发送--单发送

    1:连接图

    2:函数介绍

    3:代码 

    B:串口发送+接收 

    1:函数介绍

     2:串口发送+接收 -----查询代码

    3:函数介绍

    4:串口发送+接收 -----中断代码

    四:USART串口数据包

    1:简历

    2:HEX数据包

    3: 文本数据包

    4:HEX数据包接收

    5:文本数据包接收

    6: 案例

    1:连接图

    A:发送HEX数据包---固定数据长度

    2:连接图

    B:发送文本数据包---数据长度 


    一:串口协议

    1:通信接口

    通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

    通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

    USART通信:

            TX:  发送数据的引脚

            RX : 接收数据的引脚

    I2C通信:

            SCL: 时钟     SDA:数据

    SPI通信:

            SCLK:时钟   MOSl:主机输出数据脚    MISO :  主机输入数据脚    CS : 片选,用于指定通信的对象

    CAN通信:

            是差分数据脚,用两个引脚表示一个差分数据

    USB通信:

            也是 是差分数据脚

     双工

    全双工:就是指通信双方能够同时进行双向通信,  两个数据线分别负责发送和接收数据

    半双工 : 一根数据线负责发送和接收数据,   eg:I2C通信的SDA线

    时钟

    同步: 接收方可以在时钟信号的指引下进行采样

    异步 : 没有时钟线,  所以需要双方约定一个采样频率,   还需要加一些帧头帧尾等,进行采样位置的对齐

    电平

    单端: 它们引脚的高低电平都是对GND的电压差,   所以单端信号通信的双方必须要共地,就是把GND接在一起

    差分 : 差分信号,   它是靠两个差分引脚的电压差来传输信号的,   在通信的时候,可以不需要GND,   使用差分信号可以极大地提高抗干扰特性

    设备

    点对点 : 直接传输数据就可以了

    多设备 : 一对多,  需要有一个导址的过程,以确定通信的对象

    2:串口通信

            串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

            单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力

    3:硬件电路

            简单双向串口通信有两根通信线(发送端TX和接收端RX)

            TX与RX要交叉连接

            当只需单向的数据传输时,可以只接一根通信线

            当电平标准不一致时,需要加电平转换芯片-----------相同的电平标准才可以通信

     VCC的连接

            上面的VCG,如果两个设备都有独立供电,  VCC可以不接

            如果一个设备没有独立供电,  需要VCC把他们连接起来

    4:电平标准

            电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

            TTL电平:+3.3V或+5V表示1,0V表示0

            RS232电平:-3~-15V表示1,+3~+15V表示0

            RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

    5:串口参数及其时序

            波特率:串口通信的速率--------波特率表示单位时间内传送的码元符号的个数.      规定串口通信的速率,   串口一般是使用异步通信,  发送和接收,必须要约定好速率,  速率参数,就是波特率.   双方规定波特率为1000bps,   那就表示,1s要发1000位,每一位的时间就是1ms

            起始位:标志一个数据帧的开始,固定为低电平------串口的空闲状态是高电平,起始位产生一个下降沿, 告诉接收设备要开始传输数据了

            停止位:用于数据帧间隔,固定为高电平-------停止位固定为1,把引脚恢复成高电平,方便下次的数据传输,   可以选择1位、1.5位、2位等

            数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

            校验位:用于数据验证,根据数据位计算得来------校验可以选择3种方式,无校验、奇校验和偶校验

            串口中,每一个字节都装载在一个数据帧里面,   每个数据帧都由起始位、数据位和停止位组成

            左边: 这里数据位有8个,代表一个字节的8位         (一个字节为8位)

            右边 : 数据帧里面,还可以在数据位的最后,加一个奇偶校验位 ,这样数据位就9位

    奇偶校验位----实际是对高电频1的校验

            奇校验 : 发送数据0000 1111 采用右边的数据位为9位, 给第9位补1, 这时候1就为5个为奇数,      接收方一验证,发现1的个数不是奇数,那就认为传输出错,  就可以选择丢弃,或者要求重传

            偶校验: 发送数据0000 1111 采用右边的数据位为9位, 给第9位补0, 这时候1就为4个为偶数, 接收方一验证,发现1的个数不是偶数,那就认为传输出错,  就可以选择丢弃,或者要求重传

            奇偶校验只能保证一定程度上的数据校验

    数据位的2中表示方法

            一种是把校验位作为数据位的一部分,  分为8位数据和9位数据,   其中9位数据,就是8位有效载荷和1位校验位,   另一种就是把数据位和校验位独立开,  数据位就是有效载荷,校验位就是独立的1位

    二:USART介绍

    1:简历

            USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器

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

            自带波特率发生器,最高达4.5Mbits/s 可配置数据位长度(8/9)、停止位长(0.5/1/1.5/2)

            可选校验位(无校验/奇校验/偶校验)

            支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

    STM32F103C8T6 USART资源: USART1、 USART2、 USART3

            硬件流控制,-----------比如A设备有个TX向B设备的RX发送数据,   A设备一直在发,发的太快了,  如果没有硬件流控制,   那B就只能抛弃新数据或者覆盖原数据了.     如果有硬件流控制,在硬件电路上,会多出一根线,   如果B没准备好接收,就置高电平,如果准备好了,就置低电平;    A接收到了B反馈的准备信号,就只会在B准备好的时候,才发数据

            硬件流控制,可以防止因为B处理慢而导致数据丢失的问题

    2:USART框图

    寄存器

            DR寄存器 : TDR和RDR数据寄存器占用同一个地址,在程序上他们表现为一个寄存器DR寄存器,   TDR是只写的RDR是只读的,  当你进行写操作时 数据就写入到TDR寄存器.   当你进行读操作时,数据就是从RDR读出来的

            发送(接收)移位寄存器:  发送移位寄存器的作用就是,把个字节的数据一位一位地移出去

    标志位-----移位完成产生标志位

            TXE : 在存器里就是二进制存储,0101 0101,   硬件检测到你写入数据了,  就会检查,当前移位寄存器是不是有数据正在移位;   如果没有,这个0101 0101就会立刻全部移动到发送移位寄存器,  准备发送.  当数据从TDR移动到移位寄存器时会置一个标志位(TXE置1),叫TXE,  发送寄存器空,  就可以在TDR写入下一个数据了

            当TXE标志位置1时,  数据其实还没有发送出去,    只要数据从TDR转移到发送移位寄存器了   ,   TXE就会置1,我们就可以写入新的数据了

            

    while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

            检查标志位USART1的TEX标志为是否等于0-----TDR寄存器的数据有没有移动到发送移位寄存器里面去

            RXNE: 和TXE相同的道理:   当数据从接收移位寄存器,    移动到移位RDR寄存器时会置一个标志位(RXNE置1),  这个也不用手动清除标志位, 和TXE原理相同

    3:USART的基本结构

    4:数据帧

    5: 波特率发生器

            发送器和接收器的波特率由波特率寄存器BRR里的DIV确定

            计算公式:波特率 = fPCLK2/1 / (16 * DIV)

            配置USART1为9600的波特率

    6:数据模式

            HEX模式/十六进制模式/二进制模式:以原始数据的形式显示

            文本模式/字符模式:以原始数据编码后的形式显示

    三:案例

    A:串口发送--单发送

    1:连接图

    2:函数介绍

    在stm32f10x usart.h文件中-----配置USART

    void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

    在stm32f10x usart.h文件中-----发送数据

    void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

     在stm32f10x usart.h文件中-----检查某个寄存器的中断标志位

    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

    USART_GetFlagStatus :      获取标志位状态的函数

    3:代码 

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "Serial.h"
    5. #include
    6. void serial_init(void){
    7. //开启RCC时钟
    8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    10. //配置TI的GPIO
    11. GPIO_InitTypeDef GPIO_structinit;
    12. GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设
    13. GPIO_structinit.GPIO_Pin=GPIO_Pin_9;
    14. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    15. GPIO_Init(GPIOA,&GPIO_structinit);
    16. //USART的配置
    17. USART_InitTypeDef USART_structinit;
    18. USART_structinit.USART_BaudRate=9600;//通信的波特率
    19. USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用
    20. USART_structinit.USART_Mode=USART_Mode_Tx;//配置GPIO为TX发送数据模式
    21. USART_structinit.USART_Parity=USART_Parity_No; //选择校验方式---无校验
    22. USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数
    23. USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为
    24. USART_Init(USART1,&USART_structinit);
    25. //启动USART
    26. USART_Cmd(USART1,ENABLE);
    27. }
    28. //发送数据
    29. void Serial_SendByte(uint8_t Byte)
    30. {
    31. //发送数据的函数
    32. USART_SendData(USART1,Byte);
    33. //检查某个寄存器的中断标志位
    34. while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    35. /*
    36. 在完成数据发送的时候,TXE置1;
    37. 下次发送数据自动置0,所以不用手动清除中断标志位.
    38. TXE:发送数据寄存器:
    39. 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    40. 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。
    41. 0:数据还没有被转移到移位寄存器
    42. 1:数据已经被转移到移位寄存器。
    43. 注意:单缓冲器传输中使用该位。
    44. */
    45. }
    46. //发送一个数组;Array:传递的数组,Length数组的长度
    47. void Serial_SendArray(uint8_t *Array, uint16_t Length){
    48. for(uint16_t i=0;i
    49. {
    50. Serial_SendByte(Array[i]);
    51. }
    52. }
    53. //发送一个字符串
    54. //发送字符串时自带结束标志位
    55. void Serial_Sendstr(char *str)
    56. {
    57. for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'
    58. Serial_SendByte(str[i]);
    59. }
    60. }
    61. //取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
    62. //12345取3 12345/100(10^2)%10=3 x:从左往右数,不包含要取的数字
    63. uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
    64. {
    65. uint32_t Result = 1;
    66. while (Y --)
    67. {
    68. Result *= X;
    69. }
    70. return Result;
    71. }
    72. //传输数字,把数字中的每一位取出,然后发送出去
    73. //Number:传输的数字; Length:传输数字的长度
    74. void Serial_SendNumber(uint32_t Number, uint8_t Length)
    75. {
    76. uint8_t i;
    77. for (i = 0; i < Length; i ++)
    78. {
    79. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    80. }
    81. }
    82. //printf函数的底层
    83. int fputc(int ch, FILE *f)
    84. {
    85. Serial_SendByte(ch);
    86. return ch;
    87. }
    88. //spinrf函数的封装
    89. void Serial_Printf(char *format, ...)
    90. {
    91. char String[100];
    92. va_list arg;
    93. va_start(arg, format);
    94. vsprintf(String, format, arg);
    95. va_end(arg);
    96. Serial_Sendstr(String);
    97. }
    98. int main(void)
    99. {
    100. OLED_Init();
    101. serial_init();
    102. Serial_SendByte(0x41);
    103. uint8_t Array[]={0x01,0x08,0x43,0x45};
    104. Serial_SendArray(Array,4);
    105. //换行的话需要加上\r\n
    106. Serial_Sendstr("Helloword\r\n");
    107. Serial_Sendstr("123\r\n");
    108. Serial_SendNumber(231,3);
    109. //使得printf函数移植方法
    110. printf("NUM=%d,",123);
    111. char String[100];
    112. sprintf(String, "\r\nNum3=%d", 333);
    113. Serial_Sendstr(String);
    114. Serial_Printf("\r\nNum4=%d", 444);
    115. Serial_Printf("\r\n");
    116. printf("你好世界");
    117. while (1)
    118. {
    119. }
    120. }

    printf函数三中移植的方法----使得可以通过串口通信打印到其他外设:

    1:通过重写printf函数的底层,使他通过串口

    1. //printf函数的底层
    2. #include
    3. int fputc(int ch, FILE *f)
    4. {
    5. Serial_SendByte(ch);
    6. return ch;
    7. }

    2:直接使用sprintf函数

    1. char String[100];
    2. sprintf(String, "\r\nNum3=%d", 333);
    3. Serial_Sendstr(String);

    3:对sprintf函数进行封装

    1. //spinrf函数的封装
    2. #include
    3. void Serial_Printf(char *format, ...)
    4. {
    5. char String[100];
    6. va_list arg;
    7. va_start(arg, format);
    8. vsprintf(String, format, arg);
    9. va_end(arg);
    10. Serial_Sendstr(String); //调用的Serial_Sendstr函数在代码里面可查询
    11. }
    12. Serial_Printf("\r\nNum4=%d", 444);

    B:串口发送+接收 

    对于串口接收来说,可以使用查询和中断两种方法

    1:函数介绍

    在stm32f10x usart.h文件中-----返回外设最近接收的数据

    uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

    USART_ReceiveData :  返回USARTx外设最近接收到的数据

     2:串口发送+接收 -----查询代码

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "Serial.h"
    5. #include
    6. #include
    7. void serial_init(void){
    8. //开启RCC时钟
    9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    10. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    11. //配置TI的GPIO
    12. GPIO_InitTypeDef GPIO_structinit;
    13. GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设
    14. GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送
    15. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    16. GPIO_Init(GPIOA,&GPIO_structinit);
    17. GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
    18. GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收
    19. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    20. GPIO_Init(GPIOA,&GPIO_structinit);
    21. //USART的配置
    22. USART_InitTypeDef USART_structinit;
    23. USART_structinit.USART_BaudRate=9600;//通信的波特率
    24. USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用
    25. USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式
    26. USART_structinit.USART_Parity=USART_Parity_No; //选择校验方式---无校验
    27. USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数
    28. USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为
    29. USART_Init(USART1,&USART_structinit);
    30. //启动USART
    31. USART_Cmd(USART1,ENABLE);
    32. }
    33. //发送数据
    34. void Serial_SendByte(uint8_t Byte)
    35. {
    36. //发送数据的函数
    37. USART_SendData(USART1,Byte);
    38. //检查某个寄存器的中断标志位
    39. while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    40. /*
    41. 在完成数据发送的时候,TXE置1;
    42. 下次发送数据自动置0,所以不用手动清除中断标志位.
    43. TXE:发送数据寄存器:
    44. 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    45. 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。
    46. 0:数据还没有被转移到移位寄存器
    47. 1:数据已经被转移到移位寄存器。
    48. 注意:单缓冲器传输中使用该位。
    49. */
    50. }
    51. //发送一个数组;Array:传递的数组,Length数组的长度
    52. void Serial_SendArray(uint8_t *Array, uint16_t Length){
    53. for(uint16_t i=0;i
    54. {
    55. Serial_SendByte(Array[i]);
    56. }
    57. }
    58. //发送一个字符串
    59. //发送字符串时自带结束标志位
    60. void Serial_Sendstr(char *str)
    61. {
    62. for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'
    63. Serial_SendByte(str[i]);
    64. }
    65. }
    66. //取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
    67. //12345取3 12345/100(10^2)%10=3 x:从左往右数,不包含要取的数字
    68. uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
    69. {
    70. uint32_t Result = 1;
    71. while (Y --)
    72. {
    73. Result *= X;
    74. }
    75. return Result;
    76. }
    77. //传输数字,把数字中的每一位取出,然后发送出去
    78. //Number:传输的数字; Length:传输数字的长度
    79. void Serial_SendNumber(uint32_t Number, uint8_t Length)
    80. {
    81. uint8_t i;
    82. for (i = 0; i < Length; i ++)
    83. {
    84. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    85. }
    86. }
    87. //printf函数的底层
    88. int fputc(int ch, FILE *f)
    89. {
    90. Serial_SendByte(ch);
    91. return ch;
    92. }
    93. //spinrf函数的封装
    94. void Serial_Printf(char *format, ...)
    95. {
    96. char String[100];
    97. va_list arg;
    98. va_start(arg, format);
    99. vsprintf(String, format, arg);
    100. va_end(arg);
    101. Serial_Sendstr(String);
    102. }
    103. uint8_t RXdata;
    104. int main(void)
    105. {
    106. OLED_Init();
    107. serial_init();
    108. while (1)
    109. {
    110. if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){
    111. RXdata=USART_ReceiveData(USART1);//返回外设最近接收的数据
    112. OLED_ShowHexNum(1,1,RXdata,3);
    113. }
    114. }
    115. }

    PA9口和PA10口的GPIO的模式不同

    引脚的定义

    PA9-----TX发送引脚;          PA10--------Rx接收引脚     

    GPIO工作模式的选择          

            输入工作模式----------将引脚的信号读取到微型控制器---PA10

            输出工作模式---------将微型控制器信号读取到阴极段--PA9

    发送输出;   接收输入

    3:函数介绍

    在stm32f10x usart.h文件中-----使能中断输出信号

    void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

    USART_ITConfig : 启用或禁用指定的USART中断

    配置NVIC在misc.h文件中的函数-----配置NVIC

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
    void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

    NVIC_PriorityGroupConfig:用来中断分组的,参数是中断分组的方式

    NVIC_Init: 根据结构体里面指定的参数初始化NMIC

     在stm32f10x usart.h文件中-----检查某个寄存器的中断标志位

    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

     在stm32f10x usart.h文件中-----清除中断标志位

    void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

     USART_ClearITPendingBit  :        清除USARTx的中断挂起位

    4:串口发送+接收 -----中断代码

            在开启USART之前

    1: 启动USART的RXNE中断,  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    2: 配置NVIC

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "Serial.h"
    5. #include
    6. #include
    7. uint8_t Serial_RxData;
    8. uint8_t Serial_RxFlag;
    9. void serial_init(void){
    10. //开启RCC时钟
    11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    12. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    13. //配置TI的GPIO
    14. GPIO_InitTypeDef GPIO_structinit;
    15. GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设
    16. GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送
    17. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    18. GPIO_Init(GPIOA,&GPIO_structinit);
    19. GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
    20. GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收
    21. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    22. GPIO_Init(GPIOA,&GPIO_structinit);
    23. //USART的配置
    24. USART_InitTypeDef USART_structinit;
    25. USART_structinit.USART_BaudRate=9600;//通信的波特率
    26. USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用
    27. USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式
    28. USART_structinit.USART_Parity=USART_Parity_No; //选择校验方式---无校验
    29. USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数
    30. USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为
    31. USART_Init(USART1,&USART_structinit);
    32. //启动USART的RXNE中断
    33. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    34. //开启NVIC
    35. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    36. NVIC_InitTypeDef NVIC_initstruct;
    37. NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道
    38. NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;
    39. NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;
    40. NVIC_initstruct.NVIC_IRQChannelSubPriority=1;
    41. NVIC_Init(&NVIC_initstruct);
    42. //启动USART
    43. USART_Cmd(USART1,ENABLE);
    44. }
    45. //发送数据
    46. void Serial_SendByte(uint8_t Byte)
    47. {
    48. //发送数据的函数
    49. USART_SendData(USART1,Byte);
    50. //检查某个寄存器的中断标志位
    51. while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    52. /*
    53. 在完成数据发送的时候,TXE置1;
    54. 下次发送数据自动置0,所以不用手动清除中断标志位.
    55. TXE:发送数据寄存器:
    56. 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    57. 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。
    58. 0:数据还没有被转移到移位寄存器
    59. 1:数据已经被转移到移位寄存器。
    60. 注意:单缓冲器传输中使用该位。
    61. */
    62. }
    63. //发送一个数组;Array:传递的数组,Length数组的长度
    64. void Serial_SendArray(uint8_t *Array, uint16_t Length){
    65. for(uint16_t i=0;i
    66. {
    67. Serial_SendByte(Array[i]);
    68. }
    69. }
    70. //发送一个字符串
    71. //发送字符串时自带结束标志位
    72. void Serial_Sendstr(char *str)
    73. {
    74. for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'
    75. Serial_SendByte(str[i]);
    76. }
    77. }
    78. //取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
    79. //12345取3 12345/100(10^2)%10=3 x:从左往右数,不包含要取的数字
    80. uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
    81. {
    82. uint32_t Result = 1;
    83. while (Y --)
    84. {
    85. Result *= X;
    86. }
    87. return Result;
    88. }
    89. //传输数字,把数字中的每一位取出,然后发送出去
    90. //Number:传输的数字; Length:传输数字的长度
    91. void Serial_SendNumber(uint32_t Number, uint8_t Length)
    92. {
    93. uint8_t i;
    94. for (i = 0; i < Length; i ++)
    95. {
    96. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    97. }
    98. }
    99. //printf函数的底层
    100. int fputc(int ch, FILE *f)
    101. {
    102. Serial_SendByte(ch);
    103. return ch;
    104. }
    105. //spinrf函数的封装
    106. void Serial_Printf(char *format, ...)
    107. {
    108. char String[100];
    109. va_list arg;
    110. va_start(arg, format);
    111. vsprintf(String, format, arg);
    112. va_end(arg);
    113. Serial_Sendstr(String);
    114. }
    115. uint8_t Serial_GetRxFlag(void)
    116. {
    117. if (Serial_RxFlag == 1)
    118. {
    119. Serial_RxFlag = 0;
    120. return 1;
    121. }
    122. return 0;
    123. }
    124. uint8_t Serial_GetRxData(void)
    125. {
    126. return Serial_RxData;
    127. }
    128. //USART的中断函数----在启动文件中找
    129. void USART1_IRQHandler(){
    130. //判断RXNE的中断标志位
    131. if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){
    132. Serial_RxData = USART_ReceiveData(USART1);
    133. Serial_RxFlag = 1;
    134. USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
    135. }
    136. }
    137. uint8_t RxData;
    138. int main(void)
    139. {
    140. OLED_Init();
    141. OLED_ShowString(1, 1, "RxData:");
    142. serial_init();
    143. while (1)
    144. {
    145. if (Serial_GetRxFlag() == 1)
    146. {
    147. RxData = Serial_GetRxData();
    148. Serial_SendByte(RxData);
    149. OLED_ShowHexNum(1, 8, RxData, 3);
    150. }
    151. }
    152. }

    四:USART串口数据包

    1:简历

      数据包作用 : 把一个个单独的数据给打包起来,   方便我们进行多字节的数据通信

    需要把多个字节打包为一个整体进行发送, 极大的方便了我们的使用

    2:HEX数据包

            数据包的包头和包尾是可以自己进行设定的,  它并不是一个固定的

            固定包长, 含包头包尾 : 每个数据包的长度都固定不变 (自己定数据包的长度) ,  数据包前面是包头,后面是包尾

            可变包长,含包头包尾 : 每个数据包的长度可以是不一样的,  数据包前面是包头,后面是包尾

    包头包尾和数据载荷重复的问题 

            当包头包尾的数据和传输的数据重复时-----定义FF为包头,FE为包尾,  如果我传输的数据本身就是FF和FE,  可能会引起误判 

            解决:

            A: 限制载荷数据的范围-------可以在发送的时候,对数据进行限幅.   比如XYZ,3个数据,变化范围都可以是0~100.   我们可以在载荷中只发送0~100的数据

            B:无法避免载荷数据和包头包尾重复-----尽量使用固定长度的数据包,  由于载荷数据是固定的,  只要通过包头和包尾对齐的数据.   就可以哪个数据应该是包头包尾,哪个数据应该是载荷数据.        在接收载荷数据的时候,我们并不会判断它是否是包头包尾,   而在接收包头包尾的时候,我们会判断它是不是确实是包头包尾

            C:增加包头包尾的数量---------尽量呈现出载荷数据出现不了的状态

    固定包长和可变包长的选择问题 

            载荷会出现和包头包尾重复的情况--------最好选择固定包长

            反之选择可变包长

    3: 文本数据包

    在HEX数据包里面,数据都是以原始的字节数据本身呈现的,   而在文本数据包里面,每个字节就经过了一层编码和译码,  最终表现出来的,就是文本格式.   其实都还是一个字节的HEX数据

    4:HEX数据包接收

            每收到一个字节,程序都会进一遍中断 .

    状态机:

            最开始,S=0,  收到一个数据,进中断,   判断数据是不是包头FF,  如果是FF,则代表收到包头,  之后置S=1,退出中断,结束.   下次再进中断,根据S=1,就可以进行接收数据的程序了.   这时再收到数据,我们就直接把它存在数组中,  另外再用一个变量,记录收了多少个数据,  如果没收够规定的数据,就一直是接收状态, 如果收够了,就置S=2.   下次中断时,就可以进入下一个状态了.       最后一个状态就是等待包尾了,判断数据是不是FE,  这样就可以置S=0,回到最初的状态,开始下一个轮回

    5:文本数据包接收

    6: 案例

    1:连接图

    A:发送HEX数据包---固定数据长度

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "Serial.h"
    5. #include "Key.h"
    6. #include
    7. #include
    8. uint8_t Serial_RxFlag;//一个数据包发送完成的标志位
    9. uint8_t Serial_TXPacket[4];//存放发送的数据---STM32向外设发送
    10. uint8_t Serial_RXPacket[4];//存放接收的数据---外设向STM32发送数据
    11. void serial_init(void){
    12. //开启RCC时钟
    13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    14. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    15. //配置TI的GPIO
    16. GPIO_InitTypeDef GPIO_structinit;
    17. GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设
    18. GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送
    19. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    20. GPIO_Init(GPIOA,&GPIO_structinit);
    21. GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
    22. GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收
    23. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    24. GPIO_Init(GPIOA,&GPIO_structinit);
    25. //USART的配置
    26. USART_InitTypeDef USART_structinit;
    27. USART_structinit.USART_BaudRate=9600;//通信的波特率
    28. USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用
    29. USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式
    30. USART_structinit.USART_Parity=USART_Parity_No; //选择校验方式---无校验
    31. USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数
    32. USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为
    33. USART_Init(USART1,&USART_structinit);
    34. //启动USART的RXNE中断
    35. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    36. //开启NVIC
    37. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    38. NVIC_InitTypeDef NVIC_initstruct;
    39. NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道
    40. NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;
    41. NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;
    42. NVIC_initstruct.NVIC_IRQChannelSubPriority=1;
    43. NVIC_Init(&NVIC_initstruct);
    44. //启动USART
    45. USART_Cmd(USART1,ENABLE);
    46. }
    47. /**
    48. * @brief 发送一个字节的数据--8位STM32向外设发送===通过USARTx外设传输单个数据
    49. * @param 需要发送的数据
    50. * @retval 无
    51. */
    52. void Serial_SendByte(uint8_t Byte)
    53. {
    54. //发送数据的函数
    55. USART_SendData(USART1,Byte);
    56. //检查某个寄存器的中断标志位
    57. while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    58. /*
    59. 在完成数据发送的时候,TXE置1;
    60. 下次发送数据自动置0,所以不用手动清除中断标志位.
    61. TXE:发送数据寄存器:
    62. 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    63. 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。
    64. 0:数据还没有被转移到移位寄存器
    65. 1:数据已经被转移到移位寄存器。
    66. 注意:单缓冲器传输中使用该位。
    67. */
    68. }
    69. /**
    70. * @brief 发送一个数组
    71. * @param Array:传递的数组
    72. * @param Length数组的长度
    73. * @retval 无
    74. */
    75. void Serial_SendArray(uint8_t *Array, uint16_t Length){
    76. for(uint16_t i=0;i
    77. {
    78. Serial_SendByte(Array[i]);
    79. }
    80. }
    81. /**
    82. * @brief 发送一个字符串
    83. * @param 需要发送的字符串
    84. * @retval 无
    85. */
    86. void Serial_Sendstr(char *str)
    87. { //发送字符串时自带结束标志位
    88. for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'
    89. Serial_SendByte(str[i]);
    90. }
    91. }
    92. /**
    93. * @brief 取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
    94. 12345取3 12345/100(10^2)%10=3 x:从左往右数,不包含要取的数字
    95. * @param X:底数
    96. * @param Y:指数
    97. * @retval 无
    98. */
    99. uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
    100. {
    101. uint32_t Result = 1;
    102. while (Y --)
    103. {
    104. Result *= X;
    105. }
    106. return Result;
    107. }
    108. /**
    109. * @brief 输数字,把数字中的每一位取出,然后发送出去
    110. * @param 传输的数字
    111. * @param 传输数字的长度
    112. * @retval 无
    113. */
    114. void Serial_SendNumber(uint32_t Number, uint8_t Length)
    115. {
    116. uint8_t i;
    117. for (i = 0; i < Length; i ++)
    118. {
    119. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    120. }
    121. }
    122. //printf函数的底层
    123. int fputc(int ch, FILE *f)
    124. {
    125. Serial_SendByte(ch);
    126. return ch;
    127. }
    128. //spinrf函数的封装
    129. void Serial_Printf(char *format, ...)
    130. {
    131. char String[100];
    132. va_list arg;
    133. va_start(arg, format);
    134. vsprintf(String, format, arg);
    135. va_end(arg);
    136. Serial_Sendstr(String);
    137. }
    138. /**
    139. * @brief 知道把中断标志位置位0
    140. * @retval 无
    141. */
    142. uint8_t Serial_GetRxFlag(void)
    143. {
    144. if (Serial_RxFlag == 1)
    145. {
    146. Serial_RxFlag = 0;
    147. return 1;
    148. }
    149. return 0;
    150. }
    151. //------------------HEX包----------------------------
    152. /**
    153. * @brief 发送HEX数据包---STM32发送到其他外设
    154. * @retval 无
    155. */
    156. uint16_t Send_HEX()
    157. {
    158. Serial_SendByte(0XFF);
    159. Serial_SendArray(Serial_TXPacket,4);
    160. Serial_SendByte(0XFE);
    161. }
    162. /**
    163. * @brief 接收HEX数据包---其他外设发送到STM32上面
    164. * @retval 无
    165. */
    166. void USART1_IRQHandler(){
    167. //每收到一个字节,程序都会进一遍中断
    168. //static---- 函数进入只会初始化一次,在函数退出后,数据仍然有效
    169. static uint8_t RxState = 0;//状态机的标志位
    170. static uint8_t pRxPacket = 0;//数据的包长
    171. //判断RXNE的中断标志位
    172. if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){
    173. uint8_t data=USART_ReceiveData(USART1);//32接收的数据
    174. if (RxState==0)
    175. {
    176. if (data==0XFF)
    177. {
    178. RxState=1;
    179. }
    180. }
    181. else if (RxState==1)
    182. {
    183. Serial_RXPacket[pRxPacket]=data; //右边的值赋值给等号的左边
    184. pRxPacket++;
    185. if (pRxPacket>=4)
    186. {
    187. pRxPacket=0;
    188. RxState=2;
    189. }
    190. }
    191. else if (RxState==2)
    192. {
    193. if (data==0xFE)
    194. {
    195. RxState=0;
    196. Serial_RxFlag=1;//一个数据包发送完成的标志位
    197. }
    198. }
    199. USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
    200. }
    201. }
    202. uint8_t RxData;
    203. uint8_t num;
    204. int main(void)
    205. {
    206. Key_Init();
    207. OLED_Init();
    208. serial_init();
    209. OLED_ShowString(1,1,"RX_Data:");
    210. OLED_ShowString(3,1,"TX_Data:");
    211. Serial_TXPacket[0]=0x01;
    212. Serial_TXPacket[1]=0x02;
    213. Serial_TXPacket[2]=0x03;
    214. Serial_TXPacket[3]=0x04;
    215. while (1)
    216. { num=Key_GetNum();
    217. if (num==1)
    218. {
    219. //发送数据
    220. Serial_TXPacket[0]++;
    221. Serial_TXPacket[1]++;
    222. Serial_TXPacket[2]++;
    223. Serial_TXPacket[3]++;
    224. Send_HEX();
    225. OLED_ShowHexNum(2, 1, Serial_TXPacket[0], 2);
    226. OLED_ShowHexNum(2, 4, Serial_TXPacket[1], 2);
    227. OLED_ShowHexNum(2, 7, Serial_TXPacket[2], 2);
    228. OLED_ShowHexNum(2, 10, Serial_TXPacket[3], 2);
    229. }
    230. //接收数据
    231. if (Serial_GetRxFlag()==1)
    232. {
    233. OLED_ShowHexNum(4, 1, Serial_RXPacket[0], 2);
    234. OLED_ShowHexNum(4, 4, Serial_RXPacket[1], 2);
    235. OLED_ShowHexNum(4, 7, Serial_RXPacket[2], 2);
    236. OLED_ShowHexNum(4, 10, Serial_RXPacket[3], 2);
    237. }
    238. }
    239. }

    2:连接图

    B:发送文本数据包---数据长度 

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "Serial.h"
    5. #include "Key.h"
    6. #include "LED.h"
    7. #include
    8. #include
    9. #include
    10. uint8_t Serial_RxFlag;//一个数据包发送完成的标志位
    11. uint8_t Serial_TXPacket[4];//存放发送的数据---STM32向外设发送
    12. char Serial_RXPacket[100];//存放接收的数据---外设向STM32发送数据
    13. void serial_init(void){
    14. //开启RCC时钟
    15. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    16. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    17. //配置TI的GPIO
    18. GPIO_InitTypeDef GPIO_structinit;
    19. GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设
    20. GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送
    21. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    22. GPIO_Init(GPIOA,&GPIO_structinit);
    23. GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
    24. GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收
    25. GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;
    26. GPIO_Init(GPIOA,&GPIO_structinit);
    27. //USART的配置
    28. USART_InitTypeDef USART_structinit;
    29. USART_structinit.USART_BaudRate=9600;//通信的波特率
    30. USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用
    31. USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式
    32. USART_structinit.USART_Parity=USART_Parity_No; //选择校验方式---无校验
    33. USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数
    34. USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为
    35. USART_Init(USART1,&USART_structinit);
    36. //启动USART的RXNE中断
    37. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    38. //开启NVIC
    39. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    40. NVIC_InitTypeDef NVIC_initstruct;
    41. NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道
    42. NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;
    43. NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;
    44. NVIC_initstruct.NVIC_IRQChannelSubPriority=1;
    45. NVIC_Init(&NVIC_initstruct);
    46. //启动USART
    47. USART_Cmd(USART1,ENABLE);
    48. }
    49. /**
    50. * @brief 发送一个字节的数据--8位STM32向外设发送===通过USARTx外设传输单个数据
    51. * @param 需要发送的数据
    52. * @retval 无
    53. */
    54. void Serial_SendByte(uint8_t Byte)
    55. {
    56. //发送数据的函数
    57. USART_SendData(USART1,Byte);
    58. //检查某个寄存器的中断标志位
    59. while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    60. /*
    61. 在完成数据发送的时候,TXE置1;
    62. 下次发送数据自动置0,所以不用手动清除中断标志位.
    63. TXE:发送数据寄存器:
    64. 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    65. 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。
    66. 0:数据还没有被转移到移位寄存器
    67. 1:数据已经被转移到移位寄存器。
    68. 注意:单缓冲器传输中使用该位。
    69. */
    70. }
    71. /**
    72. * @brief 发送一个数组
    73. * @param Array:传递的数组
    74. * @param Length数组的长度
    75. * @retval 无
    76. */
    77. void Serial_SendArray(uint8_t *Array, uint16_t Length){
    78. for(uint16_t i=0;i
    79. {
    80. Serial_SendByte(Array[i]);
    81. }
    82. }
    83. /**
    84. * @brief 发送一个字符串
    85. * @param 需要发送的字符串
    86. * @retval 无
    87. */
    88. void Serial_Sendstr(char *str)
    89. { //发送字符串时自带结束标志位
    90. for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'
    91. Serial_SendByte(str[i]);
    92. }
    93. }
    94. /**
    95. * @brief 取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
    96. 12345取3 12345/100(10^2)%10=3 x:从左往右数,不包含要取的数字
    97. * @param X:底数
    98. * @param Y:指数
    99. * @retval 无
    100. */
    101. uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
    102. {
    103. uint32_t Result = 1;
    104. while (Y --)
    105. {
    106. Result *= X;
    107. }
    108. return Result;
    109. }
    110. /**
    111. * @brief 输数字,把数字中的每一位取出,然后发送出去
    112. * @param 传输的数字
    113. * @param 传输数字的长度
    114. * @retval 无
    115. */
    116. void Serial_SendNumber(uint32_t Number, uint8_t Length)
    117. {
    118. uint8_t i;
    119. for (i = 0; i < Length; i ++)
    120. {
    121. Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    122. }
    123. }
    124. //printf函数的底层
    125. int fputc(int ch, FILE *f)
    126. {
    127. Serial_SendByte(ch);
    128. return ch;
    129. }
    130. //spinrf函数的封装
    131. void Serial_Printf(char *format, ...)
    132. {
    133. char String[100];
    134. va_list arg;
    135. va_start(arg, format);
    136. vsprintf(String, format, arg);
    137. va_end(arg);
    138. Serial_Sendstr(String);
    139. }
    140. /**
    141. * @brief 知道把中断标志位置位0
    142. * @retval 无
    143. */
    144. uint8_t Serial_GetRxFlag(void)
    145. {
    146. if (Serial_RxFlag == 1)
    147. {
    148. Serial_RxFlag = 0;
    149. return 1;
    150. }
    151. return 0;
    152. }
    153. //------------------HEX包----------------------------
    154. /**
    155. * @brief 发送HEX数据包---STM32发送到其他外设
    156. * @retval 无
    157. */
    158. uint16_t Send_HEX()
    159. {
    160. Serial_SendByte(0XFF);
    161. Serial_SendArray(Serial_TXPacket,4);
    162. Serial_SendByte(0XFE);
    163. }
    164. /**
    165. * @brief 接收HEX数据包---其他外设发送到STM32上面
    166. * @retval 无
    167. */
    168. void USART1_IRQHandler(){
    169. //每收到一个字节,程序都会进一遍中断
    170. //static---- 函数进入只会初始化一次,在函数退出后,数据仍然有效
    171. static uint8_t RxState = 0;//状态机的标志位
    172. static uint8_t pRxPacket = 0;//数据的包长
    173. //判断RXNE的中断标志位
    174. if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){
    175. uint8_t data=USART_ReceiveData(USART1);//32接收的数据
    176. if (RxState==0)
    177. {
    178. if (data=='@')
    179. {
    180. RxState=1;
    181. pRxPacket=0;
    182. }
    183. }
    184. else if (RxState==1)
    185. {
    186. if (data=='\r') //\r 的意思是: 回车。将当前位置移到本行的开头。
    187. {
    188. RxState=2;
    189. }
    190. else
    191. {
    192. Serial_RXPacket[pRxPacket]=data; //右边的值赋值给等号的左边
    193. pRxPacket++;
    194. }
    195. }
    196. else if (RxState==2)
    197. {
    198. if (data=='\n')//\n 的意思是:回车换行。将当前位置移到下一行的开头。
    199. {
    200. RxState=0;
    201. Serial_RXPacket[pRxPacket]='\0';
    202. Serial_RxFlag=1;//一个数据包发送完成的标志位
    203. }
    204. }
    205. USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
    206. }
    207. }
    208. uint8_t RxData;
    209. uint8_t num;
    210. int main(void)
    211. {
    212. OLED_Init();
    213. serial_init();
    214. LED_Init();
    215. OLED_ShowString(1,1,"RX_Data:");
    216. OLED_ShowString(3,1,"TX_Data:");
    217. while (1)
    218. {
    219. //接收数据
    220. if (Serial_RxFlag==1)
    221. { OLED_ShowString(4,1," ");
    222. OLED_ShowString(4,1,Serial_RXPacket);
    223. if (strcmp(Serial_RXPacket, "LED_ON")==0)
    224. {
    225. LED1_ON();
    226. Serial_Sendstr("LED_ON_OK\r\n");//使用32把数据发送到外设中去
    227. OLED_ShowString(2, 1, " ");
    228. OLED_ShowString(2, 1, "LED_ON_OK");
    229. }
    230. else if(strcmp(Serial_RXPacket, "LED_OFF")==0)
    231. {
    232. LED1_OFF();
    233. Serial_Sendstr("LED_Off_OK\r\n");//使用32把数据发送到外设中去
    234. OLED_ShowString(2, 1, " ");
    235. OLED_ShowString(2, 1, "LED_Off_OK");
    236. }
    237. else
    238. {
    239. Serial_Sendstr("ERROR_COMMAND\r\n");//使用32把数据发送到外设中去
    240. OLED_ShowString(2, 1, " ");
    241. OLED_ShowString(2,1,"ERROR_COMMAND");
    242. }
    243. Serial_RxFlag = 0;
    244. }
    245. }
    246. }

  • 相关阅读:
    使用机器学习做医学图像分类的开源项目集锦
    Mycat实现分库分表
    sql server判断两个集合字符串是否存在交集
    【错误记录】Navigation 导航组件报错 ( Activity xxActivity@3f does not have a NavController set on 2131xx )
    Sprite Renderer
    Java泛型漫谈
    计算机系统(23)--- 死锁的处理策略
    WPF元素绑定
    关于rsync用不了之后
    图片加水印怎么弄?小白都会的加水印方法
  • 原文地址:https://blog.csdn.net/m0_74739916/article/details/132677838