目录
IC输入捕获
解析输入捕获时钟树
频率测量
输入捕获测频率
主从模式的选择
用PWMI测频率和占空比
案例程序
编码器接口测速
编码器接口简介
编码器接口托管时钟(计数时钟和计数方向)
编码器接口的时钟树
增量(正交)编码器
案例程序
补充
易混淆的点
二编补丁
设置CNT的值
对上文“ 增量(正交)编码器的工作模式的补丁 ”
对上文的 “ 用PWMI测频率和占空比 ”补丁
对上文的 “ 编码器接口测速 ”补丁
IC输入捕获
- IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。
- 每个高级定时器和通用定时器都拥有4个输入捕获通道。
- 可配置为PWMI模式,同时测量频率和占空比。
- 可配合主从触发模式,实现硬件全自动测量。
解析输入捕获时钟树
输入信号过来,来到了输入滤波器和边缘检测器。
- 输入滤波器可以对信号进行滤波,避免一些高频的毛刺信号误触发。
- 然后边缘检测器,可以选择高电平触发或者低电平触发,当出现指定的电平时,边缘检测器就会触发后续电路执行动作。
- 另外,这里他其实设计了两套滤波和边缘检测电路,第一套电路经过滤波和极性选择得到TI1FP1,输入给通道1的后续电路。第二套电路经过另一个滤波和极性选择得到TI1FP2。(TI1 Filter Polarity 滤波器)
输入给下面通道2的后续电路,同理,下面TI2信号进来也经过两套滤波和边沿检测,得到TI2FP1和TI2FP2。其中TI2FP1输入给上面,TI2FP2输入给下面。
- 在这里两个信号进来,可以选择各走各的。
- 也可以选择进行一个交叉,让CH2引脚输入给通道1,或者CH1引脚输入给通道2。
两个信号进来——各走各的:
两个信号进来——进行一个交叉,让CH2引脚输入给通道1,或者CH1引脚输入给通道2:
这里为什么要进行一个交叉连接呢?
目的有两个
- 第一个目的:可以灵活切换后续捕获电路的输入。比如一会想以CH1作为输入,一会想以CH2作为输入,这样就可以通过这个数据选择器灵活进行选择。
- 第二个目的(主要):可以把一个引脚的输入同时映射到两个捕获单元,也就是PWMI模式的经典结构。
第一个捕获通道使用上升沿触发,用来捕获周期。
第二个通道使用下降沿触发,用来捕获占空比。
两个通道同时对一个引脚进行捕获,就可以同时测量频率和占空比,这就是PWMI模式。
3.(续上文的1和2) 输入信号进行滤波和极性选择后。TI1FP1信号来到预分频器,每个通道都有一个预分频器。可以对前面的信号进行分频,分频之后的触发信号IC1PS就可以触发捕获电路进行工作。
4.每来一个触发信号CNT的值就会向CCR转运一次,转运的同时会发生一个捕获事件,这个事件会在状态寄存器置标志位,同时也可以产生中断。如果需要在捕获的瞬间处理一些事的话,就可以开启这个捕获中断。
这就是整个电路的工作流程,比如我们可以配置上升沿触发捕获,每来一个上升沿CNT转运到CCR一次。又因为这个CNT计数器是由内部的标准时钟驱动的,所以CNT的数值其实就可以用来记录两个上升沿之间的时间间隔。这个时间间隔就是周期,再取个倒数就是测周法测量的频率了。
上升沿用于触发输入捕获,CNT用于计数计时。
每来一个上升沿取一个CNT,取一下CNT的值自动存在CCR里。
CCR捕获到的值就是计数值。
Maybe,哪怕是预分频后的值,也还是频率,单位是Hz。
比如systick嘀嗒定时器168MHz,所以计数一下是1/168us。
这里的CNT是计数次数,使用的频率是fc,fc/N == fc/CNT== fc/CCR
CNT的驱动时钟就是fc,fc/N就得到待测信号的频率。
另外,这里有个细节,每次捕获之后,都要把CNT清零。下次上升沿再捕获的时候,取出CNT才是两个上升沿的时间间隔。再一次捕获后自动将CNT清零的步骤,可以用主从触发模式自动来完成。
频率测量
测频法和测周法
本次程序使用的是测周法测量PWM波形频率。
输入捕获测频率
主从模式的选择
用PWMI测频率和占空比
TIM_PWMIConfig()
// 根据TIM_ICInitStruct中的指定参数配置TIM外设,以测量外部PWM信号。
案例程序
/** ****************************************************************************** * @file main.c * @author * @version * @date * @brief 利用通用定时器TIM10_CH1实现输入捕获频率和占空比 TIM10_CH1 -- PB8 -- 输出脉冲 TIM4_CH2 -- PB7 -- 输入捕获 用PB8产生PWM脉冲,用PB9输入捕获PB8的频率和占空比 ****************************************************************************** **/ #include "stm32f4xx.h" //必须要包含的头文件 #include <stdio.h> #include <string.h> void delay_ms(uint32_t nms) { SysTick->CTRL = 0; // 关闭systick的控制状态寄存器――该寄存器的bit0置0 SysTick->LOAD = ( 21*1000*nms - 1); // systick的重载寄存器――计数时长 = 计数周期 * 计数次数 SysTick->VAL = 0; // 清空systick的当前数值寄存器 SysTick->CTRL = 1; // 使能systick的控制状态寄存器――该寄存器的bit0置1 while ((SysTick->CTRL & 0x00010000)==0);// 递减计数到了则控制状态寄存器的bit16为1,计数次数没到则bit16为0. SysTick->CTRL = 0; //关闭systick的控制状态寄存器 } void USART1_Config(unsigned int baud) { USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; //Enable peripheral clock using the following functions /* Enable USART clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //According to the USART mode, enable the GPIO clocks /* Enable GPIO clock */ RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE); //Peripheral's alternate function: /* Connect USART pins to AF7 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); 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_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Program the Baud Rate, Word Length , Stop Bit, Parity, Hardware flow control and Mode(Receiver/Transmitter) using the USART_Init() function. */ USART_InitStructure.USART_BaudRate = baud; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); //Enable the NVIC and the corresponding interrupt /* NVIC configuration */ /* Configure the Priority Group to 2 bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Enable the USARTx Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//接收缓冲区为空的时候使用中断 // Enable the USART using the USART_Cmd() function. USART_Cmd(USART1, ENABLE); } /* TIM10_CH1 -- PB8 -- 输出脉冲 */ void TIM10_Config(void) { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; GPIO_InitTypeDef GPIO_InitStructure; //Enable TIM clock using RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE); /* GPIOC clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //Configure the TIM pins by configuring the corresponding GPIO pins /* GPIOC Configuration: PF9--TIM14_CH1*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_TIM10); //Configure the Time base TIM_TimeBaseStructure.TIM_Period = 100-1; //250us * 100 = 25000us = 25ms TIM_TimeBaseStructure.TIM_Prescaler = 42000-1; // 168000000/42000 = 4000 f=4000Hz T=250us TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM10, &TIM_TimeBaseStructure); //Fill the TIM_OCInitStruct TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 50; //占空比50% TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Call TIM_OCxInit(TIMx, &TIM_OCInitStruct) to configure the desired channel TIM_OC1Init(TIM10, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM10, TIM_OCPreload_Enable); //TIM_OC4PreloadConfig(TIM14, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM10, ENABLE); //Call the TIM_Cmd(ENABLE) function to enable the TIM counter. TIM_Cmd(TIM10, ENABLE); } //向计算机的串口调试助手发送一个字符串,该接口专门用于发送字符串。 void SendComputerString(char *string) //参数里传入一个字符串 { while(*string != '\0') { USART_SendData(USART1, *string++ ); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET); } } //TIM4_CH2 -- PB7 -- 输入捕获 void TIM4_ICConfig(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; //启用TIM时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //通过配置相应的GP10引脚来配置TIM引脚 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOB, &GPIO_InitStructure); TIM_InternalClockConfig(TIM4); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4); //Configure the Time base TIM_TimeBaseStructure.TIM_Period = 65536-1; //ARR计数周期。 TIM_TimeBaseStructure.TIM_Prescaler = 84-1; //预分频器.TIM4的时钟频率是84MHz 8400000/84 = 1MHz TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数 TIM_TimeBaseStructure.TIM_RepetitionCounter= 0; //重复计数器,高级定时器才会用到 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //选择配置定时器通道1 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 = 0x2; //输入滤波器参数,可以过滤信号抖动 TIM_ICInit(TIM4, &TIM_ICInitStructure); // TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1 // TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //极性,选择为下降沿触发捕获 // TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; //选择器 不直接选择 // TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获 // TIM_ICInitStructure.TIM_ICFilter = 0x2; //输入滤波器参数,可以过滤信号抖动 // TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_PWMIConfig(TIM4,&TIM_ICInitStructure); //TIM_PWMIConfig()可以代替上面6行,是库函数提供的简易接口 /* 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计数器。 TIM_Cmd(TIM4, ENABLE); //启用相应的中断(或DMA请求)以读取捕获值 // TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE); } int32_t GetFreq(void) { //使用TIM GetCapturex(TlMx)来读取捕获的值 return ( 1000000 / TIM_GetCapture2(TIM4) ); // fc / CCR = 1000000 / CCR = 40Hz } int32_t GetFreqDuty(void) { //使用TIM GetCapturex(TlMx)来读取捕获的值 return ( TIM_GetCapture1(TIM4)*100 / TIM_GetCapture2(TIM4) ); // CCR2 / CCR1 = duty } int main() { char buff[32] = {0}; int FreqRet = 0; int DutyRet = 0; USART1_Config(9600); TIM10_Config(); //Freq = 168000000 / ( 42000 * 100 ) = 40Hz T = 25000us = 25ms TIM4_ICConfig(); while(1) { FreqRet = GetFreq(); DutyRet = GetFreqDuty(); sprintf(buff,"Freq=%dHz,Duty=%d%%\r\n",FreqRet,DutyRet); SendComputerString(buff); delay_ms(500); memset(buff,0,32); } }编码器接口测速
编码器接口简介
Encoder Interface 编码器接口
- 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
- 每个高级定时器和通用定时器都拥有1个编码器接口
- 两个输入引脚借用了输入捕获的通道1和通道2
编码器接口托管时钟(计数时钟和计数方向)
编码器接口的输出执行流程增量/正交编码器的AB相,按照之前编码器AB相总结的表,如果出现了边缘信号,并且对应另一相的状态为正转,则控制CNT自增,否则控制CNT自减。
注意这里,我们之前一直在使用的是72MHz内部时钟,和我们在时基单元初始化时设计的计数方向并不会使用,因为此时计数时钟和计数方向都处于编码器接口托管的状态。计数器的自增和自减受编码器控制,这就是编码器接口的电路结构。
编码器接口时钟是上升沿、下降沿都有效的,上升沿、下降沿都需要计次。
编码器接口会托管时钟,编码器接口是个带方向控制的外部时钟,所以内部时钟就没用了。
编码器接口自动控制定时器时基单元中的CNT计数器进行自增或自减。
比如:右转产生一个脉冲,CNT就加一次。
右转产生10个脉冲后停下,CNT由0自增10后停下。
编码器在左转5个脉冲,那CNT在原来的10的基础上自建5,后停下。
这个编码器接口,其实就相当于是一个带有方向控制的外部时钟,它同时控制着CNT的计数时钟和计数方向,这样的话,CNT的值就表示了编码器的位置。
如果我们每隔一段时间取一次CNT的值,再把CNT清零,每次取出来的值就表示了编码器的速度。
编码器接口的时钟树
增量(正交)编码器
增量(正交)编码器的工作模式
反相与不反相,是作用在极性选择器里的。
不反相,则直接通过极性选择器;反相,则通过极性选择器里的非门,做一个极性转换。
这个选择器是用于调整编码器左右方向的。如果想要右转为正数,但实际值是个负数,可以把编码器接口的极性转为反相。
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
// 配置编码器模式以及两个输入通道是否反相
// 注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
// 此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
案例程序
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Timer.h" int16_t Speed; //定义速度变量 /** * 函 数:编码器初始化 * 参 数:无 * 返 回 值:无 */ void Encoder_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*GPIO初始化*/ 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); //将PA6和PA7引脚初始化为上拉输入 /*时基单元初始化*/ 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 = 1 - 1; //预分频器,即PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元 /*输入捕获初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 TIM_ICStructInit(&TIM_ICInitStructure); //结构体初始化,若结构体没有完整赋值 //则最好执行此函数,给结构体所有成员都赋一个默认值 //避免结构体初值不确定的问题 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1 TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动 TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //选择配置定时器通道2 TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动 TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道 /*编码器接口配置*/ TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //配置编码器模式以及两个输入通道是否反相 //注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相 //此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行 } /** * 函 数:获取编码器的增量值 * 参 数:无 * 返 回 值:自上此调用此函数后,编码器的增量值 */ int16_t Encoder_Get(void) { /*使用Temp变量作为中继,目的是返回CNT后将其清零*/ int16_t Temp; Temp = TIM_GetCounter(TIM3); TIM_SetCounter(TIM3, 0); return Temp; } int main(void) { /*模块初始化*/ OLED_Init(); //OLED初始化 Timer_Init(); //定时器初始化 Encoder_Init(); //编码器初始化 /*显示静态字符串*/ OLED_ShowString(1, 1, "Speed:"); //1行1列显示字符串Speed: while (1) { OLED_ShowSignedNum(1, 7, Speed, 5); //不断刷新显示编码器测得的最新速度 } } /** * 函 数:TIM2中断函数 * 参 数:无 * 返 回 值:无 * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行 * 函数名为预留的指定名称,可以从启动文件复制 * 请确保函数名正确,不能有任何差异,否则中断函数将不能进入 */ void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判断是否是TIM2的更新事件触发的中断 { Speed = Encoder_Get(); //每隔固定时间段读取一次编码器计数增量值,即为速度值 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位 //中断标志位必须清除 //否则中断将连续不断地触发,导致主程序卡死 } }补充
另外,这里还有一个TRC信号,也可以选择作为捕获部分的输入。这个TRC信号是来源于上面的TRC,这样设计是为了无刷电机的驱动。
易混淆的点
TIM的IC的CNT是用来计数的,CNT会转存到CCR中。
TIM的IC的CCR是用来存储捕获到的CNT计数值的,不同于TIM_OC输出比较的CCR用来限制占空比。
用TIM的编码器接口来测试时,编码器接口会托管时钟和计数器,所以TIM的编码器接口在用getcount()函数时使用的是边沿计数,而不是定时器的内部时钟。
二编补丁
CCR记录的是CNT
又因为输入捕获IC的CNT记录2个上升沿/下降沿
所以CCR记录的是2个相同边沿的时间间隔。
设置CNT的值
/* Set the Counter Register value */
void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter)
{ TIMx->CNT = Counter; }
对上文“增量(正交)编码器的工作模式的补丁 ”
TI2在低电平时,TI1FP1是上升沿 => 向上计数
TI1在高电平时,TI2FP2是上升沿 => 向上计数
.....
以此类推
对上文的 “ 用PWMI测频率和占空比 ”补丁
逻辑:
TIM10输出比较OC输出40Hz的脉冲,
配置TIM4的通道2和通道1的输入捕获IC脉冲的周期计数和高电平计数。
对上文的 “ 编码器接口测速 ”补丁
TIM的编码器接口 用于 “ 接收正交编码器信号 ”
此时编码器的计数始终,受AB相 信号广理,
此时的CNT为边沿数量。
TIM2的中断函数,包含TIM3编码器的计数,
只有TIM2发送中断,就获得一个编码器计数值,
因为TIM2的中断时间很短,
所以TIM3编码器计数值 == 电机转速