STM32F407VET6 双重ADC规则同步模式,定时器输出PWM波触发,DMA传输数据,显示波形

本设计基于2019电赛 电路特性测试仪一题,目的在于显示放大电路输入输出波形,保证不会出现失真,从而使电路的增益测量结果更加准确。
这里使用定时器TIM3输出PWM波触发ADC采样,根据需要采样的波形频率为1kHz设置合适的定时器的预分频系数以及自动重装载值。

STM32F4xx 通用定时器相关知识

STM32F4定时器系统包括,高级控制定时器 TIM1和 TIM8、通用定时器TIM2~TIM5、通用定时器TIM9 ~TIM14、基本定时器TIM6和TIM7。我们重点关注通用定时器的相关配置。

通用定时器TIM2~TIM5包含一个 16 位或 32 位自动重载计数器,该计数器由可编程预分频器驱动。它们可用于多种用途,包括测量输入信号的脉冲宽度(输入捕获)或生成输出波形(输出比较和 PWM)。使用定时器预分频器和 RCC 时钟控制器预分频器,可将脉冲宽度和波形周期从几微秒调制 到几毫秒。这些定时器彼此完全独立,不共享任何资源。

TIM3配置函数如下,注意GPIO复用,自动重装载值和分频系数的设置。定时器溢出时间Tout和重装载值arr以及预分频系数psc的关系如下:

  • Tout=((arr+1)*(psc+1))/TCLK
//初始化定时器
 void ADC12_TIM3_Mode_Config(void)
 {
	  GPIO_InitTypeDef     GPIO_InitStructure;
	  TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
		TIM_OCInitTypeDef         TIM_OCInitStructure;

	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  	//TIM3时钟使能    
	 // RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); 	//使能PORTC时钟	
	
	  GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3); //GPIOC6(USART)复用为定时器3
	
	 
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;           //GPIOC6
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;        //下拉
	  GPIO_Init(GPIOC,&GPIO_InitStructure);              //初始化PC6
	 
		TIM_TimeBaseStructure.TIM_Prescaler = 83;//psc=83
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
		TIM_TimeBaseStructure.TIM_Period =49;//arr=49
		TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
		TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

		 
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
		TIM_OCInitStructure.TIM_Pulse=25;//自动重装载值为49,占空比设置为50%,则这里应赋值25
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;       

		TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器
    TIM_ARRPreloadConfig(TIM3,ENABLE);//ARPE使能 

		TIM_Cmd(TIM3, ENABLE);


 }

DMA相关配置

在配置DMA时要注意以下几点

  1. 由于我们采用双重ADC模式采样,必须使用ADC1和ADC2,ADC1为主,ADC2为从,因此根据STM32F4xx中文参考手册中的DMA请求映射表
    在这里插入图片描述
    我们应选择ADC1对应的DMA2的通道0和数据流0。
  2. 由于我们采用的是双重ADC规则同步模式,ADC采集的数据并没有存储在ADC1的数据寄存器中,而是在ADC->CDR寄存器中,所以DMA传输的源地址要改写成ADC->CDR
  3. DMA目的地址为自己设定的数组ADC_ConvertedValue[]
  4. 另外,双重ADC 模式下,ADC1和2的数据都存储在同一个32位的寄存器中,低半字为ADC1的数据,高半字为ADC2的数据,所以要设置源和目的数据大小为一个字。
    DMA相关配置函数如下:
//初始化DMA2
void ADC12_DMA2_Mode_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);    //使能DMA2时钟
	
	//DMA是一种快速的数据传送方式
	while(DMA_GetCmdStatus(DMA2_Stream0)!=DISABLE);
	DMA_InitStructure.DMA_BufferSize=NUM;
	DMA_InitStructure.DMA_Channel=DMA_Channel_0;
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory; 
	DMA_InitStructure.DMA_Memory0BaseAddr=(u32)ADC_ConvertedValue;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_Word;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(ADC->CDR);
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
  
	
  //使能DMA通道2
  DMA_Cmd(DMA2_Stream0, ENABLE); 
}

ADC1和ADC2的配置

  1. ADC通用设置中要将模式设置为双重模式ADC_DualMode_RegSimult
  2. 注意ADC的时钟最好不要超过36Mhz,否则ADC采集的数据将会不理想。
  3. 要设置ADC1为定时器触发,ADC2要设置为软件触发,使用ADC_SoftwareStartConv(ADC2)函数实现。
  4. DMA设置为多重模式 ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE)
    配置函数如下:
/********************************
配置ADC1,ADC2和DMA,利用DMA来读取ADC采
集到的数据  
********************************/
 void ADC12_Mode_Config(void)
{
  
  ADC_InitTypeDef ADC_InitStructure;	
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//使能ADC1时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);	//使能ADC2时钟   
	
	ADC12_GPIO_Config();
	ADC12_DMA2_Mode_Config();
	ADC12_TIM3_Mode_Config();
	
  //ADC通用配置
	ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;//双重模式
  ADC_CommonInitStructure.ADC_TwoSamplingDelay =ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟 5 个时钟,影响不大
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2; //DMA 模式选择
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频 4 分频。
   //ADCCLK=PCLK2/4=84/4=21Mhz,ADC 时钟最好不要超过 36Mhz 
  ADC_CommonInit(&ADC_CommonInitStructure);//初始化
	
  //配置ADC1
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;               //使用12 位分辨率
  ADC_InitStructure.ADC_ScanConvMode =DISABLE;                         //非扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                  //只采集一次,等待下次触发
	ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;//上升沿触发
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_CC1;         //定时器触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //ADC数据右对齐方式
  ADC_InitStructure.ADC_NbrOfConversion = 1;                  // 用来设置规则序列的长度,我们只对一个ADC通道进行转换
  ADC_Init(ADC1, &ADC_InitStructure);
	ADC_Cmd(ADC1, ENABLE);                     //使能ADC1	 
	 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_84Cycles); //
 // ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);

  //ADC_DMACmd(ADC1, ENABLE);	                 //使能ADC1的DMA
	
    //配置ADC2
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;               //使用12 位分辨率
  ADC_InitStructure.ADC_ScanConvMode =DISABLE;                         //非扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                  //只采集一次,等待下次触发
	//ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;//上升沿触发
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConvEdge_None;         //从ADC不设置外部触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //ADC数据右对齐方式
  ADC_InitStructure.ADC_NbrOfConversion = 1;                  // 用来设置规则序列的长度,我们只对一个ADC通道进行转换
  ADC_Init(ADC2, &ADC_InitStructure);
	ADC_Cmd(ADC2, ENABLE);                     //使能ADC2

	ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_84Cycles); //
	 // ADC_DMARequestAfterLastTransferCmd(ADC2,ENABLE);
  //ADC_DMACmd(ADC2, ENABLE);	                 //使能ADC1的DMA 
		ADC_SoftwareStartConv(ADC2);
	ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

}

数据转换

将采集到的数据转化为两组数据,输入波形数据和输出波形数据

/******************************************************************
将采集到的数据转化为两组数据,输入数据和输出数据
*******************************************************************/
void zhuanhua(void)
{int i=0;
	for(i=0;i<2000;i++)
	{ ADC2_ConvertedValue[i]=(u16)((ADC_ConvertedValue[i]&0xFFFF0000)>>16);
		ADC1_ConvertedValue[i]=(u16)(ADC_ConvertedValue[i]&0xFFFF);
	}

}	
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值