STM32----ADC进行信号(跳变沿、PWM)的捕获

      一般情况下进行信号的捕获,如上升沿或者下降沿。均可采用外部触发进行捕获。这是基于信号比较稳定的情况,如信号出现较大的纹波或者易受到干扰。会出现“误触”的现象,此时用外部中断难以捕获到正确的信号。

       这种情况的解决办法,可以采用以下办法:

(1)使用定时器进行捕获,并开启定时器的滤波功能。在库函数结构体中,为:

        TIM_ICInitStruct.TIM_ICFilter = 0x0f;(滤波系数可填0x00~0x0f)

        当系数开到最大(0x0f)可有效过滤大部分纹波以及干扰信号,但对于持续时间较长的干扰无法过滤。

(2)使用ADC模拟看门狗功能。

        比如当前信号为高电平,触发信号为下降沿,存在着一定的纹波以及偶发的干扰如图:

        

        这种信号,采用第一种方法并不能很好地捕获。但如果使用ADC模拟看门狗功能则能很好地识别。方法如下:

   (1)初始化看门狗触发阈值为低电平触发。假设触发信号的电平为0.2V,干扰信号最低达到0.6V。设置看门狗阈值为:0.4V~3.3V(STM32F1供电3.3V),此时0.4V~3.3V的信号不会触发看门狗中断,但0.2V(触发信号)可成功触发中断。达到了过滤干扰信号的目的。

   (2)当触发信号触发模拟看门狗中断后,处理完触发信号的程序后,更改看门狗触发阈值为高电平状态。如0V~2V。目的是防止触发信号时间过长,频繁进入看门狗中断。当触发信号恢复高电平状态,因为已经设置了看门狗中断为高电平触发,此时会进入一次中断。中断中只需要将看门狗触发阈值改为低电平触发,即可等待下一次的触发信号。

 

具体实现代码如下:

void  ADC2_AWGZcpInit(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	ADC_InitTypeDef  ADC_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;

	/*********************初始化ADC GPIO********************/
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
	 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	 GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	/**********************ADC2 NVIC************************/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	 NVIC_InitStruct.NVIC_IRQChannel = ADC1_2_IRQn;
	 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;

	 NVIC_Init(&NVIC_InitStruct);

	/************************初始化ADC2************************/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //72M/6 = 12M
	
	ADC_InitStruct.ADC_ContinuousConvMode = 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 = 1;
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;
	
	ADC_Init(ADC2,&ADC_InitStruct);
	
	ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 1, ADC_SampleTime_7Cycles5);
	
	/***************************ADC看门狗设置****************************/
    ADC_AnalogWatchdogThresholdsConfig(ADC2,ADC2_AEG[2],ADC2_AEG[3]);
	
    ADC_AnalogWatchdogSingleChannelConfig(ADC2, ADC_Channel_8);
	
	ADC_AnalogWatchdogCmd(ADC2,ADC_AnalogWatchdog_SingleRegEnable);
	
	/***************************ADC校准****************************/
	ADC_Cmd(ADC2, ENABLE);

    ADC_ResetCalibration(ADC2);
	while(ADC_GetResetCalibrationStatus(ADC2)&&(timeout--));
	
	ADC_StartCalibration(ADC2);
	while(ADC_GetCalibrationStatus(ADC2)&&(timeout--));	

	ADC_ITConfig(ADC2,ADC_IT_AWD, ENABLE);
	
	ADC_SoftwareStartConvCmd(ADC2, ENABLE);
}

u16 ADC2_AEG[5]={4095,250,3850,0,1};  //模拟看门狗阈值数组,第0、1元素为监测低电平触发信号阈值,2、3为高阈值  
void ADC1_2_IRQHandler(void)
{
	  ADC2_AEG[4] = !ADC2_AEG[4]*2;
	
	  ADC2->HTR = ADC2_AEG[0+ADC2_AEG[4]];  //更改ADC看门狗阈值
      ADC2->LTR = ADC2_AEG[1+ADC2_AEG[4]];
	
	  if(ADC2_AEG[4]<1)  //下降沿触发输出
     {
	    //code	
	 }
	  ADC2->SR &= 0xfffe;  //清除标志位	
}




猜你喜欢

转载自blog.csdn.net/a3748622/article/details/79565396