Usart 串口发送数据包 两种方式(遍历结构体,指针数组)

博客介绍了Usart串口发送数据包的两种方式,分别是结构体指针方式,涉及结构体和联合体以及纯结构发送形式,还有指针数组形式。

Usart 串口发送数据包 两种方式(结构体,指针数组)

1.结构体指针

1.1 结构体和联合体

/*
	叙述:这种直观性比较,利用联合体和结构体的形式组成数据包,通过结构体指针发送
*/
typedef union{
	struct
	{
		unsigned char id;
		unsigned char addr;
		unsigned char head; 
		unsigned char left_time; 		
		unsigned char left_hour; 				
		unsigned char right_time; 		
		unsigned char right_hour; 						 
		unsigned char key_high; 						  
		unsigned char key_low; 						  	 
		unsigned char sofa_left; 						  
		unsigned char sofa_right; 						  	 
		unsigned char funtion_dis; 						  	 
		unsigned char checksum;
		unsigned char stop;
	}led_sta;
	unsigned char tx_buf[BUF_SIZE];
}
DATA_FORMAT_TX;

void   send_buf(DATA_FORMAT_TX *buf) {
	unsigned char i;	
	for(i =  0 ; i <14;i++ ){
			printf("%c", buf->tx_buf[i]); 			
	}			
}

void send_buf_packet(void){	
	DATA_FORMAT_TX buf;
	buf.led_sta.id 	   			=0x05;
	buf.led_sta.addr  			=0x03 ;
	buf.led_sta.head  			=0xE1 ; 
	buf.led_sta.left_time 		= 0 ; 		
	buf.led_sta.left_hour 		= 1 ; 				
	buf.led_sta.right_time 		= 2 ; 		
	buf.led_sta.right_hour 		= 3 ; 						 
	buf.led_sta.key_high 	 	= 4 ; 						 
	buf.led_sta.key_low    		= 5 ; 						 
	buf.led_sta.sofa_left		= 6 ; 						 
	buf.led_sta.sofa_right 		= 7 ; 						 
	buf.led_sta.funtion_dis		= 8 ; 						 
	buf.led_sta.checksum		= 0XAA;
	buf.led_sta.stop 			= 0XFB;		
	send_buf(&buf);
}

1.2 纯结构发送的形式

/*
	叙述:这种跟前面一种较为相似, 直接操作结构体
*/

void send_buf_packet(void) {
	DATA_FORMAT_TX  send_dat,*p  = &send_dat ;  // 定义一个结构,把地址传给指针
	unsigned char *pstu,i,len;
	p->id 	   				= 0x05;
	p->addr  				= 0x03 ;
	p->head  				= 0xE1 ; 
	p->left_time 			= 0 ; 		
	p->left_hour 			= 1 ; 				
	p->right_time 			= 2 ; 		
	p->right_hour 			= 3 ; 						 
	p->key_high 	 		= 4 ; 						 
	p->key_low    			= 5 ; 						 
	p->sofa_left			= 6 ; 						 
	p->sofa_right 			= 7 ; 						 
	p->funtion_dis			= 8 ; 						 
	p->checksum				= 0XAA;
	p->stop 				= 0XFB;
	pstu = (unsigned char *)&send_dat;  // 强制转换地址,前提结构一种类型(unsigned char)
	len = sizeof(send_dat);   		   //  计算结构体的长度
	for(i =  0 ; i <len;i++ ){		  
			printf("%c",*pstu++);     // 输出遍历结构元素
	}
}

2.指针数组形式

/*
	这种比较简单暴力直观明了,利用指针数组的形式传递数据
*/

