一般情况下进行信号的捕获,如上升沿或者下降沿。均可采用外部触发进行捕获。这是基于信号比较稳定的情况,如信号出现较大的纹波或者易受到干扰。会出现“误触”的现象,此时用外部中断难以捕获到正确的信号。
这种情况的解决办法,可以采用以下办法:
(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; //清除标志位
}