当前位置: 首页 > wzjs >正文

网站开发技术发展历程推广资源整合平台

网站开发技术发展历程,推广资源整合平台,免费公司网站设计,厦门公司注册名称查询系统目录 前言 ​编辑 技术实现 接线图 代码实现 技术要点 DMA时钟 DMA初始化 DMA数据传输设置 数据改变与显示 实验结果 问题记录 前言 DMA(Direct Memory Access)直接存储器存取,用来提供在外设和存储器 之间或者存储器和存储器之间的高速数据传输。无需…

目录

前言

​编辑 技术实现

接线图

代码实现 

技术要点 

DMA时钟

DMA初始化

DMA数据传输设置

数据改变与显示

实验结果

问题记录


前言

DMA(Direct Memory Access)直接存储器存取,用来提供在外设和存储器 之间或者存储器和存储器之间的高速数据传输。无需CPU干预,数据可以通过DMA快速地移动,这样可以节省CPU的资源进行其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自与一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

DMA的主要特性

  • 12个独立的可配置的通道(请求):DMA1有7个 通道,DMA2有5个通道
  • 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  • 在同一个DMA模块上多个请求见的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先与请求1,以此类推)。
  • 独立数据源和目标数据区的传输字节宽度(字节、半字、字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
  • 支持循环的缓冲器管理
  • 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这三个事件标志逻辑或成为一个单独的中断请求。
  • 存储器和存储器之间的传输。
  • 外设和存储器、存储器和外设之间的传输。
  • Flash、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。
  • 可编程的数据传输数目。

 技术实现

接线图

代码实现 

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"						//延时函数
#include "OLED.h"
#include "My_DMA.h"uint8_t Dat_A[] = {0x01,0x02,0x03,0x04};
uint8_t Dat_B[] = {0,0,0,0};int main(void)
{/*OLED初始化*/OLED_Init();/*DMA初始化*/MyDMA_Init((uint32_t)Dat_A,(uint32_t)Dat_B,4);OLED_ShowString(1,1,"Dat_A");OLED_ShowHexNum(1,8,(uint32_t)Dat_A,8);									//显示Dat_A数组的地址(存放在SRAM)OLED_ShowString(3,1,"Dat_B");OLED_ShowHexNum(3,8,(uint32_t)Dat_B,8);									//显示Dat_B数组的地址(存放在SRAM)/*显示初始的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);while(1){/*源数据自增*/Dat_A[0]++;Dat_A[1]++;Dat_A[2]++;Dat_A[3]++;/*显示转运前的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);/*启动DMA转运*/MyDMA_Transfer();/*显示转运后的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);}
}

 My_DMA.h

#ifndef MY_DMA_H
#define MY_DMA_H#include "stm32f10x.h"void MyDMA_Init(uint32_t Addr_A, uint32_t Addr_B,uint16_t Size);
void MyDMA_Transfer(void);#endif

 My_DMA.c

#include "My_DMA.h"uint16_t MyDMA_Size = 8;/** * @brief  初始化DMA* @param  用于指定源数据和目标存储器的地址以及缓冲区大小*          @arg Addr_A 源数据地址*			 @arg Addr_B 目标存储器地址*          @arg Size   缓冲区大小* @retval None
**/
void MyDMA_Init(uint32_t Addr_A, uint32_t Addr_B,uint16_t Size)
{MyDMA_Size = Size;//开启DMA时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//初始化DMA DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_BufferSize			= Size;							//缓冲区的大小,由于CNDTR寄存器的高16位保留,这里缓冲区大小的变量的大小使用//uint16_t即可DMA_InitStruct.DMA_DIR  				= DMA_DIR_PeripheralSRC; 		//外设站点是数据源DMA_InitStruct.DMA_MemoryBaseAddr 		= Addr_B;						//存储器站点的基地址DMA_InitStruct.DMA_MemoryDataSize		= DMA_MemoryDataSize_Byte;		//接收的数据以字节形式传输DMA_InitStruct.DMA_Mode					= DMA_Mode_Normal;				//DAM传输计数器不使用自动重装模式DMA_InitStruct.DMA_M2M					= DMA_M2M_Enable;				//DMA为存储器到存储器传输的方式DMA_InitStruct.DMA_MemoryInc			= DMA_MemoryInc_Enable;			//存储器站点自增DMA_InitStruct.DMA_PeripheralInc		= DMA_PeripheralInc_Enable;		//外设站点自增DMA_InitStruct.DMA_PeripheralBaseAddr 	= Addr_A;						//要传输的数据的基地址DMA_InitStruct.DMA_PeripheralDataSize	= DMA_PeripheralDataSize_Byte;	//传输数组中的数据以字节形式传输DMA_InitStruct.DMA_Priority				= DMA_Priority_VeryHigh;		//只有一个通道,DMA优先级随便选DMA_Init(DMA1_Channel1,&DMA_InitStruct);								//使用软件触发,通道可以任意选择DMA_Cmd(DMA1_Channel1,DISABLE);
}/** * @brief  DMA传输函数* @param  None* @retval None
**/
void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);											//DMA失能DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);												//传输计数器赋值DMA_Cmd(DMA1_Channel1,ENABLE);	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);						//等待DMA转运完成DMA_ClearFlag(DMA1_FLAG_TC1);
}

 OLED部分代码参照文章《STM32基础教程——OLED显示》http://【STM32基础教程 ——OLED显示 - CSDN App】https://blog.csdn.net/2301_80319641/article/details/145837521?sharetype=blog&shareId=145837521&sharerefer=APP&sharesource=2301_80319641&sharefrom=link

