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

这篇具有很好参考价值的文章主要介绍了stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、基本储存单元

  • 位(bit):

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

  • 字节(Byte):

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

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

  • 字(Word):

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

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

二、通信协议

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

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

  • 并行通信

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

    例如:SDIO,FSMC(16位的)–发送数据都是所有数据位同时传输
    stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

  • 串行通信

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

    例如:USART,IIC,SPI三种都是串行方式-----发送数据时都是一位一位的进行发送数据
    stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

  • 串行通信与并行通信特征

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

(二)三种工作方式

  • 全双工

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

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

  • 半双工

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

  • 单工

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

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

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

  • 同步通信

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

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

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

  • 异步通信

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

    例如:UART(通用异步收发器),单总线。
    stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

  • 同步通信和异步通信比较

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

(四)通信速率

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

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

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

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

三、串口通信协议

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

(一)RS232

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

TTL电平是直接从单片机(或者芯片)里面出来的:高电平用3.3V或者5v来表示,低电平用0表示
RS232中1用-15V表示,0用+15V表示,逻辑正好时相反的,低电平和高电平的差距非常大
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

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

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

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

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

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

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

  • 奇校验

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

  • 偶校验

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

四、寄存器

(一)状态寄存器:USART_SR

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

  • 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

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

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

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

  • 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中断)

(四)串口接收和发送数据

  • 发送数据流程

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

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

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

**

  • 接收数据流程

**

stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
此时UE=1,RX=1
数据从RX引脚进来来,数据是一位一位进行接收的。

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

五、STM32固件库函数

stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
几个常用的固件库函数
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
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是一个字节
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

3、函数3-发送一个数组数据
//发送一个数组数据
void Usart_SendArray(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num)
{
	//每次想要发送多少数据,通过形参num传进来,num定义的是8位的,那么函数最多发送255个
	int i;
	for(i=0;i<num;i++)
	{
		//调用发送一个字节函数发送数据(下面两种写法都可以)
		//Usart_SendByte(USART1,*array++);
		Usart_SendByte(USART1,array[i]);//每次只能发送8位数据
	}
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);//等待发送完毕
}

判断发送一个字节的数据标志位:USART_FLAG_TXE
判断发送一连串字节的数据标志位:USART_FLAG_TC

在主函数中定义一个数组

uint8_t a[12]={1,2,3,4,5,6,7,8,9,10,98,100};

将数据内容发送出去

Usart_SendArray(USART1,a,12);

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

串口助手:非十六进制数据形式接收数据:1-10的ASCII是无法显示的
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

4、函数4-发送字符串函数
//发送字符串
	void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str)//指定串口,要发送的字符串内容
	{
		uint8_t i=0;
		//使用do-while循环,do的时候已经开始发送了
		do{
			//需要调用发送一个字节函数
			Usart_SendByte(USART1,*(str+i));//发送一次之后指针地址后移一个
			i++;
		}while(*(str+i)!='\0');//最后结尾不等于'\0'为真,继续发送
		//如果='\0'表示发送完毕
		while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);//等待发送完毕
	}

在主函数中调用函数发送一个字符串

Usart_SendStr(USART1,"欢迎使用stm32\n");//此时发送的是字符,串口助手要取消十六进制接收
5、函数5-使用printf函数进行打印数据

有时候想直接用printf函数直接发送,肯定是不可以的
printf函数底层会有一个fputc,如果想要使用,需要重新定义

int fputc(int ch FILE *f)
{
	//发送一个字节数据到串口
	USART_SendData(USART1,(uint8_t)ch);
	//等待发送完毕
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	//检测发送数据寄存器是否为空USART_FLAG_TXE

	return (ch);
}

在主函数中编写代码

printf("串口测试实验\n");
//发送一个字符也可以直接使用putchar('a')

putchar('a');//串口助手会接收到字母a
6、函数6-使用getchar函数

getchar()等价于scanf()函数
如果使用getchar函数也需要重新定义
重定向c库函数scanf到串口,重写后可以使用scanf和getchar函数

重定向c库函数scanf到串口,重写后可以使用scanf和getchar函数
int fgetc(FILE *f)
{
	//等待串口输入数据
	/* 有了这个等待就不需要在中断中进行了 */
	while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
	return (int)USART_ReceiveData(USART1);
}

如果在主函数中使用getchar()需要把下面的中断设置代码注释掉(下图),否则会冲突
因为不需要在中断中进行

stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
在主函数的while(1)循环中加入接收数据和发送数据的代码

ch=getchar();
printf("ch=%c\n",ch);//打印接收到的字符

用串口助手发送什么字符,串口助手就会接收到单片机返回什么字符
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

