久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2549|回復: 3
收起左側

STM32單片機串口DMA數據讀取(詳細代碼)

[復制鏈接]
ID:955050 發表于 2023-4-8 16:12 | 顯示全部樓層 |閱讀模式
最近重新開始學STM32單片機,搞到串口 DMA 的時候, 數據讀取卡了很長一段時間,最終,功夫不負有心人終于搞出來了。在此以記錄一下,方便以后查詢使用。
在調試的過程中也遇到了很多bug,有些簡直就是低級問題,但是還是卡了很久,在此寫出來給自己加深印象,同時已給后來者一個前車之鑒
1、在32的程序編寫中,若使用到了中斷部分,特別是中斷函數一定要注意,查詢清除中斷標志位到底是什么。
獲取中斷標志位 是 USART_GetITStatus 函數,筆者就是沒弄清 用成了 USART_ GetFlagStatus 函數,
USART_GetITStatus   檢查指定的 USART 中斷發生與否
USART_ GetFlagStatus 檢查指定的 USART 標志位設置與否
就是這個問題卡了筆者很久,甚至筆者檢查了很多次都沒注意到

2、中斷函數的使用, 這個在使用時若不注意就會用錯,比如 中斷串口2 ,卻使用成了 中斷串口1
關于中斷函數的查詢可以通過kile5 Startup文件夾 下的 startup_stm32f10x_md.s 進行查詢

3、代碼功能獨立
這部分主要就是要將各函數功能進行,獨立。方便理清邏輯,可能很多人覺得很麻煩,且很多人沒有此習慣,但是在學習和工作中稍微花點時間,將其進行整理還是很有必要的。
筆者在調試這部分時,就出現了邏輯混亂的情況,將 GPIO, 串口,DMA 全部寫在一起,導致最后混亂。最終每次只會搬運最后一個字符。具體原因筆者也沒搞清楚。若有大佬能夠了解,望指點一二。

—————————————————————分割線———————————————

以上廢話,下為正文
DMA 串口數據讀取主要就是 將串口的數據搬移到內存中
在實際代碼中,筆者定義了一個char 數組進行存儲。并通過重定義printf 的方式將 char 數組內的內容輸出出來(后面看大家需不需要,也可以將DMA 數據發送的代碼 分享出來 嘿嘿嘿)。
主要步驟如下
1、選擇使用的串口(串口1)
2、查詢該串口對應的引腳及DMA通道(A9,A10, DMA1chanel4, DMA1chanel5)Tip:可以通過STM32參考手冊查詢,后面會放的(感謝正點原子)
3、配置串口1 GPIO
4、配置串口1 USART 及 中斷
5、配置串口1 對應 DMA

著重需要注意的是:這里使用的是 串口1 的 空閑中斷?臻e中斷在設備接收到數據后 一個字節內的時間還是為接收到數據就會產生,在清除之后,當下一次接收到數據之后的1個字節時間內才會再次產生。   說人話就是,正常情況下不會產生,只有在接收數據后,沒有數據了,才會再次產生。
此處使用串口 的空閑中斷可以實現 接收不定長數據,若使用的是 定長數據 就可以使用DMA 的接收完成中斷(接收完成是當前數據接收完成,還需要判斷接收次數是否為 0)

筆者設備 STM32F103RCT6 + window10,若其他設備可根據提供的資料進行查詢對應的引腳和通道


—————————————分割線———————————————
開始放代碼
配置引腳
  1. void USART1_GPIO_Init(void){//初始化 串口 1 GPIO
  2.                 //GPIO引腳功能初始化結構體
  3.                 GPIO_InitTypeDef GPIO_InitStruct;
  4.                 //1、使能串口引腳,復用功能
  5.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
  6.                
  7.                 //2、初始化引腳功能 輸入 懸空(輸入高為高, 輸入低為低), 輸出 復用推挽
  8.                 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//初始化引腳為 A9
  9.                 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//初始化引腳功能為 復用推挽模式
  10.                 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//設置引腳傳輸速率為 10MHz
  11.                 GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A9引腳 (發送)
  12.                
  13.                 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//初始化引腳為 A10
  14.                 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//初始化引腳功能為 懸空輸入
  15.                 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//設置引腳傳輸速率為 10MHz
  16.                 GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A1引腳 (接收)
  17. }
