我的板子是探索者F407,前几天看到
使用串口1配合DMA接收不定长数据,大大减轻CPU载荷这篇帖子,觉得不错,想拿来做实验,结果出问题了,代码反复看了,总是找不出问题,拜托各位大神帮帮忙,我菜鸟一只!!!
使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。此贴的描述说明。
最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断。但是用来做通信的时候需要不停的产生串口接收中断,会严重影响主程序的运行。后来采用DMA接收的方式,但是一般情况下配置的DMA都是接定长的串口数据,对于未知长度的串口数据接收并不适用。后来在网上发现了一种方法可以利用串口的空闲中断+DMA接收的方法完美解决此类问题,特别适用于不需要每个就收字节都判断的串口数据接收,下面说一下事实现思路和程序。
实现思路:采用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。
帖子上使用的是103芯片,我是用F407芯片的,不知道是不是两个芯片的DMA模块上使用有区别,我都是照帖子的程序照搬过来的。
MYDMA_Enable(DMA2_Stream5,SEND_BUF_SIZE); //恢复DMA指针,等待下一次接受
//开启一次DMA传输
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Cmd(DMA_Streamx, DISABLE);
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}
DMA_SetCurrDataCounter(DMA_Streamx,ndtr);
DMA_Cmd(DMA_Streamx, ENABLE);
}
觉得可能是上面这几段代码有问题,感觉DMA指针没有恢复的样子
不要在中断服务函数中使用printf(个人建议),操作步骤大体相当
我的发送函数
void HAL_Submcu_uart_dma_Transmit(uint16_t Size)
{
DMA1_Channel2->CNDTR = (uint16_t)Size;
DMA_Cmd(DMA1_Channel2, ENABLE); //开始传输
}
中断服务函数
void USART3_IRQHandler(void)
{
#if MB_SUB_USER_DMA_EN
if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) //产生了空闲中断
{
if ((usart_dma_dev.MB_SUB_USART_Flag & MB_SUB_USART_Flag_TC) != 0)
{
DMA_Cmd(DMA1_Channel3, DISABLE); //先关闭,预防干扰
usart_dma_dev.MB_SUB_USART_RX_Index = usart_dma_dev.MB_SUB_USART_RX_Length - DMA_GetCurrDataCounter(DMA1_Channel3); //获取当前接收到的数据长度
DMA1_Channel3->CNDTR = (uint16_t)usart_dma_dev.MB_SUB_USART_RX_Length; //重新配置接收长度
DMA_Cmd(DMA1_Channel3, ENABLE);
(void)USART_ReceiveData(USART3);
usart_dma_dev.MB_SUB_USART_Flag |= MB_SUB_USART_Flag_RXE;
// printf("usart dma rcv ok %d ", usart_dma_dev.MB_SUB_USART_RX_Index);
}
}
/* ==================== STM32F30x Series chips ==================== */
#if __STM32xx == 0x03 //STM32F30x
USART_ClearITPendingBit(USART3, USART_IT_IDLE);
#endif
#else
uint8_t res=0;
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收到数据
{
res = USART_ReceiveData(USART3); //读取接收到的数据
if (HAL_UART_RXCount < HAL_UART_RXD_Num)
{
HAL_UART_RXBuf[HAL_UART_RXCount] = res; //记录接收到的值
HAL_UART_RXCount++; //接收数据增加1
}
}
#endif
}
MYDMA_Enable()函数的实现:
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Cmd(DMA_Streamx, DISABLE); //1رÕDMA′«êä
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //è·±£DMA¿éòÔ±»éèÖÃ
DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //êy¾Y′«êäá¿
DMA_Cmd(DMA_Streamx, ENABLE); //¿aÆôDMA′«êä
}
问题1:如果是DMA指针没有复位的问题,那么是为什么没有复位呢?
问题2:DMA的初始化的循环模式与普通模式到底有什么具体的区别。
[mw_shl_code=c,true]#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "dma.h"
//ALIENTEK ì½Ë÷ÕßSTM32F407¿a·¢°å êμÑé23
//DMA êμÑé-¿aoˉêy°æ±¾
//¼¼êõÖ§3Ö£owww.openedv.com
//ìÔ±|μêÆì£ohttp://eboard.taobao.com
//1ãÖYêDDÇòíμç×ó¿Æ¼¼óDÏT1«Ë¾
//×÷ÕߣoÕyμãÔ-×ó @ALIENTEK
#define SEND_BUF_SIZE 200
extern u8 SendBuff[SEND_BUF_SIZE];
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//éèÖÃÏμí3ÖD¶ÏóÅÏ輶·Ö×é2
delay_init(168); //3õê¼»ˉÑóê±oˉêy
uart_init(115200); //3õê¼»ˉ′®¿ú2¨ìØÂêÎa115200
MYDMA_Config(DMA2_Stream5,DMA_Channel_4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA2,STEAM7,CH4,íaéèÎa′®¿ú1,′æ′¢Æ÷ÎaSendBuff,3¤¶èÎa:SEND_BUF_SIZE.
MYDMA_Enable(DMA2_Stream5,SEND_BUF_SIZE); //¿aÆôò»′ÎDMA′«êä
while(1);
}
[/mw_shl_code]
[mw_shl_code=c,true]#include "dma.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//±¾3ìDòÖ»1©Ñ§Ï°ê1óã¬Î′¾-×÷ÕßDí¿é£¬2»μÃóÃóúÆäËüèÎoÎóÃí¾
//ALIENTEK STM32F407¿a·¢°å
//DMA Çy¶ˉ′úÂë
//ÕyμãÔ-×ó@ALIENTEK
//¼¼êõÂÛì3:www.openedv.com
//′′½¨èÕÆú:2014/5/6
//°æ±¾£oV1.0
//°æè¨ËùóD£¬μá°æ±Ø¾¿¡£
//Copyright(C) 1ãÖYêDDÇòíμç×ó¿Æ¼¼óDÏT1«Ë¾ 2014-2024
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//DMAxμĸ÷í¨μàÅäÖÃ
//ÕaàïμÄ′«êäDÎê½êÇ1춨μÄ,Õaμãòa¸ù¾Y2»í¬μÄÇé¿öà′DT¸Ä
//′ó′æ′¢Æ÷->íaéèÄ£ê½/8λêy¾Y¿í¶è/′æ′¢Æ÷Ôöá¿Ä£ê½
//DMA_StreamxMAêy¾Yá÷,DMA1_Stream0~7/DMA2_Stream0~7
//chxMAí¨μàÑ¡Ôñ,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
//par:íaéèμØÖ·
//mar:′æ′¢Æ÷μØÖ·
//ndtr:êy¾Y′«êäá¿
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
DMA_InitTypeDef DMA_InitStructure;
if((u32)DMA_Streamx>(u32)DMA2)//μÃμ½μ±Ç°streamêÇêôóúDMA2»1êÇDMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2ê±Öóê1Äü
}else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1ê±Öóê1Äü
}
DMA_DeInit(DMA_Streamx);
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//μè′yDMA¿éÅäÖÃ
/* ÅäÖÃ DMA Stream */
DMA_InitStructure.DMA_Channel = chx; //í¨μàÑ¡Ôñ
DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMAíaéèμØÖ·
DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA ′æ′¢Æ÷0μØÖ·
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//íaéèμ½′æ′¢Æ÷Ä£ê½
DMA_InitStructure.DMA_BufferSize = ndtr;//êy¾Y′«êäá¿
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//íaéè·ÇÔöá¿Ä£ê½
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//′æ′¢Æ÷Ôöá¿Ä£ê½
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//íaéèêy¾Y3¤¶è:8λ
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//′æ′¢Æ÷êy¾Y3¤¶è:8λ
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// ê1óÃÑ-»·Ä£ê½£¬2»¿é2éóÃÆÕí¨Ä£ê½£¬2»ÖaÎaoÎ
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//ÖDμèóÅÏ輶
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//′æ′¢Æ÷í»·¢μ¥′Î′«êä
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//íaéèí»·¢μ¥′Î′«êä
DMA_Init(DMA_Streamx, &DMA_InitStructure);//3õê¼»ˉDMA Stream
}
//¿aÆôò»′ÎDMA′«êä
//DMA_StreamxMAêy¾Yá÷,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:êy¾Y′«êäá¿
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Cmd(DMA_Streamx, DISABLE); //1رÕDMA′«êä
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //è·±£DMA¿éòÔ±»éèÖÃ
DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //êy¾Y′«êäá¿
DMA_Cmd(DMA_Streamx, ENABLE); //¿aÆôDMA′«êä
}
[mw_shl_code=c,true]#include "sys.h"
#include "usart.h"
#include "dma.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//èç1ûê1óÃucos,Ôò°üà¨ÏÂÃæμÄí·Îļt¼′¿é.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos ê1óÃ
#endif
//////////////////////////////////////////////////////////////////////////////////
//±¾3ìDòÖ»1©Ñ§Ï°ê1óã¬Î′¾-×÷ÕßDí¿é£¬2»μÃóÃóúÆäËüèÎoÎóÃí¾
//ALIENTEK STM32F4ì½Ë÷Õß¿a·¢°å
//′®¿ú13õê¼»ˉ
//ÕyμãÔ-×ó@ALIENTEK
//¼¼êõÂÛì3:www.openedv.com
//DT¸ÄèÕÆú:2014/6/10
//°æ±¾£oV1.5
//°æè¨ËùóD£¬μá°æ±Ø¾¿¡£
//Copyright(C) 1ãÖYêDDÇòíμç×ó¿Æ¼¼óDÏT1«Ë¾ 2009-2019
//All rights reserved
//********************************************************************************
//V1.3DT¸ÄËμÃ÷
//Ö§3Öêêó|2»í¬ÆμÂêÏÂμÄ′®¿ú2¨ìØÂêéèÖÃ.
//¼óèëá˶ÔprintfμÄÖ§3Ö
//Ôö¼óáË′®¿ú½óêÕÃüáî1|Äü.
//DTÕyáËprintfμúò»¸ö×Ö·û¶aê§μÄbug
//V1.4DT¸ÄËμÃ÷
//1,DT¸Ä′®¿ú3õê¼»ˉIOμÄbug
//2,DT¸ÄáËUSART_RX_STA,ê1μÃ′®¿ú×î′ó½óêÕ×Ö½úêyÎa2μÄ14′η½
//3,Ôö¼óáËUSART_REC_LEN,óÃóú¶¨òå′®¿ú×î′óÔêDí½óêÕμÄ×Ö½úêy(2»′óóú2μÄ14′η½)
//4,DT¸ÄáËEN_USART1_RXμÄê1Äü·½ê½
//V1.5DT¸ÄËμÃ÷
//1,Ôö¼óá˶ÔUCOSIIμÄÖ§3Ö
//////////////////////////////////////////////////////////////////////////////////
#define SEND_BUF_SIZE 200 //·¢Ëíêy¾Y3¤¶è,×îoÃμèóúsizeof(TEXT_TO_SEND)+2μÄÕûêy±¶.
u8 SendBuff[SEND_BUF_SIZE]; //·¢Ëíêy¾Y»o3åÇø
//////////////////////////////////////////////////////////////////
//¼óèëòÔÏÂ′úÂë,Ö§3Öprintfoˉêy,¶ø2»DèòaÑ¡Ôñuse MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//±ê×¼¿aDèòaμÄÖ§3Öoˉêy
struct __FILE
{
int handle;
};
FILE __stdout;
//¶¨òå_sys_exit()òÔ±üÃaê1óðëÖ÷»úÄ£ê½
_sys_exit(int x)
{
x = x;
}
//Öض¨òåfputcoˉêy
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//Ñ-»··¢Ëí,Ö±μ½·¢Ëííê±Ï
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //èç1ûê1Äüá˽óêÕ
void Usart1_Send(u8 *buf,u8 len)
{
u8 t;
for(t=0;t<len;t++) //Ñ-»··¢Ëíêy¾Y
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1,buf[t]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
//3õê¼»ˉIO ′®¿ú1
//bound:2¨ìØÂê
void uart_init(u32 bound){
//GPIO¶Ë¿úéèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //ê1ÄüGPIOAê±Öó
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//ê1ÄüUSART1ê±Öó
//′®¿ú1¶Ôó|òy½Å¸′óÃó3éä
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9¸′óÃÎaUSART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10¸′óÃÎaUSART1
//USART1¶Ë¿úÅäÖÃ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9óëGPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸′óÃ1|Äü
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //Ëù¶è50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //íÆíì¸′óÃêä3ö
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //éÏà-
GPIO_Init(GPIOA,&GPIO_InitStructure); //3õê¼»ˉPA9£¬A10
//USART1 3õê¼»ˉéèÖÃ
USART_InitStructure.USART_BaudRate = bound;//2¨ìØÂêéèÖÃ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö3¤Îa8λêy¾Y¸ñê½
USART_InitStructure.USART_StopBits = USART_StopBits_1;//ò»¸öí£Ö1λ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎTÆæżD£Ñéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎTó2¼têy¾Yá÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //êÕ·¢Ä£ê½
USART_Init(USART1, &USART_InitStructure); //3õê¼»ˉ′®¿ú1
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //ê1Äü′®¿ú1 DMA½óêÕ
USART_Cmd(USART1, ENABLE); //ê1Äü′®¿ú1
//USART_ClearFlag(USART1, USART_FLAG_TC);
#if EN_USART1_RX
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//¿aÆôÏà1ØÖD¶Ï
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//′®¿ú1ÖD¶Ïí¨μà
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//ÇàÕ¼óÅÏ輶3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //×óóÅÏ輶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQí¨μàê1Äü
NVIC_Init(&NVIC_InitStructure); //¸ù¾YÖ¸¶¨μÄ2Îêy3õê¼»ˉVIC¼Ä′æÆ÷¡¢
#endif
}
void USART1_IRQHandler(void) //′®¿ú1ÖD¶Ï·tÎñ3ìDò
{
u8 Usart1_Rec_Cnt;
#if SYSTEM_SUPPORT_OS //èç1ûSYSTEM_SUPPORT_OSÎaÕ棬ÔòDèòaÖ§3ÖOS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //½óêÕÖD¶Ï(½óêÕμ½μÄêy¾Y±ØDëêÇ0x0d 0x0a½áÎ2)
{
USART_ReceiveData(USART1);//¶áè¡êy¾Y ×¢òa£oÕa¾ä±ØDëòa£¬·ñÔò2»Äü1»Çå3yÖD¶Ï±ê־λ¡£Îòò22»ÖaμàÎa鶣¡
Usart1_Rec_Cnt = SEND_BUF_SIZE-DMA_GetCurrDataCounter(DMA2_Stream5); //Ëã3ö½ó±¾Ö¡êy¾Y3¤¶è
//***********Ö¡êy¾Y′|àíoˉêy************//
printf ("The lenght:%d ",Usart1_Rec_Cnt);
printf ("The data: ");
Usart1_Send(SendBuff,Usart1_Rec_Cnt);
printf (" Over! ");
//*************************************//
USART_ClearITPendingBit(USART1, USART_IT_IDLE); //Çå3yÖD¶Ï±êÖ¾
// DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5);//Çå3yDMA2_Steam7′«êäíê3é±êÖ¾
// while(1)
// {
// if(DMA_GetFlagStatus(DMA2_Stream5,DMA_FLAG_TCIF5)!=RESET)//μè′yDMA2_Steam7′«êäíê3é
// {
// DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5);//Çå3yDMA2_Steam7′«êäíê3é±êÖ¾
// break;
// }
// }
MYDMA_Enable(DMA2_Stream5,SEND_BUF_SIZE); //»Ö¸′DMAÖ¸Õ룬μè′yÏÂò»′ÎμĽóêÕ
}
#if SYSTEM_SUPPORT_OS //èç1ûSYSTEM_SUPPORT_OSÎaÕ棬ÔòDèòaÖ§3ÖOS.
OSIntExit();
#endif
}
#endif
[/mw_shl_code]
[/mw_shl_code]
一周热门 更多>