void  send_buf_packet(void)
{
	unsigned char *p, arr[10] = {0,1,2,3,4,5,6,7,8,9};
	for(p = &arr[0]; p < &arr[10];){   //把地址的位置值取出来				
		printf("%c",*p); 			 //打印数据
		*p++;						//指向地址
	}	
}
在STM32平台上实现一个MQTT报文缓冲区,支持QoS 1/2,使用二维数组存储报文,并实现增删改查等等功能以及重传机制。重传时选择ID最小且重传次数未超限的报文。 设计要点: 二维数组:第一维表示缓冲区数量(固定大小),第二维存储每个报文的数据,严格按照下面数据结构: [0][1]: packet_id (两个字节) [2]: retries (重传次数,一个字节) [3][4]: len (两个字节,表示实际数据长度) [5]:packet开始:实际数据包 模块化函数设计: 初始化缓冲区 添加报文(QoS1/2存储) 根据ID查找报文(返回缓冲区索引) 根据ID删除报文(将对应的packet_id置为0x0000,并标记为空闲) 更新重传次数 重传机制:遍历缓冲区,找到重传次数小于最大重传次数且ID最小的报文,进行重传 重传机制: 每次重传前,先找到满足条件的报文(重传次数未超限,且ID最小) 重传后,该报文的重传次数加1 如果重传次数达到上限,则删除该报文(或标记为失败) 发送函数:提供send(char *data, int len)函数发送[5]及后面的数据部分。 跟随stm32使用小端; (由调用者提供packet_id (两个字节) retries (重传次数,一个字节) len (两个字节,表示实际数据长度) packet(实际数据包) ), 不使用时间戳,不使用结构体 QoS1/2在添加之前已经发送过一次,所以在添加进数组时不需要马上发送,不用再分析QoS0的情况,QoS0不添加到数组。 添加报文函数,参数应包括ID,重传次数,数据指针数据长度
最新发布
09-16
#include "bsp_usart.h" #include "EEPROM.h" #include "write.h" #include "systick.h" //串口发送 USART0 uint8_t buff[1024]={0}; //存放元素的索引 uint16_t index = 0; static void GPIO_config(){ /********************** 引脚GPIO配置 **********************/ //1.PA9 TX (打开时钟 配置模式 复用编号) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIO初始化 GPIO_Init(GPIOA,&GPIO_InitStruct); //2.PA10 RX //1.PA9 TX (打开时钟 配置模式 复用编号) // RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIO初始化 GPIO_Init(GPIOA,&GPIO_InitStruct); } static void USART1_config(uint32_t bandrate){ /********************** USART1配置 **********************/ //重置USART USART_DeInit(USART1); //2.1 打开时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //USART初始化结构体 USART_InitTypeDef USART_InitStruct; //结构体初始化 USART_StructInit(&USART_InitStruct); //波特率 USART_InitStruct.USART_BaudRate = bandrate; //配置允许发送 USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_WordLength = USART_WordLength_8b; //初始化 USART_Init(USART1,&USART_InitStruct); NVIC_InitTypeDef NVIC_InitStruct; //中断请求 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //优先级 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; //优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //打开中断 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); //2.开启中断(RBNE和IDLE中断) hello USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); USART_ITConfig(USART1,USART_IT_IDLE,DISABLE); //使能USART1 USART_Cmd(USART1,ENABLE); } //初始化USART1 void bsp_usart1_init(uint32_t bandrate){ //GPIO初始化 GPIO_config(); //USART1初始化 USART1_config(bandrate); } //通过串口发送字符数据 void send_data(uint8_t dat){ //发送1byte数据 USART_SendData(USART1,dat); //等待串口发送完成 while(RESET==USART_GetFlagStatus(USART1,USART_FLAG_TXE)); } //通过串口发送字符串 字符串就是字符数组,最后\0 void send_string(uint8_t* dats){ for (; *dats != 0; dats++){ send_data((uint8_t)(*dats)); //遇到停止符0结束 } } //必须要勾线使用微库 //printf内部会调用这个方法 int fputc(int ch, FILE *f){ //通过串口发送 send_data((uint8_t)ch); return ch; } #define UART_BUFFER_SIZE 1024 typedef struct { uint8_t buffer[UART_BUFFER_SIZE]; volatile uint16_t head; // 写入位置 volatile uint16_t tail; // 读取位置 } RingBuffer; RingBuffer uart_rx_buf; // 全局接收缓冲区 //串口接收中断处理函数 void USART1_IRQHandler(void){ //接收数据 判断中断标志位 清除标志位 //RXNE 接收1byte 保存 if(SET==USART_GetITStatus(USART1,USART_IT_RXNE)){ //清除标志位 USART_ClearITPendingBit(USART1,USART_IT_RXNE); //读取1byte uint8_t dat = USART_ReceiveData(USART1); uint16_t next_head = (uart_rx_buf.head + 1) % UART_BUFFER_SIZE; if(next_head != uart_rx_buf.tail) { // 缓冲区未满 uart_rx_buf.buffer[uart_rx_buf.head] = dat; uart_rx_buf.head = next_head; } } } extern void handle_uart(uint8_t *buff, uint16_t len); unsigned char xor_checksum(const unsigned char *data, unsigned int length) { unsigned char checksum = 0; // 初始校验值为0 for (unsigned int i = 0; i < length; i++) // 遍历所有数据字节进行异或累加 { checksum ^= data[i]; // 按位异或运算 } return checksum; } void uart_buff_init(void) { uart_rx_buf.head=0; uart_rx_buf.tail=0; } void process_uart_data() { static enum {WAIT_START, IN_PACKET} state = WAIT_START; static uint8_t packet[UART_BUFFER_SIZE]; static uint16_t index = 0; static uint8_t end_count = 0; uint8_t checksum = 0; while(uart_rx_buf.tail != uart_rx_buf.head) { // 缓冲区有数据【环形缓冲区】 uint8_t data = uart_rx_buf.buffer[uart_rx_buf.tail]; uart_rx_buf.tail = (uart_rx_buf.tail + 1) % UART_BUFFER_SIZE; #if 1 extern uint8_t g_dying_gasp; if(g_dying_gasp && g_dying_gasp2 == 0) { eeprom_write_byte(0x0000,(uint8_t *)g_read_eep_times,32); delay_1ms(5); eeprom_write_byte(0x0000+32,((uint8_t *)g_read_eep_times)+32,28); delay_1ms(5); g_dying_gasp1 = 1; } #endif switch(state) { case WAIT_START: if(data == 0xee) { // 检测起始符 state = IN_PACKET; index = 0; packet[index++] = data; end_count = 0; } break; case IN_PACKET: // 检测结束序列 0xFC 0xFF 0xFF if(data == 0xFC && end_count == 0) { end_count = 1; } else if(data == 0xFF && end_count > 0) { end_count++; } else { end_count = 0; } if(end_count == 3) { packet[index++] = data; // 完整报文处理(示例) if(index > 6) { // 排除结束符 checksum=xor_checksum(packet+1,index-6); if(checksum==packet[index-5]) { handle_uart(packet, index); } end_count=0; } index=0; state = WAIT_START; break; } // 存储有效数据 if(index < sizeof(packet)) { packet[index++] = data; } else { // 数据过长 index=0; state = WAIT_START; } if(index >packet[1]) { index=0; state = WAIT_START; } break; } } } 我有自己的串口收发代码,使用我的代码完成上述的功能‘
06-20
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mg_hover

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值