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

標題: 模仿正點原子到STM32寄存器編寫-DMA [打印本頁]

作者: 鄧家文    時間: 2021-4-29 02:28
標題: 模仿正點原子到STM32寄存器編寫-DMA
本次實驗我們是模仿正點原子的寄存器Demo來深入學習DMA的工作原理并來純手工敲寫DMA實驗。DMA是可以存儲器與存儲器,外設與存儲器之間進行數(shù)據(jù)傳輸?shù)摹_@里我們
以串口1作為外設,BUFF[xx]字符數(shù)組作為存儲器的外設與存儲器之間的數(shù)據(jù)傳輸實驗。

那怎么看中文參考手冊呢?
第一步:看手冊的核心要點。
1、
簡介是表示用最簡單的語言來描述那種模塊的大致內(nèi)容,所以這個我們必須看。

2、
模塊的特性我們也需要重點關(guān)注的,因為這里描述的東西在我們配置時極大可能需要了解的又可能疏忽的點。

3、
              模塊處理過程是很重要的,我們根據(jù)理解它的處理過程來配置程序的。

4、
看到這個配置過程字眼,我們要知道,這是重點中的重點,因為我們的是根據(jù)這個爹來配置程序的。

第二步:理解了上面的描述后,我們就要理解一下這個DMA的工作框圖。
紅色線:這表示我們在平常串口通信的時候我們是將usart_dr寄存器的值放入定義好的buff[xx]緩沖區(qū)里作為接收操作,而將字符串逐個的值賦予usart_dr寄存器作為輸出操作。
從字面理解來說,這樣我們就要將MCU騰出的時間出進行串口數(shù)據(jù)接收和數(shù)據(jù)發(fā)送了,這樣就消耗了MCU的一部分資源了。
藍色線:第一條線表示MCU與DMA的連線,是用來配置DMA用的。第二條線表示外設或存儲器與DMA的數(shù)據(jù)交互的,可以理解成它就是一個小型的MCU,能直接處理存儲器與寄存器之間的數(shù)據(jù)交互,不需要STM32這個MCU的參與,這大大減小了MCU資源占用。

第三步:配置的大致我們都知道后,我們要知道一個要點,但凡我們使用一個模塊的東西去操作另一個模塊的時候,這兩個模塊之間是沒有線路直接相連的,而且還有這么多個通道那種,那么我們就要查看映射表了。
藍色框就是我們要使用的外設了,它在DMA1模塊里的通道4。

第四步:開始寫寄存器操作的程序。(我們看著剛剛那個配置過程來寫程序)
                          


配置DMA的基地址,上門圖可知,DMA這個模塊里面每個通道都有自己對應的寄存器,那么我們配置寄存器也要相應的分開配置那個通道的,所以我們基地址需要分開來。
上面程序里為什么還要分DMA_BASE呢?這需要我們?nèi)タ词謨砸粋地方,如下圖所示:
DMA_ISR和DMA_IFCR這兩個寄存器和下面的是有很明顯的區(qū)別的,下面的沒4個對應一個通道,里面除了起始地址不一樣外,大小都一樣,所以配置時可以共用一個結(jié)構(gòu)體,而那個兩個就只能用一個不同的結(jié)構(gòu)體獨立出來了,也就是為什么用DMA_BASE的原因了。
寄存器的基地址在哪里找呢?如下圖可以查找到模塊的起始地址。
而每個通道的基地址就在DMA寄存器印象和復位這個表中查找,模塊起始地址加上表左邊的偏移量就是基地址了。
這個結(jié)構(gòu)體就按照DMA寄存器印象和復位表來寫的。這里就步重復解釋了。
有以上的環(huán)境基礎下,我們就可以開始配置DMA了。
我們需要寄存器那些位呢?配置哪個寄存器就進入哪個寄存器查詢相關(guān)位的功能,列入下圖2
   
                                                        圖1                            圖2
