【STM32学习】——USART串口数据包&HEX/文本数据包&收发流程&串口收发HEX/文本数据包实操

2023-05-16

文章目录

  • 前言
  • 一、数据包格式(江科大规定)
    • 1.HEX数据包
    • 2.文本数据包
    • 3.两者对比
  • 二、数据包收发流程
    • 1.HEX数据包接收(只演示固定包长)
    • 2.文本数据包接收(只演示可变包长)
  • 三、实操案例
    • 1.串口收发HEX数据包
    • 2.串口收发文本数据包(发直接用SendString,代码主要写接收)
  • 总结


声明:学习笔记根据b站江科大自化协stm32入门教程编辑,仅供学习交流使用!

前言

本次学习有两个实操代码,第一个是串口收发HEX数据包,第二个是串口收发文本数据包


一、数据包格式(江科大规定)

数据包的作用是把一个个单独的数据打包起来,方便我们进行多字节的数据通信。之前学习的串口代码,发送一个或接收一个字节都没问题。但在实际应用中需要把多个字节打包为一个整体进行发送。比如有一个陀螺仪传感器需要用串口发送数据到STM32,比如X轴一个字节、Y轴一个字节、Z轴一个字节总共3个数据需要连续不断地发送,当按照XYZXYZXYZ…进行连续发送时会出现一个问题,接收方不知道哪个对应X、哪个对应Y,哪个对应Z,因为接收方可能会从任意位置开始接收,会出现数据错位的现象,这时需要一种方式对数据进行分割为一个个数据包,这样接收方可以方便识别第1个为X、第2个位Y、第3个为Z。
分割打包的方法可以自己发挥设计,只要逻辑合理即可比如可以设计在XYZXYZ…数据流中,数据包第1个数据也就是X数据包,它的最高位置1,其余数据包最高位都置0,当接收到数据后判断下最高位,如果是1就是X数据,然后紧跟着的两个数据就是Y和Z,这种分割方法就是把每个数据的最高位当作标志位来进行分割,实际例子比如UTF8的编码方法和这个类似(不过它更高级些)。
本节的数据包分割方法并不是这种,这种方式破坏了原有数据使用起来比较复杂,串口数据包通常使用的是额外添加包头包尾的方式


1.HEX数据包

包头包尾方法如下江科大列举了2种数据包格式:
具体格式可根据需求自己规定,也可能是买了个模块别的开发者规定的
1、固定包长,含包头包尾。即每个数据包的长度都固定不变,数据包前面的是包头,后面的是包围。
在这里插入图片描述
这里规定了一批数据有4个字节,在这4个字节首尾加上包头包围,比如规定0xFF为包头,0xFE为包围(类似一个标志位作用)。
2、可变包长,含包头包尾。每个数据包的长度可以是不一样的。
在这里插入图片描述
研究问题:
①包头包尾和数据载荷重复的问题。比如规定0xFF为包头,0xFE为包围,那如果传输的数据本身就是就是FF或FE呢?这里确实会引起误判,解决方法有:第一种,限制载荷数据的范围,在发送的时候对数据进行限幅,比如XYZ3个数据变化范围只可以0-100。第二种,如果无法避免数据与包头包尾重复,就尽量使用固定长度的数据包(固定包长),这样由于载荷数据固定只要通过包头包尾对齐了数据,就可严格知道哪个应该是包头包尾哪个应该是数据(只在特定步长处if判断是否为包头包尾)。第三种,增加包头包尾的数量,并且让它尽量呈现出载荷数据出现不了的状态,比如使用FF、FE作为包头,FD、FC作为包尾。
②包头包尾并不是全部都需要,比如可以只要包头FF不要包尾,包头+4个字节,收够4个字节后置标志位,一个数据包接收完成,只不过这样载荷和包头重复的问题会更严重些。
③固定包长和可变包长的选择。对于HEX数据包,如果载荷会出现和包头包尾重复的情况,最好选择固定包长,无重复情况可选择可变包长。
④各种数据转换为字节流。这里的数据包都是一个字节一个字节组成的,如果想发送16位整型数据、32位整型数据、float、double、甚至结构体都没问题,因为它们内部其实都是由一个字节一个字节组成的。只需要用一个uint8_t的指针指向它,把它们当作一个字节数组发送就行(可见指针学习)


