結構體對齊原則在自定義協(xié)議解析時的妙用之法
掃描二維碼
隨時隨地手機看文章
關于結構體對齊的設置,以GCC 32bit編譯為例,我們可以來看看下面這個例子:
#include <stdio.h>
//默認情況下,結構體一般在內存中的自動對齊格式是4個字節(jié)
//結構體設置手動對齊
//如果這里是4,那么下面的打印就是8
//如果這里是2,那么下面的打印就是6
//如果這里是1,那么下面的打印就是5
struct mystu
{
char a ;
int b ;
};
#pragma pack(4)
struct mystu0
{
char a ;
int b ;
};
#pragma pack()
#pragma pack(2)
struct mystu1
{
char a ;
int b ;
};
#pragma pack()
#pragma pack(1)
struct mystu2
{
char a ;
int b ;
};
#pragma pack()
int main(void)
{
printf("mystu:%d\n",sizeof(struct mystu));
printf("mystu0:%d\n",sizeof(struct mystu0));
printf("mystu1:%d\n",sizeof(struct mystu1));
printf("mystu2:%d\n",sizeof(struct mystu2));
return 0 ;
}
運行結果:
根據(jù)這樣的原理,在MCU協(xié)議數(shù)據(jù)解析的時候就很有作用了,比如下面這個例子,目前在小車上用:
//結構體,用于存儲解析的數(shù)據(jù)
typedef struct
{
//幀頭(固定解析為FF)
uint8_t frame_top ;
//版本 A1
uint8_t version ;
//方向 01(前進) 02(后退) 03(左轉) 04(右轉)
uint8_t car_direction ;
//速度 01(低速檔) 02(中速檔) 03(高速檔)
uint8_t car_speed ;
//炮臺 00(回到中間) 01(炮臺左轉) 02(炮臺右轉)
uint8_t car_fort_status ;
//夾具 00(夾具夾緊) 01(夾具松開)
uint8_t car_Fix_status ;
//幀尾(固定解析為BB)
uint8_t frame_tail ;
} Protocol;
//以下是串口回調的處理
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/*自定義協(xié)議*/
/*
幀頭 版本 方向 速度 炮臺 夾具 幀尾
ff A1
*/
uint8_t Res;
if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET))
{
HAL_UART_Receive(&huart1, &Res, 1, 1000);
if(0xBB != Res)
{
rbBuf[rx_count++] = Res ;
}
else
{
rbBuf[rx_count] = 0xBB ;
//接收到0xBB了,這時候認為已經接收到完整的一幀數(shù)據(jù),將接收標志置1
Recv_Flag = 1 ;
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
}
//在主函數(shù)中,進行數(shù)據(jù)解析
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
while (1)
{
if(1 == Recv_Flag)
{
Recv_Flag = 0 ;
//將接收緩沖區(qū)的數(shù)組強制轉換為一個結構體指針
//通過結構體指針可訪問到每一個協(xié)議規(guī)格的數(shù)據(jù)
Protocol *Car_Procol = (Protocol *)rbBuf;
printf("幀頭:0x%x\n", Car_Procol->frame_top);
printf("版本:0x%x\n", Car_Procol->version);
printf("方向:0x%x\n", Car_Procol->car_direction);
printf("速度:0x%x\n", Car_Procol->car_speed);
printf("炮臺:0x%x\n", Car_Procol->car_fort_status);
printf("夾具:0x%x\n", Car_Procol->car_Fix_status);
printf("幀尾:0x%x\n", Car_Procol->frame_tail);
rx_count = 0 ;
}
}
}
從這里可以看到,串口接收的數(shù)據(jù)是一個字節(jié)一個字節(jié)進行接收,所以接收的每個數(shù)據(jù)類型一致,我們就可以直接定義一個結構體,按照協(xié)議定義的順序,將數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)依次讀取出來。
在小熊派上的運行結果:
我在寫上位機涉及到與MCU進行協(xié)議通信的時候,經常都是這么干的,這個方法不得不說真的超方便。
案例下載
公眾號后臺回復:protocol 即可獲取本節(jié)案例的下載鏈接。
往期精彩
【為宏正名】本應寫入教科書的“世界設定”
【為宏正名】99%人都不知道的"##"里用法
學習嵌入式可以帶娃,不信你們看
ESP8266實戰(zhàn)貼:使用HTTP POST請求上傳數(shù)據(jù)到公有云OneNet
覺得本次分享的文章對您有幫助,隨手點[在看]
并轉發(fā)分享,也是對我的支持。
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!