好了下面開始配置
這個配置程序基本是根據(jù)手冊中描述通道配置來編寫的
(1打開時鐘 2設置外設 3設置存儲器 4傳輸?shù)臄?shù)量 5方向、是否循環(huán)模式、外設是否增量、存儲器是否增量、外設數(shù)據(jù)寬、存儲器數(shù)據(jù)寬、優(yōu)先級、什么模式啟動)
這里我就說一些重點,簡單的自己看手冊,只有自己學會看手冊才學到東西。
sendlen=BUFFLEN; 這是用來保存你要傳輸?shù)臄?shù)據(jù)長度,用來觸發(fā)你每次傳輸都是傳輸這個長度的數(shù)據(jù)。
循環(huán)模式:中文參考手冊有詳細解釋。
為什么要把外設和存儲器的位寬都設置8位:首先我們要理解一個過程DMA傳輸是將我們存儲器的值全部發(fā)送出去為止,那么8位為一個字節(jié),在這個傳輸?shù)倪^程就是每次取存儲器1個字節(jié)數(shù)據(jù)傳輸?shù)酵庠O,而外設也是一次取1個字節(jié)數(shù)據(jù),那么實現(xiàn)數(shù)據(jù)一一對應了。
這個沒什么好說的,就是關(guān)閉上一次已經(jīng)傳輸完成的;重置它的傳輸量,因為每次傳輸數(shù)據(jù)它都會以傳輸一個數(shù)據(jù)遞減1的形式遞減至0,并且它不會自己重載回去(循環(huán)模式就可以遞減至0又重載);開啟新的DMA傳輸。
配置完后就將我們準備好的存儲器寫滿內(nèi)容,然后進行DMA傳輸,在串口中觀看。
1、自己定義一個存儲器,記得要大點,假設我們配置的是波特率為115200,那么就說明數(shù)據(jù)傳輸速率115200bit/s = 14400字節(jié)/s,而我們用34000個字節(jié)的數(shù)據(jù)進行傳輸?shù)脑挘粋DMA傳輸過程大概花費的時間是34000/14400=2.36s左右。
2、我們使用串口作為外設
3、串口1在DMA通道1,外設為串口USART_DR,存儲器SendBuff,存儲器的數(shù)據(jù)長度。
4、弄個什么循環(huán)的把存儲器SendBuff的數(shù)據(jù)灌滿。例如下圖
5、
開啟數(shù)據(jù)傳輸,上面紅框框里的是我們將本來使用復用的PA9口作為發(fā)送端換成了DMA->USART1_TX上(這個東西就類似與GPIO口復用成串口等這樣)
上面虛線這行代碼是用不了的,若想顯示它傳輸?shù)陌俜直龋托枰肙LED屏或者使用串口2等方式顯示(原因是因為DMA直接控制USART1_DR寄存器的,不需要MCU參與,導致USART1_DR這個一直被占用,就打印出傳輸過程的百分比量了)

完整程序:
  1. #include "stdio.h"
  2. #include "gpio.h"
  3. #include "USART1.h"
  4. #include "delay_ms.h"
  5. #include "clock.h"
  6. #include "USART1.h"
  7. #include "key.h"
  8. #include "DMA.h"

  9. const u8 Text_Buff[]="鄧家文使用STM32F103 DMA串口實驗";
  10. u16 str_len=sizeof(Text_Buff);                                                                                     //str_len將要發(fā)送字符的長度
  11. u8 SendBuff[34000];                                            //發(fā)送數(shù)據(jù)緩沖區(qū)  DMA( 寄存器->存儲器SendBuff )
  12. u16 KeyKind=0;                                                                                                                                            //key_kind按鍵類

  13. float pro=0;                                                                                    //進度條
  14. u16 i,mask,tt;                               //循環(huán)體使用的臨時變量


  15. int main(void)
  16. {
  17.               RCC_Config(9);                                                        //72MHz
  18.               delay_init1(72);                                          //打開延時
  19.               GPIO_Init();                                                                      //初始化LED口
  20.               USART_INIT(72,115200);  //初始化串口
  21.               key_init();                                                                                    //初始化按鍵
  22.               DMA_INIT(DMA_Channel4,(u32)&USART1->USART_DR,(u32)SendBuff,34000);                                                        //寄存器,存儲器,存儲器大小
  23.             
  24.               for(i=0;i<34000;i++)//填充數(shù)據(jù)到SendBuff
  25.   {
  26.                             if(tt>=str_len)//加入換行符
  27.                             {
  28.                                           if(mask)
  29.                                           {
  30.                                                         SendBuff[i]=0x0a;
  31.                                                         tt=0;
  32.                                           }else
  33.                                           {
  34.                                                         SendBuff[i]=0x0d;
  35.                                                         mask++;
  36.                                           }            
  37.                             }else//復制TEXT_TO_SEND語句
  38.                             {
  39.                                           mask=0;
  40.                                           SendBuff[i]=Text_Buff[tt];
  41.                                           tt++;
  42.                             }                    
  43.   }                           
  44.               while(1)
  45.               {
  46.                             KeyKind=key_scan(0);
  47.                             if(KeyKind==2)
  48.                             {
  49.                                           GPIOB->GPIO_ODR^=1<<5;
  50.                                           USART1->USART_CR3=1<<7;                                                                                                                //使能串口1的DMA發(fā)送
  51.                                           DMA_OneSend(DMA_Channel4);                                                                                    //開啟一次發(fā)送
  52.                            
  53.                                           while(1)
  54.                                           {
  55.                                                         if(DMA->DMA_ISR&(1<<13))                            //等待通道1傳輸完成
  56.                                                         {
  57.                                                                       DMA->DMA_IFCR|=1<<13;                                          //清除通道1傳輸完成標志
  58.                                                                       break;
  59.                                                         }                                                      
  60.                                                         pro=DMA_Channel4->DMA_CNDTR;//獲取當前剩余數(shù)據(jù)量
  61.                                                         pro=1-pro/34000;                                                                                       //獲取百分比
  62.                                                         pro*=100;                                                                                                                                            //得到整數(shù)的百分比
  63.                                                         printf("residue:%f\r\n",pro);
  64.                                           }            
  65.                             }
  66.               }

  67. }
