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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2657|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

stm32之DMA研究

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:98924 發(fā)表于 2015-12-9 02:21 | 只看該作者 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
在做實(shí)驗(yàn)之前,首先必須明白什么是DMA,DMA的作用又體現(xiàn)在哪里。
DMA,即直接內(nèi)存存儲,在一些數(shù)據(jù)的傳輸中,采用DMA方式,從而將CPU解放出來。讓
CPU有足夠的時間處理其他的事情。
stm32使用DMA的相關(guān)操作:
1、DMA的配置
要配置的有DMA傳輸通道選擇,傳輸?shù)某蓡T和方向、普通模式還是循環(huán)模式等等。
void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    //DMA設(shè)置:
    //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
    //方向:內(nèi)存-->外設(shè)
    //每次傳輸位:8bit
    //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
    //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
    //DMA模式:一次傳輸,非循環(huán)
    //優(yōu)先級:中
    DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設(shè)作為DMA的目的端
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設(shè)地址不增加
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內(nèi)存地址自增1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    //DMA_Mode_Normal(只傳送一次), DMA_Mode_Circular (不停地傳送)
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優(yōu)先級為中等)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
注:
1、傳輸通道:通過查表,串口1的發(fā)送對應(yīng)的是DMA的通道4,所以此處選擇通道4.
 
2、DMA傳輸方式:
(1) DMA_Mode_Normal,正常模式,當(dāng)一次DMA數(shù)據(jù)傳輸完后,停止DMA傳送,對于
上例而言,就是
SENDBUFF_SIZE  個字節(jié)的傳送完成后,就停止傳送。
(2) DMA_Mode_Circular
循環(huán)模式,當(dāng)傳輸完一次后,重新接著傳送,永不停息。
2、外設(shè)的DMA方式設(shè)置
將串口1設(shè)置成DMA模式:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
3、待傳輸數(shù)據(jù)的定義和初始化
#define SENDBUFF_SIZE   10240
vu8 SendBuff[SENDBUFF_SIZE];
    for(i=0;i<SENDBUFF_SIZE;i++)
    {
        SendBuff[i] = i%10+'0';
    }
4、開始DMA傳輸(使能對應(yīng)的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);
5、DMA傳輸?shù)耐瓿?/font>
 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
 {
       LED_1_REV;      //LED翻轉(zhuǎn)
       Delay();        //浪費(fèi)時間
 }
當(dāng)傳輸完成后,就會跳出上面的死循環(huán)。
 
下面是九九的一個例程,測試過,可以運(yùn)行!
/******************************************************************************
* 本文件實(shí)現(xiàn)串口發(fā)送功能(通過重構(gòu)putchar函數(shù),調(diào)用printf;或者USART_SendData()
* 這里是一個用串口實(shí)現(xiàn)大量數(shù)據(jù)傳輸?shù)睦樱褂昧薉MA模塊進(jìn)行內(nèi)存到USART的傳輸
* 每當(dāng)USART的發(fā)送緩沖區(qū)空時,USART模塊產(chǎn)生一個DMA事件,
* 此時DMA模塊響應(yīng)該事件,自動從預(yù)先定義好的發(fā)送緩沖區(qū)中拿出下一個字節(jié)送給USART
* 整個過程無需用戶程序干預(yù),用戶只需啟動DMA傳輸傳輸即可
* 在仿真器調(diào)試時,可以在數(shù)據(jù)傳輸過程中暫停運(yùn)行,此時DMA模塊并沒有停止
* 串口依然發(fā)送,表明DMA傳輸是一個獨(dú)立的過程。
* 同時開啟接收中斷,在串口中斷中將數(shù)據(jù)存入緩沖區(qū),在main主循環(huán)中處理
* 作者:jjldc(九九)
* 代碼硬件基于萬利199元的EK-STM32F開發(fā)板,CPU=STM32F103VBT6
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
#include "stdio.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define USART1_DR_Base  0x40013804
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#define SENDBUFF_SIZE   10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
    u16 i;
#ifdef DEBUG
    debug();
#endif
    recv_ptr = 0;
   
    RCC_Configuration();
    GPIO_Configuration();
    NVIC_Configuration();
    DMA_Configuration();
    USART1_Configuration();
   
    printf("\r\nSystem Start...\r\n");
    printf("Initialling SendBuff... \r\n");
    for(i=0;i<SENDBUFF_SIZE;i++)
    {
        SendBuff[i] = i%10+'0';
    }
    printf("Initial success!\r\nWaiting for transmission...\r\n");
    //發(fā)送去數(shù)據(jù)已經(jīng)準(zhǔn)備好,按下按鍵即開始傳輸
    while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));
   
    printf("Start DMA transmission!\r\n");
   
    //這里是開始DMA傳輸前的一些準(zhǔn)備工作,將USART1模塊設(shè)置成DMA方式工作
    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
    //開始一次DMA傳輸!
    DMA_Cmd(DMA1_Channel4, ENABLE);
   
    //等待DMA傳輸完成,此時我們來做另外一些事,點(diǎn)燈
    //實(shí)際應(yīng)用中,傳輸數(shù)據(jù)期間,可以執(zhí)行另外的任務(wù)
    while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
    {
//        LED_1_REV;      //LED翻轉(zhuǎn)
        Delay();        //浪費(fèi)時間
    }
    //DMA傳輸結(jié)束后,自動關(guān)閉了DMA通道,而無需手動關(guān)閉
    //下面的語句被注釋
    //DMA_Cmd(DMA1_Channel4, DISABLE);
   
    printf("\r\nDMA transmission successful!\r\n");
   
    /* Infinite loop */
    while (1)
    {
    }
}
/*******************************************************************************
* Function Name  : 重定義系統(tǒng)putchar函數(shù)int fputc(int ch, FILE *f)
* Description    : 串口發(fā)一個字節(jié)
* Input          : int ch, FILE *f
* Output         :
* Return         : int ch
* 這個是使用printf的關(guān)鍵
*******************************************************************************/
int fputc(int ch, FILE *f)
{
    //USART_SendData(USART1, (u8) ch);
    USART1->DR = (u8) ch;
   
    /* Loop until the end of transmission */
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }
    return ch;
}
/*******************************************************************************
* Function Name  : Delay
* Description    : 延時函數(shù)
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Delay(void)
{
    u32 i;
    for(i=0;i<0xF0000;i++);
    return;
}
/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : 系統(tǒng)時鐘設(shè)置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{
    ErrorStatus HSEStartUpStatus;
    //使能外部晶振
    RCC_HSEConfig(RCC_HSE_ON);
    //等待外部晶振穩(wěn)定
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    //如果外部晶振啟動成功,則進(jìn)行下一步操作
    if(HSEStartUpStatus==SUCCESS)
    {
        //設(shè)置HCLK(AHB時鐘)=SYSCLK
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        //PCLK1(APB1) = HCLK/2
        RCC_PCLK1Config(RCC_HCLK_Div2);
        //PCLK2(APB2) = HCLK
        RCC_PCLK2Config(RCC_HCLK_Div1);
        //FLASH時序控制
        //推薦值:SYSCLK = 0~24MHz   Latency=0
        //        SYSCLK = 24~48MHz  Latency=1
        //        SYSCLK = 48~72MHz  Latency=2
        FLASH_SetLatency(FLASH_Latency_2);
        //開啟FLASH預(yù)取指功能
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        //PLL設(shè)置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        //啟動PLL
        RCC_PLLCmd(ENABLE);
        //等待PLL穩(wěn)定
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        //系統(tǒng)時鐘SYSCLK來自PLL輸出
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        //切換時鐘后等待系統(tǒng)時鐘穩(wěn)定
        while(RCC_GetSYSCLKSource()!=0x08);

        /*
        //設(shè)置系統(tǒng)SYSCLK時鐘為HSE輸入
        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
        //等待時鐘切換成功
        while(RCC_GetSYSCLKSource() != 0x04);
        */
    }
    //下面是給各模塊開啟時鐘
    //啟動GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \
                           RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\
                           ENABLE);
    //啟動AFIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    //啟動USART1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    //啟動DMA時鐘
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
   
}
 
