STM32F103DMA功能实现

发布者:Mengyun最新更新时间:2022-01-29 来源: eefocus关键字:STM32F103  DMA功能 手机看文章 扫描二维码
随时随地手机看文章

所谓的DMA指的是:直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。


两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。


简单的来说,DMA功能指的就是,不需要程序控制,单片机内部自己可以控制数据从一个地方到另一个地方的传输。下面直接通过代码来看DMA功能如何实现。


#include "dma.h"



u16 DMA1_MEM_LEN; //保存DMA每次数据传送的长度


//DMA1的各通道配置

//这里的传输形式是固定的,这点要根据不同的情况来修改

//从存储器->外设模式/8位数据宽度/存储器增量模式

//DMA_CHx:DMA通道CHx

//cpar:外设地址

//cmar:存储器地址

//cndtr:数据传输量

void MYDMA_Config(DMA_Channel_TypeDef *DMA_Chx, u32 cpar, u32 cmar, u16 cndtr)

{

    DMA_InitTypeDef DMA_InitStructure;


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输

    DMA_DeInit(DMA_Chx); //将DMA的通道1寄存器重设为缺省值


    DMA1_MEM_LEN = cndtr;


    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址

    DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址

    DMA_InitStructure.DMA_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);

}


void MYDMA_Enable(DMA_Channel_TypeDef* DMA_CHx)

{

DMA_Cmd(DMA_CHx,DISABLE);

DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);

DMA_Cmd(DMA_CHx,ENABLE);

}


这里使用了一个通用的DMA初始化,没有具体说明数据是从哪个内存发送到哪个外设,当哪个外设需要使用DMA功能时,在初始化的时候设置外设地址和内存地址就可以了。比如这里要使用串口发送的DMA功能。


#define SEND_BUF_SIZE 8200 //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE];


const u8 TEXT_TO_SEND[] = {"DMA 串口实验,缓冲区的数据,用DMA功能,通过串口2发送出来。"};

int main(void)

{

    u16 i;

    u8 t = 0;

    u8 j, mask = 0;

    float pro = 0;


    delay_init();

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    uart_init(115200);

    UART2_Init(115200);

    LED_Init();

    KEY_Init();

    //MYDMA_Config(DMA1_Channel4, (u32)&USART1->DR, (u32)SendBuff, SEND_BUF_SIZE);  //DMA1通道4,外设为串口1,存储器为SendBuff,长度SEND_BUF_SIZE.

    MYDMA_Config(DMA1_Channel7, (u32)&USART2->DR, (u32)SendBuff, SEND_BUF_SIZE); //DMA1通道7,外设为串口2,存储器为SendBuff,长度SEND_BUF_SIZE.



    j = sizeof(TEXT_TO_SEND);

    for(i = 0; i < SEND_BUF_SIZE; i++) //填充数据到SendBuff

    {

        if(t >= j) //加入换行符

        {

            if(mask)

            {

                SendBuff[i] = 0x0a;

                t = 0;

            }

            else

            {

                SendBuff[i] = 0x0d;

                mask++;

            }

        }

        else

        {

            mask = 0;

            SendBuff[i] = TEXT_TO_SEND[t];

            t++;

        }

    }


    printf("DMA test!!!rn");

    while(1) //串口1打印信息  通过DMA功能将SendBuff中的数据,通过串口2发送出来

    {

        t = KEY_Sacn(0);

        if(t == KEY1_PRES)

        {

            printf("Start Transimit....");

            printf("rnDMA DATA:rn");

            //串口1 DMA 发送

//            USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //使能串口1的DMA发送

//            MYDMA_Enable(DMA1_Channel4); //开始一次DMA传输


            //串口2 DMA 发送

            USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); //使能串口1的DMA发送

            MYDMA_Enable(DMA1_Channel7); //开始一次DMA传输


            //等待DMA传输完成,此时我们来做另外一些事,点灯

            //实际应用中,传输数据期间,可以执行另外的任务

            while(1)

            {

                //串口1 DMA 判断

//                if(DMA_GetFlagStatus(DMA1_FLAG_TC4) != RESET) //判断通道4传输完成

//                {

//                  DMA_ClearFlag(DMA1_FLAG_TC4); //清除通道4传输完成标志

//                    break;

//                }


                //串口2 DMA 判断

                if(DMA_GetFlagStatus(DMA1_FLAG_TC7) != RESET) //判断通道7传输完成

                {

                    DMA_ClearFlag(DMA1_FLAG_TC7); //清除通道7传输完成标志

                    break;

                }


                //pro = DMA_GetCurrDataCounter(DMA1_Channel4);

                pro = DMA_GetCurrDataCounter(DMA1_Channel7);

                pro = 1 - pro / SEND_BUF_SIZE;

                pro *= 100;

                printf("%f %%rn", pro);

            }

            printf("100%%");

            printf("rnTransimit Finished!rn");

        }

        i++;

        delay_ms(10);

        if(i == 20)

        {

            LED0 = !LED0;

            i = 0;

        }


    }

}