2.文本数据包

在HEX数据包里,数据都是以原始的字节数据本身呈现,在文本数据包里,每个字节经过了一层编码和译码,最终表现出来的就是文本格式。所以实际上每个文本字符背后都是一个字节的HEX数据:
1、固定包长,含包头包尾
在这里插入图片描述
2、可变包长,含包头包尾
在这里插入图片描述
由于数据译码成为字符形式,所以存在大量字符可作为包头包尾,可有效避免数据与包头包尾重复的问题。这里以@作为包头,\r和\n作为包尾,当我们接收到载荷数据之后得到就是一个字符串,在软件中再对字符串进行操作和判断,就可实现各种指令控制功能,且字符串数据包表达的意义很明显,可发送到串口助手在电脑显示打印,所以常以\n换行符作为包尾,这样打印是就可一行一行显示。


3.两者对比

HEX数据包优点是传输最直接、解析数据简单,比较适合一些模块发送原始数据,如一些使用串口通信的陀螺仪、温湿传感器;缺点是灵活性不足、载荷数据易于包头包尾重复。
文本数据包优点是直观易理解、灵活,比较适合一些文本指令进行人机交互的场合,如蓝牙模块常使用的AT指令、CNC和3D打印机常用的G代码都是文本数据包格式;缺点是解析效率低,比如发送一个100,HEX就直接是100一个字节,文本数据包要3个字节的字符‘1’、‘0’、‘0’,收到后还要把字符转换为数据才能得到100。


二、数据包收发流程

数据包的发送过程很简单,如HEX数据包发送,先定义一个数组,填充数据,然后用上一节写过的USART_SendArray函数;文本数据包同理,写一个字符串,调用上一节写的USART_SendString函数。之所以简单是因为发送过程完全自主可控,想发什么就发什么,上一节串口也可体会到发送比接收简单多了。
下面重点介绍下接收(HEX只演示固定包长,文本只演示可变包长)

1.HEX数据包接收(只演示固定包长)

根据之前代码,每收到一个字节程序都会进一遍中断,在中断函数里我们可以拿到这一个字节,但拿到之后就要退出中断了,所以每拿到一个数据都是一个独立的过程。而对于数据包来说,它具有前后关联性,对于包头、数据、包尾这三种状态我们需要不同的处理逻辑,所以在程序中,我们需要设计一个能记住不同状态的机制,在不同的状态执行不同的操作,同时还要进行状态的合理转移,这种程序思维叫做“状态机”。
要想设计好的“状态机”程序,画一个以下的状态转移图很有必要:
在这里插入图片描述
对于上面的一个固定包长的HEX数据包,我们定义三个状态:等待包头、接收数据、等待包尾,每个状态都需要一个变量来标志一下,比如上面依次用S=0、S=1、S=2(有点类似置标志位,只不过标志位只有0/1,而状态机是多标志位状态的一种方式)。


执行流程是
①最开始S=0。收到一个数据,进中断,根据S=0进入第一个状态的程序,判断数据是不是包头FF,如果是FF则代表收到包头,之后置S=1退出中断,结束。这样下次再进中断,根据S=1就可以进行接收数据的程序了。如果在第一个状态收到的不是FF,就说明数据包未对齐,这时应该等待数据包包头的出现,S仍是0,下次进中断仍是执行判断包头的逻辑,直到出现FF才可进入下一个状态。
②到接收数据的状态后,收到数据就把它存在数组中,再用一个变量记录接收了多少数据,没到4个就一直是这个接收数据状态,收够了就置S=2,进入下一个状态。
②最后等待包尾,判断数据是否为FE,是的话就置S=0回到最初状态,开始下一轮回。也有可能不是FE,比如数据于包头重复,导致前面包头位置判断错误,就可能导致包尾不是FE,这时就可进入重复等待包尾的状态,直到接收到真正包尾。


