STM32串口双缓冲乒乓数据传输方式

发布者:RadiantBeauty最新更新时间:2018-09-17 来源: eefocus关键字:STM32  串口  双缓冲  数据传输方式 手机看文章 扫描二维码
随时随地手机看文章

对于没玩过DMA 的朋友,这里简单说一下DMA,用自己的语言说吧,那就是,从某个位置
传输数据到某个位置,如果不用DMA,那要CPU参与操作,一个字节一个字节地搬,效率高
点的,就一个字一个字地搬.但当你用了DMA 后,那就是只需要设置:A.从哪里开始搬; B,
搬到哪里去;C以字节方式搬还是半字还是字;D:一共搬多少个.之后,启动DMA.CPU内部
就会开始搬数据了,整个搬数据的过程都不需要指令的参与,唯一要做的,就是检测什么时
候搬完.你可以扫描寄存器,也可以用中断.这里,我使用了中断.
具体设置功能看注释就可以明白了.注意一点就是,有一个设置:
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
这个是外设的地址不递增.也就是说,每次搬动,都是从源头,也就是USART1的DR寄存器
搬,但内存地址却是递增的:
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
这个历程实现了 接受 串口的数据 写到FLASH 之中工作,而DMA的作用在于将 串口收寄存器 USART1->DR 的 数据写到内存之中 比如某个数组之中 u8 USART1_DMA_Buf1[512]; 写满512个字节之后将进入DMA中断(通道5)在这里修改DMA 的内存写入入口
u8 USART1_DMA_Buf2[512]; ,同时标记 下次的入口Free_Buf_No=BUF_NO1; 与 Buf_Ok=TRUE; 证明已有数据准备完成。这时CUP将USART1_DMA_Buf1中的数据写入FLASH .
又抄了一点
这次使用的是双缓冲,也有人
叫乒乓缓冲.因为一般情况下,串口的数据DMA 传输进BUF1 的过程中,是不建议对
BUF1 进行操作的.但由于串口数据是不会等待的直传,所以你总不能等BUF1 满了,
才往FLASH 上写,因为这时候串口数据依旧是源源不断.于是,使用双缓冲就变的理
所当然了.当BUF1 满了的时候,就马上设置DMA的目标为BUF2,并且BUF1的数据
往25F080上灌.当串口DMA写满了BUF2的时候,再设置DMA的目标为BUF1,此时
再操作BUF2写进25F080.如此一直循环,就好像打乒乓球那样吧,所以就叫乒乓缓冲.
用这个方法的速度极限就是,你必须确保两点a.DMA 灌满了BUF1 的时候,会发生中
断,此时切换DMA 的目标缓冲为BUF2,而且切换的过程必须在新的串口数据溢出之
前完成.b.在DMA的BUF1满之前,另外一个有数据的BUF2必须能全部写进25F080,
其中包括了遇到新的扇区边界而要刷除扇区的操作时间!!
可以看出,BUF的增大,并不能够很大程度的提升速度极限.
STM32中USART的DMA 实现 - java - stm32学习日志
假设 USART 与 FLASH 的 底层驱动已经写好了。   点击查看。
/************DMA方式传输***************************/
#define SRC_USART1_DR    (&(USART1->DR))        //串口接收寄存器作为源头
//DMA目标缓冲,这里使用双缓冲
u8 USART1_DMA_Buf1[512];
u8 USART1_DMA_Buf2[512];
bool Buf_Ok;    //BUF是否已经可用
BUF_NO Free_Buf_No;        //空闲的BUF号 typedef enum {BUF_NO1=0,BUF_NO2=1}BUF_NO;
DMA_InitTypeDef DMA_InitStructure;
void USART_DMAToBuf1(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                             //开DMA时钟
    DMA_DeInit(DMA1_Channel5);                                                                               //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR;                //源头BUF 既是 (&(USART1->DR)) 
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;                //目标BUF 既是要写在哪个个数组之中
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                      //外设作源头//外设是作为数据传输的目的地还是来源
    DMA_InitStructure.DMA_BufferSize = 512;                                        //DMA缓存的大小 单位在下边设定
    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_PeripheralDataSize_Byte;            //内存字节为单位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                               //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                            //4优先级之一的(高优先) VeryHigh/High/Medium/Low
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //非内存到内存
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);                                    //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器
    
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);                                //DMA5传输完成中断
STM32中USART的DMA 实现 - java - stm32学习日志
     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);                               //使能USART1的接收DMA请求
    /*****************************************************************************************************************************************************/
    //初始化BUF标志
    Free_Buf_No=BUF_NO2; //因为 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1; 
    Buf_Ok=FALSE; //此时没有数据准备完成 当然FALSE
    DMA_Cmd(DMA1_Channel5, ENABLE);                                                //正式允许DMA
    
}
再来看看DMA中断:
//u16 DataCounter;
extern DMA_InitTypeDef DMA_InitStructure;
void DMA1_Channel5_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC5)) //通道5传输完成中断TC 还有传输 过半中断HT 错误中断TE 全局中断GL
     {
       //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);//获取剩余长度,一般都为0,调试用
        DMA_ClearITPendingBit(DMA1_IT_GL5);    //清除全部中断标志
        
       //转换可操作BUF
        if(Free_Buf_No==BUF_NO1)
        {    
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);
            Free_Buf_No=BUF_NO2;
        }
        else
        {
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);
            Free_Buf_No=BUF_NO1;
        }
        Buf_Ok=TRUE; //有准备好的数据了
    
     }
}
写FLASH的操作
while(1)
    {
        if(Buf_Ok==TRUE)
        {
            LED1_ON;   //一个标记
            Buf_Ok=FALSE; //操作了准备好的数据
            if((addr%4096)==0)        //跨越一个扇区,则需要先刷除
            {
                SST25SectorErase(addr);    
                sector_count++;
            }
            if(Free_Buf_No==BUF_NO1)
                SST25Write(addr,USART1_DMA_Buf1,512);
            else
                SST25Write(addr,USART1_DMA_Buf2,512);
            addr+=512;
            Timer1=5000; //时间重置
            LED1_OFF;
        }
        
       //检测超时 开了 定时器
        if(Timer1==0) //五秒内没准备好的数据
        {
           //获取长度
            len=512-DMA_GetCurrDataCounter(DMA1_Channel5);
           //写入最后数据
            if(Free_Buf_No==BUF_NO1)
                SST25Write(addr,USART1_DMA_Buf2,len);
            else
                SST25Write(addr,USART1_DMA_Buf1,len);
            addr+=len;
            
            break;
        }
    }
