前言
本文是基于嵌入式开发板CT117E,stm32f103RBT6。"空手套白狼"就是直接利用官方给的库(v3.5),进行拷贝修改形成可以正常运行的代码。
一、芯片手册
二、PWM捕获原理
- 捕获模式我这里使用的是定时器2,通道2,也就是PA1,捕获的基本编程思路:首先需要捕获两个变量,第一个是高电平的时间,和整个周期时间。
- 这里先设置高电平触发,也就是说遇到高电平就触发中断,触发中断后我们需要在中断里面搞一个小顺序捕获,就是先捕获高电平的时间,再捕获整个周期的时间,我们在第一次中断里面把CNT寄存器清0,把我们的两个变量清0,然后设置为下降沿触发,一遇到下降沿就触发中断,这时候获取CNT寄存器的值就是高电平的时间,然后我们再重新设置为上升沿触发,然后等待下次中断,中断来的时候,捕获到CNT寄存器的值就是整个pwm波的周期。
三、定时器2初始化
- 捕获模式需要初始化4个结构体,分别是gpio,中断控制器,基本配置TIM_TimeBaseStructure,捕获配置结构体TIM_ICInitStructure,开启2个时钟使能;
- 除了基本配置TIM_TimeBaseStructure,其他都可以在TIM\InputCapture里面复制稍加修改就行;TIM_TimeBaseStructure的配置无非就是之前输出比较那样子的正常配置。
STM32固件库代码V3.5版\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\OCToggle\main.c
STM32固件库代码V3.5版\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\InputCapture\main.c 和 stm32f10xx_it.c
u32 ch1_val,ch1_duty;//全局变量,供主函数调用,解析频率和占空比
u8 ch1_mode=0;
void tim2_capture_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* TIM3 channel 2 pin (PA.07) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
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_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
}
四、定时器2捕获pwm
- 中断的编写:复制TIM\InputCapture里的stm32f10xx_it.c里面的定时器3中断,改为2,开头的判断中断通道和清除标志都一样,其他内容我们需要直接编写,按照前面的思路进行编写;
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
switch(ch1_mode) //判断当前的顺序,发生中断进来按我们想要顺序执行
{
case 0: //第一次进来中断
ch1_val=0; //频率值清0
ch1_duty=0; //占空比清0
TIM_SetCounter(TIM2,0); //cnt清0
TIM_OC2PolarityConfig(TIM2,TIM_OCPolarity_Low); //触发中断的极性改为低电平
ch1_mode=1; //顺序变为1
break;
case 1: ch1_duty=TIM_GetCounter (TIM2); //获取计数值,该值就是高电平的时间
TIM_OC2PolarityConfig(TIM2,TIM_OCPolarity_High); //再次改变中断触发的极性
ch1_mode=2; //顺序变为2
break;
case 2: ch1_val=TIM_GetCounter (TIM2); //获取计时值,该值就是高电平时间加低电平时间,也就是说整个周期的时间
TIM_OC2PolarityConfig(TIM2,TIM_OCPolarity_High);
ch1_mode=3; //捕获成功,告诉主函数,进行数据解析
break;
default:break;
}
}
}
五、在主函数中的应用方法
tim3_pwm_init(); //产生pwm初始化
set_pwm(1000,50,100,20); //产生频率为1000HZ,占空比为50%,频率为100HZ,占空比为20的两路pwm波
tim2_capture_init(); //捕获初始化
while(1)
{
if(ch1_mode==3) //捕获结束标志,进行数据处理
{
sprintf((char *)buff,"val: %d w ",1000000/ch1_val); //数据转换成频率hz,定时器2程序初始化的一个计数值是1us
LCD_DisplayStringLine(Line7,buff);
sprintf((char *)buff,"duty: %d%% ",ch1_duty*100/ch1_val);//数据转换成占空比,定时器2程序初始化的一个计数值是1us
LCD_DisplayStringLine(Line8,buff);
ch1_mode=0; //重新捕获标志
}
}