<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > stm32F407之USART6的DMA工作方式

          stm32F407之USART6的DMA工作方式

          作者: 時(shí)間:2016-11-10 來源:網(wǎng)絡(luò) 收藏
          昨天調(diào)試了USART6DMA工作模式,今天補(bǔ)發(fā)上這篇筆記。

          力求簡潔,stm32的DMA就不介紹了,不了解的可以搜索一下。這里重點(diǎn)介紹一下DMA的外設(shè)地址如何確定,這個(gè)是網(wǎng)上很少涉及但是很重要的一塊,如果不清楚如何確定外設(shè)寄存器地址就無法進(jìn)行DMA功能,這里以stm32F407的USART6為例介紹,參考手冊為“RM0090 Reference manual”。

          本文引用地址:http://www.ex-cimer.com/article/201611/317475.htm

          在進(jìn)行DMA參數(shù)配置時(shí)有這樣一項(xiàng) DMA_InitStructure.DMA_PeripheralBaseAddr = ?;這句是要確定Memory與Peripheral數(shù)據(jù)傳輸時(shí)的外設(shè)數(shù)據(jù)地址,因?yàn)檫@里我們用到的是USART6從Memory的數(shù)組中取出數(shù)據(jù)并發(fā)送給上位機(jī),所以這里用到的外設(shè)地址其實(shí)是USART6的數(shù)據(jù)寄存器地址 USART6_DR,關(guān)鍵是確定他的地址。好了我們現(xiàn)在打開參考手冊,找到“Memory Map”一項(xiàng),

          打開可以看到USART6的基地址為0x4001 1400,好了,接著點(diǎn)擊后面的藍(lán)色連接

          看到USART_DR的OFFSET地址為0x04,則USART6的真實(shí)地址為 0x4001 1400+0x04 = 0x4001 1404;這樣便確定了USART6_DR的地址。其他的就好說了,代碼如下

          /************************************************************
          Copyright (C), 2012-2022, yin.
          FileName: main.c
          Author: ycw Version : 1.0 Date: 2012.04.27
          Description: USART6 DMA SendData
          Version: V3.0
          Function List:USART6 DMA SendData
          History: V1.0

          #include

          /*定義USART6的數(shù)據(jù)寄存器地址,DMA功能要用到外設(shè)的數(shù)據(jù)地址
          *USART6的數(shù)據(jù)地址為外設(shè)基地址+偏移地址,基地址在RM0090 Reference
          *manual(參考手冊)的地址映射表里(P50),為0x40011400,USART_DR
          *偏移地址在P657,為0x04,故實(shí)際地址為0x40011400+0x04 = 0x40011404 */
          #define USART6_DR_Addr 0x40011404
          /*定義一個(gè)數(shù)組,DMA工作時(shí)從內(nèi)存取數(shù)組的數(shù)據(jù)傳給USART6 */
          uint8_t Buffer[] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
          uint8_t Buffer2[] = {0x99,0x6f};
          void GPIO_Config(void);
          void USART_Config(void);
          void USART6_Puts(char * str);
          void DMA_Config(void);
          void NVIC_Config(void);
          void Delay(uint32_t nCount);

          main()
          {
          /*在主函數(shù)main之前通過調(diào)用啟動(dòng)代碼運(yùn)行了SystemInit函數(shù),而這個(gè)函數(shù)位于system_stm32f4xx.c”。
          程序運(yùn)行起始于啟動(dòng)文件的第175行(LDR R0, =SystemInit)。sys時(shí)鐘為HSE頻率/PLL_M*PLL_N/PLL_P,
          定義HSE為25M,則sys時(shí)鐘頻率為168M */

          GPIO_Config();
          USART_Config();
          DMA_Config();
          NVIC_Config();
          GPIO_SetBits(GPIOG, GPIO_Pin_6); //關(guān)閉LED
          while (1)
          {
          USART_DMACmd(USART6, USART_DMAReq_Tx, ENABLE); //使能USART6的發(fā)送數(shù)據(jù)DMA請(qǐng)求,至此USART6與DMA開始工作
          /*因?yàn)镈MA工作是獨(dú)立于CPU之外的,所以在DMA工作的同時(shí)CPU可以做其他事
          *我們等到DMA傳輸完畢后產(chǎn)生一個(gè)狀態(tài)指示,即點(diǎn)亮一個(gè)LED */
          /*查詢模式
          while (DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6) == RESET)
          {
          GPIO_ResetBits(GPIOG,GPIO_Pin_6); //點(diǎn)亮LED
          }
          */
          //DMA_Cmd(DMA2_Stream6, DISABLE); //DMA傳輸完畢后會(huì)自動(dòng)關(guān)閉通道,這句可以不寫
          }
          }

          /*************************************************
          Function: void GPIO_Config(void)
          Description: GPIO配置函數(shù)
          Input: 無
          Output:無
          Return:無
          *************************************************/
          void GPIO_Config(void)
          {
          /*定義了一個(gè)GPIO_InitStructure的結(jié)構(gòu)體,方便一下使用 */
          GPIO_InitTypeDef GPIO_InitStructure;
          /* 初始化GPIOG時(shí)鐘*/
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG , ENABLE);//使能GPIOG時(shí)鐘(時(shí)鐘結(jié)構(gòu)參見“stm32圖解.pdf”)
          /*僅設(shè)置結(jié)構(gòu)體中的部分成員:這種情況下,用戶應(yīng)當(dāng)首先調(diào)用函數(shù)PPP_SturcInit(..)
          *來初始化變量PPP_InitStructure,然后再修改其中需要修改的成員。這樣可以保證其他
          *成員的值(多為缺省值)被正確填入。
          */
          GPIO_StructInit(&GPIO_InitStructure);
          /* 初始化GPIOG的Pin_6為推挽輸出*/
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //指定第六引腳
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //模式為輸出
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //頻率為快速
          GPIO_Init(GPIOG, &GPIO_InitStructure); //調(diào)用IO初始化函數(shù)
          }

          /*************************************************
          Function: void USART_Config(void)
          Description: USART配置函數(shù)
          Input: 無
          Output:無
          Return:無
          *************************************************/
          void USART_Config(void)
          {
          GPIO_InitTypeDef GPIO_InitStructure;
          USART_InitTypeDef USART_InitStructure;
          USART_ClockInitTypeDef USART_ClockInitStruct;
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE); //開啟USART6時(shí)鐘
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //開啟GPIOC時(shí)鐘
          GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);//這相當(dāng)于M3的開啟復(fù)用時(shí)鐘?只配置復(fù)用的引腳,
          GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);//
          /*配置GPIOC*/
          GPIO_StructInit(&GPIO_InitStructure); //缺省值填入

          /*配置GPIOC_Pin6為TX輸出*/
          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //設(shè)置為復(fù)用,必須為AF,OUT不行
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_Init(GPIOC,&GPIO_InitStructure);

          /*配置GPIOC_Pin7為RX輸入*/
          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //這也必須為復(fù)用,與M3不同!
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_Init(GPIOC,&GPIO_InitStructure);

          /*IO引腳復(fù)用功能設(shè)置,與之前版本不同*/
          /*配置USART6*/
          USART_StructInit(&USART_InitStructure);
          USART_InitStructure.USART_BaudRate =115200;
          USART_InitStructure.USART_WordLength = USART_WordLength_8b;
          USART_InitStructure.USART_StopBits = USART_StopBits_1;
          USART_InitStructure.USART_Parity = USART_Parity_No;
          USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
          USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
          USART_Init(USART6, &USART_InitStructure);
          USART_ClockStructInit(&USART_ClockInitStruct); //之前沒有填入缺省值,是不行的
          USART_ClockInit(USART6, &USART_ClockInitStruct);

          USART_ITConfig(USART6, USART_IT_RXNE, ENABLE); //使能 USART6中斷
          USART_Cmd(USART6, ENABLE); //使能 USART6
          //USART_DMACmd(USART6, USART_DMAReq_Tx, ENABLE); //使能USART6的發(fā)送數(shù)據(jù)DMA請(qǐng)求,至此USART6與DMA開始工作,可以寫在主函數(shù)里隨時(shí)工作
          }

          void NVIC_Config()
          {
          /*USART6中斷配置*/
          NVIC_InitTypeDef NVIC_InitStructure;
          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //嵌套優(yōu)先級(jí)分組為 1
          NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn; //嵌套通道為USART6_IRQn
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優(yōu)先級(jí)為 0
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)優(yōu)先級(jí)為 0
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中斷使能
          NVIC_Init(&NVIC_InitStructure);

          /*DMA中斷配置*/
          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //嵌套優(yōu)先級(jí)分組為 1
          NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn; //嵌套通道為DMA2_Stream6_IRQn
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優(yōu)先級(jí)為 1
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)優(yōu)先級(jí)為 0
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中斷使能
          NVIC_Init(&NVIC_InitStructure);

          }

          /*************************************************
          Function: void USART6_Puts(char * str)
          Description: USART6發(fā)送數(shù)據(jù)
          Input: 待發(fā)送數(shù)據(jù)指針
          Output:無
          Return:無
          *************************************************/
          void USART6_Puts(char * str)
          {
          while (*str)
          {
          USART_SendData(USART6, *str++);
          /* Loop until the end of transmission */
          while (USART_GetFlagStatus(USART6, USART_FLAG_TXE) == RESET); //詳見英文參考的521頁,當(dāng)TXE被置起時(shí),一幀數(shù)據(jù)傳輸完成
          }
          }

          /*************************************************
          Function: void DMA_Config(void)
          Description: DMA配置函數(shù)
          Input: 延時(shí)的時(shí)間
          Output:無
          Return:無
          *************************************************/
          void DMA_Config(void)
          {
          DMA_InitTypeDef DMA_InitStructure;
          /*首先開DMA2時(shí)鐘,由407參考手冊-RM0090-Reference manual
          165頁可知,UASRT6與DMA2映射,而且DMA2掛載在AHB1時(shí)鐘總線上*/
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
          /*由RM0090-Reference manual第165頁映射表可知,USART6映射在
          Channel_5的Stream6和Stream7上,在這里可以選擇Stream6 */
          DMA_DeInit(DMA2_Stream6);
          DMA_StructInit( &DMA_InitStructure);
          DMA_InitStructure.DMA_Channel = DMA_Channel_5; //選擇Channel_5
          DMA_InitStructure.DMA_PeripheralBaseAddr = USART6_DR_Addr; //數(shù)據(jù)傳輸?shù)耐庠O(shè)首地址,詳解見上
          DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer; //自己定義待發(fā)送數(shù)組的首地址,要強(qiáng)制轉(zhuǎn)換為32位
          DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //數(shù)據(jù)傳輸方向選擇為內(nèi)存->外設(shè)
          DMA_InitStructure.DMA_BufferSize = 8; //傳輸數(shù)據(jù)大小為8,單位由以下確定,大小要配合定義的數(shù)組類型和外設(shè)數(shù)據(jù)類型
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設(shè)地址寄存器自動(dòng)增加禁止,因?yàn)檫@里只用到了DR數(shù)據(jù)寄存器
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存地址自增允許,因?yàn)橐x取一個(gè)數(shù)組
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設(shè)的數(shù)據(jù)大小,因?yàn)閁SART6_DR數(shù)據(jù)寄存器為8為,故選Byte
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //這里也選Byte
          DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA傳輸模式為Normal,如果為Circular,將會(huì)循環(huán)傳輸
          DMA_InitStructure.DMA_Priority = DMA_Priority_High; //優(yōu)先級(jí)為High
          /*雙緩沖模式,在DMA_Init之前調(diào)用在Circular模式有效,會(huì)強(qiáng)制Circular,
          *不支持Memory toMemory,(uint32_t)Buffer2為DMA_Memory_1,DMA先將Buffer
          *中的數(shù)據(jù)發(fā)送完畢后在發(fā)送Buffer2的數(shù)據(jù),當(dāng)然順序可以改變
          DMA_DoubleBufferModeConfig(DMA2_Stream6, (uint32_t)Buffer2, DMA_Memory_0);
          DMA_DoubleBufferModeCmd(DMA2_Stream6, ENABLE);
          */
          DMA_Init(DMA2_Stream6, &DMA_InitStructure);
          DMA_Cmd(DMA2_Stream6, ENABLE);//使能DMA2_Stream6通道
          /*DMA中斷開*/
          DMA_ITConfig(DMA2_Stream6, DMA_IT_TC, ENABLE);
          }

          /*************************************************
          Function: void Delay(uint32_t nCount)
          Description: 延時(shí)函數(shù)
          Input: 延時(shí)的時(shí)間
          Output:無
          Return:無
          *************************************************/
          void Delay(uint32_t nCount)
          {
          while (nCount--);
          }

          中斷服務(wù)函數(shù):

          /**名稱:DMA中斷服務(wù)程序
          *作用:DMA數(shù)據(jù)完全完成后產(chǎn)生中斷,并點(diǎn)亮LED
          */
          void DMA2_Stream6_IRQHandler(void)
          {
          if (DMA_GetITStatus(DMA2_Stream6, DMA_IT_TCIF6) != RESET) //判斷為接收中斷
          {
          DMA_ClearITPendingBit(DMA2_Stream6, DMA_IT_TCIF6);
          GPIO_ResetBits(GPIOG, GPIO_Pin_6); //點(diǎn)亮LED,起到中斷指示作用
          }
          }

          調(diào)試結(jié)果如下:



          關(guān)鍵詞: stm32F407USART6DMA工作方

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();