DMA数据转运&DMA+AD多通道----DMA直接存储器存取

定义一个变量在OLED显示屏上看到是0x2000开头的说明早SRAM上;在变量前加上const使其变成常量再查看地址以0x8000开头说明在Flash上,如果有一块不需要更改的数据较大的内容可以将它存储在Flash中以节省SRAM空间。

对于外设寄存器它们的地址是固定的:先查寄存器所在外设的起始地址(第二章存储器映像),然后在外设的寄存器总表查偏移。结果是起始地址+偏移。

定义一个外设结构体。如果指定这个结构体起始地址就是ADC1外设寄存器起始地址,那么结构体内存就会和外设寄存器内存完美映射,所以访问结构体某个成员变量相当于访问这个外设的某个寄存器

ADC1->DR   ADC1是结构体指针,指向的是ADC1外设的起始地址,访问结构体成员就相当于加一个偏移,起始地址加偏移就是指定的寄存器。


DMA数据转运

#include "stm32f10x.h"                  // Device header
uint16_t MyDMA_Size;

void MyDMA_Init(uint32_t ADDRA,uint32_t ADDRB,uint16_t size)
{
	MyDMA_Size=size;
	//DMA是AHB总线的设备,所以要用AHB开启时钟的函数。
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr=ADDRA;
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	//外设自增
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;
	DMA_InitStruct.DMA_MemoryBaseAddr=ADDRB;
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	//存储器自增
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_BufferSize=size;
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
	//软件触发
	DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;
	DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
	
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
    DMA_Cmd(DMA1_Channel1,ENABLE);
	DMA_Cmd(DMA1_Channel1,DISABLE);
}
//上述代码是初始化后立刻转运,转运一次DMA就停止,
//调用一次这个函数就启动一次DMA转运
void MyDMA_Transfer(void)
{
	//设置传输计数器值,先失能再使能
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	//等待转运完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	//清除标志位
	DMA_ClearFlag(DMA1_FLAG_TC1);
	
}

主函数 

uint8_t DataA[]={0x01,0x02,0x03,0x04};
uint8_t DataB[]={0,0,0,0};

int main(void)
{
	OLED_Init();
	
	MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);
	OLED_ShowString(1,1,"DataA");
	OLED_ShowString(3,1,"DataB");
	
	OLED_ShowHexNum(1,8,(uint32_t)DataA,8);
	OLED_ShowHexNum(3,8,(uint32_t)DataB,8);

	while(1)
	{

		DataA[0]++;
		DataA[1]++;
		DataA[2]++;
		DataA[3]++;
		OLED_ShowHexNum(2,1,DataA[0],2);
		OLED_ShowHexNum(2,4,DataA[1],2);
		OLED_ShowHexNum(2,7,DataA[2],2);
		OLED_ShowHexNum(2,10,DataA[3],2);
		OLED_ShowHexNum(4,1,DataB[0],2);
		OLED_ShowHexNum(4,4,DataB[1],2);
		OLED_ShowHexNum(4,7,DataB[2],2);
		OLED_ShowHexNum(4,10,DataB[3],2);
		
		Delay_ms(1000);
		//在while里,手动调用转运,调用一次转运一次
		MyDMA_Transfer();
		
		OLED_ShowHexNum(2,1,DataA[0],2);
		OLED_ShowHexNum(2,4,DataA[1],2);
		OLED_ShowHexNum(2,7,DataA[2],2);
		OLED_ShowHexNum(2,10,DataA[3],2);
		OLED_ShowHexNum(4,1,DataB[0],2);
		OLED_ShowHexNum(4,4,DataB[1],2);
		OLED_ShowHexNum(4,7,DataB[2],2);
		OLED_ShowHexNum(4,10,DataB[3],2);
		
	}
} 

DMA+AD多通道

被注释掉的是单次模式

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4];
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);  //12MHZ
	
	GPIO_InitTypeDef GPIO_Init_Structure;
	//配置为模拟输入模式
	GPIO_Init_Structure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_Init_Structure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_Init_Structure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Init_Structure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);  //55.5+12.5=68
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);  //55.5+12.5=68
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);  //55.5+12.5=68
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);  //55.5+12.5=68

	ADC_InitTypeDef ADC_InitStruct;
//	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE; //单次模式 
	ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续模式  是否连续扫描

	ADC_InitStruct.ADC_ScanConvMode=ENABLE;
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=4;  //四个位置
	ADC_Init(ADC1,&ADC_InitStruct);
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;   //4001244C
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;  //低16位ADC1,高16ADC2
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设是否自增
	DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)AD_Value;
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//
	DMA_InitStruct.DMA_BufferSize=4;
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
	DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;   //不使用软件触发
//	DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;//循环模式:传输计数器自动重装
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
	//ADC1的硬件触发只接在了DMA的通道1,看DMA请求映像图
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	//开启ADC到DMA的输出,也就是DMA请求映像图中外设请求信号
	ADC_DMACmd(ADC1,ENABLE);

	//使能啦
	ADC_Cmd(ADC1,ENABLE);
	
	//复位校准
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET); //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1) == SET);
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//连续模式:把ADC触发直接放在初始化的最后一行,AD_GetValue不需要
}
/**
  * @brief ADC开始转换,连续扫描4个通道,DMA也同步进行转运 
  * @param  
  * @retval 
  */
//void AD_GetValue(void)
//{
//	//单次模式 需要软件触发ADC开始
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
//	
//	DMA_Cmd(DMA1_Channel1,DISABLE);
//	DMA_SetCurrDataCounter(DMA1_Channel1,4);
//	DMA_Cmd(DMA1_Channel1,ENABLE);

//	//转运在转换之后
//	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
//	DMA_ClearFlag(DMA1_FLAG_TC1);

//}

主函数显示传感器的变化 


int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"AD0:");//电位器
	OLED_ShowString(2,1,"AD1:");//红外传感
	OLED_ShowString(3,1,"AD2:");//温度传感
	OLED_ShowString(4,1,"AD3:");//对射式红外传感

	while(1)
	{
		
		OLED_ShowNum(1,5,AD_Value[0],4);
		OLED_ShowNum(2,5,AD_Value[1],4);
		OLED_ShowNum(3,5,AD_Value[2],4);
		OLED_ShowNum(4,5,AD_Value[3],4);
		
		Delay_ms(1000);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值