復制代碼

二、DMA.h
  1. #include "stdio.h"
  2. #include "gpio.h"
  3. #include "USART1.h"
  4. #include "delay_ms.h"
  5. #include "clock.h"
  6. #include "USART1.h"
  7. #include "key.h"
  8. #include "DMA.h"

  9. const u8 Text_Buff[]="鄧家文使用STM32F103 DMA串口實驗";
  10. u16 str_len=sizeof(Text_Buff);                                                                                     //str_len將要發(fā)送字符的長度
  11. u8 SendBuff[34000];                                            //發(fā)送數(shù)據(jù)緩沖區(qū)  DMA( 寄存器->存儲器SendBuff )
  12. u16 KeyKind=0;                                                                                                                                            //key_kind按鍵類

  13. float pro=0;                                                                                    //進度條
  14. u16 i,mask,tt;                               //循環(huán)體使用的臨時變量


  15. int main(void)
  16. {
  17.               RCC_Config(9);                                                        //72MHz
  18.               delay_init1(72);                                          //打開延時
  19.               GPIO_Init();                                                                      //初始化LED口
  20.               USART_INIT(72,115200);  //初始化串口
  21.               key_init();                                                                                    //初始化按鍵
  22.               DMA_INIT(DMA_Channel4,(u32)&USART1->USART_DR,(u32)SendBuff,34000);                                                        //寄存器,存儲器,存儲器大小
  23.             
  24.               for(i=0;i<34000;i++)//填充數(shù)據(jù)到SendBuff
  25.   {
  26.                             if(tt>=str_len)//加入換行符
  27.                             {
  28.                                           if(mask)
  29.                                           {
  30.                                                         SendBuff[i]=0x0a;
  31.                                                         tt=0;
  32.                                           }else
  33.                                           {
  34.                                                         SendBuff[i]=0x0d;
  35.                                                         mask++;
  36.                                           }            
  37.                             }else//復制TEXT_TO_SEND語句
  38.                             {
  39.                                           mask=0;
  40.                                           SendBuff[i]=Text_Buff[tt];
  41.                                           tt++;
  42.                             }                    
  43.   }                           
  44.               while(1)
  45.               {
  46.                             KeyKind=key_scan(0);
  47.                             if(KeyKind==2)
  48.                             {
  49.                                           GPIOB->GPIO_ODR^=1<<5;
  50.                                           USART1->USART_CR3=1<<7;                                                                                                                //使能串口1的DMA發(fā)送
  51.                                           DMA_OneSend(DMA_Channel4);                                                                                    //開啟一次發(fā)送
  52.                            
  53.                                           while(1)
  54.                                           {
  55.                                                         if(DMA->DMA_ISR&(1<<13))                            //等待通道1傳輸完成
  56.                                                         {
  57.                                                                       DMA->DMA_IFCR|=1<<13;                                          //清除通道1傳輸完成標志
  58.                                                                       break;
  59.                                                         }                                                      
  60.                                                         pro=DMA_Channel4->DMA_CNDTR;//獲取當前剩余數(shù)據(jù)量
  61.                                                         pro=1-pro/34000;                                                                                       //獲取百分比
  62.                                                         pro*=100;                                                                                                                                            //得到整數(shù)的百分比
  63.                                                         printf("residue:%f\r\n",pro);
  64.                                           }            
  65.                             }
  66.               }

  67. }
復制代碼

