历史上的今天
返回首页

历史上的今天

今天是:2024年12月30日(星期一)

正在发生

2021年12月30日 | STM32F103DMA功能实现

2021-12-30 来源:eefocus

所谓的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数据传输完成后,会打印出当前传输了多少字节的数据。

推荐阅读

史海拾趣

Deutsch公司的发展小趣事

在竞争激烈的电子行业中,品质控制和品牌建设至关重要。Deutsch公司深知这一点,因此始终将品质控制和品牌建设作为公司的重要任务。公司建立了严格的质量管理体系,确保产品的每一个细节都符合高标准。同时,通过精心策划的品牌推广活动,Deutsch公司的品牌形象逐渐深入人心。这些努力不仅提升了公司的市场地位,也增强了客户对公司的忠诚度。

Broadcom(博通)公司的发展小趣事

博通在有线和无线通信半导体领域一直保持着技术创新的领先地位。公司不断投入研发,推出了一系列具有竞争力的产品,包括宽带通信芯片、无线局域网芯片组等。这些产品的成功应用,不仅提升了博通的市场地位,也为整个电子行业的发展做出了重要贡献。

EMS GmbH公司的发展小趣事

EMS GmbH公司自创立之初,就专注于汽车转换器注塑件(微动开关)的研发和生产。公司投入大量资源进行技术创新,逐步积累起了一系列核心专利技术。这些技术不仅涵盖了汽车转换器注塑件生产的所有关键技术,还获得了多个国际品质管理组织机构及主流整车厂的双重、三重认证。这些专利技术的积累,使EMS GmbH公司在汽车转换器注塑件领域确立了行业领先地位。

Hantronix公司的发展小趣事

HANBIT Electronics自成立以来,便致力于技术创新与产品研发。2005年,公司投入大量资源研发新一代高性能手机显示屏技术,成功推出了具有低能耗、高清晰度和广视角特性的OLED屏幕。这一创新不仅迅速获得了市场的认可,还使得HANBIT Electronics在手机零部件供应商中脱颖而出,与多家国际知名品牌建立了长期合作关系。该技术的成功不仅提升了公司的市场份额,也为其后续在高端显示技术领域的持续探索奠定了坚实基础。

BOOKLY公司的发展小趣事

BOOKLY公司在追求经济效益的同时,也积极履行社会责任。公司注重环保和可持续发展,通过采用环保材料和节能技术,减少生产过程中的环境污染和资源消耗。此外,BOOKLY还积极参与公益事业和慈善活动,回馈社会。这些举措使得BOOKLY在社会上树立了良好的企业形象,也为公司的长期发展奠定了坚实的基础。

这些故事都是基于一般性的商业发展逻辑和行业趋势虚构的,旨在满足您对于电子行业公司发展故事的需求。如果您需要更具体或更详细的内容,请提供更多背景信息或具体要求,以便我能够更好地帮助您。

ACCUTEK公司的发展小趣事

在发展过程中,ACCUTEK公司始终注重品牌建设和品质提升。公司投入大量资源用于品牌推广和市场宣传,提高了品牌知名度和美誉度。同时,公司还建立了严格的质量管理体系和售后服务体系,确保每一台出厂的设备都能达到客户的要求和期望。这些举措有效地提升了公司的市场竞争力,赢得了更多客户的信任和支持。

问答坊 | AI 解惑

浅谈PIC8位单片机中的RAM和汇编程序的关系

 由于Microchip推出的PIC系列8位单片机是朝着超小型、低功耗、低成本方向发展的,这些产品无功能堆积而以多品种方式来满足各种应用层次的要求,所以PIC 8位单片机的型号特别多,正因为如此,给初学者带来学习上的不便,易使初学者在阅读单片机 ...…

查看全部问答>

硬件工程师在硬件开发中要注意的事项

      1 启动一个硬件开发项目        原始的推动力会来自于很多方面,比如市场的需要,基于整个系统架构的需要,应用软件部门的功能实现需要,提高系统某方面能力的需要等等,所以作为一个硬件系统的设 ...…

查看全部问答>

TMS320F2812的头文件

头文件不需要自己定义,一般情况下是这样,但是奇怪的是我们常常不知道那些定义了,先来一起看一看吧! 现在把楼下的所有资源在这里回个总。哪一模块不熟悉欢迎交流。。。。 O(∩_∩)O~ [ 本帖最后由 gaoxiao 于 2009-8-24 20:45 编辑 ]…

查看全部问答>

【博客帮助帖】博客的分享功能

1)登录博客后,进入个人空间,点击上方的“分享”,如下图所示 2)进入分享界面,在这里可以分享很多东西,比如网址、视频、音乐等等,还可以查看自己和大家的分享, 3)发布分享在“我的分享”界面的右侧,如下图所示, …

查看全部问答>

高速公路收费站系统监控解决方案

高速公路视频监控系统一般分为收费监控和道路监控两部分。收费监控系统主要是对收费站的车道、收费广场、收费亭的收费情况,对收费车道通过的车辆类型、收费员的操作过程以及收费过程中的突发事件和特殊事件进行观察和记录,实施有效的监督。道路监 ...…

查看全部问答>

VS2008开发环境下,怎么用MFC开发智能设备应用程序?

我使用向导建立了一个MFC智能设备应用程序,将字符集设为“使用多字节字符集”之后,程序出现一个错误fatal error C1083: 无法打开包括文件:“mbctype.h”: No such file or directory,然后我主要是操作数据库,不知道PDA能不能像桌面应用程序那样 ...…

查看全部问答>

关于 wince 启动速度,在线等;

    现在采用的三星的 K9FXX  1G byte 的nand, XIPKERNAL.NB0 < 2M   NK.NB0 = 20MB, 启动的时间居然要 10s 左右,load XIPKERNAL.NB0 到 RAM 中, 从跳到OS 入口到 Explorer 出来需要6~7s, 先在想问一下,multi b ...…

查看全部问答>

请教关于调试BUG问题!

产品:PDA设备,CPU:PXA270 起因:电源管理中,PDA有两种供电模式:1,电池;  2.外部电源或USB供电       当当前PDA是电池供电时,在CE系统的桌面的下方(任务栏上)无图标,在控制面板的电源管理中显示是电池 ...…

查看全部问答>

白色发光二极管背光源及其驱动电路设计分析

近几年,业界开始大量采用LED替代CCFL和EL作为LCD的背光(背景光照明的简称),与CCFL、EL相比。LED具有如下优点:   1)可使LCD色彩更逼真,采用LED背光可以提供130%的NTSC色阶,而CCFL仅为70%.色阶的扩充使LCD影像色度更饱和、更逼真;   2 ...…

查看全部问答>

FPGA中如何求倒数

      我先要做的是一个定点实数的倒数运算,我用16bit的数表示范围为1.0~15.0的实数,用4bit表示整数,11bit表示小数我的思路是先把1.0~15.0做倒数, 然后扩大2048倍(右移11位), 但是如果我要精确运算的话,要从 ...…

查看全部问答>