文档视界 最新最全的文档下载
当前位置:文档视界 › 基于STM32串口空闲中断与DMA,配合ucos信号量接收未知大小数据

基于STM32串口空闲中断与DMA,配合ucos信号量接收未知大小数据

/*************************************
使用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);

}

}


相关文档
相关文档 最新文档