在初始化的时候,将串口数据发送寄存器作为外设地址,将存储发送数据的地址作为内存地址。数据的传输方向是从内存读取数据然后发送到外设地址中去。也就是一旦开启DMA传输功能之后,单片机就会自动将数组中的数据依次传输到串口发送数据寄存器中。这样数据就自动从串口发送出来了。不需要程序控制。


这里分别使用串口1和串口2进行了测试,每按一次按键,就启动一次DMA数据传输。在传输数据的过程中模拟程序执行其他操作。当DMA数据传输完成后,会打印出当前传输了多少字节的数据。

关键字:STM32F103  DMA功能 引用地址:STM32F103DMA功能实现

上一篇:STM32F103单片机使用DMA功能读取ADC采样数据
下一篇:STM32F103使用DAC功能输出正弦波

推荐阅读最新更新时间:2024-11-07 10:55

STM32F103的时钟配置源码学习记录
时钟的配置源码在文件system_stm32f10x.c中。程序先通过判断使用的f10芯片的种类,选择你要的系统时钟频率SYSCLK。我用的芯片系统频率最高为72Mhz,芯片容量为大容量型,所以预编译后选择的是SYSCLK_FREQ_72MHz 72000000。 下面这段代码在时钟配置中没什么用,只是在以后的程序中可以通过SystemCoreClock来读出系统时钟的频率。 下面代码通过宏定义来选择配置系统时钟的函数,上边函数定义了SYSCLK_FREQ_72MHz,所以程序执行void SetSysClockTo72(void)。跳转到这个函数 下面这段函数不重要,直接跳过
[单片机]
STM32F103RB 实作笔记(二)- Beep/Buzzer蜂鸣器
延续上一篇 ”STM32F103RB 实作笔记(一)- 跑马灯(正点原子 STM32F103 nano开发板)程式解析“,我们今天进行第二个程式解析。 和上一篇一样,进入找到 USER 的档案夹,直接点开 BEEP 项目档,并且进行编译和执行。 硬件配置 先看一下 线路图,可以知道 选择 PB8 来控制这个蜂鸣器。 BEEP 要用低电平 来驱动。 从原厂附上的资源配置图片,表明左下角的 BEEP 是”有源“型式的。 有源型式的 BEEP 在百度查得的说明如下图,就是”给他电力就会直接叫“。 主程式 Main.c 主程式 Main.c 的内容如下: #include sys.h #include
[单片机]
<font color='red'>STM32F103</font>RB 实作笔记(二)- Beep/Buzzer蜂鸣器
stm32f103定时器中断
stm32为我们提供了8个定时器,分为:通用是定时器(TIM2~TIM5),高级定时器(TIM1和TIM8),基本定时器(TIM6和TIM7)。 至于三者之间的区别可以参考以下博客:https://blog.csdn.net/dukai392/article/details/72058041 本次我们主要讨论的是通用定时器的基本知识以及更新中断的配置过程。 通用定时器框图如下: 由于stm32的定时器十分复杂,功能特多而本次我们只讨论他的计数跟新功能(定时)。 时钟的选择: 由框图中红色部分可知定时器的时钟来源有三个:内部时钟(CK_INT),外部时钟(TIMx_ETR),其他定时器的时钟(ITR0-ITR
[单片机]
<font color='red'>stm32f103</font>定时器中断
FreeRTOS移植到STM32F103
1.创建工程 2.将FreeRTOS源码,拷贝到工程目录 3.删除其它架构和编译器的代码 查看portable文件夹发现 MemMang为内存管理相关文件需要保留 Commom里面有个mpu相关代码,我们不使用mpu,可以删除 我们的开发环境是keil,打开keil文件夹,提示我们参照RVDS,因此保留RVDS,其它删除 打开RVDS文件夹 STM32F103的内核为CORTEX-M3,删除其它架构相关文件 4.将FreeRTOS文件添加进工程 添加好之后,编译出现错误,缺少FreeRTOSConfig.h文件 5.添加配置文件
[单片机]
FreeRTOS移植到<font color='red'>STM32F103</font>
基于STM32F103VCT6单片机和步进电机的三维微位移控制系统设计
为实现X-Y-Z三维工作台的精确定位,设计了一种基于STM32F103VCT6单片机和步进电机的三维微位移控制系统。该系统可与上位机实现串口通信,接收上位机命令并把处理结果反馈给上位机;根据光栅传感器提供的位置反馈信息,系统可以通过对步进电机的方向、速度调节来实现精确定位;采用匀加速和匀减速方式对步进电机的速度进行调节,避免了因步进电机的突然加速和急停所带来的丢步和冲击现象。控制系统的测量实验结果表明,步进电机运行平稳,噪音低,定位精度高,控制系统性能稳定可靠。 微位移控制系统是一种集机械、光学、电子和计算机等多种技术于一体的智能化仪器。在先进制造技术与科学研究中有着极其广泛的应用,也是现代工业检测、质量控制和制造技术
[单片机]
基于<font color='red'>STM32F103</font>VCT6单片机和步进电机的三维微位移控制系统设计
stm32f103读取红外接收HS0038A2
软件: IAR 7.4 STM32CubeMX 4.14.0 硬件: STM32F103VBT6 原理图,和手册建议的基本一致,只是上拉电阻不是手册建议的10K以上,这里的面板距离控制器比较远,可能是考虑到线阻。 HAL配置,使用Cubemx。 HS0038A2的输出,带有上拉电阻,接着一个led灯,因此TIM3的IC脚浮空。 设计者恰好把IR设计在TIM3的通道4上。如果使用了通道1/2, 就可以使用PWM输入方式来捕捉红外脉冲,可以拿到每个脉冲的数据。 IC模式使用下降沿。 红外控制这里是常用的NEC协议。遥控器输出高电平,而HS0038A2转换低电平输出。 如,一个9ms高+4.5ms的低,组成一个h
[单片机]
<font color='red'>stm32f103</font>读取红外接收HS0038A2
STM32F103C8T6-LED点亮程序
#include stm32f10x.h //----------------------------------------------------------------------------- void mydelay_ms(int ms) { volatile int i; int k = ms * 2333 ; for ( i=0; i k; i++ ) { ; } } //----------------------------------------------------------------------------- int main(void) { // 初始化 只执行一
[单片机]
如何使用STM32F103C8的GPS模块获取位置坐标
GPS代表全球定位系统,用于检测地球上任何位置的纬度和经度,具有精确的UTC时间(协调世界时)。该设备每秒接收来自卫星的坐标,包括时间和日期。GPS 提供了很高的准确性,并且除了位置坐标之外还提供其他数据。 我们都知道 GPS 是一个非常有用的设备,在手机和其他便携式设备中非常常用来跟踪位置。它在各个领域都有非常广泛的应用,从在家中叫出租车到跟踪飞机的高度。 在本教程中,我们将GPS 模块与 STM32F103C8 微控制器连接,以查找位置坐标并将其显示在16x2 LCD 显示屏上。 所需组件 STM32F103C8微控制器 GPS模块 16x2 液晶显示器 面包板 连接电线 GPS模块 这是一个 GY-NEO6MV2
[单片机]
如何使用<font color='red'>STM32F103</font>C8的GPS模块获取位置坐标