/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : GPIO設(shè)置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    //PC口4567腳設(shè)置GPIO輸出,推挽 2M
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    //KEY2 KEY3 JOYKEY
    //位于PD口的3 4 11-15腳,使能設(shè)置為輸入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\
        GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    //USART1_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    //USART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
 
/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : NVIC設(shè)置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
#ifdef  VECT_TAB_RAM
    // Set the Vector Table base location at 0x20000000
    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
    // Set the Vector Table base location at 0x08000000
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
    //設(shè)置NVIC優(yōu)先級分組為Group2:0-3搶占式優(yōu)先級,0-3的響應(yīng)式優(yōu)先級
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //串口接收中斷打開   
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/*******************************************************************************
* Function Name  : USART1_Configuration
* Description    : NUSART1設(shè)置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USART1_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
   
    USART_InitStructure.USART_BaudRate = 9600;
    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_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
   
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
   
    USART_Cmd(USART1, ENABLE);
}

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    //DMA設(shè)置:
    //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
    //方向:內(nèi)存-->外設(shè)
    //每次傳輸位:8bit
    //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
    //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
    //DMA模式:一次傳輸,非循環(huán)
    //優(yōu)先級:中
    DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設(shè)作為DMA的目的端
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設(shè)地址不增加
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內(nèi)存地址自增1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode =  DMA_Mode_Normal;
    //DMA_Mode_Normal(只傳送一次), DMA_Mode_Circular (不停地傳送)
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優(yōu)先級為中等)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
 需要說明的是,由于DMA傳輸不需要CPU的參與。
所以在調(diào)試的時候會發(fā)現(xiàn),在我們單步停止的時候,串口依然不停地向外發(fā)送數(shù)據(jù)。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产区在线观看 | 三级黄色片在线观看 | 狠狠的操 | 亚洲狠狠| 亚洲成年影院 | 久久成人精品一区二区三区 | 国产成人99久久亚洲综合精品 | 欧美一区二区在线看 | 97视频在线观看网站 | 亚洲精品在线视频 | 巨大黑人极品videos精品 | 中文字幕一区二区三区精彩视频 | 欧美久久精品一级黑人c片 91免费在线视频 | 成人欧美一区二区三区在线观看 | 成人a免费 | 国产一区二区免费 | 日韩高清中文字幕 | 精品久久久久久亚洲精品 | 亚洲激精日韩激精欧美精品 | 黑人巨大精品欧美一区二区一视频 | 国产色爽 | 中文字幕 欧美 日韩 | 91视频官网| 精品一区二区三区免费视频 | 午夜影院操| 国产一区二区在线免费播放 | 九色.com | 国产一区二区在线免费播放 | 国产一区二区三区高清 | caoporn国产精品免费公开 | 四虎影院在线播放 | 中文字幕日韩欧美一区二区三区 | 成人在线精品视频 | 欧美成人猛片aaaaaaa | 久久久青草婷婷精品综合日韩 | 国产三区视频在线观看 | 午夜一区 | 成人午夜视频在线观看 | 欧美vide | 亚洲欧美激情精品一区二区 | 在线观看亚洲精品视频 |