状态机”是一种普遍编程思路,一般最好配合状态转移图思路更加清晰。比如做个菜单,按什么键切换什么菜单,执行什么程序;还有一些芯片内部逻辑,芯片什么时候进入待机状态什么时候进入工作状态,都会用到状态机。


2.文本数据包接收(只演示可变包长)

在这里插入图片描述
流程类似,只不过这里因为演示的是可变包长接受数据的状态(S=1)在进行数据接收的逻辑时,还要兼具等待包尾的功能:收到一个数据判断是否为\r,如果不是\r则正常接收数据;如果是\r则不接收数据,同时跳到下一个状态(S=2),等待包尾\n。因为这里设置了两个包尾\r、\n,所以需要第三个状态(S=2),如果只有一个包尾\r,那么在S=1状态中逻辑判断出现包尾\r,后就可直接回到初始状态。


三、实操案例

接线图与上次串口的基本相同,只不过HEX数据包接线图里PB1口接了个按键,用于控制;收发文本的接线图,在PA1口接了LED用于指示。按键和LED的附加功能可自己实现,下面的代码只写核心部分

1.串口收发HEX数据包

在这里插入图片描述
代码是在9-2串口发送+接收(只可一个字节)基础上改进而成:

//Serial.c
//在9-2串口发送+接收(只可一个字节)基础上改进


#include "stm32f10x.h"   
//先定义两个缓存区的数组,4个字节(只存储发送或接收的载荷数据)
//在头文件里声明外部可调用,使它们可在main.c里使用赋值
uint8_t Serial_RxPacket[4];
uint8_t Serial_TxPacket[4];

uint8_t Serial_RxFlag;

void Serial_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate= 9600;
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode= USART_Mode_Tx |USART_Mode_Rx;
	USART_InitStructure.USART_Parity= USART_Parity_No;
	USART_InitStructure.USART_StopBits= USART_StopBits_1;
	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
	USART_Init(USART1,&USART_InitStructure);
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1,ENABLE);
}

void Serial_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	
}

void Serial_SendArray(uint8_t* Array,uint16_t Length){
	uint16_t i;
	for(i=0;i<Length;i++){
		Serial_SendByte(Array[i]);
	}
}

//函数功能:发送。调用后,TxPacket数组里的4个数据,就会自动加上包头包尾发送出去
void Serial_SendPacket(void){
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket,4);
	Serial_SendByte(0xFE);
}

uint8_t Serial_GetRxFlag(void){//用于判断是否收到了数据包
	if(Serial_RxFlag == 1){
		Serial_RxFlag=0;
		return 1;
	}
	return 0;
}
void USART1_IRQHandler(void){
	static uint8_t RxState = 0;//状态变量S(接收)
	//这个静态变量类似于全局变量,函数进入后只会初始化一次0,函数退出后数据仍然有效
	//与全局变量不同的是,静态变量只能在本函数使用
	static uint8_t pRxPacket = 0;//指示接收到哪一个字节(载荷数据)
	if (USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET){
		uint8_t RxData = USART_ReceiveData(USART1);//取出接收到的字节(一次一个)
		if (RxState == 0){
			if (RxData == 0xFF){//检测到包头
				RxState = 1;//进入下一个状态
				pRxPacket = 0;//在进入S=1前,提前清0
			}
		}
		else if (RxState == 1){
			Serial_RxPacket[pRxPacket] = RxData;//传给接收数组
			pRxPacket++;
			if (pRxPacket >=4){//接收够4个字节的载荷数据
				RxState = 2;//进入下一个状态
			}
		}
		else if (RxState == 2){
			if (RxData == 0xFE){//检测到包尾
				RxState = 0;//S清0开始下一轮回
				Serial_RxFlag = 1;//一个数据包接收完毕,置一个标志位
			}
		}
		//别用3个if,防止上一个if执行一半时出现多分枝同时成立,执行故障。比如if(RxState=0)执行到置S为1时...
		//用else if可保证每次进来只能选择一个分支执行,也可用switch实现
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
}
//Serial.h
#ifndef __SERIAL_H
#define __SERIAL_H

extern uint8_t Serial_RxPacket[];//数组声明时数量可以不要
extern uint8_t Serial_TxPacket[];

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array,uint16_t Length);
uint8_t Serial_GetRxFlag(void);
void Serial_SendPacket(void);
#endif
//main.c
#include "stm32f10x.h"   
#include "Delay.h"   
#include "OLED.h"
#include "Serial.h"

