精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

HAL庫UART在cubemx中的配置

jf_L18yujSQ ? 來源:小飛哥玩嵌入式 ? 2023-07-05 09:47 ? 次閱讀

串口原理圖

串口1咱們已經用作rtt的print使用了,所以使用另外一組串口來進行串口的教程,這里一定要注意下,alios的這個板子原理圖是有點問題的,標注的是串口3PA2和PA3,實際上小飛哥調了好久,最后萬用表量引腳才發現是原理圖標注錯誤,實際上是UART4,PA0和PA1

86dfda86-1a6f-11ee-962d-dac502259ad0.png

cubemx中引腳選擇預配置

選擇PA0、PA1,配置為串口模式,波特率什么的見圖示:

8712d2c4-1a6f-11ee-962d-dac502259ad0.png

開啟中斷,優先級可以根據自己的需求配置,本次不使用DMA,所以DMA就先不進行配置了

8755e60e-1a6f-11ee-962d-dac502259ad0.png

配置是非常簡單的,就不多啰嗦了,配置完直接生成代碼就OK了

HAL庫串口代碼詳解

cubemx里面配置了一大堆,生成的應用代碼主要在初始化中:

876ece94-1a6f-11ee-962d-dac502259ad0.png87a026a6-1a6f-11ee-962d-dac502259ad0.png

關于串口的接口是很多的,本次主要使用3個接口,發送、接收和接收回調

87c89cbc-1a6f-11ee-962d-dac502259ad0.png

HAL庫數據接收的設計思想是底層配置完成后,暴露給用戶的是一組回調函數,用戶不用關心底層實現,只需要關注應用層邏輯即可,回調函數是定義為_weak屬性的接口,用戶可以在應用層實現

/**
*@briefRxTransfercompletedcallback.
*@paramhuartUARThandle.
*@retvalNone
*/
__weakvoidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{
/*Preventunusedargument(s)compilationwarning*/
UNUSED(huart);

/*NOTE:Thisfunctionshouldnotbemodified,whenthecallbackisneeded,
theHAL_UART_RxCpltCallbackcanbeimplementedintheuserfile.
*/
}

發送也有對應的callback,我們只需要在callback處理我們的邏輯即可。

串口收發設計

教程不玩虛的,本章節小飛哥從實際應用出發,通過解析協議數據,順便講解uart的收發設計。

1、串口接收:

先來看看HAL庫串口接收的接口函數,這就是使用庫函數的好處,底層實現不用關心,只要會用接口就行了

/**
*@briefReceiveanamountofdataininterruptmode.
*@noteWhenUARTparityisnotenabled(PCE=0),andWordLengthisconfiguredto9bits(M1-M0=01),
*thereceiveddataishandledasasetofu16.Inthiscase,Sizemustindicatethenumber
*ofu16availablethroughpData.
*@paramhuartUARThandle.
*@parampDataPointertodatabuffer(u8oru16dataelements).
*@paramSizeAmountofdataelements(u8oru16)tobereceived.
*@retvalHALstatus
*/
HAL_StatusTypeDefHAL_UART_Receive_IT(UART_HandleTypeDef*huart,uint8_t*pData,uint16_tSize);

如何使用這個接口接收數據呢?

從接口描述可以看到,第1個參數是我們的串口號,第2個參數數我們用于接收數據的buffer,第3個參數是數據長度,即要接受的數據量,這里我們每次僅接收一個數據即進入邏輯處理

每次取一個數據,放到rxdata的變量中

HAL_UART_Receive_IT(&huart4,&rxdata,1);

HAL庫所有的串口是共享一個回調函數的,那么如何區分數據是來自哪一個串口的?這個邏輯可以在應用實現,區分不同的串口號,根據對應的串口號實現對應的邏輯即可

voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{

if(huart->Instance==UART4)
{
//rt_sem_release(sem_uart_rec);
embedded_set_uart_rec_flag(RT_TRUE);
embedded_set_uart_timeout_cnt(0);
HAL_UART_Receive_IT(&huart4,&rxdata,1);
mb_process_frame(rxdata,CHANNEL_MODBUS);
}
}

2、數據幀接收完成判斷

通訊基本上都是不定長數據的接收,一般對于一個完整的通訊幀來說,是有長度字段的,分以下幾種接收完成判斷方式

特殊數據格式,比如結束符,像正點原子串口教程的“回車、換行(0x0D,0x0A)”

數據長度,適用已知數據長度的數據幀,根據接收到的數據長度跟數據幀里面的長度是否一致,判斷接受是否完成

超時判斷,定時器設計一個超時機制,一定時間內沒有數據進來即認為數據傳輸結束

空閑中斷,串口是有個空閑中斷的,這個實現類似于超時機制

