微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 玩转stm32 usart 串口功能 库函数 详解和DMA 串口高级运用

玩转stm32 usart 串口功能 库函数 详解和DMA 串口高级运用

时间:11-24 来源:互联网 点击:

基本需要配置的工作

DMA_DeInit(DMA1_Channel4);

上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef *)USART1)->DR);
上面是设置外设地址

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) USART_DMA_BUF;

上面这句很显然是DMA要连接在Memory中变量的地址,上面设置存储器地址;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

上面的这句是设置DMA的传输方向,就如前面我所说的,从存储器到外设,也可以从外设到存储器,:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。

DMA_InitStructure.DMA_BufferSize = 0;

上面的这句是设置DMA在传输时缓冲区的长度,前面有定义过了buffer的起始地址:为了安全性和可靠性,一般需要给buffer定义一个储存片区,这个参数的单位有三种类型:Byte、HalfWord、word,我设置的2个half-word(见下面的设置);32位的MCU中1个half-word占16 bits。

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

上面的这句是设置DMA的外设递增模式,如果DMA选用的通道(CHx)有多个外设连接,需要使用外设递增模式:DMA_PeripheralInc_Enable;我的例子选用DMA_PeripheralInc_Disable

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

上面的这句是设置DMA的内存递增模式,DMA访问多个内存参数时,需要使用DMA_MemoryInc_Enable,当DMA只访问一个内存参数时,可设置成:DMA_MemoryInc_Disable。

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

上面的这句是设置DMA在访问时每次操作的数据长度。有三种数据长度类型,前面已经讲过了,这里不在叙述。

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

与上面雷同。在此不再说明。

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

上面的这句是设置DMA的传输模式:连续不断的循环模式,若只想访问一次后就不要访问了(或按指令操作来反问,也就是想要它访问的时候就访问,不要它访问的时候就停止),可以设置成通用模式:DMA_Mode_Normal

DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

上面的这句是设置DMA的优先级别:可以分为4级:VeryHigh,High,Medium,Low.

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

上面的这句是设置DMA的2个memory中的变量互相访问的

DMA_Init(DMA_Channel1,&DMA_InitStructure);

前面那些都是对DMA结构体成员的设置,在次再统一对DMA整个模块做一次初始化,使得DMA各成员与上面的参数一致。

DMA_Cmd(DMA_Channel1,ENABLE);

ok上面的配置工作完成了,相当于设定了一根管道通过DMA把缓冲区中要发送的数据发送到串口中。当然要使得DMA与usart1相连接,在usart1中还要把usart的DMA功能打开:USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);接着在程序中只需要监控,数据发送的状态,并适时的打开或关闭DMA,留着下一次的串口发送用。

函数重载的printf()函数如下

int fputc(int ch, FILE *f)
{
while(En_Usart_Queue(ch)==-1);
return ch;
}

起始就是往环形缓冲区中添加要串口打印的数据,这个动作是比较快的。因为cpu直接移动数据很快,而通过cpu来操作串口,等待收获反映,有个while(..)是比较慢得,故有几个毫秒的延时。现在好了,cpu ,通过printf只是移动数据到了缓冲区,缓冲区在一定的时候,cpu指挥dma来开始接下来的操作,然后dma操作,cpu接着做其他的事情,仅仅只要在下次空闲的时候来查一下dma有木有传输完成,或者有没有传输错误,并改变环形队列首位的位置,以及更改相应的状态就可以了。这样可以大大的节省很多的时间哦。
环形队列的结构,大家可以看一些算法,不是很难的。

下面是运行过程中,cpu操作查询的函数。

void DMA_USART_Handler(void){
u16 num=0;
s16 read;
if(DMA_GetCurrDataCounter(DMA1_Channel4)==0){ //检查DMA是否完成传输任务
DMA_Cmd(DMA1_Channel4, DISABLE);
while((read=De_Usart_Queue())!=-1){
USART_DMA_BUF[num]=read;
num++;
if(num==USART_DMA_BUF_SIZE)
break;
}
if(num>0){
((DMA_Channel_TypeDef *)DMA1_Channel4)->CNDTR = num;//数量寄存器清零
DMA_Cmd(DMA1_Channel4, ENABLE);
}
}
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top