int main(void){
	OLED_Init();
	
	Serial_Init();
	
	Serial_TxPacket[0]=0x11;//赋值要发送的
	Serial_TxPacket[1]=0x22;
	Serial_TxPacket[2]=0x33;
	Serial_TxPacket[3]=0x44;
	
	while(1){
		if (Serial_GetRxFlag() == 1){//如果接收到外部数据包,则显示
			OLED_ShowHexNum(1,1,Serial_RxPacket[0],2);
			OLED_ShowHexNum(2,1,Serial_RxPacket[1],2);
			OLED_ShowHexNum(3,1,Serial_RxPacket[2],2);
			OLED_ShowHexNum(4,1,Serial_RxPacket[3],2);
			//程序问题:Serial_RxPacket是一个同时被写入又同时被读出的数组,
			//在中断函数里依次把接收的字节写入它,在main.c里由依次读出它显示,
			//这会导致数据包之间会混在一起,比如读出速度太慢,读到一半数组就刷新了
			//解决方法:在接收部分加入判断,在数据包读取完成后再写入下一轮
			//很多情况不需要考虑此问题,这种HEX数据包多用于传输各种传感器的每个独立数据:
			//比如陀螺仪的X、Y、Z轴数据,温湿度数据等,它们相邻数据包之间的数据具有连续性即使混在一起也没关系
		}
	}
}

2.串口收发文本数据包(发直接用SendString,代码主要写接收)

在这里插入图片描述

//Serial.c
#include "stm32f10x.h"  

char Serial_RxPacket[100];//数量100给大点,防止溢出,这要求单条指令不可超过100个字符

uint8_t Serial_RxFlag;

void Serial_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate= 9600;
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode= USART_Mode_Tx |USART_Mode_Rx;
	USART_InitStructure.USART_Parity= USART_Parity_No;
	USART_InitStructure.USART_StopBits= USART_StopBits_1;
	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
	USART_Init(USART1,&USART_InitStructure);
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1,ENABLE);
}

void Serial_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	
}