(二)接收数据

当接收到数据时产生中断

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断

有中断就要设置中断优先级

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寄存器

编写中断服务函数

1、串口助手发送并返回数据中断函数

串口助手发送什么数据给单片机,单片机自动将接收到的数据返回给串口助手

//中断服务函数
void USART1_IRQHandler() 
{
	u8 ucTemp;
	if(USART_GetFlagStatus(USART1,USART_IT_RXNE)!=RESET)
	{
		ucTemp=USART_ReceiveData(USART1);
		USART_SendData(USART1, ucTemp);
	}
}

当外部设备或者串口调试助手给单片机发送数据时,单片机检测到数据接收寄存器非空,表示数据来了此时产生中断,进去中断服务函数调用固件库函数这个标志位是否真正置1,以免产生误中断,如果真的产生1时,调用USART_ReceiveData(USART1)函数接收数据,把数据放ucTemp变量中
再调用USART_SendData(USART1, ucTemp)把数据发送回串口助手

2、串口发送数据控制led亮灭

通过串口接收到的数据进行控制led灯,这样子就不需要中断来接收了,通过查询方法即可,这时候要把中断部分给注释了,中断服务函数注释掉就可以了

在主函数中加入以下代码:

   u8 ch;//存放电脑接收到的数据
	while(1)
	{
		ch=getchar();//读取串口数据
		printf("ch=%c\n",ch);//打印接收到的字符
		switch(ch)//进行匹配
		{
			case '1':
				LED0=0;break;//打开LED0
			case '2':
				LED1=0;break;//打开LED1
		}

	}

如果出现错误:参考此链接
解决方案-链接
使用串口助手分别发送1和2就可以控制led灯的亮灭了
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

3、STM32自定义协议接收十六进制数据(使用三合一气体传感器求出CO2浓度)

前面已经说到,如果不勾选十六进制数据接收和发送的话,其他情况都是以字符的形式发送和接收的,所以此处在发送和接收数据时都要将hex选项进行勾选

三合一气体传感器串口数据流格式如下:
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

由于前两个字节数据是固定的模块地址,因为可以用来当做判断标准,定义一个接收数据的协议:只有第一个字节和第二个字节都符合条件时,才将数据存储到数组中

模块数据流:2C E4 04 00 00 AD 03 38 FC

数据流共9个字节,所以先定义一个存储9个字节的八位数组

u8 table_data[9];//这是提前定义一个数组存放接收到的数据
u8 table_cp[9];//这是额外定义一个数组,将接收到的数据复制到这里面
u16 count=0;//接收数据计数

编写中断服务函数

//使用自定义协议接收十六进制数据

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
		u8 Res,i;
		if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
		{
			Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
			
			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在数据可接收数据范围内即可进行存入数据
			{
				table_data[count]=Res;
				count++;
			}
			else if(count>=9)//如果接收数据超过数组大小,则清零重新接收
			{
				count=0;
			}		
   } 
	 
		memset(table_cp, 0, sizeof(table_data));//在使用数组table_cp时清空
		for(i=0;i<9;i++)//把接收到的数据复制到table_cp数组中
		{
			 table_cp[i]= table_data[i];
	}
} 

上面实现的是通过自定义协议接收并存储数据