三、DMA.c
  1. #include "DMA.h"
  2. #include "delay_ms.h"

  3. u16 sendlen;                                                                      //保存DMA每次數(shù)據(jù)傳送的長度,也就是最開始的傳輸量,100%

  4. //CPAR外設地址
  5. //CMAR存儲器地址
  6. //BUFFLEN數(shù)據(jù)傳輸?shù)拈L度或量
  7. void DMA_INIT(DMA_ChannelType*DMA_Chx,u32 CPAR,u32 CMAR,u16 BUFFLEN)
  8. {
  9.               RCC->RCC_AHBENR=1<<0;                                                                                      //開啟DMA1的時鐘
  10.               delay_ms1(5);                                                                                                                      //等待DMA時鐘穩(wěn)定
  11.               DMA_Chx->DMA_CPAR=CPAR;                                                                       //指向外設寄存器地址
  12.               DMA_Chx->DMA_CMAR=CMAR;                                                                                    //指向存儲器地址
  13.               sendlen=BUFFLEN;                                                                                                                              //保存DMA傳輸數(shù)據(jù)量
  14.               DMA_Chx->DMA_CNDTR=BUFFLEN;                                                        //傳輸數(shù)據(jù)量                             每次傳輸都會自動遞減,直到0后會重載配置的長度數(shù)值BUFFLEN
  15.               DMA_Chx->DMA_CCR=0x00000000;                                          //將配置寄存器的所有位清除(復位)
  16.               DMA_Chx->DMA_CCR|=1<<4;                                                                        //從存儲器讀出數(shù)據(jù)
  17.               DMA_Chx->DMA_CCR|=0<<5;                                                                                    //普通模式,不循環(huán)
  18.               DMA_Chx->DMA_CCR|=0<<6;                                                                                    //外設地址非增量模式, 這個是讀數(shù)據(jù),選擇讀出的位置大小是固定的,也就是不會隨地址改變,所以非增量
  19.               DMA_Chx->DMA_CCR|=1<<7;                                                                                    //存儲器地址增量模式   這個是寫數(shù)據(jù),需要將讀出來的數(shù)據(jù)依次的寫入對應的地方,所以增量
  20.               DMA_Chx->DMA_CCR|=0<<8;                       //外設數(shù)據(jù)寬度為8位  也就是一次讀出1個字節(jié)
  21.               DMA_Chx->DMA_CCR|=0<<10;                                                                      //存儲器數(shù)據(jù)寬度8位  也就是一次寫入1個字節(jié)
  22.               DMA_Chx->DMA_CCR|=1<<12;                                                                      //中等優(yōu)先級
  23.               DMA_Chx->DMA_CCR|=0<<14;                                                                      //啟動非存儲器到存儲器模式                             
  24. }

  25. //啟動一次DMA傳輸,上面定義的是一次傳輸1個字節(jié)
  26. void DMA_OneSend(DMA_ChannelType*DMA_Chx)
  27. {
  28.               DMA_Chx->DMA_CCR&=~(1<<0);                                          //先關(guān)閉上一次的DMA傳輸,因續(xù)上一次傳輸1個字節(jié)后并未關(guān)閉,若步關(guān)閉回影響下一次的傳輸,而且不能實現(xiàn)起停傳輸效果
  29.               DMA_Chx->DMA_CNDTR=sendlen;                                          //傳輸數(shù)據(jù)量
  30.               DMA_Chx->DMA_CCR|=1<<0;                                                                      //開啟下一次的DMA傳輸
  31. }
復制代碼

以上的的Word格式文檔51黑下載地址:
帶你模仿正點原子到寄存器編寫--DMA.docx (1.52 MB, 下載次數(shù): 14)






歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 国产黄视频在线观看 | 午夜精品一区二区三区在线播放 | 欧美黑人一区二区三区 | 一区二区视频在线播放 | 日产精品久久久一区二区 | 99re视频 | 国产主播一区二区 | 久久国产免费 | 私人午夜影院 | 免费av小说 | 天天爽天天操 | 国产不卡视频 | 色黄大色黄女片免费中国 | 日韩免费看片 | av天天操 | 日本一级淫片色费放 | 日日操夜夜 | 激情五月综合色婷婷一区二区 | 三级在线看 | 一区视频 | 亚洲精品视频免费观看 | av不卡一区| 日本三级香港三级 | 成人在线免费看 | 人人澡人人爽 | 天天草天天干 | 嫩草视频在线观看 | 国产在线观看网站 | 福利视频网站 | 一区二区三区视频 | 日韩精品免费看 | av黄色在线观看 | 黄色大片在线免费观看 | 精品蜜桃一区二区三区 | 黄色片视频 | 午夜tv| 天天曰天天操 | 午夜免费视频 | 午夜在线免费观看 | 青青伊人网 | 久草免费在线视频 |