/*************************************
使用uCOS的信号量处理串口DMA接收数据
*************************************/
#define BUFFER_SIZE (512)
//接收到数据信号量
OS_EVENT *Recv_Sem;
INT16U Recv_Size;
//DMA接收与处理缓存
INT8U Recv_Buffer[BUFFER_SIZE];
INT8U Deal_Buffer[BUFFER_SIZE];
//数据处理状态 0处理完成 1正在处理
INT8U Deal_State;
//重新设置DMA通道,重启DMA接收
void DMA_Restart(DMA_Channel_TypeDef* DMAy_Channelx,INT16U size)
{
DMA_Cmd(DMAy_Channelx,DISABLE);
DMA_SetCurrDataCounter(DMAy_Channelx,size);
DMA_Cmd(DMAy_Channelx,ENABLE);
}
//串口初始化
void USART_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
//使能外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//发送端为推挽复用输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//接收端为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//DMA初始化
DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_PeripheralBaseAddr = (INT32U)(&USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (INT32U)Recv_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据源地址
DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //数据区指针递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //配置为非循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6,&DMA_InitStructure);
//串口初始化
USART_DeInit(USART2);
USART_https://www.docsj.com/doc/ea10817783.html,ART_BaudRate = 115200;
USART_https://www.docsj.com/doc/ea10817783.html,ART_WordLength = USART_WordLength_8b;
USART_https://www.docsj.com/doc/ea10817783.html,ART_StopBits = USART_StopBits_1;
USART_https://www.docsj.com/doc/ea10817783.html,ART_Parity = USART_Parity_No ;
USART_https://www.docsj.com/doc/ea10817783.html,ART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_https://www.docsj.com/doc/ea10817783.html,ART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2,&USART_InitStructure);
//去除第一个字符发送不了的情况
USART_ClearFlag(USART2,USART_FLAG_TC);
//使能空闲总线中断
USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);
//使能接收DMA请求
USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);
//使
能DMA通道
DMA_Cmd(DMA1_Channel6,ENABLE);
//使能USART2
USART_Cmd(USART2,ENABLE);
}
//USART2中断服务函数
void USART2_IRQHandler(void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
//总线空闲中断
if(USART_GetITStatus(USART2,USART_IT_IDLE) == SET)
{
//关闭DMA通道,防止数据被破坏
DMA_Cmd(DMA1_Channel6,DISABLE);
//这两条指令用于清除空闲中断标志
USART2->SR;
USART2->DR;
//获取接收到的数据量
Recv_Size = DMA_GetCurrDataCounter(DMA1_Channel6);
Recv_Size = BUFFER_SIZE-Recv_Size;
if(Recv_Size == 0)
{
goto RETURN;
}
//判断数据是否处理完成,完成方可继续
if(Deal_State == 1)
{
goto RETURN;
}
//可以拷贝数据,也可以切换DMA缓冲指针,使用另一个缓冲进行接收
memcpy(Deal_Buffer,Recv_Buffer,Recv_Size);
//唤醒DMA处理任务
//OSSemPost(Recv_Sem);
//重启DMA通道
DMA_Restart(DMA1_Channel6,BUFFER_SIZE);
}
RETURN:
OSIntExit();
}
void Deal_Task(void *p_arg)
{
INT8U err;
//清空缓冲区
memset(Recv_Buffer,0,BUFFER_SIZE);
memset(Deal_Buffer,0,BUFFER_SIZE);
while(1)
{
Deal_State = 0;
//等待数据到来
OSSemPend(Recv_Sem,0,&err);
if(err == OS_ERR_NONE)
{
//正在处理数据置位
Deal_State = 1;
//开始处理数据
}
//清空接收到的数据
memset(Deal_Buffer,0,Recv_Size);
}
}