OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2588|回复: 1

STM32+串口+DMA接收不定长数据

[复制链接]

27

主题

70

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
384
金钱
384
注册时间
2018-11-20
在线时间
62 小时
发表于 2020-8-5 10:01:48 | 显示全部楼层 |阅读模式
STM32+串口+DMA接收不定长数据
说明:为了给CPU缓解压力,使用DMA接收串口数据。此程序仅供学习,不可进行商业用途
环境:STM32F103C8
代码:
//----------------------------------------------串口代码---------------------------------------------------//
//分配缓存空间,接收数据
u8   RS485_RX_BUF[RS485_MAX_RECV_LEN];
vu16 RS485_RX_STA = 0;
int  RS485_RX_LEN = 0;

//usart3串口中断
/*
*功能:接收数据入缓存,情况标志位
*/
void USART3_IRQHandler(void)
{
        OSIntEnter();  //使用了UCOS,通知系统进入中断
                if( USART_GetITStatus(USART3,USART_IT_IDLE) != RESET )
                {
                        //关闭DMA
                        DMA_Cmd(DMA1_Channel3,DISABLE);
                        /*关键*/
                         USART_ReceiveData(USART3);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
                         /*关键*/
                        //清USART_IT_IDLE标志
                        USART_ClearITPendingBit(USART3,USART_IT_IDLE);//清除空闲中断       
                        RS485_RX_LEN = DMA_MAX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);               
                        //设置标志位
                        RS485_RX_STA = 1;  
                       
                        MyDMA_Enable(DMA1_Channel3,DMA_MAX_LEN);//开启下一次DMA接收
                       
                }
               
        OSIntExit();
       
}
/*
功能:初始化串口3
参数:bound:波特率
*/
void RS485_Init(u32 bound)//USART3
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef  NVIC_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOA时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能

        USART_DeInit(USART3);//复位串口3
        //----------------------------GPIO---------------------------//
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10

    //USART3_RX          PB11
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11
       
        //----------------------------USART---------------------------//
        USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
        USART_Init(USART3,&USART_InitStructure);
        USART_Cmd(USART3, ENABLE);

        //----------------------------NVIC---------------------------//
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
       
       
        //USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//使能接收中断
        USART_ITConfig(USART3,USART_IT_IDLE,ENABLE);//使能空闲中断,接收完整一帧数据
        USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);//开启DMA接收
        RS485_RX_LEN=0;                //清空长度
        RS485_RX_STA=0;                //清零
        MyDMA_Config(DMA1,DMA1_Channel3,
                                 (u32)&(USART3->DR),
                                 (u32)RS485_RX_BUF,
                                 DMA_DIR_PeripheralSRC,//外设到内存DMA_DIR_PeripheralSRC 内存到外设DMA_DIR_PeripheralDST
                                 DMA_MAX_LEN);//一次接受60byte
        //使能DMA
        DMA_Cmd(DMA1_Channel3,ENABLE);  
}

//----------------------------------------------DMA代码---------------------------------------------------//
/*
功能:只支持外设到内存、内存到外设;若使用内存到内存需要更改结构体的DMA_M2M
DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
chxMA通道选择,@Ref DMA_channel DMA_Channel_0~DMA_Channel_7
par:外设地址
dirMA数据传输方向方向
mar:存储器地址
ndtr:数据传输量  
*/

void MyDMA_Config(DMA_TypeDef* DMA_Streamx,DMA_Channel_TypeDef* DMA_CHx,
                                  u32 cpar,u32 cmar,u32 dir,u16 cndtr)
{
        DMA_InitTypeDef  DMA_InitStructure;
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);//DMA2时钟使能
               
        }else
        {
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA1时钟使能
        }
       
        DMA_DeInit(DMA_CHx);   //将DMA的通道chx寄存器重设为缺省值

        DMA_InitStructure.DMA_PeripheralBaseAddr         = cpar;  //DMA外设基地址
        DMA_InitStructure.DMA_MemoryBaseAddr                = cmar;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR                                 = dir;   //DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设
        DMA_InitStructure.DMA_BufferSize                         = cndtr; //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc                         = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc                         = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize                 = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize                 = DMA_MemoryDataSize_Byte; //数据宽度为8位
        DMA_InitStructure.DMA_Mode                                 = DMA_Mode_Normal;  //工作在正常缓存模式
        DMA_InitStructure.DMA_Priority                                 = DMA_Priority_Medium; //DMA通道 x拥有中优先级
        DMA_InitStructure.DMA_M2M                                 = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART2_Tx_DMA_Channel所标识的寄存器
}

//开启一次DMA传输
void MyDMA_Enable(DMA_Channel_TypeDef* DMA_CHx,u16 cndtr)
{
        DMA_Cmd(DMA_CHx, DISABLE );  //关闭DMA 所指示的通道
        DMA_SetCurrDataCounter(DMA_CHx,cndtr);//DMA通道的DMA缓存的大小
        DMA_Cmd(DMA_CHx, ENABLE);  //使能DMA 所指示的通道
}



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

21

主题

2205

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5141
金钱
5141
注册时间
2014-8-26
在线时间
1317 小时
发表于 2020-8-5 17:50:26 | 显示全部楼层
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 10:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表