DMA俗称CPU的“好基友”,是最好的数据搬运工,在没有DMA时,任何数据的读写都要通过CPU,这样很浪费CPU的资源,使CPU的运行效率降低,当有DMA时,一些数据的搬移根本不用CPU去干预,比如:串口通信、ADC采集…大大节省了CPU的资源,使之变的更高效!~
接下来就是一个简单的DMA应用,使用DMA将字符串值通过串口传输至PC端,在串口调试助手中打印出来。
结合之前的串口通信实验,增加的DMA模块,DMA看起来是一大堆,让人望而却步,应用DMA其实就是这样的一个模板,对着手册多看多连,就对DMA不陌生啦~
/*话不多说,直接上代码~*/
#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char
/********************************************************
* IAR编译环境中位域字段默认取向采用小端模式,
* 配置结构体声明前使用#pragma bitfields=reversed取反向,
* 声明结束后恢复IAR默认方式
********************************************************/
#pragma bitfields=reversed
typedef struct
{
uchar SRCADDRH; // 源地址高8位
uchar SRCADDRL; // 源地址低8位
uchar DESTADDRH; // 目标地址高8位
uchar DESTADDRL; // 目标地址低8位
uchar VLEN :3;// 长度域模式选择
uchar LENH :5;// 传输长度高字节
uchar LENL :8;// 传输长度低字节
uchar WORDSIZE :1;// 字节或字传输
uchar TMODE :2;// 传输模式选择
uchar TRIG :5;// 触发事件选择
uchar SRCINC :2;// 源地址增量 :-1/0/1/2
uchar DESTINC :2;// 目的地址增量 :-1/0/1/2
uchar IRQMASK :1;// 中断屏蔽
uchar M8 :1;// 7或8bit传输长度,仅在字节传输模式下适用
uchar PRIORITY :2;// 优先级
}DMA_DESC;
#pragma bitfields = default
uchar a[]=" Hello zigbee ";
uchar string[]="IM A USART";
DMA_DESC dmaConfig; //DMA配置参数 结构体变量
void Init_DMA(); //声明DMA初始化函数
void Init_Cfg_32M(); //声明32M时钟初始化函数
void Init_Uart0(); //声明串口0初始化函数
void UR0SendByte(unsigned char Byte); //声明发送一个字节初始化函数
void UR0SendString(unsigned char *str);//声明发送字符串初始化函数
void main()
{
Init_DMA();
Init_Cfg_32M();
Init_Uart0();
while(1)
{
UR0SendString(string);
DMAARM=0x80; //停止DMA所有通道进行传输
DMAARM=0x01; //启用DMA通道0进行传输
DMAIRQ=0x00; //清中断标志
DMAREQ=0x01; //DMA通道0传送请求
while(!(DMAIRQ&0x01)); //等待传输结束
}
}
/*=======================DMA初始化函数============================*/
void Init_DMA()
{
/*配置源地址*/
dmaConfig.SRCADDRH=(uchar)((uint)&a >> 8);
dmaConfig.SRCADDRL=(uchar)((uint)&a & 0x00ff );
//&0X00FF 防止警告 变量赋值超出了变量类型的最大值
/*配置目的地址*/
dmaConfig.DESTADDRH=(uchar)((uint)&X_U0DBUF >> 8);
dmaConfig.DESTADDRL=(uchar)((uint)&X_U0DBUF);
/*选择LEN作为传送长度*/
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
/*设置传输长度*/
dmaConfig.LENH=(uchar)((uint)sizeof(a) >> 8);
dmaConfig.LENL=(uchar)((uint)sizeof(a));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=15; //USART0发送触发
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //清除DMA中断
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
/*将配置结构体的首地址赋予相关SFR*/
DMA0CFGH=(uchar)((uint)&dmaConfig >> 8);
DMA0CFGL=(uchar)((uint)&dmaConfig & 0x00ff);
asm("nop");
}
/*=======================串口0发送一个字节函数=======================*/
void UR0SendByte(unsigned char Byte)
{
U0DBUF = Byte; //将要发送的一个字节数据写入U0DBUF
while(!UTX0IF); //等待TX中断标志,即数据发送完成
UTX0IF = 0; //清除TX中断标志,准备下一次发送
}
/*=======================串口0发送字符串函数=========================*/
void UR0SendString(unsigned char *str)
{
while(*str != '\0')
{
UR0SendByte(*str++); //逐个发送字符串中的字节
}
}
/*=======================32M晶振初始化函数==========================*/
void Init_Cfg_32M()
{
CLKCONCMD &= ~0x40; //系统时钟源选择:外部32MHz 。
while(!(SLEEPSTA & 0x40));//等待晶振稳定
CLKCONCMD &= ~0x47; //128分频 CLKSPD不发分频
SLEEPCMD |= 0x04; //关闭不用的RC振荡器
}
/*=======================串口0初始化函数============================*/
void Init_Uart0()
{
PERCFG = 0X00; //外设控制寄存器USART 0 的IO位置:
P0SEL = 0X0C; //设置P0_2,P_3为外设功能
P2DIR &=~0XC0; //设置P0口优先为UART0,即串口0优先级最高
U0CSR |= 0XC0; //设置为UART模式
U0GCR |= 10; //查表
U0BAUD|= 216; //设置波特率为57600
U0UCR |= 0x80; //无流控,8位数据位,清空缓冲区
UTX0IF = 0; //串口0TX发送中断标志位清0
URX0IF = 0; //串口0RX接收中断标志位清0
URX0IE = 1; //开串口0接收中断
EA = 1; //开总中断
}