在接收到十六进制数据之后,想要提取其中的两个字节并将其转化为十进制数据,首先需要编写一个十六进制转换函数:(输入十六进制数据返回十进制数据

int hextoDec(int hex)
{
	 int sum=0,mul=1;
	 int i,r;
	 int count=0;
	 do{
	  r=hex%16;
	  for(i=0;i<count;i++)
	   mul*=16;
	  mul*=r;
	  sum+=mul;
	  mul=1;
	  count++; 
	 }while(hex/=16);
	 return sum;
}

主函数的while内容如下:

while(1)
	{
	  if(table_cp[0]==0x2c)//如果数组第一个十六进制数据是0X2C则进行
		{
			//用十进制数据打印一下接收到的数据
			//原始数据(十六进制数据)是2C E4 04 00 00 AD 01 23 FC
			//前两位是固定的,第7个和第8个十六进制数据分别是CO2的高八位和低八位
			for(i=0;i<9;i++)
			{
					printf(" %d \n",table_cp[i]);
				
			}
			
			printf("\r\n");//加一个回车换行
			//把对应的十六进制数据转化为十进制数据
			num_H=hextoDec(table_cp[6]);//高8位
			num_L=hextoDec(table_cp[7]);//低8位
			printf("hh=%d LL=%d \n",num_H,num_L);
			num=num_H*256+num_L;//使用CO2浓度计算公式计算出数值
			printf("CO2=%d\n",num);
				
			}
	}

stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识
验证如下:
如下图所示:使用串口助手发送十六进制数据:
2C E4 04 00 00 AD 03 38 FC

其中第7个字节是CO2的高8位,第8个字节是CO2浓度的低8位,然后再按照计算公式进行计算即可求出二氧化碳浓度
stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

完整代码下载链接文章来源地址https://www.toymoban.com/news/detail-405369.html

到了这里,关于stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 串口通信(6)应用定时器中断+串口中断实现接收一串数据

     本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步! 发布人:@日月同辉,与我共生_单片机-CSDN博客 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。 系列专栏: CSDN- 单片机串

    2024年02月06日
    浏览(57)
  • MATLAB输出串口发送所需十六进制数据

      可以用一个文件来测试其是否符合我们的要求,将一个二进制向量转化为十六进制向量,每个十六进制数表示1byte(不足1byte前面补0),并且写入txt文件中,每byte之间用空格隔开。   打开存储路径下的txt文件,可见符合预期需求。   使用串口助手载入txt文件,可见

    2024年02月16日
    浏览(48)
  • rk3566通过stty向串口发送十六进制数据

    在Unix或Linux系统中,stty命令可以用于设置和控制终端的参数。要发送十六进制数据给串口,需要使用stty命令设置终端为raw模式,这样终端就不会将输入或输出数据进行任何处理。然后,可以使用echo命令将十六进制数据写入串口。 以下是在Linux系统中发送十六进制数据的步骤

    2023年04月10日
    浏览(49)
  • STM32-串口通信(串口的接收和发送)

    本文在于记录自己的学习过程中遇到的问题和总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重,本文主要对 串口通信 做一个简要的总结。 在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输 并行数据 ,是 全双工 , 异步时钟控制 ,设备之间是

    2024年02月03日
    浏览(76)
  • stm32 串口多字节接收

    如果不想看的可以直接使用git把我的代码下载出来,里面工程挺全的,后期会慢慢的补注释之类的 码云地址:stm32学习笔记: stm32学习笔记源码 如果不会使用git快速下载可以选择直接下载压缩包或者去看看git的使用 git的使用(下载及上传_gitcode怎么下载文件_是小刘不是刘的博

    2024年02月06日
    浏览(61)
  • STM32 串口DMA接收数据(高效接收数据)

    极度不推荐在使用DMA的时候按照传统的方式进行重定义!!! 非常简单,轮询方式整个CPU 在串口发送时处于等待状态,但是使用DMA时无法确保当前DMA已经传输完成。 有同学可能会认为可以通过判断DMA的传输标志位来进行等待,但如果这样的话就丧失了DMA的设计意图: 再次使

    2024年02月16日
    浏览(51)
  • STM32串口通信—串口的接收和发送详解

    目录 前言: STM32串口通信基础知识: 1,STM32里的串口通信 2,串口的发送和接收 串口发送: 串口接收: 串口在STM32中的配置: 1. RCC开启USART、串口TX/RX所对应的GPIO口 2. 初始化GPIO口 3. 串口初始化 4. 串口使能 5. 串口发送数据 串口接收的两种实现方式: 1,轮询方式: 2,中断

    2024年04月08日
    浏览(111)
  • STM32(HAL)串口中断接收

    目录 1、简介 2 基础配置 2.1.1 SYS配置  2.1.2 RCC配置 2.2 串口外设配置  2.3 项目生成  3、KEIL端程序整合 本文对HAL串口中断函数进行介绍。 2.1.1 SYS配置  2.1.2 RCC配置 首先在main.c文件中进行接受变量声明。  接着在主函数的while循环中进行接收中断,如下所示:  最后在主函数

    2024年02月14日
    浏览(52)
  • STM32实现DMA接收串口数据

    一..首先我们得配置DMA和USARAT,我们的原理是DMA1的通道5为USART1的RX引脚。  1.USART1的配置 2.DMA的配置 二.中断进行数据处理(stm32f10x_it.c) 我们可以串口打印出数组中的数据,验证DMA是否正常工作。可以到数据处理那个地方进行处理。USART1在初始化中就已经波特率为115200.我们可以

    2024年02月16日
    浏览(46)
  • Qt自定义窗口部件/控件(实现一个十六进制微调框SpinBox)

    在某些情况下,我们发现Qt窗口控件需要更多的自定义定制,这些定制可能要比它在Qt设计师里可设置的属性或者对它调用的那些函数更多一些。一个简单而直接的解决方法就是对相关的窗口部件类进行子类化并且使它能够满足我们的需要。 本文主要是通过实现一个十六进制微调

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包