STM32使用DMA加串口空闲中断接收数据.docx
《STM32使用DMA加串口空闲中断接收数据.docx》由会员分享,可在线阅读,更多相关《STM32使用DMA加串口空闲中断接收数据.docx(8页珍藏版)》请在冰豆网上搜索。
STM32使用DMA加串口空闲中断接收数据
STM32使用DMA加串口空闲中断接收数据
STM32中,需要用串口接收数据,是使用串口中断来接收数据。
但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。
于是就想到用DMA来接收串口数据,这个STM32也是支持的。
但是关键的一点,怎么知道数据接收完毕了呢如果接收的数据长度固定,那就好办,直接设置DMA的接收数据个数就行了。
但是如果长度不固定了,那应该怎么办了
这个时候,就要用到STM32在串口中提供的另一个好用的东西了,就是串口空闲中断。
在STM32的串口控制器中,设置了有串口空闲中断,即如果串口空闲,又开
启了串口空闲中断的话,就触发串口空闲中断,然后程序就会跳到串口中断去执行。
有了这个,是不是可以判断什么时候串口数据接收完毕了呢因为串口数据接收完毕后,串口总线肯
定是会空闲的嘛,那这个中断肯定是会触发的了。
r
1
USART.BRR
皿—°
iTiX21游怡主
下面用代码来说明。
1、配置串口。
包括设置串口的引脚配置,串口的配置,串口中断的配置,串口的
接收DMA勺配置
voidUSART_init(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDefUSART_InitStructure;
NVIC_InitTypeDefNVIC_InitStructure;
//开启时钟
RCC_APB2PeriphClockCmd(USART_RCC,ENABLE);
//配置TX端口
=GPIO_USART_TX;
=GPIO_Mode_AF_PP;
=GPIO_Speed_5OMHz;
GPIOInit(GPIOUSARTTYPE,&GPIOInitStructure);
//配置RX端口
=GPIO_USART_RX;
=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure);
//配置串口模式
=115200;
=USART_WordLength_8b;
=USART_StopBits_1;
=USART_Parity_No;
=USART_HardwareFlowControl_None;
=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
//中断配置
=USART1_IRQn;
=1;
=0;
=ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*若总线空闲,产生中断*/
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
/*开启串口DMA接收*/
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
USART_Cmd(USART1,ENABLE);
代码比较简单,一看就明白了,这就是使用库函数开发的好处,代码易
懂。
这里,关键的是要开启总线空闲中断,并且开启串口DMA接收。
注意,不要开启串口接
收中断,不然接收数据就会一直产生中断了。
2、DMA配置
DMA配置,要先查看串口接收是使用的哪个DMA的哪个通道,对于USART1_R使用的是
DMA1的5通道。
然后就是代码配置DMATo
voidDMA_init(void)
{
DMA」nitTypeDefDMA」nitstructure;
//NVIC_InitTypeDefNVIC_Initstructure;
/*开启DMA时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
///*EnabletheDMA1Interrupt*/
〃=DMA1_Channel4_IRQn;II通道设置为串口1中断
//=1;II中断响应优先级0
//=1;
//=ENABLE;//打开中断
//NVIC_Init(&NVIC_Initstructure);
/*DMA配置*/
=(u32)(&USART1->DR);;
=(u32)receive_data;
=DMA_DIR_PeripheralSRC;
=128;
=DMA_PeripheralInc_Disable;
=DMA_MemoryInc_Enable;
=DMA_PeripheralDataSize_Byte;
=DMA_MemoryDataSize_Byte;
=DMA_Mode_Normal;
=DMA_Priority_High;
=DMA_M2M_Disable;
DMA_Init(DMA1_Channel5,&DMA_Initstructure);
//启动DMA
DMA_Cmd(DMA1_Channel5,ENABLE);
//开启DMA发送发成中断
//DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
}
因为这里,不需要用到DMA中断,所以DMA中断就不要使能了。
因此
DMA中断配置也就不需要了。
这里,关键的是要设置DMA_DIF为DMA_DIR_PeripheralSRC,表
示数据是从外设到内存。
这里设定的DMA_Mod(是普通模式,即数据传输就只能一次。
3、串口中断程序编写
这个就是关键的地方了。
在这里,需要做什么了。
需要对DMA设置下。
当进入这个中断
的时候,串口接收的数据,已经在内存的数组中了。
通过读取DMA勺计数值,就可以知道接
收到了多少个数据。
然后再把DMA合diable掉,重新设置接收数据长度,在开启DMA接
收下一次串口数据。
为什么要这么做了,因为在STM32手册中有如下说明:
勺H伯餉冷山』川辐iI虬堡勺冉/TDMAIH1此丿临7射
JtWOMA通逍前惴况厂ADMACNDTRx4f#tt屮盼新耳人礼输数弭一
另外还有一点,串口空闲中断触发后,硬件会自动将串口空闲中断标志位给置1我们
是需要将给标志位给置0的,不然又要进中断了,这个在手册中也有说明。
IDLEiKH;i讣.a■■-<10LEllrwdtMed)
3料测测◎堆咿litRWflKM-illItUSARTGRlb^lDLflE^I'.势产無即務・曲
2■"护;沾建紀!
V,iUSAR7_SR..^i,KiU5ART_DRf
觇没fl柑斟到空袒总纜*
It检褚刘卒團总浚」
n-fiIDLE"4令押次誠翟侖f[州RXM曰进槪龙址(即工斷Nf酬歆空岡4找)
|JMF■」・11/A.
代码就如下了:
voidUSART1_IRQHandler(void)
{
unsignedcharnum=0;
if(USART_GetlTStatus(USART1,USART_IT_IDLE)==SET)
{
num=USART1->SR;
num=USART1->DR;//清USART_IT_IDLE标志
DMA_Cmd(DMA1_Channel5,DISABLE);//关闭DMA
num=128-DMA_GetCurrDataCounter(DMA1_Channel5);//得到真正接收数
据个数
receive_data[num]='\0:
DMA1_Channel5->CNDTR=128;//重新设置接收数据个数
DMA_Cmd(DMA1_Channel5,ENABLE);//开启DMA
receive_flag=1;II接收数据标志位置1
}
关键的一点,就是要读取SR,DR将USART_IT_IDLE标志给清掉,
DMA设置要注意下。
在主函数中,使用下面代码测试:
intmain()
{
periph_init();
printf("helloworld'n");
while
(1)
{
while(receive_flag==0);
receive_flag=0;
printf("%s",receive_data);
}
}
当串口接收数据后,中断程序会使receive_flag为1,然后就跳岀
循环。
打印接收到的数据。
然后
while
测试结果:
发送什么,就接收什么。
还测试了下,在波特率460800下,都还是能正常的工作的。