使用 STM32 测量频率和占空比的几种方法
以前在本科时写的教程文章,主要是把自己当时参赛的方法拿出来做了个总结。
想当年天天水论坛好为人师,现在已经全面转向计算机视觉方向了,颇为感慨。不过,自己的理性选择,个中得失早就意料之中。塞翁失马,焉知非福?
原文链接:http://www.openedv.com/forum.php?mod=viewthread&tid=82594&extra=
【教程】使用STM32测量频率和占空比的几种方法(申请置酷!)
void Tim2_PWMIC_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;TIM_ICInitTypeDef TIM_ICInitStructure;/* TIM4 clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);/* GPIOB clock enable */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);/* TIM4 chennel2 configuration : PB.07 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Connect TIM pin to AF2 */GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4);/* Enable the TIM4 global Interrupt */NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICFilter = 0x0;TIM_PWMIConfig(TIM4, &TIM_ICInitStructure);/* Select the TIM4 Input Trigger: TI2FP2 */TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);/* Select the slave Mode: Reset Mode */TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);/* TIM enable counter */TIM_Cmd(TIM4, ENABLE);/* Enable the CC2 Interrupt Request */TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);}
//中断程序:
void TIM4_IRQHandler(void)
{/* Clear TIM4 Capture compare interrupt pending bit */TIM_ClearITPendingBit(TIM4, TIM_IT_CC1|TIM_IT_CC2);/* Get the Input Capture value */IC2Value = TIM_GetCapture2(TIM4);//周期if (IC2Value != 0){highval[filter_cnt]=TIM_GetCapture1(TIM4);//高电平周期waveval[filter_cnt]=IC2Value;filter_cnt++;if(filter_cnt>=FILTER_NUM)filter_cnt=0;}else{DutyCycle = 0;Frequency = 0;}
}
//主循环:while (1){uint32_t highsum=0,wavesum=0,dutysum=0,freqsum=0;LCD_Clear(0);for(i=0;i<FILTER_NUM;i++){highsum+=highval[i];wavesum+=waveval;}[/i] delay_ms(1);DutyCycle=highsum*1000/wavesum;Frequency=(SystemCoreClock/2*1000/wavesum);freq=Frequency*2.2118-47.05;//线性补偿sprintf(str,"DUTY:%3d\nFREQ:%.3f KHZ\n",DutyCycle,freq/1000);LCD_ShowString(0,200,str);delay_ms(100);}
//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);//初始化TIM5输入捕获参数TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波TIM_ICInit(TIM5, &TIM5_ICInitStructure);TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断 TIM_Cmd(TIM5,ENABLE ); //使能定时器5NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、}
//捕获状态(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
//定时器5中断服务程序
void TIM5_IRQHandler(void)
{ if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件{if(edge==RESET)//上升沿{rising=TIM5->CCR1-rising_last;rising_last=TIM5->CCR1;TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=0 设置为上升沿捕获edge=SET;}else{falling=TIM5->CCR1-rising_last;TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获edge=RESET;}}TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
主程序:while (1){uint32_t highsum=0,wavesum=0,dutysum=0,freqsum=0;LCD_Clear(0);delay_ms(1);sprintf(str,"rise:%3d\nfall:%d\nfall-rise:%d",rising,falling,falling-rising);LCD_ShowString(0,100,str);sprintf(str,"Freq:%.2f Hz\nDuty:%.3f\n",90000000.0/rising,(float)falling/(float)rising);//频率、占空比LCD_ShowString(0,200,str);delay_ms(100);}
注意的是,中断程序当中的变量rising,last因为多次修改的缘故,与名称本身含义有所区别,示意如下:
/TIM2_CH1->PA5
//TIM2_CH2->PB3
void TIM2_CH1_Cap_Init(u32 arr,u16 psc)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;TIM_ICInitTypeDef TIM_ICInitStructure;TIM_DeInit(TIM2);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM2时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //PA0复用位定时器5GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);//初始化TIM2输入捕获参数TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波TIM_ICInit(TIM2, &TIM_ICInitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 选择输入端 IC1映射到TI1上TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //上升沿捕获TIM_ICInit(TIM2, &TIM_ICInitStructure);TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
// TIM2_CH1_Cap_DMAInit();TIM_Cmd(TIM2,ENABLE ); //使能定时器5NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、}
//定时器2中断服务程序(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
void TIM2_IRQHandler(void)
{ if(TIM2->SR&TIM_FLAG_CC1)//TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件{rising=TIM2->CCR1-rising_last;rising_last=TIM2->CCR1;return;}if(TIM2->SR&TIM_FLAG_CC2)//TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET){falling=TIM2->CCR2-rising_last;return;}TIM2->SR=0;
}
这样,最高频率能够达到约1.1MHz,是一个不小的进步。但是,其根本问题——中断太频繁——仍然存在。
解决思路也是存在的。本质上,我们实际上只需要读取CCR1和CCR2寄存器。而在内存复制过程中,面对大数据量的转移时,我们会想到什么?显然,我们很容易想到——利用DMA。所以,我们使用输入捕获事件触发DMA来搬运寄存器而非触发中断即可,然后将这些数据存放在一个数组当中并循环刷新。这样,我们可以随时来查看数据并计算出频率。
这一方法我曾经尝试过,没有调出来,因为,有一个更好的方法存在。但是理论上这是没有问题的,以供参考我列出如下。
【注意:这段程序无法工作,仅供参考!!!】
//TIM2_CH1->DMA1_CHANNEL3_STREAM5
u32 val[FILTER_NUM]={0};
void TIM2_CH1_Cap_DMAInit(void)
{NVIC_InitTypeDef NVIC_InitStructure;DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 DMA_DeInit(DMA1_Stream5);while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){}//等待DMA可配置 /* 配置 DMA Stream */DMA_InitStructure.DMA_Channel = DMA_Channel_3; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM5->CCR1);//DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)val;//DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//存储器到外设模式DMA_InitStructure.DMA_BufferSize = FILTER_NUM;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输DMA_Init(DMA1_Stream5, &DMA_InitStructure);//初始化DMA StreamTIM_DMAConfig(TIM5,TIM_DMABase_CCR1,TIM_DMABurstLength_16Bytes);TIM_DMACmd(TIM5,TIM_DMA_CC1,ENABLE);//如果需要DMA中断则如下面所示NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; //使能TIM中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA1_Stream5,DMA_IT_TC,ENABLE); //开启DMA传输 DMA_Cmd(DMA1_Stream5, ENABLE);
}
void DMA1_Stream5_IRQHandler(void)
{DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_TCIF5);
}
因此,高频时仍然推荐以下方法。
思路四:使用外部时钟计数器
这种方法是我这几天回答问题时推荐的方法。思路是配置两个定时器,定时器a设置为外部时钟计数器模式,定时器b设置为定时器(比如50ms溢出一次,也可以用软件定时器),然后定时器b中断函数中统计定时器a在这段时间内的增量,简单计算即可。
代码:
//TIM7->100ms
//TIM2_CH2->PB3
void TIM_Cnt_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;TIM_DeInit(TIM2);TIM_DeInit(TIM7);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM7,ENABLE); //TIM2时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟
//IO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //下拉GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5
//TIM2配置TIM_TimeBaseStructure.TIM_Prescaler=0; //定时器分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_Period=0xFFFFFFFF; //自动重装载值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising,0);//外部时钟源
//TIM7 100ms TIM_TimeBaseStructure.TIM_Prescaler=18000-1; //定时器分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_Period=1000-1; //自动重装载值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure);
//中断NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);//允许更新中断 ,允许CC1IE捕获中断 TIM_Cmd(TIM7,ENABLE ); //使能定时器5TIM_Cmd(TIM2,ENABLE ); //使能定时器5
}
u32 TIM7_LastCnt;
//频率为TIM_ExtCntFreq
void TIM7_IRQHandler(void)
{char str[32];TIM_ExtCntFreq=(TIM2->CNT-TIM7_LastCnt)*(1/SAMPLE_PERIOD);// SAMPLE_PERIOD为采样周期0.1ssprintf(str,"%3.3f",TIM_ExtCntFreq/1000.0);//必须加这一句,莫明其妙TIM7_LastCnt=TIM2->CNT;TIM_ClearITPendingBit(TIM7,TIM_IT_Update);
}
当采样数n趋于无穷时,事件A的概率即趋近于统计的频率。所以,当采样数越大,则采样到的高电平占样本总数的频率即趋近于概率——占空比!
//ADC1-CH13-PC3
//DMA2-CH0-STREAM0#define ADCx ADC1#define ADC_CHANNEL ADC_Channel_13#define ADCx_CLK RCC_APB2Periph_ADC1#define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOC#define GPIO_PIN GPIO_Pin_3#define GPIO_PORT GPIOC#define DMA_CHANNELx DMA_Channel_0#define DMA_STREAMx DMA2_Stream0#define ADCx_DR_ADDRESS ((uint32_t)&(ADCx->DR))//((uint32_t)0x4001224C)
void ADC_DMAInit(void)
{ADC_InitTypeDef ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;DMA_InitTypeDef DMA_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable ADCx, DMA and GPIO clocks ****************************************/RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE); RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);/* DMA2 Stream0 channel2 configuration **************************************/DMA_InitStructure.DMA_Channel = DMA_CHANNELx; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS;DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&(ADC_DATAPOOL[0]);DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStructure.DMA_BufferSize = ADC_POOLSIZE;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA_STREAMx, &DMA_InitStructure);DMA_Cmd(DMA_STREAMx, ENABLE);/* Configure ADC3 Channel7 pin as analog input ******************************/GPIO_InitStructure.GPIO_Pin = GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIO_PORT, &GPIO_InitStructure);/* ADC Common Init **********************************************************/ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;ADC_CommonInit(&ADC_CommonInitStructure);/* ADC3 Init ****************************************************************/ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 1;ADC_Init(ADCx, &ADC_InitStructure);/* ADC3 regular channel7 configuration **************************************/ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_480Cycles);/* Enable DMA request after last transfer (Single-ADC mode) */ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);/* Enable ADC3 DMA */ADC_DMACmd(ADCx, ENABLE);/* Enable ADC3 */ADC_Cmd(ADCx, ENABLE);
}
主程序:for(j=0;j<ADC_POOLSIZE;j++){if(ADC_DATAPOOL[j]>0x01)posicnt++;}duty=100*posicnt/(float)(ADC_POOLSIZE)+0.1f;//线性补偿
使用 STM32 测量频率和占空比的几种方法相关推荐
- 测量频率和占空比的几种方法
转:https://blog.csdn.net/yyx112358/article/details/78414594 想当年天天水论坛好为人师,现在已经全面转向计算机视觉方向了,颇为感慨.不过,自己的 ...
- STM32测量频率、占空比
等精度测量频率 常用的频率测量方法有直接测频法,测周期法和等精度测频法. 直接测频法是由时基信号产生闸门,对被测信号进行计数,此法只适合测高频信号.测周期法是由被测信号产生闸门,对时基脉冲进行计数,此 ...
- STM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)
STM32延时函数的三种方法:普通延时.SysTick 定时器延时(1.中断方式:2.非中断方式) 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ ...
- STM32 LED灯的另一种写法
STM32 LED灯的另一种写法 #ifndef __BSP_LED_ #define __BSP_LED_#include <MM32x103.h> // 这个换成STM32的库文件就行 ...
- stm32 lwip 如何发送不出_mbedtls | 移植mbedtls库到STM32裸机的两种方法
一.mbedtls 开源库 1. mbedtls是什么 Mbed TLS是一个开源.可移植.易于使用.代码可读性高的SSL库.可实现加密原语,X.509证书操作以及SSL / TLS和 DTLS 协议 ...
- GD32F303固件库开发(13)----定时器TIM捕获PWM测量频率与占空比
GD32F303固件库开发.13----定时器TIM捕获PWM测量频率与占空比 概述 视频教学 csdn课程 样品申请 生成例程 keil配置 使能串口 串口重定向 占空比与频率计算 GPIO初始化 ...
- STM32 最小系统中的4种电路
STM32 最小系统中的4种电路 单片机最小系统是指用最少的电路组成单片机可以工作的系统,通常最小系统包含:电源电路.时钟电路.复位电路.调试/下载电路,对于STM32还需要启动选择电路. 1. 电源 ...
- Arduino产生PWM的3种方法
Arduino产生PWM的3种方法! PWM是个啥? 有人翻译成:脉冲宽度调制 PWM 是用占空比不同的方波 ...
- 本地html自动跳转,HTML页面跳转的5种方法
下面列了五个例子来详细说明,这几个例子的主要功能是:在5秒后,自动跳转到同目录下的hello.html(根据自己需要自行修改)文件. 1) html的实现 优点:简单 缺点:Struts Tiles中 ...
最新文章
- SpringMVC中过滤器和拦截器的区别
- 获取地址栏URL中参数, getQuerySting()方法
- 工作群里常见表情的真正含义……
- 架构师:我们需要顶层设计
- 在raspbian上配置apache2/subversion/xdebug及mysql远程访问
- vs python opencv配置_OPENCV入门教程二:opencv+VS2015开发环境配置
- 【MySQL】ODBC数据源配置
- xposed框架 微信群发源码
- Go语言核心:Go的基本结构
- thinkpad t570更换内存条教程
- python 时间序列预测——NARX循环神经网络
- ssm基于BS架构的校园爱心捐赠与物品交换平台的设计与实现毕业设计源码
- Error using symconvertChar (sym使用报错)
- 【NOI2005】 月下柠檬树
- docker入门(镜像)
- 短信猫数据库中间件二次开发使用说明
- /proc/self/environ等敏感文件
- python链表详细教程_详细介绍python数据结构之链表
- Linux下parted分区超过2TB硬盘-分区格式化
- 【Linux】Linux系统调用
热门文章
- 【Android QR Code】开源项目:ZXing(三)二维码解码
- 双控专业就业机器人_东北大学自动化双控考研专业就业方向
- 衡阳南华学校计算机,热烈祝贺计算机学院在第八届衡阳市大学生科技创新大赛南华大学初赛中取得优异成绩...
- Unity景深效果解析
- 十万部冷知识:“沙特”为什么能赢“阿根廷”
- 精益质量管理简析(转载)
- 【网络经济与企业管理】选择题,错题
- 4k显示器用html好还是dp,4k显示器用hdmi还是dp
- docker挂载mysql会失败_Docker Mysql 挂载 /var/lib/mysql 后无法启动
- “COMSOL 多场耦合仿真技术与应用”光电专题培训