技术要点 

DMA时钟

//开启DMA时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

        由图可知DMA隶属于AHB外设, 故应调用RCC_AHBPeriphClockCmd()函数开启AHB外设时钟。

DMA初始化

//初始化DMA DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_BufferSize			= Size;							//缓冲区的大小,由于CNDTR寄存器的高16位保留,这里缓冲区大小的变量的大小使用//uint16_t即可DMA_InitStruct.DMA_DIR  				= DMA_DIR_PeripheralSRC; 		//这里是将一个数组中的数据转运到另一个数组,是存储器(片上SRAM)到存储器(片上SRAM),这里用不到外设,值可以设置为默认值DMA_InitStruct.DMA_MemoryBaseAddr 		= Addr_B;						//存储器站点的基地址DMA_InitStruct.DMA_MemoryDataSize		= DMA_MemoryDataSize_Byte;		//接收的数据以字节形式传输DMA_InitStruct.DMA_Mode					= DMA_Mode_Normal;				//DAM传输计数器不使用自动重装模式DMA_InitStruct.DMA_M2M					= DMA_M2M_Enable;				//DMA为存储器到存储器传输的方式DMA_InitStruct.DMA_MemoryInc			= DMA_MemoryInc_Enable;			//存储器站点自增DMA_InitStruct.DMA_PeripheralInc		= DMA_PeripheralInc_Enable;		//外设站点自增DMA_InitStruct.DMA_PeripheralBaseAddr 	= Addr_A;						//要传输的数据的基地址DMA_InitStruct.DMA_PeripheralDataSize	= DMA_PeripheralDataSize_Byte;	//传输数组中的数据以字节形式传输DMA_InitStruct.DMA_Priority				= DMA_Priority_VeryHigh;		//只有一个通道,DMA优先级随便选DMA_Init(DMA1_Channel1,&DMA_InitStruct);								//使用软件触发,通道可以任意选择

        DMA的每个通道都可以在有固定地址的外设寄存器和存储器地址之间执行DMA传输,DMA数据是可编程的,最大达到65536,由DMA_CNDTR寄存器控制,该寄存器只启用低16位,这个寄存器只能在不工作(DMA_CCRx的EN=0)时写入。通道开启后该寄存器变为只读,指示剩余的带传输字节数目,数据项数量寄存器,在每次传输后递减。数据传输结束后,寄存器的内容或者变为0,或者当该通道配置为自动重加载模式时,寄存器的内容被自动重新加载为之前配置时的数值。当寄存器的内容为0时,无论通道是否开启,都不会发生任何数据传输。

       由于本实验是将一个数组中的数据转移到另外一个数组,初始化结构成员DMA_M2M设置为DMA_M2M_Enable,即DMA数据转运为存储器到存储器,后续DIR成员设置数据读取的方向,将数组Dat_A[]数组赋给外设基地址(此时外设只是一个标号,实际为存储器,因为将DMA_CCR寄存器的MEM2MEM位置1了,使能了存储器到存储器模式),将Dat_B[]数组地址赋给存储器基地址。在数据传输过程中外设和存储器的数据宽度均设为字节长度。DMA数据传输寄存器不使用自动重装模式,即完成一次DMA转换后即停止,实验中使用手动开启DMA转换。

        数据缓冲区的大小设置为了4,要传输4组数据,两个数据站点均要自增,不然接收数据的存储器不自增则数据会遭到覆盖,最终数据为最后传输的数据。若数据源的存储器站点不自增,则发送的数据为重复的数据。

DMA_Cmd(DMA1_Channel1,DISABLE);

DMA失能,后续使用单独函数设置DMA传输计数器并使能DMA。

DMA数据传输设置

