stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识 您所在的位置:网站首页 将十六进制数6d268转换为二进制数 stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

2023-09-07 20:14| 来源: 网络整理| 查看: 265

文章目录 一、基本储存单元二、通信协议(一)并行通信和串行通信(二)三种工作方式(三)收发数据同步或异步传输(四)通信速率 三、串口通信协议(一)RS232(二)USB转串口(TTL标准)(三)串口到串口(TTL->TTL)(四)串口数据包的基本组成 四、寄存器(一)状态寄存器:USART_SR(二)数据寄存器USART_DR(三)控制寄存器1(USART_CR1)(四)串口接收和发送数据 五、STM32固件库函数六、USART应用(一)发送数据1、函数1-串口发送一个字节数据2、函数2-发送两个字节数据3、函数3-发送一个数组数据4、函数4-发送字符串函数5、函数5-使用printf函数进行打印数据6、函数6-使用getchar函数 (二)接收数据1、串口助手发送并返回数据中断函数2、串口发送数据控制led亮灭3、STM32自定义协议接收十六进制数据(使用三合一气体传感器求出CO2浓度)

一、基本储存单元

位(bit):

二进制数中的一个数位,可以是0或者1,是计算机中数据的最小单位。

字节(Byte):

计算机中数据的基本单位,每8位组成一个字节。各种信息在计算机中存储、处理至少需要一个字节。

例如,一个ASCII码用一个字节表示,一个汉字用两个字节表示。

字(Word):

两个字节称为一个字。汉字的存储单位都是一个字。

1个字节(byte)=8位(bit)数据 1个汉字是一个字,即两个字节,16位数据

二、通信协议

通信方式-框图-参考链接

(一)并行通信和串行通信

并行通信

8位数据并列的传输,传一个8位的数据是需要8根线一起传输。

例如:SDIO,FSMC(16位的)–发送数据都是所有数据位同时传输 在这里插入图片描述

串行通信

8位数据一位一位的传输,只需要一根线即可进行传输。

例如:USART,IIC,SPI三种都是串行方式-----发送数据时都是一位一位的进行发送数据 在这里插入图片描述

串行通信与并行通信特征

在这里插入图片描述

(二)三种工作方式

全双工

有两根数据线,一个用来接收数据,一个用来发送数据,互不干扰,可以同时发送和接收数据。

例如:usart(可以半双工或全双工通信),SPI(可以半双工或者全双工通信)

半双工

有两根数据线,但是不可以同时发送数据,可以分时收发数据

单工

只有一根数据线,只可以单向通信(只可以往某一个方向进行)

例如:IIC

000-串口通讯的单工、半双工和全双工的定义、区别及应用-

(三)收发数据同步或异步传输

同步通信

数据同步方式,两个设备的时钟信号是同一个(有时钟信号的是同步)。

在传输数据时为了保证数据传输的准确性: (1)时钟在高电平时,数据有效 (2)时钟信号在低电平时数据时无效的 (3)对时钟的要求很高(如果时钟有尖峰或者杂波,则数据传输就不准确了)

例如:SPI,IIC通信接口。 在这里插入图片描述

异步通信

没有时钟信号:为了保证数据传输的准确性是通过加上一些辅助的标识符

例如:UART(通用异步收发器),单总线。 在这里插入图片描述

同步通信和异步通信比较

(1)在同步通信中,数据信号所传输的内容绝大部分就是有效数据。 (2)在异步通信中,传输的数据会包含有帧的各种标识符。 (3)所以同步通信的效率更好,但是对于时钟允许误差较小,异步通信对于时钟允许误差较大。

(四)通信速率

比特率:每秒钟传输的二进制数单位:bit/s

IIC,SPI(同步通信,一个时钟下传输一个数据,通过时钟来控制)

波特率:每秒钟传输的码元个数(串口)

一个二进制位表示一个码元(特殊情况下)

三、串口通信协议

物理层规定我们用嘴巴还是肢体进行交流 协议层就是规定我们用汉语还是英文来交流

(一)RS232

1、RS232和TTL就是在电平上的区别

TTL电平是直接从单片机(或者芯片)里面出来的:高电平用3.3V或者5v来表示,低电平用0表示 RS232中1用-15V表示,0用+15V表示,逻辑正好时相反的,低电平和高电平的差距非常大 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

