我這里使用的芯片是 F1 系列的,主要是利用 DMA 數(shù)據(jù)傳輸方式實現(xiàn)的,在配置工程的時候要注意配置好 DMA,并開啟中斷。
如果出現(xiàn)數(shù)據(jù)長度對,可是數(shù)據(jù)接收不完整,把Memory勾選即可:
1、利用STM32 cubemx 建立一個工程,工程建立請參考我以前的文章:https://www.cnblogs.com/xingboy/p/9597464.html
2、利用STM32 cubemx 生成代碼后,我們先定義一些變量來使用
/* 自己添加代碼部分 */
volatile uint8_t rx_len=0; //接收數(shù)據(jù)長度
volatile uint8_t recv_end_flag=0; //接收完成標(biāo)記位
uint8_t rx_buffer[100]; //接收緩存
char BUFFER_SIZE=100; //不定長數(shù)據(jù)的最大長度,設(shè)置為100則最大長度為100
這里為什么要定義volatile 關(guān)鍵字呢?
主要是因為volatile 關(guān)鍵字提醒編譯器定義的變量是易變的,編譯后的程序每次需要存儲或讀取該變量時,會直接從變量地址讀取數(shù)據(jù)。在中斷或多線程中使用volatile關(guān)鍵字可以避免不同優(yōu)化等級時程序出錯,提高程序的魯棒性。
接著對串口初始化添加一些代碼,程序如下:
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/* 自己添加代碼部分 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); //使能idle中斷
HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE); //打開DMA接收,數(shù)據(jù)存入rx_buffer數(shù)組中。
}
3、接收函數(shù)我寫在了另一個文件上,其他文件要用到上面 main文件里面定義的變量就要聲明一個外部變量
extern volatile uint8_t rx_len;
extern volatile uint8_t recv_end_flag;
extern uint8_t rx_buffer[100];
extern char BUFFER_SIZE;
4、接著修改串口中斷服務(wù)函數(shù),在串口中斷服務(wù)函數(shù)里添加接收代碼,代碼如下:
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* 自己添加代碼部分 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE); //獲取IDLE標(biāo)志位
if((tmp_flag != RESET)) //idle標(biāo)志被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2); //清除標(biāo)志位
temp = huart2.Instance->SR; //清除狀態(tài)寄存器SR(F0的HAL庫USART_TypeDef結(jié)構(gòu)體中名字為ISR:USART Interrupt and status register),讀取SR可以清楚該寄存器
temp = huart2.Instance->DR; //讀取數(shù)據(jù)寄存器中的數(shù)據(jù),讀取DR(F0中為RDR:USART Receive Data register)
HAL_UART_DMAStop(&huart2);
temp = hdma_usart2_rx.Instance->CNDTR; //獲取DMA中未傳輸?shù)臄?shù)據(jù)個數(shù),NDTR寄存器分析見下面
rx_len = BUFFER_SIZE - temp; //總計數(shù)減去未傳輸?shù)臄?shù)據(jù)個數(shù),得到已經(jīng)接收的數(shù)據(jù)個數(shù)
recv_end_flag = 1; //接受完成標(biāo)志位置1
}
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
上面的 CNDTR 寄存器在 DMA 通道結(jié)構(gòu)體中定義了 CNDTR 寄存器,這個不同的芯片HAL庫里面定義的命名有點不同,有興趣的可以自己去查看一下,那為什么是未傳輸?shù)臄?shù)據(jù)數(shù)呢,STM32的中文手冊給出了該寄存器的具體說明。(注意:建立工程的時候要添加串口TX RX 的DMA通道,以及打開DMA中斷)
/**
* @brief DMA Controller
*/
typedef struct
{
__IO uint32_t CCR;
__IO uint32_t CNDTR;
__IO uint32_t CPAR;
__IO uint32_t CMAR;
} DMA_Channel_TypeDef;
寄存器說明如下:
5、接著編寫接收處理函數(shù),代碼如下:
/***************************************************************
*函數(shù)名:Data_Turn
*輸 入:無
*說 明:串口接收完成,返回串口查看接收情況
*返回值:無
**/
void Data_Turn(void)
{
if(recv_end_flag ==1)
{
printf('rx_len=%drn',rx_len); //打印接收長度
HAL_UART_Transmit(&huart2,rx_buffer, rx_len,200); //接收數(shù)據(jù)打印出來
for(uint8_t i=0;i rx_buffer[i]=0; //清接收緩存 } rx_len=0; //清除計數(shù) recv_end_flag=0; //清除接收結(jié)束標(biāo)志位 } } 6.再主函數(shù)里的的while循環(huán)里再次打開DMA中斷接收 HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE); //重新打開DMA接收 運行效果如下圖,我的代碼是接收到Do-0:1字符串,判斷字符串,返回我需要的字符串,效果正確。 補充一點最近新發(fā)現(xiàn)的關(guān)于串口中斷接收的問題: 串口中斷接收如果使用HAL庫的中斷接收函數(shù),接收到的數(shù)據(jù)量遠(yuǎn)小于設(shè)定要接收的數(shù)據(jù)量,串口一直處于Busy狀態(tài),會出現(xiàn)接收死循環(huán)的情況,接收的數(shù)據(jù)跟設(shè)定不符會出錯 注意: 測試過程中發(fā)現(xiàn),用接收串口助手的所有數(shù)據(jù)都沒問題,不過接收模塊的不定長數(shù)據(jù)時,如果這個數(shù)據(jù)之間包含回車換行符會接收不全,例如:ATrnOKrn,這個就只能接收到ATr,具體什么原因造成的還沒找出原因,有知道的可以告訴我一下。 不過如果是串口助手發(fā)這串?dāng)?shù)據(jù)下來,卻又可以全部接收完成,想不通。為了解決這個問題,我又找出了一個中斷接收的方法,可以實現(xiàn)了不管中間有沒有回車,都可以接收完成。
上一篇:STM32 軟件復(fù)位并模擬USB拔插
下一篇:STM32 IIC雙機(jī)通信—— HAL庫硬件IIC版
- 熱門資源推薦
- 熱門放大器推薦
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦
- LT1086CT-5 電池充電器的典型應(yīng)用
- 使用 Diodes Incorporated 的 PT8A3518 的參考設(shè)計
- 具有 200ms 瞬態(tài)穿越能力的 LTC3126EFE 3.3V 電源的典型應(yīng)用電路
- OP497GSZ精密運算放大器正峰值檢波器典型應(yīng)用電路
- LT3091ER LDO 穩(wěn)壓器在并聯(lián)器件中的典型應(yīng)用
- 適用于 D 類音頻應(yīng)用的 ADP1650 電壓調(diào)節(jié)模式的典型應(yīng)用
- LT1026CS8 正負(fù)轉(zhuǎn)換器的典型應(yīng)用電路
- 使用 Microchip Technology 的 MIC2776L-YM5 的參考設(shè)計
- DK-DEV-5M570ZNES,MAX V CPLD 開發(fā)板為低成本、低功耗 CPLD 的開發(fā)和原型設(shè)計提供硬件平臺
- 使用 NXP Semiconductors 的 TDA1566 的參考設(shè)計
- 中國制定的全球首項鋰離子電池硅基負(fù)極材料國際標(biāo)準(zhǔn)發(fā)布
- 智能汽車合成數(shù)據(jù)架構(gòu)與應(yīng)用實踐分享
- 15家車企的固態(tài)電池汽車及供應(yīng)商一覽!
- 8月交付!鋰電巨頭全固態(tài)電池商業(yè)化“快進(jìn)”
- 白皮書點破汽車智駕營銷現(xiàn)象:六個“不等于”揭示真實的輔助駕駛
- Unity引擎在智能座艙項目流程之深入優(yōu)化與未來技術(shù)
- Unity引擎在智能座艙項目流程之未來技術(shù)趨勢與高級整合
- Stellantis宣布終止氫燃料電池技術(shù)開發(fā)
- 汽車攝像頭模塊中敏感和動態(tài)電源軌的紋波降低技術(shù)
- 如何在炎熱的夏日保持汽車前攝像頭的熱性能
- Metcal焊接機(jī)器人登陸NEPCON亞洲展
- 國產(chǎn) CPU 性能最全盤點 宜良性競爭優(yōu)勝劣汰
- NI榮獲ADI兩項全球供應(yīng)商大獎
- e絡(luò)盟供應(yīng)大量飛行時間傳感器以滿足工業(yè)應(yīng)用需求
- 上海高校研究生腦洞打開,“Arm杯”刮起創(chuàng)新風(fēng)暴
- K50宇宙:集齊安卓陣營最強芯
- MIUI 13適配名單解密:千元神機(jī)也有份
- 今年iPhone 13用了300萬塊京東方OLED屏
- 盧偉冰:Note 11才是中端顏值最美手機(jī),價格1199元!
- 小米旋出式攝像模組相關(guān)專利獲授權(quán):可加快攝像頭旋出