復制代碼
配置串口
  1. void USART1_Init(uint32_t BaudRate){               
  2.                 //串口初始化結構體
  3.                 USART_InitTypeDef USART_InitStruct;
  4.                 //串口優先級結構體
  5.                 NVIC_InitTypeDef NVIC_InitStruct;

  6.                 //1、使能串口引腳,復用功能
  7.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  8.                 //2、串口初始化
  9.                 //2.1 初始化波特率
  10.                 USART_InitStruct.USART_BaudRate = BaudRate;//初始化串口波特率(使用形參確定)
  11.                 //2.2 初始化數據位
  12.                 USART_InitStruct.USART_WordLength = USART_WordLength_8b;//初始化串口數據位為 8 位
  13.                         //2.3 初始化停止位
  14.                 USART_InitStruct.USART_StopBits = USART_StopBits_1;//初始化串口數據位為 0 位
  15.                 //2.4 初始化奇偶校驗位
  16.                 USART_InitStruct.USART_Parity = USART_Parity_No;//初始化串口奇偶校驗位
  17.                 //2.5 初始化流控
  18.                 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//初始化串口控制為無流控
  19.                 //2.6 初始化串口工作模式
  20.                 USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

  21.                 USART_Init(USART1, & USART_InitStruct);               

  22.                 //3、設置串口 接收中斷 (空閑中斷-搬運數據完畢 或 未搬運數據 當開始搬運數據后 一段時間未搬運下一個數據,發出此中斷)
  23.                 //3.1 配置串口中斷優先級通道
  24.                 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  25.                 //3.2 使能命令
  26.                 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  27.                 //3.3 設置搶占優先級
  28.                 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  29.                 //3.4 設置優先級
  30.                 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  31.                 NVIC_Init( & NVIC_InitStruct);
  32.                
  33.                 //5、配置串口接收中斷
  34.                 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//串口1 空閑中斷               
  35.                 //5、中斷處理
  36.                 USART_DMACmd(USART1,USART_DMAReq_Rx, ENABLE);//開啟串口1 DMA 接收請求
  37.                 //6、使能串口
  38.                 USART_Cmd(USART1,ENABLE);//若重載 printf ,就無需使用 DMA 進行數據搬移。(故此處應該無需使用重載)
  39. }
復制代碼

配置 DMA
  1. void USART1_DMA_Init(void){
  2.         //DMA初始化結構體
  3.         DMA_InitTypeDef DMA_InitStruct;

  4.         //1、使能DMA時鐘
  5.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  6.         
  7.         //2、接收數據 DMA通道5初始化
  8.         //2.1 初始化外設地址
  9.         DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)& USART1->DR;//設置串口發送數據寄存器
  10.         //2.2 初始化內存地址
  11.         DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Get_Date;//接收內存地址
  12.         //2.3 初始化 DMA 方向
  13.         DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//外設為源地址
  14.         //2.4 初始化 發送數據大小 ,6.2內存大小
  15.         DMA_InitStruct.DMA_BufferSize = BUFFSIZE;//此處的接收數據大小設置一個固定的,較大的
  16.         //2.5 初始化外設地址增量(向發送端寫入數據,無需使用增量)
  17.         DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//無增量
  18.         //2.6 初始化內存地址增量(讀取內存地址,寫入外設,有增量)
  19.         DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//有增量
  20.         //2.7 初始化外設數據寬度
  21.         DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//無增量的話應該不用設置
  22.         //2.8 初始化內存數據寬度
  23.         DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//增量為全字
  24.         //2.9 初始化DMA工作模式
  25.         DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;//正常循環模式
  26.         //2.10 初始化DMA通道優先級
  27.         DMA_InitStruct.DMA_Priority = DMA_Priority_High;//通道優先級 高
  28.         //2.11 初始化DMA存儲器to存儲器(內存寫入外設,無需使用)
  29.         DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//不使用 內存到內存               

  30.         DMA_Init(DMA1_Channel5, & DMA_InitStruct);//通道5 串口1 讀數據

  31.         DMA_Cmd(DMA1_Channel5, ENABLE);//開啟通道5 使能位
  32. }