(二)USB转串口(TTL标准)

在这里插入图片描述

(三)串口到串口(TTL->TTL)

在这里插入图片描述

(四)串口数据包的基本组成

在这里插入图片描述

奇校验

在这里插入图片描述

偶校验

在这里插入图片描述

四、寄存器 (一)状态寄存器:USART_SR

在这里插入图片描述

TXE-发送数据寄存器空

当TDR寄存器中的数据被硬件转移到移位寄存器的时候,TXE位被硬件置位。 如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。

0-数据还没有转移到移位寄存器 1-数据已经转移到移位寄存器

TC-发送完成

当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将TC位置’1’。 如果USART_CR1中的TCIE=1,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。 TC位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。

0-发送还没有完成 1-发送已经完成

RXNE-读数据寄存器非空

当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位(RXNE)被硬件置位。 如果USART_CR1寄存器中的RXNEIE=1,则产生中断。对USART_DR的读操作可以将该位清零。 RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。

0-数据没有收到 1-收到数据可以读出

(二)数据寄存器USART_DR

在这里插入图片描述

(三)控制寄存器1(USART_CR1)

在这里插入图片描述

UE是使能串口 (1-模块使能)TE是发送使能(0-禁止发送,1-使能发送)RE是接收使能(0-禁止接收,1-使能接收)PEIE是PE中断使能(0-禁止产生中断,1-当USART_SR的PE为1时,产生USART中断)TCIE是发送完成中断使能(0-禁止产生中断,1-当USART_SR中的TC为’1’时,产生USART中断)RXNEIE:接收缓冲区非空中断使能(0-禁止产生中断,1-当USART_SR中的ORE或者RXNE为’1’时,产生USART中断) (四)串口接收和发送数据 发送数据流程

在这里插入图片描述

此时UE=1,TE=1 上图对应的顺序依次是1->2->3,数据来源于CPU或者DMA,数据来了之后首先是放到发送寄存器(TDR)中,然后会再放到发送数据移位寄存器中,由于数据是8位的,会将数据一位一位的发送出去(使用TX引脚)。

当数据由发送寄存器到发送数据移位寄存器时,TXE会被置1,即TXE=1,表示发送数据寄存器为空了,但是并不表示数据已经发送出去了。因为还要通过发送移位寄存器进行一位一位的发送数据,如果发送移位寄存器数据全部发送出去了,TC会被置1,即TC=1表示发送数据完毕。

**

接收数据流程

**

在这里插入图片描述 此时UE=1,RX=1 数据从RX引脚进来来,数据是一位一位进行接收的。

首先放到数据接收移位寄存器然后将数据传递到数据接收寄存器(RDR),此时RXNE会被置1,即RXNE=1,表示数据接收寄存器不是空的(收到数据可以读出) 五、STM32固件库函数

在这里插入图片描述 几个常用的固件库函数 在这里插入图片描述 在这里插入图片描述

串口初始化函数

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);引脚、波特率、位数,校验、时钟等

串口使能

USART_Cmd(USART1, ENABLE); //使能串口—配置的是UE位

中断使能

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

发送数据

STM32 库函数操作 USART_DR 寄存器发送数据的函数是:通过该函数向串口寄存器 USART_DR 写入一个数据。

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

接收数据

STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:通过该函数可以读取串口接收到的数据。

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

获取标志位

该函数只判断标志位。在没有使能相应的中断函数时,通常使用该函数来判断标志位是否置1

Flagstatus USART_GetFlagStatus(USARTx,USART_FLAG)

中断状态位获取函数

不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断。所以在串口中断函数中,如果要获取中断标志位,通常使用该函数。

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)

清楚中断标志位

Void USART_Flag_Clear(USARTx,USART_FLAG)

几个标志位函数的区分说明–链接

六、USART应用

串口初始化函数