也可以從軟件設計實現,比如設計一個隊列,取數據即可,隊列中沒數據即認為數據接受完成

方式有很多,本章節主要使用數據長度和定時器超時兩種方式來講解

3、串口發送

串口發送比較簡單,先來看看發送接口函數,類似接收函數,只需要把我們的數據放進發送buffer,啟動發送即可

/**
*@briefSendanamountofdatainblockingmode.
*@noteWhenUARTparityisnotenabled(PCE=0),andWordLengthisconfiguredto9bits(M1-M0=01),
*thesentdataishandledasasetofu16.Inthiscase,Sizemustindicatethenumber
*ofu16providedthroughpData.
*@noteWhenFIFOmodeisenabled,writingadataintheTDRregisteraddsone
*datatotheTXFIFO.WriteoperationstotheTDRregisterareperformed
*whenTXFNFflagisset.Fromhardwareperspective,TXFNFflagand
*TXEaremappedonthesamebit-field.
*@paramhuartUARThandle.
*@parampDataPointertodatabuffer(u8oru16dataelements).
*@paramSizeAmountofdataelements(u8oru16)tobesent.
*@paramTimeoutTimeoutduration.
*@retvalHALstatus
*/
HAL_StatusTypeDefHAL_UART_Transmit(UART_HandleTypeDef*huart,constuint8_t*pData,uint16_tSize,uint32_tTimeout);

數據接收及協議幀解析設計

數據接收:

基于數據長度和超時時間完成數據幀發送完成的判斷:

定時器中斷回調設計,實現邏輯為,當收到串口數據時,開始計時,超過100ms無數據進來,認為數據幀結束,同時釋放數據接收完成的信號量,接收到接受完成的信號量之后,重置一些數據,為下一次接收做好準備

voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim)
{
if(htim->Instance==TIM15)
{
//if(RT_EOK==rt_sem_take(sem_uart_rec,RT_WAITING_NO))
//{
if(embedded_get_uart_rec_flag())
{
/*100ms超時無數據接收*/
if(embedded_get_uart_timeout_cnt()>9)
{
embedded_set_uart_rec_flag(RT_FALSE);

rt_sem_release(sem_uart_timeout);
}
}

//}
}
}

串口回調設計:

串口回調要實現的邏輯比較簡單,主要是數據接收、解析:

voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{
if(huart->Instance==UART4)
{
//rt_sem_release(sem_uart_rec);
embedded_set_uart_rec_flag(RT_TRUE);
embedded_set_uart_timeout_cnt(0);
HAL_UART_Receive_IT(&huart4,&rxdata,1);
process_frame(rxdata,CHANNEL_UART4);
}
}

/協議架構/

/數據頭(2字節)+數據長度(2字節,不包含數據頭)+功能碼+數據+校驗碼(CRC16-MODBUS)/

我們采用這個協議框架來解析數據,數據解析可以設計成一個簡單的狀態機,根據每一步決定下一步做什么

比如針對上面的協議,我們就可以分幾步設計:

1、解析數據頭1;

2、解析數據頭2;

3、解析數據長度;

4、接收數據;

5、校驗數據CRC;

6、調用命令回調函數;

把握好這個步驟,設計其實非常簡單

先來定義一個簡單的枚舉,表示每一個狀態:

typedefenum
{
STATUS_HEAD1=0,
STATUS_HEAD2,
STATUS_LEN,
STATUS_HANDLE_PROCESS
}frame_status_e;

然后封裝數據解析函數:

/*協議架構*/

/**數據頭(1字節)+數據長度(2字節,不包含數據頭)+功能碼+數據+校驗碼(CRC16-MODBUS)**/

#definePROTOCOL_HEAD10x5A
#definePROTOCOL_HEAD20xA5