/** * @brief  DMA传输函数* @param  None* @retval None
**/
void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);											//DMA失能DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);												//传输计数器赋值DMA_Cmd(DMA1_Channel1,ENABLE);	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);						//等待DMA转运完成DMA_ClearFlag(DMA1_FLAG_TC1);
}

失能DMA,设置数据传输计数器的大小然后使能DMA,启动DMA数据转换,DMA数据转换完成后,硬件会自动将DMA_ISR寄存器的TCIF位置1,while循环等待DMA数据转换的完成,数据转换完成后清除标志位。

数据改变与显示

/*DMA初始化*/MyDMA_Init((uint32_t)Dat_A,(uint32_t)Dat_B,4);OLED_ShowString(1,1,"Dat_A");OLED_ShowHexNum(1,8,(uint32_t)Dat_A,8);									//显示Dat_A数组的地址(存放在SRAM)OLED_ShowString(3,1,"Dat_B");OLED_ShowHexNum(3,8,(uint32_t)Dat_B,8);									//显示Dat_B数组的地址(存放在SRAM)/*显示初始的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);while(1){/*源数据自增*/Dat_A[0]++;Dat_A[1]++;Dat_A[2]++;Dat_A[3]++;/*显示转运前的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);/*启动DMA转运*/MyDMA_Transfer();/*显示转运后的数据*/OLED_ShowHexNum(2,1,Dat_A[0],2);OLED_ShowHexNum(2,5,Dat_A[1],2);OLED_ShowHexNum(2,9,Dat_A[2],2);OLED_ShowHexNum(2,13,Dat_A[3],2);OLED_ShowHexNum(4,1,Dat_B[0],2);OLED_ShowHexNum(4,5,Dat_B[1],2);OLED_ShowHexNum(4,9,Dat_B[2],2);OLED_ShowHexNum(4,13,Dat_B[3],2);Delay_ms(1000);}

先初始化DMA,在OLED第一行一列显示Dat_A,其后显示数组的地址。在第三行第三列显示Dat_B,其后紧跟该数组的地址。

然后在第二行和第四行分别显示数组A和数组B的初始数据,延时1000ms,防止变化过快人眼观察不到。进入死循环后,先递增数组原始数据,然后在转运前显示修改后的数据,然后启动DMA转换,再显示经DMA转换后的数据,以此流程循环显示。

uint16_t MyDMA_Size = 8;

设置公共变量MyDMA_Size用于指定DMA数据传输计数器的大小,默认值为8(在不影响程序运行的情况下随意设置,但最大值不应超过65536)。

void MyDMA_Init(uint32_t Addr_A, uint32_t Addr_B,uint16_t Size)
{MyDMA_Size = Size;

 进入初始化函数之后将缓冲区的大小传递给它,两种并无直接关联,这里只是方便设置。

void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);											//DMA失能DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);						//传输计数器赋值

 在MyDMA_Transfer()函数中MyDMA_Size用于传递数据传输计数器的大小。

实验结果

DMA

问题记录

暂无

http://www.dtcms.com/wzjs/264109.html

相关文章:

  • 公司网站未备案吗新手做网络销售难吗
  • 苏州网站建设规划线上营销渠道
  • 可以做来电名片的网站启动互联全网营销推广
  • 行业b2b网站今天发生的新闻
  • 政府门户网站建设问卷调查武汉千锋教育培训机构怎么样
  • 沈阳网站建设的公司seo优化工作怎么样
  • 北京企业网站案例最新新闻国内大事件
  • 建设积分兑换官方网站百度推广
  • 专业网站建设出售成品网站1688入口的功能介绍
  • 给你一个网站你怎么做seo外链要做些什么
  • 网页制作教学设计搜seo
  • 在网站建设中要注意的问题代发新闻稿最大平台
  • 专门做招商的网站是什么苏州百度推广代理商
  • 好的产品设计网站南阳seo
  • 网站建设深圳给原码手机怎么建自己的网站
  • 网站建设丨找王科杰上词快怎么可以让百度快速收录视频
  • 施工企业资质查询官网网站推广优化价格
  • 网站设计规划国外独立网站如何建站
  • 建网站能在家里做吗营销网站系统
  • 温州做网站最好的百度首页入口
  • 网站发帖做业务seo可以提升企业网站的
  • 网站建设文化咨询企排排官网
  • 网站建设的价位百度一下就知道官方
  • 个人 做自媒体 建网站系统优化的例子
  • 江西智能网站建设线上推广营销
  • 北京做网站多少钱aso是什么意思
  • 帝国系统怎样做网站地图上海公司网站seo
  • 淘宝官方网站登录页面seo如何提高网站排名
  • 做喷绘的图在哪个网站找免费发布外链
  • 网站建设绵阳辉煌电商北京百度seo服务