|
最近重新開(kāi)始學(xué)STM32單片機(jī),搞到串口 DMA 的時(shí)候, 數(shù)據(jù)讀取卡了很長(zhǎng)一段時(shí)間,最終,功夫不負(fù)有心人終于搞出來(lái)了。在此以記錄一下,方便以后查詢(xún)使用。
在調(diào)試的過(guò)程中也遇到了很多bug,有些簡(jiǎn)直就是低級(jí)問(wèn)題,但是還是卡了很久,在此寫(xiě)出來(lái)給自己加深印象,同時(shí)已給后來(lái)者一個(gè)前車(chē)之鑒
1、在32的程序編寫(xiě)中,若使用到了中斷部分,特別是中斷函數(shù)一定要注意,查詢(xún)清除中斷標(biāo)志位到底是什么。
獲取中斷標(biāo)志位 是 USART_GetITStatus 函數(shù),筆者就是沒(méi)弄清 用成了 USART_ GetFlagStatus 函數(shù),
USART_GetITStatus 檢查指定的 USART 中斷發(fā)生與否
USART_ GetFlagStatus 檢查指定的 USART 標(biāo)志位設(shè)置與否
就是這個(gè)問(wèn)題卡了筆者很久,甚至筆者檢查了很多次都沒(méi)注意到
2、中斷函數(shù)的使用, 這個(gè)在使用時(shí)若不注意就會(huì)用錯(cuò),比如 中斷串口2 ,卻使用成了 中斷串口1
關(guān)于中斷函數(shù)的查詢(xún)可以通過(guò)kile5 Startup文件夾 下的 startup_stm32f10x_md.s 進(jìn)行查詢(xún)
3、代碼功能獨(dú)立
這部分主要就是要將各函數(shù)功能進(jìn)行,獨(dú)立。方便理清邏輯,可能很多人覺(jué)得很麻煩,且很多人沒(méi)有此習(xí)慣,但是在學(xué)習(xí)和工作中稍微花點(diǎn)時(shí)間,將其進(jìn)行整理還是很有必要的。
筆者在調(diào)試這部分時(shí),就出現(xiàn)了邏輯混亂的情況,將 GPIO, 串口,DMA 全部寫(xiě)在一起,導(dǎo)致最后混亂。最終每次只會(huì)搬運(yùn)最后一個(gè)字符。具體原因筆者也沒(méi)搞清楚。若有大佬能夠了解,望指點(diǎn)一二。
—————————————————————分割線———————————————
以上廢話,下為正文
DMA 串口數(shù)據(jù)讀取主要就是 將串口的數(shù)據(jù)搬移到內(nèi)存中
在實(shí)際代碼中,筆者定義了一個(gè)char 數(shù)組進(jìn)行存儲(chǔ)。并通過(guò)重定義printf 的方式將 char 數(shù)組內(nèi)的內(nèi)容輸出出來(lái)(后面看大家需不需要,也可以將DMA 數(shù)據(jù)發(fā)送的代碼 分享出來(lái) 嘿嘿嘿)。
主要步驟如下
1、選擇使用的串口(串口1)
2、查詢(xún)?cè)摯趯?duì)應(yīng)的引腳及DMA通道(A9,A10, DMA1chanel4, DMA1chanel5)Tip:可以通過(guò)STM32參考手冊(cè)查詢(xún),后面會(huì)放的(感謝正點(diǎn)原子)
3、配置串口1 GPIO
4、配置串口1 USART 及 中斷
5、配置串口1 對(duì)應(yīng) DMA
著重需要注意的是:這里使用的是 串口1 的 空閑中斷。空閑中斷在設(shè)備接收到數(shù)據(jù)后 一個(gè)字節(jié)內(nèi)的時(shí)間還是為接收到數(shù)據(jù)就會(huì)產(chǎn)生,在清除之后,當(dāng)下一次接收到數(shù)據(jù)之后的1個(gè)字節(jié)時(shí)間內(nèi)才會(huì)再次產(chǎn)生。 說(shuō)人話就是,正常情況下不會(huì)產(chǎn)生,只有在接收數(shù)據(jù)后,沒(méi)有數(shù)據(jù)了,才會(huì)再次產(chǎn)生。
此處使用串口 的空閑中斷可以實(shí)現(xiàn) 接收不定長(zhǎng)數(shù)據(jù),若使用的是 定長(zhǎng)數(shù)據(jù) 就可以使用DMA 的接收完成中斷(接收完成是當(dāng)前數(shù)據(jù)接收完成,還需要判斷接收次數(shù)是否為 0)
筆者設(shè)備 STM32F103RCT6 + window10,若其他設(shè)備可根據(jù)提供的資料進(jìn)行查詢(xún)對(duì)應(yīng)的引腳和通道
—————————————分割線———————————————
開(kāi)始放代碼
配置引腳
- void USART1_GPIO_Init(void){//初始化 串口 1 GPIO
- //GPIO引腳功能初始化結(jié)構(gòu)體
- GPIO_InitTypeDef GPIO_InitStruct;
- //1、使能串口引腳,復(fù)用功能
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
-
- //2、初始化引腳功能 輸入 懸空(輸入高為高, 輸入低為低), 輸出 復(fù)用推挽
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//初始化引腳為 A9
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//初始化引腳功能為 復(fù)用推挽模式
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//設(shè)置引腳傳輸速率為 10MHz
- GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A9引腳 (發(fā)送)
-
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//初始化引腳為 A10
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//初始化引腳功能為 懸空輸入
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//設(shè)置引腳傳輸速率為 10MHz
- GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A1引腳 (接收)
- }
復(fù)制代碼 配置串口
- void USART1_Init(uint32_t BaudRate){
- //串口初始化結(jié)構(gòu)體
- USART_InitTypeDef USART_InitStruct;
- //串口優(yōu)先級(jí)結(jié)構(gòu)體
- NVIC_InitTypeDef NVIC_InitStruct;
- //1、使能串口引腳,復(fù)用功能
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- //2、串口初始化
- //2.1 初始化波特率
- USART_InitStruct.USART_BaudRate = BaudRate;//初始化串口波特率(使用形參確定)
- //2.2 初始化數(shù)據(jù)位
- USART_InitStruct.USART_WordLength = USART_WordLength_8b;//初始化串口數(shù)據(jù)位為 8 位
- //2.3 初始化停止位
- USART_InitStruct.USART_StopBits = USART_StopBits_1;//初始化串口數(shù)據(jù)位為 0 位
- //2.4 初始化奇偶校驗(yàn)位
- USART_InitStruct.USART_Parity = USART_Parity_No;//初始化串口奇偶校驗(yàn)位
- //2.5 初始化流控
- USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//初始化串口控制為無(wú)流控
- //2.6 初始化串口工作模式
- USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
- USART_Init(USART1, & USART_InitStruct);
- //3、設(shè)置串口 接收中斷 (空閑中斷-搬運(yùn)數(shù)據(jù)完畢 或 未搬運(yùn)數(shù)據(jù) 當(dāng)開(kāi)始搬運(yùn)數(shù)據(jù)后 一段時(shí)間未搬運(yùn)下一個(gè)數(shù)據(jù),發(fā)出此中斷)
- //3.1 配置串口中斷優(yōu)先級(jí)通道
- NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
- //3.2 使能命令
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- //3.3 設(shè)置搶占優(yōu)先級(jí)
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
- //3.4 設(shè)置優(yōu)先級(jí)
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
- NVIC_Init( & NVIC_InitStruct);
-
- //5、配置串口接收中斷
- USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//串口1 空閑中斷
- //5、中斷處理
- USART_DMACmd(USART1,USART_DMAReq_Rx, ENABLE);//開(kāi)啟串口1 DMA 接收請(qǐng)求
- //6、使能串口
- USART_Cmd(USART1,ENABLE);//若重載 printf ,就無(wú)需使用 DMA 進(jìn)行數(shù)據(jù)搬移。(故此處應(yīng)該無(wú)需使用重載)
- }
復(fù)制代碼
配置 DMA
- void USART1_DMA_Init(void){
- //DMA初始化結(jié)構(gòu)體
- DMA_InitTypeDef DMA_InitStruct;
- //1、使能DMA時(shí)鐘
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
-
- //2、接收數(shù)據(jù) DMA通道5初始化
- //2.1 初始化外設(shè)地址
- DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)& USART1->DR;//設(shè)置串口發(fā)送數(shù)據(jù)寄存器
- //2.2 初始化內(nèi)存地址
- DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Get_Date;//接收內(nèi)存地址
- //2.3 初始化 DMA 方向
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//外設(shè)為源地址
- //2.4 初始化 發(fā)送數(shù)據(jù)大小 ,6.2內(nèi)存大小
- DMA_InitStruct.DMA_BufferSize = BUFFSIZE;//此處的接收數(shù)據(jù)大小設(shè)置一個(gè)固定的,較大的
- //2.5 初始化外設(shè)地址增量(向發(fā)送端寫(xiě)入數(shù)據(jù),無(wú)需使用增量)
- DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//無(wú)增量
- //2.6 初始化內(nèi)存地址增量(讀取內(nèi)存地址,寫(xiě)入外設(shè),有增量)
- DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//有增量
- //2.7 初始化外設(shè)數(shù)據(jù)寬度
- DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//無(wú)增量的話應(yīng)該不用設(shè)置
- //2.8 初始化內(nèi)存數(shù)據(jù)寬度
- DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//增量為全字
- //2.9 初始化DMA工作模式
- DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;//正常循環(huán)模式
- //2.10 初始化DMA通道優(yōu)先級(jí)
- DMA_InitStruct.DMA_Priority = DMA_Priority_High;//通道優(yōu)先級(jí) 高
- //2.11 初始化DMA存儲(chǔ)器to存儲(chǔ)器(內(nèi)存寫(xiě)入外設(shè),無(wú)需使用)
- DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//不使用 內(nèi)存到內(nèi)存
- DMA_Init(DMA1_Channel5, & DMA_InitStruct);//通道5 串口1 讀數(shù)據(jù)
- DMA_Cmd(DMA1_Channel5, ENABLE);//開(kāi)啟通道5 使能位
- }
復(fù)制代碼
中斷和調(diào)用函數(shù)部分
- void Mov_DmaDate_To_Buffer(void){//搬移函數(shù),將DMA寄存器中的數(shù)據(jù)搬移到另一個(gè)寄存器
- DMA_Cmd(DMA1_Channel5, DISABLE);//關(guān)閉 DMA 通道 5 (關(guān)閉串口1 讀)
-
- DMA1_Channel5->CNDTR = BUFFSIZE;//重新設(shè)置 通道 待傳輸數(shù)據(jù)大小
-
- DMA_Cmd(DMA1_Channel5, ENABLE);//開(kāi)啟 DMA 通道 5 (開(kāi)啟串口1 讀)
-
- printf("%s\n",Get_Date);//輸出接收的數(shù)據(jù)
- }
- void USART1_IRQHandler(void){//串口1 中斷處理函數(shù)
- if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){//若中斷標(biāo)志位為 空閑中斷
- //調(diào)用搬移函數(shù)
- Mov_DmaDate_To_Buffer();//調(diào)用空閑中斷處理函數(shù)
- USART_ReceiveData(USART1);//通過(guò)讀取數(shù)據(jù)實(shí)現(xiàn)關(guān)閉 空閑中斷
-
- //清除標(biāo)志位
- Recevie_State = true;//設(shè)置接收數(shù)據(jù)完畢標(biāo)志位
- }
- }
復(fù)制代碼
Keil代碼下載:
代碼STM32_Study_Serial_DMA_Read.7z
(193.55 KB, 下載次數(shù): 52)
2023-4-8 16:57 上傳
點(diǎn)擊文件名下載附件
代碼 下載積分: 黑幣 -5
|
評(píng)分
-
查看全部評(píng)分
|