怎么做个网站演示,软件技术培训,全国水利建设市场信用信息平台网站,html怎么做静态网站一、编码器简介 编码电机 旋转编码器 A,B相分别接通道一和二的引脚#xff0c;VCC#xff0c;GND接单片机VCC#xff0c;GND 二、正交编码器工作原理 以前的代码是通过触发外部中断#xff0c;然后在中断函数里手动进行计次。使用编码器接口的好处就是节约软件资源。对于频…一、编码器简介 编码电机 旋转编码器 A,B相分别接通道一和二的引脚VCCGND接单片机VCCGND 二、正交编码器工作原理 以前的代码是通过触发外部中断然后在中断函数里手动进行计次。使用编码器接口的好处就是节约软件资源。对于频繁执行操作简单的任务一般设计一个硬件电路模块来自动完成。 使用定时器的编码器接口再配合编码器就可以测量旋转速度和旋转方向。编码器测速一般应用在电机控制的项目上。使用PWM驱动电机再使用编码器测量电机的速度然后再使用PID算法进行闭环控制。 平横车经常用到 1.计数方式 2.框图分析 由图可知只有CH1和CH2有编码器接口且编码器只用到了输入捕获结构体的输入滤波和边沿检测器则其余的结构体成员都不用区配置。 由框图可知配置Encoder需要配置GPIO输入捕获结构体的部分元素时基单元我们一般给ARR为65535-1即最大计数量程防止计数溢出。PSC1-1不分频直接72M进行计数 3.计数方向与编码器信号的关系 TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising) 这里TIM_EncoderMode_TI12即对应上面的计数边沿仅在TI1和TI2计数就相当于只在A或B相的边沿计数我们一般都使用AB相都计数 极性修改可以使用上方的函数进行也可以硬件直接调换AB相引脚 三、固件库使用 1.开启GPIO和TIM的时钟 2.配置GPIO结构体模式配置为上拉输入 3.不用配置内部时钟源因为编码器托管了时钟编码器接口就是带方向控制的外部时钟 所以内部时钟就没有用了 4.配置时基单元计数模式就不用配置了取决于编码器的AB相边沿ARR为65535-1 PSC 1-1不分频 5.配置输入捕获单元因为是由TI1FP1和2接入到编码器接口的所以捕获单元结构体 元素只需配置输入滤波和边沿检测即可这里边沿检测给上升沿还是下降沿并不是说是 哪个有效因为编码器模式下上/下沿都有效这里指电平极性是否翻转高电平不反转 低电平翻转 6.TIM_EncoderInterfaceConfig()配置编码器TIM_Cmd();使能定时器 7.使用中断读取Encoder的值测速度 若要测位置就直接读取Encoder的值即可不需要中断 上拉输入还是下拉输入的选择 一般可以看一下接在这个引脚的外部模块输出的默认电平如果外部模块空闲默认输出高电平我们就选择上拉输入默认输入高电平如果外部模块默认输出低电平我们配置下拉输入默认输入低电平。总结将需要配置电平的位置和外部模块保持默认状态一致防止默认电平打架。 如果不确定外部模块输出的默认状态或者外部信号输出功率非常小这时尽量选择浮空输入浮空输入没有上下拉电阻去影响外部信号缺点是当引脚悬空时没有默认电平输入就会受噪声干扰来回不断跳变。 测位置A、B相各出现了一个下降沿和上升沿所以计次总共加了4次。 如果转到0再往左转0自减计数器反向溢出回到自动重装值65535然后继续往下减 解决方法是如果我们想让0自减为-1直接把uint16_t类型强制转换成int16_t即可 如果想让编码器测速度可以在固定的闸门时间读一次CNT然后把CNT清零此时CNT的值代表速度单位是脉冲个数/S 测频法 #include encoder.hvoid Encoder_Init(void)
{//开启GPIO和TIM3时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//初始化GPIOGPIO_InitTypeDef GPIO_InitStruct;//定义GPIO结构体//GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;//输入不需要配置速度GPIO_InitStruct.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7;GPIO_Init(GPIOA,GPIO_InitStruct);//因为编码器接口会托管时钟编码器接口就是带方向控制的外部时钟所以内部时钟就没有用了 //TIM_InternalClockConfig(TIM2);//配置时基单元//初始化时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler 1-1;//PSC-预分频器给0不分频//TIM_TimeBaseInitStruct.TIM_CounterMode TIM_CounterMode_Up;//计数方向被编码器托管了TIM_TimeBaseInitStruct.TIM_Period 65535-1;//ARR寄存器-重装载寄存器TIM_TimeBaseInitStruct.TIM_ClockDivision TIM_CKD_DIV1;/*不分频----滤波器的采样频率 可以由内部时钟直接提供 也可以由内部时钟加一个时钟分频而来分频系数就是由TIM_ClockDivision决定*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter 0;//重复计数器只有高级定时器才有 TIM_TimeBaseInit(TIM3,TIM_TimeBaseInitStruct);//配置输入捕获单元TIM_ICInitTypeDef TIM_ICInitStruct;TIM_ICStructInit(TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel TIM_Channel_1;TIM_ICInitStruct.TIM_ICPolarity TIM_ICPolarity_Rising;//电平极性选择高电平极性不反 转低电平极性反转//TIM_ICInitStruct.TIM_ICSelection //直连or交叉连//TIM_ICInitStruct.TIM_ICPrescaler //分频器因子即每N个边沿跳变事件捕获一次-CCMR1_ICPSTIM_ICInitStruct.TIM_ICFilter 0xF;//CCMR1_ICFTIM_ICInit(TIM3, TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel TIM_Channel_2;TIM_ICInitStruct.TIM_ICPolarity TIM_ICPolarity_Rising;//电平极性选择高电平极性不反 转低电平极性反转TIM_ICInitStruct.TIM_ICFilter 0xF;//CCMR1_ICFTIM_ICInit(TIM3,TIM_ICInitStruct);TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//这里的上升沿和上面结构体配置的效果一样所以前面的可以删去//使能TIMTIM_Cmd(TIM3,ENABLE);
}int16_t Encoder_Get(void)//int16_t 为了显示负数
{int16_t temp;temp TIM_GetCounter(TIM3);TIM_SetCounter(TIM3,0);//这里每次获得了编码器的值后就清零CNT是为了得到速度//我们使用了中断一秒进入一次然后读取CNT的值作为旋转速度return temp;
}
#include bsp_tim.hvoid Time_Config()
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟故不写这一个也行TIM_InternalClockConfig(TIM2);//初始化时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler 7200-1;//PSC-预分频器TIM_TimeBaseInitStruct.TIM_CounterMode TIM_CounterMode_Up;//向上计数 TIM_TimeBaseInitStruct.TIM_Period 10000-1;//ARR寄存器-重装载寄存器TIM_TimeBaseInitStruct.TIM_ClockDivision TIM_CKD_DIV1;/*不分频----滤波器的采样频率可以由内部时钟直接提供也可以由内部时钟加一个时钟分频而来分频系数就是由TIM_ClockDivision决定*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter 0;//重复计数器只有高级定时器才有TIM_TimeBaseInit(TIM2,TIM_TimeBaseInitStruct);//使能中断-事件更新TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);TIM_ClearFlag(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit函数最后有一个直接操作UG位的操作//使得直接产生了一个更新事件因此直接进行给UIE位置1//直接进入了中断使得我们初始化ARR和PSC还未写入到//影子寄存器使得Num一上电就是1//所以在进入中断之前先清楚中断标志位//使能中断之后就要进入NVIC了//先优先级分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//配置结构体NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel TIM2_IRQn;//中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority 1;NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStruct);//启动定时器TIM_Cmd(TIM2,ENABLE);//在_it文件里编写中断服务函数
}
#include .\tim\bsp_tim.h
#include encoder.h
#include .\OLED\OLED.hint16_t speed;
int main()
{Time_Config();Encoder_Init();OLED_Init();while(1){OLED_ShowSignedNum(1,5,speed,5);}
}
void TIM2_IRQHandler()
{//先获取中断标志位if(TIM_GetITStatus(TIM2,TIM_IT_Update) SET){speed Encoder_Get();//清楚中断标志位TIM_ClearFlag(TIM2,TIM_FLAG_Update);}
}