intprocess_frame(constuint8_tdata,constuint8_tchannel)
{
uint16_tcrc=0;
uint16_tlen=0;

staticframe_status_eframe_status;
staticuint16_tindex=0;

/*timeoutresetthereceivestatus*/
if(RT_EOK==rt_sem_take(sem_uart_timeout,RT_WAITING_NO))
{
index=0;
frame_status=STATUS_HEAD1;
}
switch(frame_status)
{
caseSTATUS_HEAD1:
if(data==PROTOCOL_HEAD1)
{
frame_status=STATUS_HEAD2;
buffer[index++]=data;
}
else
{
frame_status=STATUS_HEAD1;
index=0;
}
break;
caseSTATUS_HEAD2:
if(data==PROTOCOL_HEAD2)
{
frame_status=STATUS_LEN;
buffer[index++]=data;
}
else
{
frame_status=STATUS_HEAD1;
index=0;
}
break;
caseSTATUS_LEN:
if(data>=0&&data<=?MAX_DATA_LEN)
????????{
????????????frame_status?=?STATUS_HANDLE_PROCESS;
????????????buffer[index++]?=?data;
????????}
????????else
????????{
????????????frame_status?=?STATUS_HEAD1;
????????????index?=?0;
????????}
????????break;
????case?STATUS_HANDLE_PROCESS:
????????buffer[index++]?=?data;
????????len?=?buffer[LEN_POS];
????????if?(index?-?3?==?len)
????????{
????????????crc?=?embedded_mbcrc16(buffer,?index?-?2);
????????????if?(crc?==?(buffer[index?-?1]?|?buffer[index?-?2]?<

對用的功能函數:

我們采用 attribute at機制的方式,將我們的回調函數注冊進去:

typedefvoid(*uart_dispatcher_func_t)(constuint32_t,constuint8_t*,constuint32_t);
typedefstructuart_dispatcher_item
{
union
{
struct
{
uint8_tchannel;
uint8_tcmd_id;
};

uint32_tmagic_number;
};

uart_dispatcher_func_tfunction;

}uart_dispatcher_item_t;

#defineUART_DISPATCHER_CALLBACK_REGISTER(ch,id,fn)staticconstuart_dispatcher_item_tuart_dis_table_##ch##_##id
__attribute__((section("uart_dispatcher_table"),__used__,aligned(sizeof(void*))))=
{.channel=ch,.cmd_id=id,.function=fn}
intcall_reg_cb(uint8_t*frame,uint8_tdata_len,intchannel,uint8_tcmd_id);

回調函數:

這樣設計可以把驅動層,協議解析層和應用層完全分開,用戶只需要注冊相關的命令,實現回調即可,完全不用關心底層實現

voiddispatcher_on_02_callback(constuint32_tchannel,constuint8_t*data,constuint32_tdata_len)
{
constchar*str="func02isrunning
";
uart_write((uint8_t*)str,rt_strlen(str),100);
rt_kprintf("func02isrunning
");
}
UART_DISPATCHER_CALLBACK_REGISTER(1,0x02,dispatcher_on_02_callback);

voiddispatcher_on_03_callback(constuint32_tchannel,constuint8_t*data,constuint32_tdata_len)
{
constchar*str="func03isrunning
";
uart_write((uint8_t*)str,rt_strlen(str),100);
rt_kprintf("func03isrunning
");
}
UART_DISPATCHER_CALLBACK_REGISTER(1,0x03,dispatcher_on_03_callback);

voiddispatcher_on_04_callback(constuint32_tchannel,constuint8_t*data,constuint32_tdata_len)
{
constchar*str="func04isrunning
";
uart_write((uint8_t*)str,rt_strlen(str),100);
rt_kprintf("func04isrunning
");
}
UART_DISPATCHER_CALLBACK_REGISTER(1,0x04,dispatcher_on_04_callback);

voiddispatcher_on_05_callback(constuint32_tchannel,constuint8_t*data,constuint32_tdata_len)
{
rt_kprintf("func05isrunning
");
}
UART_DISPATCHER_CALLBACK_REGISTER(1,0x05,dispatcher_on_05_callback);

voiddispatcher_on_06_callback(constuint32_tchannel,constuint8_t*data,constuint32_tdata_len)
{
rt_kprintf("func06isrunning
");
}
UART_DISPATCHER_CALLBACK_REGISTER(1,0x06,dispatcher_on_06_callback);

測試效果

通過上面的回調函數注冊,我們來測試下是不是達到預期情況:

87fd2ba8-1a6f-11ee-962d-dac502259ad0.png





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 定時器
    +關注

    關注

    23

    文章

    3241

    瀏覽量

    114486
  • RTT
    RTT
    +關注

    關注

    0

    文章

    65

    瀏覽量

    17088
  • UART接口
    +關注

    關注

    0

    文章

    124

    瀏覽量

    15268
  • HAL庫
    +關注

    關注

    1

    文章

    114

    瀏覽量

    6177

原文標題:04-HAL庫UART配置及協議解析設計

文章出處:【微信號:小飛哥玩嵌入式,微信公眾號:小飛哥玩嵌入式】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    stm32 HALUART中斷 使用說明

    大家參考。發帖真的不習慣,word粘貼也不好。所以詳見附件吧。也有例程一個。首先,下載一個STM32CubeMX,圖形化配置外設,十分方便。至此,已非常明確HAL
    發表于 06-30 22:32

    STM32 HAL CUBEMX配置 ADC采集 精選資料分享

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔文章目錄STM32 HAL CUBEMX配置 ADC采集軟硬件型號1.單通道不定時任意時刻采集信號
    發表于 08-11 07:46

    HAL配合CUBEMX配置

    本次教程主要介紹 :HAL配合CUBEMX配置一些常用外設的初始化,直觀感受STM32編程,用最短時間入門STM32。
    發表于 08-11 07:07

    【STM32的HAL開發】CubeMX配置HAL,不進串口中斷的問題 精選資料分享

    【STM32的HAL開發】串口中斷開發環境main.c添加代碼(1/2)stm32f4xx_it.c添加代碼(2/2)注意附代碼開發環境cub
    發表于 08-16 07:00

    使用CUBEMX配置hal輸入捕獲

    之前有使用標準配置的,具體可以看我之前的博客這個項目是使用CUBEMX配置hal來寫,相
    發表于 01-06 07:23

    STM32CubeMX 配置STM32F407 實現HAL延時微妙方案

    STM32CubeMX 配置STM32F407 實現HAL延時微妙方案
    發表于 11-24 20:51 ?20次下載
    STM32<b class='flag-5'>CubeMX</b> <b class='flag-5'>配置</b>STM32F407 實現<b class='flag-5'>HAL</b><b class='flag-5'>庫</b>延時微妙方案

    串口通信小試牛刀~使用STM32CubeMX+ HAL點亮流水燈

    STM32CubeMX與Keil MDK配合HAL完成流水燈的點亮。目錄一、STM32串口通信基礎二、STM32CubeMX與keil基于HAL
    發表于 12-07 10:06 ?14次下載
    串口通信小試牛刀~使用STM32<b class='flag-5'>CubeMX</b>+ <b class='flag-5'>HAL</b><b class='flag-5'>庫</b>點亮流水燈

    STM32 CubeMX+HAL基本操作

    STM32 CubeMX+HAL基本操作
    發表于 12-07 11:21 ?50次下載
    STM32 <b class='flag-5'>CubeMX+HAL</b><b class='flag-5'>庫</b>基本操作

    STM32實戰 2 | STM32CubeMXHAL點亮LED

    STM32實戰 2 | STM32CubeMXHAL點亮LED
    發表于 12-08 12:36 ?34次下載
    STM32實戰 2 | STM32<b class='flag-5'>CubeMX</b>及<b class='flag-5'>HAL</b><b class='flag-5'>庫</b>點亮LED

    【STM32 HALUART串口通訊

    HALUART的三種收發方式(一)阻塞收發特點:簡單粗暴,占滿單片機資源進行收發簡介:發送:發送指定長度的數據。如果超時沒發送完成,則不再發送,返回超時標志接收:接收指定長度的數據
    發表于 12-24 18:44 ?5次下載
    【STM32 <b class='flag-5'>HAL</b>】<b class='flag-5'>UART</b>串口通訊

    STM32 HAL CubeMX教程(五)串口通信基礎

    STM32 HAL CubeMX教程(五)串口通信基礎串口通信簡介CubeMX配置初始化程序分析程序編寫
    發表于 12-24 18:49 ?12次下載
    STM32 <b class='flag-5'>HAL</b><b class='flag-5'>庫</b> <b class='flag-5'>CubeMX</b>教程(五)串口通信基礎

    第六節:STM32基于HAL的IIC通信

    STM32 IIC通信; CubeMX配置, HAL, IAR或者Keil編程CubeMX系列使用經驗分享
    發表于 12-27 18:45 ?26次下載
    第六節:STM32基于<b class='flag-5'>HAL</b><b class='flag-5'>庫</b>的IIC通信

    STM32 HAL CUBEMX配置 ADC采集

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔文章目錄STM32 HAL CUBEMX配置 ADC采集軟硬件型號1.單通道不定時任意時刻采集信號
    發表于 12-27 18:57 ?25次下載
    STM32 <b class='flag-5'>HAL</b><b class='flag-5'>庫</b> <b class='flag-5'>CUBEMX</b><b class='flag-5'>配置</b> ADC采集

    STM32串口通信HAL配置 UART_IT_xx與UART_FLAG_xx 的區別

    STM32串口通信HAL配置 UART_IT_xx與UART_FLAG_xx 的區別:(最后
    發表于 12-28 19:05 ?2次下載
    STM32串口通信<b class='flag-5'>HAL</b><b class='flag-5'>庫</b><b class='flag-5'>配置</b><b class='flag-5'>中</b> <b class='flag-5'>UART</b>_IT_xx與<b class='flag-5'>UART</b>_FLAG_xx 的區別

    HAL無法實現UART的DMA傳輸真是這樣嗎?

    使用STM32CubeMx進行圖形化配置,并生成基于HAL的初始代碼,要實現UART收發功能的DMA傳輸的話,除了安排好的收發緩沖內存外,
    的頭像 發表于 01-08 11:16 ?2647次閱讀