復制代碼

中斷和調用函數部分
  1. void Mov_DmaDate_To_Buffer(void){//搬移函數,將DMA寄存器中的數據搬移到另一個寄存器
  2.         DMA_Cmd(DMA1_Channel5, DISABLE);//關閉 DMA 通道 5 (關閉串口1 讀)
  3.                         
  4.         DMA1_Channel5->CNDTR = BUFFSIZE;//重新設置 通道 待傳輸數據大小
  5.                
  6.         DMA_Cmd(DMA1_Channel5, ENABLE);//開啟 DMA 通道 5 (開啟串口1 讀)
  7.         
  8.         printf("%s\n",Get_Date);//輸出接收的數據
  9. }


  10. void USART1_IRQHandler(void){//串口1 中斷處理函數
  11.         if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){//若中斷標志位為 空閑中斷
  12.                 //調用搬移函數
  13.                 Mov_DmaDate_To_Buffer();//調用空閑中斷處理函數

  14.                 USART_ReceiveData(USART1);//通過讀取數據實現關閉 空閑中斷
  15.                
  16.                 //清除標志位
  17.                 Recevie_State = true;//設置接收數據完畢標志位
  18.         }
  19. }
復制代碼

Keil代碼下載: 代碼STM32_Study_Serial_DMA_Read.7z (193.55 KB, 下載次數: 52)

評分

參與人數 1黑幣 +80 收起 理由
admin + 80 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:353115 發表于 2023-4-8 17:15 | 顯示全部樓層
定長和不定長都可以使用DMA功能,限制最大接收數量就好了。
既然用了空閑中斷,定長數據和不定長數據就失去了意義,反正空閑之后標志這一幀結束。在空閑中斷中要停用串口的DMA功能,處理完數據后再開啟串口的DMA功能。
回復

使用道具 舉報

ID:955050 發表于 2023-4-8 20:01 | 顯示全部樓層
qsssuv 發表于 2023-4-8 17:15
定長和不定長都可以使用DMA功能,限制最大接收數量就好了。
既然用了空閑中斷,定長數據和不定長數據就失 ...

多謝補充,
回復

使用道具 舉報

ID:291668 發表于 2023-4-8 20:28 | 顯示全部樓層
學以致用,這種方法很好! 學習了
回復

使用道具 舉報

5#
無效樓層,該帖已經被刪除
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲 精品 综合 精品 自拍 | 久草视频网站 | 久久国产成人 | 精品久久香蕉国产线看观看亚洲 | 亚洲精品日日夜夜 | 精品视频在线一区 | 91精品国产综合久久久久 | 亚洲69p| 精品一区二区三区在线播放 | 精品久久久网站 | 欧美区在线 | 亚洲国产一区在线 | 亚洲国产成人精品女人久久久 | 中文字幕免费在线观看 | 免费国产视频在线观看 | 欧美二区在线 | 亚洲成av人片在线观看 | 久久69精品久久久久久久电影好 | 欧美亚洲另类丝袜综合网动图 | 狠狠色狠狠色综合日日92 | 中文字幕人成乱码在线观看 | 日本网站免费观看 | 国产亚洲一区精品 | 福利片在线看 | 91视频麻豆 | 男女免费在线观看视频 | 午夜精品久久久久久久星辰影院 | 国产一级精品毛片 | 秋霞a级毛片在线看 | 色综合99| 毛片国产 | 午夜激情一区 | 亚洲高清视频一区二区 | 91九色在线观看 | 精品国产18久久久久久二百 | 欧美日韩综合精品 | 黄色在线免费播放 | 欧美成人精品一区 | 免费一级片| www亚洲精品 | 日韩 欧美 二区 |