STM32中USART的DMA 实现 - java - stm32学习日志
还是很简单的。
有一点比较困扰 就是 FlagStatus标志位 与 ITStatus中断标志位 的区别。 其实就 DMA 来说 DMA_IT值 与 DMA_FLAG值

 是一样的
甚至2者值的获取 都是读 DMA ISR register 的值 清除也是设置 DMA_IFCR 寄存器来清除的所以貌似没有区别.........STM32中USART的DMA 实现 - java - stm32学习日志同理这

个问题在别的中断也存在但我还不可保证 IT 与FLAG 的值总是相同的这个存在也许是为了兼容但一定有其意义务必不可混用即

使有时用错也正确.....


关键字:STM32  串口  双缓冲  数据传输方式 引用地址:STM32串口双缓冲乒乓数据传输方式

上一篇:STM32 USB 从机HID分析
下一篇:STM32双缓冲机制初始化(使用STM32CubeMX)

推荐阅读最新更新时间:2024-03-16 16:14

关于stm32的USB学习笔记之usbcore.c
#include stm32f10x_lib.h #include usbreg.h #include usbcore.h #include usbuser.h #include usbcfg.h #include usb.h #include usb_hw.h #include usbdesc.h #include hid.h #include hiduser.h #define _DEBUG_ #include debug.h #pragma diag_suppress 111,1441 //用来指示USB设备的状态 WORD USB_DeviceStatus
[单片机]
STM32进阶-红外遥控器的应用详细步骤
红外遥控器概述 红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。 同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。 红外遥控的编码目前广泛使用的是:NEC Protocol 的PWM(脉冲宽度调制)和Philips RC-5 Protocol 的PPM(脉冲位置调制)。 NEC协议的特征: 1、8位地址和8位指令长度; 2、地址和命令两次传输;(确保可靠性) 3、PWM脉冲宽度调制,以发射红外载波的占空比代表“0”和“1”; 4、载波频率为38KHz 5、位时
[单片机]
<font color='red'>STM32</font>进阶-红外遥控器的应用详细步骤
IIC读写AT24C02代码2——串口命令控制多页读写
通过串口输入 R 、W 进行控制程序读写IIC设备。波特率9600bps,晶振115200HZ。 main.c /*----------------------------------------------- IIC编程 1 编写:Louis 邮箱:kaly.liu@163.com 日期:2015.06.01 修改:通过串口命令R/W,控制EEPROM的读R写W。并从串口提示。 改进:增加对页读写功能 晶振:11.0592MHZ NOTE:*通过实测发现,AT24C02可以连续写入16BYTE字节,而且地址要连续的两个页。就是0~15,16~31,。。。 -------------------------
[单片机]
PC机串口调试助手与单片机通信字符问题
在利用PC机的串口调试助手与单片机通信时,单片机与PC机是以ASCII码的形式通信的,比如发送1,其实发送的是字符1,如果在接收区以十六进制显示的话,是31(1的ASCII码)。具体如下: 1. 十六进制发送与十六进制显示都为选中,发送与接收的都是字符的形式; 2.如果以十六进制发送或者十六进制显示的话,就是以十六进制的ASCII码的形式发送或显示。 如果在串口调试助手中发送十六进制数字,以单片机的数码管显示的话,把十六进制ASCII码,换算成十进制ASCII码,然后显示在数码管上。以下是程序示例:(单片机开发板为普中科技的HC6800-EM3 v3.0) /************************* * 目标:以16
[单片机]
STM32复习笔记(十一)USMART调试组件
一、什么是USMART? USMART是正点原子团队为其STM32开发平台开发的一种类似linux的shell的调试工具。具体工作过程是通过串口发送命令给单片机,然后单片机收到命令之后调用单片机里面对应的相关函数,并执行,同时支持返回结果。 二、USMART调试过程: 三、USMART应用场景: 开发过程中,经常需要修改函数入口参数,查看运行效果的情况下应用非常方便。不用多次下载代码,或者多次用JLINK调试。 四、USMART特点: 可以调用绝大部分用户直接编写的函数。 资源占用极少(最少情况:FLASH:4K;SRAM:72B)。 支持参数类型多(数字(包含10/16进制)、字符串、函数指针等)。 支
[单片机]
<font color='red'>STM32</font>复习笔记(十一)USMART调试组件
STM32低功耗模式简介
STM32F10xxx有三中低功耗模式: ●睡眠模式(Cortex?-M3内核停止,外设仍在运行) ●停止模式(所有的时钟都以停止) ●待机模式(1.8V电源关闭) 时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,是32位市场上功耗最低的产品,相当于0.5mA/MHz。 上电,默认使用内部HSI时钟8M,经测试10mA左右。待机模式可实现系统的最低功耗。 可将电流消耗降至两微安。 在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚: ●复位引脚(始终有效) ●当被设置为防侵入或校准输出时的TAMPER引脚 ●被使能的唤醒引脚 /*按钮GPIOB9进入睡眠,WKUP pin(GPIOA0)唤
[单片机]
<font color='red'>STM32</font>低功耗模式简介
STM32 Cubemax(一)——PWM配置及控制SG90舵机
前言 这是一篇基于STM32F429的保姆级入门的用CubeMAX配置生成并编写的控制舵机SG90的教程 一、SG90舵机 常见的SG90舵机 SG90引出三条线,分别是控制线(橙色),VCC(红色),GND(黑色),用杜邦线依次连接在开发板上即可 SG90舵机要求工作在频率为50HZ——周期为20ms的PWM波,且对应信号的高低电平在0.5ms - 2.5ms之间,对应的舵机转动角度如下表所示(当然也可以按照这个线性的对应关系去达到转动自己想要的角度,如想要转动60°,则高电平脉宽为大概为1.2ms,具体能不能转到特定的角度还和舵机的精度有关) 二、CubeMax配置 1.选型(这里用实验的开发板为正点原子的F4
[单片机]
<font color='red'>STM32</font> Cubemax(一)——PWM配置及控制SG90舵机
一种低成本的DSP快速开发方法
摘要:针对目前 DSP 的算法开发主要依赖手工编写C代码,不但工作量大,而且程序的下载依赖于专门的昂贵的仿真器的问题,在此提出了基于Matlab/ Simulink 环境的DSP算法开发,并利用 串口 通信实现程序下裁的综合方案。该方案能很好地利用Matlab现有的功能模块,大大降低了DSP的算法开发难度,利用 RTW 技术,可将算法自动生成C代码。利用串口通信下载调试程序,方便有效,节约了系统开发的成本。经实验验证,利用该方案缩短了算法开发的周期,结果可靠,成本低。 关键词:DSP;串口; RTW;Simulink 0 引言 数字信号处理器(Digital Signal Processing,DSP)是
[嵌入式]
一种低成本的DSP快速开发方法
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved