网站开发技术简介dw,浏览器下载安装大全免费下载,网站站制做,开发公司截留占用住宅专项维修资金的整治方案文章目录 输入捕获简介频率测量输入捕获通道输入捕获基本结构PWMI的基本结构输入捕获模式测量PWM频率和占空比代码 编码器接口正交编码器工作模式接口基本结构TIM编码接口器测速代码#xff1a; 输入捕获简介
输入捕获IC(Input Capture)#xff0c;是处理器捕获外部输入信号… 文章目录 输入捕获简介频率测量输入捕获通道输入捕获基本结构PWMI的基本结构输入捕获模式测量PWM频率和占空比代码 编码器接口正交编码器工作模式接口基本结构TIM编码接口器测速代码 输入捕获简介
输入捕获IC(Input Capture)是处理器捕获外部输入信号的功能。基于定时器抓取输入信号指定触发方式之间的长度。通过输入捕获功能我们可以测量脉冲宽度和测量频率。
在每个高级定时器和通用器都有4个输入捕获通道。
当通道输入引脚出现指定电平跳变时当前CNT的值将被锁存到CCR中可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。 输入捕获功能主要涉及以下几个关键概念 捕获通道Capture Channel定时器可以配置多个捕获通道每个通道用于捕获一个外部事件的触发时间和脉冲宽度。 计数器Counter定时器的计数器用于记录定时器的计数值表示经过的时间。 捕获寄存器Capture Register捕获寄存器用于存储捕获通道捕获到的时间戳或者脉冲宽度值。 触发源Trigger Source触发源可以是定时器的输入引脚如外部信号源或者是定时器自身的输出如另一个定时器的通道输出。 中断Interrupt当捕获事件发生时定时器会触发相应的中断可以在中断服务程序中处理捕获结果。 频率测量 测频法在闸门时间T内对上升沿计次得到N则频率f_xN / T. 这种方法要求测量的频率比较快计算频率的N越多计算的越精确也就表明频率越快 测周法两个上升沿内以标准频率fc计次得到N 则频率f_xf_c / N. 这种方法要求所测频率比较低要求标准频率要远大于所测频率这样N会算的越多所测频率越准确。 中界频率测频法与测周法误差相等的频率点f_m√f_c / T 这种方法主要用来判断所测频率用哪种方法比较合适根据所给的标准频率和时间T去验证。 输入捕获通道
先看总框图 最左边的是输入捕获的通道引脚有4个可以参考引脚定义表来确认通道 进来之后有一个三输入的异或门执行逻辑是当三个引脚有任何一个引脚有电平翻转的时候输出引脚就发生电平翻转之后输出通过数据选择器到达输入捕获通道1异或这里有两个选择如果是上面那个那输入捕获通道1就是三个引脚的异或值如果选择下面一个那么异或门就没有用直接四个通道各用各的引脚。这个异或门主要用于三相无刷电机。
接着进入输入滤波器和边沿检测器滤波器可以对输入信号进行滤波避免毛刺和干扰信号边沿检测器可以选择上升沿触发或者下降沿触发触发后执行后续电路并且这里是设计了两套滤波检测电路第一套电路经过滤波和极性选择得到TI1FP1进入后续电路第二套电路同样的操作得到TI2FP2进入后续电路输入通道2也是同样的道理。对于TI1FP1会进入通道1的后续电路TI2FP2会进入通道2的后续电路。这样做就能让一个引脚的输入映射到两个捕获单元了。下面还有一个TRC输入也是用于无刷电机的驱动。
走到预分频器每个通道都各有一个可以对输入的频率进行分频分频后的信号就能够触发捕获电路开始工作。每来一个值CNT中的值就会转到捕获寄存器进行锁存。可以根据这个值进行时间频率的计算。同时也会产生捕获事件CC1I还会产生标志位U到寄存器上可以产生中断。
再看捕获通道 通过输入引脚引入滤波器TI1就是输入的引脚输出的TI1F就是滤波后的信号fDTS是滤波器的采样时钟来源下面是CCMR1是控制滤波器参数的寄存器 滤波后的信号进入边沿检测器捕获上升沿或者下降沿用下面的CCER寄存器就能选择极性。 得到的TI1FP1通过数据选择器进入通道1的后续电路。 CC1S可以对数据选择器进行选择IPPS可以对分频器进行配置CCIE控制输出的使能。 这个TI1FP1信号触发进入通道1后续电路时也可以同时触发从模式从模式中有模式可以对CNT进行自动清0。 主模式将定时器的内部信号映射到TRGO引脚用于触发别的外设 从模式就是接收其他外设或者自身外设的信号用于控制自身定时器的运行。 触发源可以选择一个信号到TRGI引脚上 像我们刚才的选择就是触发源选择TI1FP1从模式的Reset这样就完成对CNT自动清零的设置。
输入捕获基本结构 这里我们将采用上面的测周法进行测量
举个例子我们事先给时间单元的预分频器给72接上内部时钟72MHz那么频率就为1000000Hz。GPIO口输入一个频率为100Hz的PWM通过滤波器和边缘检测极性选择TI1FP1信号会触发后续通道电路并且触发从模式以100Hz的一个周期来算也就是在两个上升沿100Hz期间1000000Hz的可以计算10000次1000000/100那么捕获寄存器就会得到10000的值接着从模式会对CNT清零。这样得到的捕获值就可以对输入的频率进行计算。 当然我们无法保证最后100Hz最后的周期是完整的所以会有所误差±1。
PWMI的基本结构 相比于上面的基本结构这里多了一条捕获通道这个TI2FP2触发的极性与TI1FP1相反我们利用这个TI2FP2可以计算PWM的占空比。 例如TI1FP1触发极性为上升沿TI2FP2触发极性为下降沿我们还是以上面的例子展开延申一个100Hz的周期内可以计算到10000次的标准频率周期假设占空比为50%那么在100Hz周期内以标准频率去算的话将会有5000次那么这样把5000除以10000就可以得到占空比了。
输入捕获模式测量PWM频率和占空比
接线模式 我们将在A0口输出一个PWM由A6进行对A0口的PWM频率和占空比的测量。
代码 OLED所取路径 PWM.h
#ifndef __PWM_H__
#define __PWM_H__void PWM_Init();
void PWM_SetCompare(uint16_t Compare);
void PWM_Prescaler(uint16_t Prescaler);#endif
PWM.c
#include stm32f10x.h // Device headervoid PWM_Init()
{//开启APB1外设开关RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_ModeGPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_PinGPIO_Pin_0;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStructure);//配置内部时钟TIM2TIM_InternalClockConfig(TIM2);//时钟结构体初始化TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivisionTIM_CKD_DIV1; //划分TIM2TIM_TimeBaseInitStructure.TIM_CounterModeTIM_CounterMode_Up; //计时器模式TIM_TimeBaseInitStructure.TIM_Period100-1; //自动加载寄存器周期值TIM_TimeBaseInitStructure.TIM_Prescaler720-1; //预分频值TIM_TimeBaseInitStructure.TIM_RepetitionCounter0; //指定重复计时器的值这里不用到TIM_TimeBaseInit(TIM2,TIM_TimeBaseInitStructure);//配置输出比较结构体TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCInitStructure.TIM_OCModeTIM_OCMode_PWM1; //配置输出比较模式TIM_OCInitStructure.TIM_OCPolarityTIM_OCPolarity_High; //指定输出极性TIM_OCInitStructure.TIM_OutputStateTIM_OutputState_Enable;//输出比较状态TIM_OCInitStructure.TIM_Pulse0; //指定要捕获的脉冲值CCRTIM_OC1Init(TIM2,TIM_OCInitStructure);//启用TIM2外设控制TIM_Cmd(TIM2,ENABLE);}
//可以设置占空比
void PWM_SetCompare(uint16_t Compare)
{//配置TIM2比较值TIM_SetCompare1(TIM2,Compare);
}
//配置TIMx的预调度器,可以设置PWM频率
void PWM_Prescaler(uint16_t Prescaler)
{TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}
IC.h
#ifndef __IC_H__
#define __IC_H__void IC_Init();
uint32_t IC_GetFreq();
uint16_t IC_GetDuty();#endif
IC.c
#include stm32f10x.h // Device header
#include PWM.hvoid IC_Init()
{//开启外设时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//引脚输出初始化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);//Time内部时钟TIM_InternalClockConfig(TIM3);//内部时钟初始化TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period 65536 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler 72 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter 0;TIM_TimeBaseInit(TIM3, TIM_TimeBaseInitStructure);//输入捕获初始化TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_ChannelTIM_Channel_1; //选择通道TIM_ICInitStructure.TIM_ICFilter0xF; //指定输入捕获过滤器TIM_ICInitStructure.TIM_ICPolarityTIM_ICPolarity_Rising; //触发方式TIM_ICInitStructure.TIM_ICPrescalerTIM_ICPSC_DIV1; //不分频TIM_ICInitStructure.TIM_ICSelectionTIM_ICSelection_DirectTI; //直流方式//配置TIM3外设测量通道2输出初始化通道相反流相反触发方式相反的成员TIM_PWMIConfig(TIM3,TIM_ICInitStructure);//选择输入触发源TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//选择从模式TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);TIM_Cmd(TIM3,ENABLE);
}//获取输入捕获PWM频率
uint32_t IC_GetFreq()
{//72M/721Mreturn 1000000/(TIM_GetCapture1(TIM3)1);//根据计算验证捕获值为9999有1的误差
}
//获取输入捕获PWM占空比
uint16_t IC_GetDuty()
{return ((TIM_GetCapture2(TIM3))*100/TIM_GetCapture1(TIM3)1);
}
main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include PWM.h
#include IC.hint main()
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1,1,Freq:00000Hz);OLED_ShowString(2, 1, Duty:00%);PWM_Prescaler(7200-1); //Freq72M/(PSC1)/100PWM_SetCompare(75); //DutyCCR/100;不能超过100while(1){OLED_ShowNum(1,6,IC_GetFreq(),5);OLED_ShowNum(2,6,IC_GetDuty(),2);}
}
编码器接口
编码器接口常应用于测量、控制和位置检测等领域的传感器用于监测旋转和线性运动的位置和速度。 每个高级定时器和通用定时器都拥有1个编码器接口。 两个输入引脚借用了输入捕获的通道1和通道2。 编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。
正交编码器
正交编码器通常由两个光电传感器组成分别成为A相和B相。这两个相位差90°的信号输出可以通过检测两个相位信号的变化来确认旋转方向和计数值。 在正交编码器中两个相位信号的波形是基于格雷码Gray Code的。格雷码是一种二进制编码相邻的数值只有一个位数发生变化。这样设计的好处是在旋转过程中即使出现脉冲跳变也不会导致计数错误。
通过对A相和B相信号进行解码可以获取准确的旋转位置和方向。例如当顺时针旋转时A相先变化然后B相变化而逆时针旋转时B相先变化然后A相变化。
工作模式 我们主要用TI1和TI2上的计数模式。 举个例子在TI1低电平时TI2上升沿那么计数减少TI2下降沿计数增加。在TI1高电平时TI2上升沿那么计数增加TI2下降沿计数减少 这是极性不反向的情况也就是TI1和TI2的触发极性相同时
若是相反
接口基本结构 这里的编码器接口充当外部时钟通过捕获输入的频率作为时钟源。
TIM编码接口器测速
接线方式 通过编码器的旋转速度让它显示在屏幕上。
代码
Timer.h
#ifndef __TIMER_H__
#define __TIMER_H__void Timer_Init();#endif
Timer.c
#include stm32f10x.h // Device headervoid Timer_Init()
{//开启APB1外设开关RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//配置TIM2为内部时钟TIM_InternalClockConfig(TIM2);//时钟结构体初始化TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivisionTIM_CKD_DIV1; //划分TIM2TIM_TimeBaseInitStructure.TIM_CounterModeTIM_CounterMode_Up; //计时器模式TIM_TimeBaseInitStructure.TIM_Period10000-1; //自动加载寄存器周期值TIM_TimeBaseInitStructure.TIM_Prescaler7200-1; //预分频值TIM_TimeBaseInitStructure.TIM_RepetitionCounter0; //指定重复计时器的值这里不用到TIM_TimeBaseInit(TIM2,TIM_TimeBaseInitStructure);//TIM_ClearFlag(TIM2, TIM_FLAG_Update);//启用TIM2中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//配置优先级分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC初始化NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannelTIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmdENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority2;NVIC_InitStructure.NVIC_IRQChannelSubPriority1;NVIC_Init(NVIC_InitStructure);//启用TIM2外设控制TIM_Cmd(TIM2,ENABLE);
} 内部时钟中断利用TIM2作为时间中断每隔一秒钟将会进入中断函数。 Encoder.h
#ifndef __ENCODER_H__
#define __ENCODER_H__void Encoder_Init();
int16_t Encoder_Get();#endif
Encoder.c
#include stm32f10x.h // Device headervoid Encoder_Init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);//编码器接口模式相当于接入一个外设时钟TIM_TimeBaseInitTypeDef TimeBaseInitStructure;TimeBaseInitStructure.TIM_ClockDivisionTIM_CKD_DIV1;TimeBaseInitStructure.TIM_CounterModeTIM_CounterMode_Up;TimeBaseInitStructure.TIM_Period65535-1; //ARRTimeBaseInitStructure.TIM_Prescaler1-1; //PSCTimeBaseInitStructure.TIM_RepetitionCounter0;TIM_TimeBaseInit(TIM3,TimeBaseInitStructure);//输入捕获TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICStructInit(TIM_ICInitStructure);TIM_ICInitStructure.TIM_ChannelTIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter0xF;TIM_ICInit(TIM3,TIM_ICInitStructure);TIM_ICInitStructure.TIM_ChannelTIM_Channel_2;TIM_ICInitStructure.TIM_ICFilter0xF;TIM_ICInit(TIM3,TIM_ICInitStructure);//编码接口器TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//设置两个触发极性为相同的//启用TIM外设TIM_Cmd(TIM3,ENABLE);
}
//获取速度值获取后将计数器清0
int16_t Encoder_Get()
{int16_t Temp;TempTIM_GetCounter(TIM3);TIM_SetCounter(TIM3,0);return Temp;
}
main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include Encoder.h
#include Timer.hint16_t Speed;int main()
{OLED_Init();Timer_Init();Encoder_Init();OLED_ShowString(1,1,Speed:);while(1){OLED_ShowSignedNum(1,7,Speed,4);}
}
//中断函数
void TIM2_IRQHandler()
{if(TIM_GetITStatus(TIM2,TIM_IT_Update)SET){//将数值赋给SpeedSpeedEncoder_Get();TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}