日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

STM32----摸石头过河系列(五)

發(fā)布時(shí)間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32----摸石头过河系列(五) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天總結(jié)一下DMA(Direct Memory Access,直接存儲(chǔ)器存儲(chǔ)),在以往我們從串口讀取數(shù)據(jù)到內(nèi)存的流程是,cpu通過串口讀取導(dǎo)數(shù)據(jù),然后CPU再將數(shù)據(jù)寫入固定的內(nèi)存。這種讀取方式占用了大量的cpu資源,如果數(shù)據(jù)量非常大,CPU將耗費(fèi)大量的時(shí)間來(lái)進(jìn)行數(shù)據(jù)的讀寫操作。因此DMA應(yīng)運(yùn)而生。DMA的作用是啥呢?從名字能看出來(lái)一二,它可以直接從串口讀取數(shù)據(jù)存儲(chǔ)在內(nèi)存中,幾乎不占用CPU的資源。打個(gè)比方來(lái)說(shuō),一個(gè)砌墻的工人,他的主要工作是砌墻,但他首先需要耗費(fèi)大量時(shí)間去搬磚到自己身邊,然后才開始砌墻,這樣他砌墻的進(jìn)度肯定很慢。現(xiàn)在砌墻的工人不自己去搬磚了,他雇傭了另外一個(gè)人來(lái)幫助他去把磚搬過來(lái),在搬之前砌墻的工人告訴搬磚的工人,他要去哪里搬磚、搬什么樣的磚、搬磚的速度、搬過來(lái)后放在那里等問題。這樣雖然在開始耗費(fèi)了點(diǎn)時(shí)間去告訴搬磚工人一些要求,看起來(lái)比較繁瑣,其實(shí)這些所占用的時(shí)間比起自己去搬磚耗費(fèi)的時(shí)間少多了。在這個(gè)例子中,砌墻的工人就是我們所說(shuō)的CPU,磚就是需要讀寫數(shù)據(jù),搬磚工人就是DMA,DMA的引入為CPU讀寫數(shù)據(jù)節(jié)省了大量的時(shí)間,CPU只需要在開始耗費(fèi)極少的時(shí)間對(duì)DMA進(jìn)行相關(guān)的配置,就可以去做其他的事情。

我在做實(shí)驗(yàn)的過程中,遇到了很多狗血的bug,不過最終都得以解決。今天做的實(shí)驗(yàn)是利用DMA通過USART1向發(fā)送數(shù)據(jù),同時(shí)LED持續(xù)點(diǎn)亮,當(dāng)發(fā)送數(shù)據(jù)完成時(shí),進(jìn)入中斷將LED熄滅,從而來(lái)驗(yàn)證DMA工作時(shí)CPU可以去做別的事情,而沒有影響。下面來(lái)總結(jié)一下DMA的開發(fā)流程:

  • NVIC中斷優(yōu)先級(jí)的配置
  • DMA_InitTypeDef結(jié)構(gòu)體的配置(記得調(diào)用NVIC配置的函數(shù),我多次忘記調(diào)用)
  • 初始化DMA,DMA_Init(DMA1_Channel4,&結(jié)構(gòu)體)(DMA1_Channel4為串口1的發(fā)送,具體的可以看手冊(cè))
  • 使能DMA,DMA_Cmd(DMA1_Channel4,ENABLE)
  • 配置并使能中斷DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE)
  • 開始利用DMA進(jìn)行串口發(fā)送數(shù)據(jù)USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  • 在中斷中DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET來(lái)確定發(fā)送數(shù)據(jù)完成
  • 根據(jù)以上步驟進(jìn)行先關(guān)的配置,其他的比如串口和LED的配置在前面已經(jīng)配置過了直接把USART和LED的配置文件添加在該項(xiàng)目中即可。下面來(lái)看代碼,代碼中只有DMA的配置和主函數(shù)。

    下面這是dma.c文件中的內(nèi)容:

    #include"dma.h"uint16_t SendBuff[SENDSBUFF_SIZE];static void NVIC_Config(void) {NVIC_InitTypeDef nvic_struct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);nvic_struct.NVIC_IRQChannel = DMA1_Channel4_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 1;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct); }void DMA1_Config(void) {DMA_InitTypeDef dma_struct;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);NVIC_Config();dma_struct.DMA_PeripheralBaseAddr = USART1_BASE + 0x04;//數(shù)據(jù)要到達(dá)的地址dma_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//每次發(fā)送數(shù)據(jù)的大小dma_struct.DMA_MemoryBaseAddr = (u32)SendBuff;//數(shù)據(jù)所在的地址dma_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//每次讀取數(shù)據(jù)的大小dma_struct.DMA_BufferSize = SENDSBUFF_SIZE;//總共傳輸?shù)臄?shù)據(jù)的大小dma_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;//存儲(chǔ)數(shù)據(jù)的地址是否自動(dòng)增加dma_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//數(shù)據(jù)到達(dá)的地址是否自動(dòng)增加dma_struct.DMA_DIR = DMA_DIR_PeripheralDST;//傳輸?shù)姆较騼?nèi)存到外設(shè)dma_struct.DMA_M2M = DMA_M2M_Disable;//內(nèi)存到內(nèi)存是否允許dma_struct.DMA_Mode = DMA_Mode_Normal;//傳輸方式,發(fā)送一次還是循環(huán)發(fā)送dma_struct.DMA_Priority = DMA_Priority_Medium;//優(yōu)先級(jí)DMA_Init(DMA1_Channel4,&dma_struct);//初始化DMA_Cmd(DMA1_Channel4,ENABLE);//使能DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//中斷配置并使能}

    SendBuff數(shù)組存儲(chǔ)的是要發(fā)送的數(shù)據(jù),兩個(gè)函數(shù)為中斷配置函數(shù),在前面的外部中斷中已經(jīng)配置過了。第二個(gè)函數(shù)為DMA的配置函數(shù),與其他外設(shè)的配置類似,先定義一個(gè)結(jié)構(gòu)體,然后開啟時(shí)鐘。這個(gè)DMA1的時(shí)鐘和之前的都不一樣,在AHB上,配置時(shí)需要注意。

    在main.c文件中:

    #include"led.h" #include"usart.h" #include"dma.h"extern uint16_t SendBuff[SENDSBUFF_SIZE];//引用外部定義的變量 int i;int main(void)//主函數(shù) {GPIO_LED_Config();USART1_Config();DMA1_Config();for(i = 0;i < SENDSBUFF_SIZE;i++)//為發(fā)送數(shù)據(jù)賦值{SendBuff[i] = 0xff;}printf("Send start!");USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);LED(ON);printf("wait interrupt!");while(1); }void DMA1_Channel4_IRQHandler(void)//中斷函數(shù) {printf("into interrupt!");if(DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET)//判斷是否發(fā)送完成{printf("send success");LED(OFF);DMA_ClearFlag(DMA1_FLAG_TC4);//清除標(biāo)志位} }

    在實(shí)驗(yàn)的過程中,編譯出現(xiàn)symbol multiply defined錯(cuò)誤的原因,因?yàn)樵趚xx.h中定義了許多變量,xxx.c中調(diào)用xxx.h中的變量,在主文件中也調(diào)用了xxx.h中的變量,導(dǎo)致變量被重復(fù)定義。

    解決辦法:不應(yīng)該在xxx.h中定義xxx.c中使用的變量,應(yīng)該在xxx.c中定義所需要的變量,然后再在主程序中將調(diào)用xxx.c中定義的變量使用extern 例:extern u32 test.

    總結(jié)

    以上是生活随笔為你收集整理的STM32----摸石头过河系列(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。