stm32f103输入捕获

简介

输入捕获功能同样只有高级/通用定时器才具有. 

输入捕获英文名字为Input Capture. 是定时器外设另一个大的功能, 与输出比较OC共用CCR寄存器, 因此一个定时器只可以使用一种功能, CCR(Capture Compare Register捕获比较寄存器).

信号输入引脚出现指定电平跳变时, 当前CNT的值将被锁存到CCR中, 可用于测量PWM波形的频率, 占空比, 脉冲间隔, 电平持续时间等参数. 这里我们将使用PWMI模式, 捕获上一节产生的PWM波, 来测量频率占空比.

注意这里只能测量方波, 如果是正弦波需要经过电压比价器转化为方波再测.

如果电压过高, 需要隔离放大器或者电压互感器, 否则将会烧毁.

测量频率原理

 测量频率有两种方法:

1. 测频法.(适用于高频信号, 使用的技术是: 外部时钟源定时器计数)

使用一个定时器正常计时Ts, 以另一个定时器待测量的信号为时钟源, 产生一次电平跳变记次+1, 总共计次N, 待测频率为Fx = N / T;

2. 测周法(适用于低频信号, 使用的技术是: 输入捕获)

使用一个定时器设置为输入捕获功能, 设置该定时器的时基单元固定好标准频率fc, 将自动重装值设定为最大值, 防止CNT溢出. 每次经过一个上升沿, CCR捕获CNT的值为N, 并且将CNT清零, 此时为一个待测信号的周期走了N个标准频率fc, 所以待测频率为fx = 1 / T = 1 / (1/fc * N) = fc / N;

总结: 测频法是一段时间内的平均值, 时间慢, 值平滑. 测周法, 是一个周期出结果, 时间与一个周期长度相关, 更新快.

可能出现的误差

1. 正负一误差: 如最后测了半个, 算一个还是算0个, 就会出现正负一误差.

2. 单片机的时钟源是晶振, 晶振可能产生误差.

3. 外界信号的干扰产生误差.

如何减小误差, 测频法增加测量的时间, 测周法减小标准频率fc. 增加滤波功能.

测量占空比

 使用PWMI模式配置交叉通道, 让CCR2捕获下降沿, CCR1捕获上升沿, 使用从模式将CNT清零. 这样CCR1捕获的是一个周期N个fc, CCR2捕获的是一个周期高电平的N2个fc, 占空比 = CCR2 / CCR1 * 100 %.

输入捕获电路

 输入信号源CH1会经过数据选择器到达TI1, 经过滤波器和边沿检测器可以输出TI1FP1信号, 经过预分频器可以触发输入捕获中断, 触发事件CCR将会捕获CNT的值, 中断可以将CNT清零, 等待下次的捕获, 但过于浪费软件资源, 让CPU持续工作在中断的状态下, 所以有从模式可以硬件将CNT清零. 但是只有通道1和2有, 如果是通道3或者4只能使用中断手动清零, 所以不要使用3/4通道.

 

IC模式和PWMI模式

 IC模式下只能初始化一条通道, 两次初始化也可以实现PWMI模式, 就是要麻烦一些.

PWMI模式下可以初始化两条通道, 一条通道为监测上升沿/直连, 会自动配置另一个通道为监测下降沿/交叉连接, 方便快速配置好可以检测频率和占空比两项的操作.

主从触发模式

 主从触发模式实现硬件全自动测量.

首先是触发源的选择为: TI1FP1, 从模式选择Reset.

注意要先捕获后清零, 否则会捕获到0.

代码逻辑

  1.  RCC开启GPIO, TIM时钟
  2. GPIO上拉/浮空输入模式
  3. 时基单元配置
  4. 从模式触发源选择
  5. 从模式选择
  6. 启动定时器

代码参考

void ICInit()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    //选择时基单元的时钟源
    TIM_InternalClockConfig(TIM3);
    
    //配置GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //配置时基单元, fc = 1Mhz.
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
    TIM_TimeBaseInitStructure.TIM_Period = 65536-1;//ARR自动重装值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//PSC预分频器值
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值(高级定时器才有)
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    
    //配置PWMI模式
    TIM_ICInitTypeDef TIM_ICInitStruct;
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; //通道1
    TIM_ICInitStruct.TIM_ICFilter = 0xf; //最大滤波
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕获上升沿
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//不分频
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//直连通道
    TIM_PWMIConfig(TIM3, &TIM_ICInitStruct);
    
    //选择输入触发源,和从模式
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    
    TIM_Cmd(TIM3, ENABLE);
}


uint16_t getFreq()
{
    return 1000000 / (TIM_GetCapture1(TIM3)+1);
}

uint16_t getDuty()
{
    return (TIM_GetCapture2(TIM3)+1)*100 / (TIM_GetCapture1(TIM3)+1);

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值