新建工程,在HARDWARE目錄下新建dma.c及dma.h文件。編輯dma.c,如下:
#include "dma.h"
DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_MEM_LEN;//保存DMA每次數據傳送的長度
//DMA1的各通道配置
//這里的傳輸形式是固定的,這點要根據不同的情況來修改
//從存儲器->外設模式/8位數據寬度/存儲器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外設地址
//cmar:存儲器地址
//cndtr:數據傳輸量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA時鐘
DMA_DeInit(DMA_CHx); //將DMA的通道1寄存器重設為缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外設ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA內存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //數據傳輸方向內存到外設
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA緩存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址不變
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內存地址寄存器遞增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//數據寬度為8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //數據寬度
//為8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常緩存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DM通道擁有中優先級
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非內存到內存傳輸
DMA_Init(DMA_CHx, &DMA_InitStructure); //初始化DMA的通道
}
//開啟一次DMA傳輸
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //關閉USART1 TX DMA1 所指示的通道
DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//設置DMA緩存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道
}
該部分代碼僅僅2個函數,MYDMA_Config函數實現DMA的初始化,該函數在外部只能修改通道、源地址、目標地址和傳輸數據量等幾個參數,更多的其他設置只能在該函數內部修改。MYDMA_Enable函數設置DMA緩存大小并且使能DMA通道。
返回主界面,編寫main.c函數:
#define SEND_BUF_SIZE 8200
u8 SendBuff[SEND_BUF_SIZE];//發送數據緩沖區
const u8 TEXT_TO_SEND[]={"ALIENTEK WarShip STM32F1 DMA 串口實驗"};
int main(void)
{
u16 i;
u8 t=0;
u8 j,mask=0;
float pro=0;//進度
delay_init();//延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置中斷優先級分組為組2
uart_init(115200);//串口初始化為115200
LED_Init();//初始化與LED連接的硬件接口
LCD_Init();//初始化LCD
KEY_Init();//按鍵初始化
MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,
(u32)SendBuff,SEND_BUF_SIZE);
POINT_COLOR=RED;//設置字體為紅色
LCD_ShowString(30,50,200,16,16,"WarShip STM32");
LCD_ShowString(30,70,200,16,16,"DMA TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2015/1/15");
LCD_ShowString(30,130,200,16,16,"KEY0:Start");
//顯示提示信息
j=sizeof(TEXT_TO_SEND);
for(i=0;i<SEND_BUF_SIZE;i++)//填充數據到SendBuff
{
if(t>=j)//加入換行符
{
if(mask)
{
SendBuff=0x0a;
t=0;
}else
{
SendBuff=0x0d;
mask++;
}
}else//復制TEXT_TO_SEND語句
{
mask=0;
SendBuff=TEXT_TO_SEND[t];
t++;
}
}
POINT_COLOR=BLUE;//設置字體為藍色
i=0;
while(1)
{
t=KEY_Scan(0);
if(t==KEY0_PRES)//KEY0按下
{
LCD_ShowString(30,150,200,16,16,"Start Transimit....");
LCD_ShowString(30,170,200,16,16," %");//顯示百分號
printf("\r\nDMA DATA:\r\n");
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//使能串口1的DMA發送
MYDMA_Enable(DMA1_Channel4);//開始一次DMA傳輸!
//等待DMA傳輸完成,此時我們來做另外一些事,點燈
//實際應用中,傳輸數據期間,可以執行另外的任務
while(1)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)//判斷通道4傳輸完成
{
DMA_ClearFlag(DMA1_FLAG_TC4);//清除通道4傳輸完成標志
break;
}
pro=DMA_GetCurrDataCounter(DMA1_Channel4);//得到當前剩余數據量
pro=1-pro/SEND_BUF_SIZE;//得到百分比
pro*=100; //擴大100倍
LCD_ShowNum(30,170,pro,3,16);
}
LCD_ShowNum(30,170,100,3,16);//顯示100%
LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示傳送完成
}
i++;
delay_ms(10);
if(i==20)
{
LED0=!LED0;//提示系統正在運行
i=0;
}
}
}
main函數的流程如下:先初始化內存SendBuff的值,然后通過KEY0開啟串口DMA發送,在發送過程中,通過DMA_GetCurrDataCounter()函數獲取當前還剩余的數據量來計算傳輸百分比,最后在傳輸結束之后清除相應標志位,提示已經傳輸完成。需要要注意的是,因為使用串口1 DMA發送,所以代碼中使用USART_DMACmd函數開啟串口的DMA發送:
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA發送
至此,DMA串口傳輸的軟件設計就完成了。
|