//初始化IO 串口1 //bound:波特率 void uart_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体指针 USART_InitTypeDef USART_InitStructure;//串口结构体指针 NVIC_InitTypeDef NVIC_InitStructure;//中断分组结构体指针 //1、使能串口时钟,串口引脚时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 //2、复位串口 USART_DeInit(USART1); //复位串口1 //3、发送接收引脚的设置 //USART1_TX PA.9(由图 可知设置为推挽复用输出) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9 //USART1_RX PA.10(有图可知浮空输入) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10 //4、USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//一般设置为9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_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_Init(USART1, &USART_InitStructure); //初始化串口 #if EN_USART1_RX //如果使能了接收 //5、Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //6、开启接收数据中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断 #endif //7、使能串口 USART_Cmd(USART1, ENABLE); //使能串口 } (一)发送数据 1、函数1-串口发送一个字节数据 void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data) { //调用固件库函数 USART_SendData(pUSARTx,data);//往串口中写入数据 //发送完数据是检测TXE这个位是否置1,发送数据寄存器空了,表明已经把数据传递到数据移位寄存器了 //检测TXE这个位也需要一个固件库函数 while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET); //如果这个位一直为0的话就一直等待,只有当被设为SET后才会跳出这个循环(表示一个字节发送出去了) }

在main主函数中编写语句:

//在主函数里面发送一个数据试试 Usart_SendByte(USART1,100);//往串口1中写入数据100

串口调试助手并没有显示100,而是显示的一个字母d 串口调试助手不管接收到的是什么数据,都会转化为字符 只有发送十六进制数据,串口助手使用十六进制形式接收数据时才不是字符

Usart_SendByte(USART1,'A');//往串口1里面写入一个字符A //串口接收到字符A

串口助手无论是收发都是以字符的形式进行传输的

假如说串口助手发送一个数字1,stm32串口如果能够接收的话,在进行数据解析过程中需要按照字符 ’1‘ 来进行解析(把1当成是字符,而不是十进制1 )

2、函数2-发送两个字节数据

有时候传感器数据可能是16位的,怎么发送?发送两个字节? 发送两个字节的数据就是十六位的。

//发送两个字节数据函数 void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data) { //发送十六位数据要分为两次来发送,先定义两个变量 uint8_t temp_h,temp_l;//定义8位的变量(分别存储高8位和低8位) //首先取出高8位 temp_h=(data&0xff00)>>8;//低八位先与0相&,低8位变为0再右移8位(0xff00共16位二进制) //再取出低8位 temp_l=data&0xff;//取出低8位数据 //16位的数据这样子就放到了两个变量里面(共16位) //调用固件库函数 USART_SendData(pUSARTx,temp_h);//先发送高8位 while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);//等待数据发送完毕 USART_SendData(pUSARTx,temp_l);//再发送低8位 while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);//等待数据发送完毕 }

在主函数中发送十六进制数据:

Usart_SendHalfWord(USART1,0XFF56);//发送16位数据

串口助手显示的是字符,要想接收到的数据和发送的一样,需要把串口助手选择为16进制接收 串口助手接收到ff 56。虽然是16位的数据但是显示的时候还是一个字节一个字节的显示,十六进制ff是一个字节 56是一个字节 在这里插入图片描述

3、函数3-发送一个数组数据 //发送一个数组数据 void Usart_SendArray(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num) { //每次想要发送多少数据,通过形参num传进来,num定义的是8位的,那么函数最多发送255个 int i; for(i=0;iDR); //读取接收到的数据 if(count==0)//如果是接收的第一个数据 { table_data[count]=Res;//将第一个数据存到数据中第一元素 if(table_data[0]==0x2c)//判断接收的第一个数据是不是十六进制0X2C count++;//如果第一个数据是0X2C则表示正确计数+1 } else if(count==1)//第一个数据接收正确的情况下,判断第二个数据 { if(Res==0xe4)//如果刚接收的数据是0xE4则表示数据正确 { table_data[count]=Res;//将数据储存到数组第二个元素位置 count++;//接收数据计数+1 } else//如果第二个字符不是0XE4则计数清零,重新接收 count=0; } else if(count==2&&Res==0)//如果前两个数据正确,接收的第三个数据是0,则清零计数,重新接收数据 { count=0; } else if(count>1&&count=9)//如果接收数据超过数组大小,则清零重新接收 { count=0; } } memset(table_cp, 0, sizeof(table_data));//在使用数组table_cp时清空 for(i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有