void Serial_SendArray(uint8_t* Array,uint16_t Length){
	uint16_t i;
	for(i=0;i<Length;i++){
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char* String){
	uint8_t i;
    for(i=0;String[i] != '\0';i++){
		Serial_SendByte(String[i]);
	}
	
}

uint32_t Serial_Pow(uint32_t X,uint32_t Y){
	uint32_t Result = 1;
	while(Y--){
		Result *= X;
	}
	return Result;
}
void Serial_SendNumer(uint32_t Number,uint8_t Length){
	uint8_t i;
	for(i=0;i<Length;i++){
		Serial_SendByte(Number/Serial_Pow(10,Length-i-1)%10+0x30);
	}
	
}


uint8_t Serial_GetRxFlag(void){//用于判断是否收到了数据包
	if(Serial_RxFlag == 1){
		Serial_RxFlag=0;
		return 1;
	}
	return 0;
}
void USART1_IRQHandler(void){
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET){
		uint8_t RxData = USART_ReceiveData(USART1);
		if (RxState == 0){
			if (RxData == '@'){
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1){
			if (RxData == '\r'){//因为可变包长,接受前先判断包尾
				RxState = 2;
			}
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket++;
		}
		else if (RxState == 2){
			if (RxData == '\n'){
				RxState = 0;
				Serial_RxPacket[pRxPacket] = '\0';
				//接收到之后还要在字符数组的最后加上结束标志位'\0',方便后续对字符串进行处理
				Serial_RxFlag = 1;
			}
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
}
//main.c
#include "stm32f10x.h"   
#include "Delay.h"   
#include "OLED.h"
#include "Serial.h"

int main(void){
	OLED_Init();
	OLED_ShowString(1,1,"RxPacket");
	
	Serial_Init();
	
	while(1){
		if (Serial_GetRxFlag() == 1){
			OLED_ShowString(2,1,"              ");//清屏
			OLED_ShowString(2,1,Serial_RxPacket);
		}
		
	}
}


总结

做任何事情,都要有一股坚忍不拔的毅力,只要坚持,挺过风雨,终会看见彩虹;只要坚持,走过黑暗,总会拥抱黎明;只要坚持,战胜失败,总能赢得成功!
今天的学习分享到此就结束了,我们下次再见!!
在这里插入图片描述往期精彩:
STM32定时器输入捕获(IC)
STM32定时器输出比较(PWM波)
STM32定时中断
STM32外部中断
STM32GPIO精讲

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32学习】——USART串口数据包&HEX/文本数据包&收发流程&串口收发HEX/文本数据包实操 的相关文章

  • 有没有办法将 sys.fn_varbintohexstr 结果转回 varbinary?

    有没有function in SQL Server要做到这一点 扭转sys fn varbintohexstr 您需要在动态 SQL 语句中使用十六进制字符串 以便将其解析为 varbinary 下面是如何做到这一点的一个示例 Our or
  • C# 中的十六进制运算[重复]

    这个问题在这里已经有答案了 有关在 C 中解析 转换 操作十六进制值的任何提示吗 特别是我想将十进制整数转换为十六进制 然后输出为字符串 Int32 decValue 42 string hexValue decValue ToString
  • Python ord 函数中的多个字符

    编程初学者在这里 Python 2 7 是否有解决方法可以在 Python 的 ord 函数中使用多个字符 例如 我有一个十六进制字符串 xff x1a 我想要它的十进制值 以便我可以将其与其他十六进制字符串求和 但是 ord 只接受单个十
  • EBCDIC 十六进制字符串的 Python 字节表示

    我有一个十六进制字符串 Hex E388854083969497A4A38599408881A2409985829696A38584408699969440814082A48783888583924B 作为字节对象 它看起来像这样 b xe
  • Java 中的 \x 转义?

    我想知道 Java 中是否有类似 C 中的十六进制 x 转义 例如 char helloworld x48 x45 x4C x4C x4F x20 x57 x47 x52 x4C x44 printf s helloworld 从目前看来
  • Hexfloat机械手和精度

    如何使用输出hexfloat操纵器忽略任何精度ostream include
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • 如何在x86汇编编程中表示诸如FFFFFFBB之类的十六进制值?

    我正在学习 x86 内联汇编编程 我想写mov ecx FFFFFFBB 但是编译器无法识别它 像这样的十六进制数字应该如何在内联汇编代码中编写 这取决于您的汇编器的风格 美国电话电报公司 movl 0xFFFFFFBB ecx Intel
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • 操作码的十六进制值

    我创建了一个非常简单的汇编程序 可以在 DOS 中打印字母 a 我在十六进制编辑器中打开它 结果是这样的 汇编代码 mov ah 2 mov dx a int 21h 十六进制代码 B4 02 B2 61 CD 21 我想了解它是如何生成的
  • java中2的十六进制数到十进制的补码

    我有一个表示 2 的补码数的十六进制字符串 有没有一种简单的方法 库 函数 可以将十六进制转换为十进制而不直接使用其位 例如 这是左边十六进制的预期输出 0000 gt 0 7FFF gt 32767 max positive number
  • C 中的十六进制到字符数组

    Given a string of hex values i e e g 0011223344 so that s 0x00 0x11 etc 如何将这些值添加到 char 数组 相当于说 char array 4 0x00 0x11 您无
  • QSpinBox 具有用于十六进制输入的 Unsigned Int

    这里写了很多关于 QSpinBox 使用 int 作为其数据类型的限制的问题 人们通常希望显示更大的数字 就我而言 我希望能够以十六进制显示无符号 32 位整数 这意味着我希望我的范围为 0x0 0xFFFFFFFF 正常的 QSpinBo
  • 如何将十六进制字符串转换为十进制值

    我尝试将十六进制字符串转换为十进制值 但它没有给我预期的结果 I tried convert toint32 hexa 16 convert todecimal hexa 我有一个看起来像这样的字符串 1 12 94 201 198 我把它
  • 在两种颜色之间进行插值的最有效方法是什么? (预计有伪代码和按位运算)

    制作一个黑莓应用程序 想要一个渐变类 插入两种颜色的最有效方法 例如速度和电池寿命 是什么 请具体说明 Java of course int c1 0xFFAA0055 color 1 ARGB int c2 0xFF00CCFF colo
  • 帮助我将以十六进制表示的长值转换回日期/时间

    我有一个日期值 据说它是 8 个字节 一个 long 又名 int64 值 并转换为十六进制 60f347d15798c901 我如何使用 PHP 将这个和类似的值转换为时间 日期 将其转换为十进制给我 96 243 71 209 87 1
  • Java/Android 字符串到颜色的转换

    我正在制作一个应用程序 我希望能够通过用户输入 edittext 和十六进制值设置各种颜色 例如 eeeeee等等 问题是我似乎不知道如何转换它们 如果我在代码中做这样的事情 它工作得很好 标题栏 setBackgroundColor 0x
  • 读取STM32 MCU SPI数据寄存器的值

    有很多类似的问题 但似乎没有一个问题完全相同 我正在将 STML4 MCU 连接到 6 轴传感器 LSM6DS3 我已经成功地在 I2C 中实现了所有内容 但想要 SPI 的额外速度 和 DMA 如果我能让这些第一步工作起来的话 因此 第一
  • STM32F4 定时器 - 计算周期和预分频,以生成 1 ms 延迟

    我在用STM32F407VGT6 with CubeMX 因此 我从通用定时器开始 但我被预分频值和周期值所困扰 基本上我想每隔一段时间生成一个定时器中断n 其中 n 1 2 3 ms 并执行一些任务 计算周期和预分频值的公式有很多变化 公

随机推荐

  • 【图解】八幅图带你轻松掌握八大排序(上):冒泡排序、选择排序、插入排序、快速排序

    在算法中 xff0c 八大排序算是最简单的也是重中之重 xff0c 所以掌握好八大排序的思想是非常重要的 xff0c 很多人学排序的时候会觉得似懂非懂 xff0c 本篇文章作者耗时两小时绘制了八大排序的详细图解 xff0c 让大家快速理解八
  • 最详细整理STL之vector基础

    前言 xff1a Vector是一种可以存储任意类型的动态数组 xff0c 属于序列式容器 xff0c 可以用sort对其进行排序 xff0c 底层数据结构是数组 xff0c 可以随机访问元素 Vectors 包含着一系列连续存储的元素 其
  • STL之vector扩容机制

    前言 大家好 xff0c 我是萝卜 上期结尾说到vector的push back操作一般情况下时间复杂度为O 1 xff0c 是否存在特殊情况 那么本期就讲讲vector在容器空间不足时进行push back操作会发生什么 vector作为
  • 求职嵌入式软件开发linux kernel/BSP leader/工程师职位

    个人工作说明 xff1a 目前从事linux系统网络设备的开发工作 xff0c 负责bootloader linux kernel文件系统 xff0c driver移植 xff0c 以及开源app移植 主要技能和过去的经验 xff1a 1
  • 【2023最新】计算机网络面试题【收藏持续更新】

    你好 xff0c 我是萝卜 xff0c 我会在本篇文章持续更新关于计算机网络的面试题 最新内容更新日期 xff1a 2023 04 11 基础 说一下计算机网络体系结构 网络体系结构一般有三种 xff1a ISO七层模型 xff0c TCP
  • UDP协议详解

    概述 xff1a UDP只在IP的数据报服务之上增加了两个最基本的服务 xff1a 复用和分用以及差错检测 UDP不保证可靠交付 xff0c 但是不意味着应用对数据的要求是不可靠的 xff0c 只是所有维护可靠性的工作可由用户在应用层完成
  • TCP传输可靠性保证机制之重传机制

    TCP重传机制 tcp重传机制包括超时重传 快速重传 带选择确认的重传 SACK 重复SACK 四种 超时重传 xff1a 超时重传是tcp协议保证数据可靠性的一个重要机制 原理是在发送某一个数据以后开启一个计时器 xff0c 在一定时间内
  • VSCode:终端控制台常用指令

    常用的指令 以下是一些在 Visual Studio Code 终端控制台中常用的指令 xff1a 1 清除终端 xff1a clear 2 列出当前目录中的文件和文件夹 xff1a ls 3 切换到指定目录 xff1a xff1a cd
  • Ubuntu18.04安装ROS时rosdep update报错解决办法

    在安装ros进行rosdep update时经常会报错 xff0c 有时候可以通过换网解决 xff0c 但从我安装那么多次的经验来看 xff0c 仅有一次换手机热点后更新成功了 xff0c 其他都是失败 xff0c 成功率太低 从网上搜到了
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信 xff08 Serial Communications xff09 实现单片机与电脑或者其它外设进行通信 xff0c 通信时只需两根线 xff08 TX xff0c RX xff09 就可以实现数据传输 STM32f103有三个串
  • C语言学习笔记——(2)数组

    数组 1 什么是是数组2 数组的定义2 1数组的表达2 2数组的含义2 3数组的大小 xff1a 3 字符数组4 字符串操作5 二维数组 1 什么是是数组 数组是指有序的元素序列 如果将有限个类型相同的变量的集合命名 xff0c 那么这个名
  • 多线程编程实验

    xff08 一 xff09 查看下列程序并运行 xff0c 掌握如何通过扩展Thread类创建线程 span class token keyword package span span class token namespace case1
  • 实验一:基于Ubuntu系统实现无人机自主飞行

    ps xff1a 为避免出现错误 xff0c 在进行新的一步时 xff0c 需要关闭由于上一步操作打开的终端 xff0c 并开启一个新的终端 例如 xff1a 在开始第5步 安装MAVROS 之前 xff0c 关闭由于第3步 安装ROS 打
  • 5000字学习C语言错误处理的四种方式。

    C错误处理 在C语言中 xff0c 错误处理是一个非常重要的主题 通常情况下 xff0c 程序员需要在代码中处理错误 xff0c 以保证程序能够在出现错误时正确地处理这些情况 C语言中常见的错误类型包括 xff1a 语法错误 逻辑错误 运行
  • yum 源制作

    YUM介绍 YUM主要用于自动升级 安装 移除 rpm 软件包 xff0c 它能自动查找并解决 rpm 包之间的依赖关系 xff0c 要成功的使用 YUM 工具更新系统和软件 xff0c 需要有一个包含各种 rpm 软件包的 reposit
  • MATLAB021b与VS2022混编

    MATLAB2021b与VS2022混编 前言 目前在做一个大创项目 xff0c 其中用到关于Matlab与C的混合编程 xff0c 特此记录 Matlab2021b 如图所示 xff0c 红线划出的是即将使用的 c函数 xff0c 在左侧
  • 香橙派5使用NPU加速yolov5的实时视频推理(一)

    前言 xff1a 寒假里 xff0c 博主完成了树莓派4B搭载yolofastest V2的ncnn加速 xff0c 效果挺不错的 xff0c 但总感觉还是稍微差点意思 xff0c 于是就购买了一块香橙派5 xff0c 想要用RK3588芯
  • 香橙派5使用NPU加速yolov5的实时视频推理(二)

    三 将best onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20 04系统中了 xff0c 我的Ubuntu系统中已经下载好了anaconda xff0c 使用anaconda的好处就是可以方便的安装一些库 xff0c 而且
  • 【STM32学习】——串口通信协议&STM32-USART外设&数据帧/输入数据策略/波特率发生器&串口发送/接受实操

    文章目录 前言一 串口通信1 通信接口2 串口通信 xff08 1 xff09 串口简介 xff08 2 xff09 串口硬件电路 xff08 3 xff09 串口软件部分 二 STM32的USART外设1 USART简介2 图示详解 三
  • 【STM32学习】——USART串口数据包&HEX/文本数据包&收发流程&串口收发HEX/文本数据包实操

    文章目录 前言一 数据包格式 xff08 江科大规定 xff09 1 HEX数据包2 文本数据包3 两者对比 二 数据包收发流程1 HEX数据包接收 xff08 只演示固定包长 xff09 2 文本数据包接收 xff08 只演示可变包长 x