推荐帖子

uClinux BOA SERVER CGI 支持中文吗?
我在用CGI返回中文时printf(中文\\n);浏览器在该行显示Invalidmultibyteformatstring在网上搜了一下有一种说法如下在MIME头里加上对字符集charset:gb2312现在我的MIME头如下:printf(Content-type:text/html\\ncharset:gb2312\\nPragma:no-cache\\n\\n);仍然是Invalidmultibyteformatstring。于是我想应该是我的u
zengliwen1987 Linux与安卓
隔离变压器是一种1比1的变压器
隔离变压器是一种1比1的变压器隔离变压器是一种1比1的变压器keyiRe:隔离变压器是一种1比1的变压器xiexiele回复:隔离变压器是一种1比1的变压器顶,好东西呀!回复:隔离变压器是一种1比1的变压器怎么下载不了啊回复:隔离变压器是一种1比1的变压器看看再说.........................回复:隔离变压器是一种1比1的变压器
wangqingtao 电源技术
精彩贴片集成电路的焊接图文教程
本帖最后由qwqwqw2088于2014-5-1511:03编辑 焊接心得作为一名电子工程师,如果不会拿烙铁焊接,真的说不过去。而现在很多年青的工程师确确实实在忽略这方面动手能力的培养或很少有机会自己焊接板子,心里只想着学ARM,学Linux,而换个电阻、电容有时都要找焊接工人,更不用提TSOP等密集型的贴片IC了。所以在此希望我们大伙都重视这些基础方便的训练,自己能焊的尽量自己焊,学着焊,如果有条件可以多请教那些焊接工人,他们都会有自己的技巧和心得。
qwqwqw2088 PCB设计
Nand Flash中的特殊硬件结构
由于nandflash相对其他常见设备来说,比较特殊,所以,特殊的设备,也有特殊的设计,所以,有些特殊的硬件特性,就有比较解释一下:1.页寄存器(PageRegister):由于NandFlash读取和编程操作来说,一般最小单位是页,所以,nandflash在硬件设计时候,就考虑到这一特性,对于每一片,都有一个对应的区域,专门用于存放,将要写入到物理存储单元中去的或者刚从存储单元中读取出来的,一页的数据,这个数据缓存区,本质上就是一个buffer,但是只是名字叫法不同,datas
13691982107 医疗电子
小工具解放双手的年代
这就是一张图片涵盖了射频工作者的用心都是免费的数据准不准需要自己验证小工具解放双手的年代总结的很详细,都是一些很实用的设计工具,工程师都经常要用的. 干我们这个必须借助工具啊不然头发掉得快是呀,有工具可以提高工作效率,明确方向,减少错误. 你也做这方面工作吗 一起交流分享学习讨论这个还得归功于写代码的隔空感谢码代码的兄弟
btty038 RF/无线
【DIY创意LED】WS2812效果显示文件
这次将LED的效果显示单独拿出来,可以编写各种效果,就看大家的创造力了。一个效果文件的基本程序结构如下(这是一个红色呼吸灯的效果):fromcommonimport*defrun():clear(np)n=0while1:clear(np,(abs(32-n),0,0))n=(n+1)%64sleep_ms(100) 每个效果文件可以impo
dcexpert 单片机
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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