MCU:HC32L130
引脚:PB06,PB07,端口复用af4,af5;定时器:TIM0
实现功能:正确识别旋钮编码器步进,实现挡位调节
官方例程对这个的描述很少,一步一步踩出来的!!
1.编码器认识
1.1结构
1.2接线
编码器规格书额定电压5V,实际可以当作普通按键来用,3V也能正常使用。
DE端相当于普通按键,
AB端接上拉电阻到VCC,C端接GND,
A,B端建议加滤波电容,实测10nf效果挺好,太大会影响波形
1.3波形
正向旋扭时波形
反向旋钮时波形
2.程序实现
2.1定时器配置:
1.基本功能配置:时钟使能,计数方式,周期设置,计数值设置,重载值,定时器功能等
2.正交编码器功能配置,此项配置完成会记录编码器波形边沿个数
3.通道配置:输入捕获,触发方式,滤波设置
4.触发中断使能
/*******************************************************************************
* Function Name : encoder_Capture_Init();
* Description : 编码器正交编码计数
* Input : PB6 PB7
*
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void encoder_Capture_Init(void)
{
uint16_t u16ArrValue;
uint16_t u16CntValue;
stc_bt_mode23_cfg_t stcBtBaseCfg;
stc_bt_m23_master_slave_cfg_t stcBtmasterslaveCfg;
stc_bt_m23_input_cfg_t stcBtPortCapCfg;
//结构体初始化清零
DDL_ZERO_STRUCT(stcBtBaseCfg);
DDL_ZERO_STRUCT(stcBtPortCapCfg);
Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能
stcBtBaseCfg.enWorkMode = BtWorkMode2; //锯齿波模式
stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK
stcBtBaseCfg.enPRS = BtPCLKDiv64; //PCLK/64
stcBtBaseCfg.enCntDir = BtCntUp; //向上计数,在三角波模式时只读
Bt_Mode23_Init(TIM0, &stcBtBaseCfg); //TIM0 的模式2功能初始化
u16ArrValue = 0XFFFF;
Bt_M23_ARRSet(TIM0, u16ArrValue, TRUE); //设置重载值,并使能缓存
u16CntValue = 0;
Bt_M23_Cnt16Set(TIM0, u16CntValue); //设置计数初值
stcBtmasterslaveCfg.enMasterSlaveSel = BtSlaveMode; ///< 从模式 此项不配置对功能不影响
stcBtmasterslaveCfg.enSlaveModeSel = BtSlaveCodeCnt3; ///< 正交编码计数模式3
stcBtmasterslaveCfg.enTsSel = BtTs0ETR; ///< 外部输输入滤波后的相位选择信号
// stcBtmasterslaveCfg.enMasterSrc = BtMasterOCA0Ref;
Bt_M23_MasterSlave_Set(TIM0,&stcBtmasterslaveCfg);
stcBtPortCapCfg.enCH0ACapSel = BtCHxCapFallRise; //CHA通道上升沿下降沿捕获都使能
stcBtPortCapCfg.enCh0ACmpCap = BtCHxCapMode; //CHA通道设置为捕获模式
stcBtPortCapCfg.enCH0AInFlt = BtFltPCLKDiv64Cnt3; //PCLK/16 3个连续有效
stcBtPortCapCfg.enCH0APolarity = BtPortPositive; //正常输入输出
stcBtPortCapCfg.enCH0BCapSel = BtCHxCapFallRise; //CHB通道上升沿下降沿捕获都使能
stcBtPortCapCfg.enCh0BCmpCap = BtCHxCapMode; //CHB通道设置为捕获模式
stcBtPortCapCfg.enCH0BInFlt = BtFltPCLKDiv64Cnt3; //PCLK/16 3个连续有效 //滤波设置 16us
stcBtPortCapCfg.enCH0BPolarity = BtPortPositive; //正常输入输出
Bt_M23_PortInput_Cfg(TIM0, &stcBtPortCapCfg); //端口输入初始化配置
Bt_M23_EnSwTrigCapCmpA(TIM0); //捕获比较A软件触发 使能
Bt_M23_EnSwTrigCapCmpB(TIM0); //捕获比较B软件触发 使能
Bt_ClearAllIntFlag(TIM0); //清中断标志
Bt_Mode23_EnableIrq(TIM0,BtCA0Irq); //使能TIM0 CB0比较/捕获中断
Bt_Mode23_EnableIrq(TIM0,BtCB0Irq); //使能TIM0 CB0比较/捕获中断
EnableNvic(TIM0_IRQn, IrqLevel3, TRUE); //TIM0中断使能
Bt_M23_Run(TIM0);
}
5.中断处理
注意:清中断方式要AB通道分别清除,如果直接清楚定时器中断,会同时清两个通道,会出现问题的
最后获得,TIM0_COUNT会是边沿的个数,编码器一个步进,AB端会分别产生一个下降沿和上升沿,共计4个
正向旋转1步,A通道的值:BtCCR0A_VAL会比TIM0_COUNT 多 1,BtCCR0A_VAL会比BtCCR0B_VAL 多 1;TIM0_COUNT + 4;
反向向旋转1步,B通道的值:BtCCR0B_VAL会比TIM0_COUNT 多 1,BtCCR0A_VAL会比BtCCR0B_VAL 少 1;TIM0_COUNT + 4;
/*******************************************************************************
* TIM0中断服务函数
******************************************************************************/
uint8_t ENCODER_CNT;
void Tim0_IRQHandler(void)
{
static uint16_t BtCCR0A_VAL,BtCCR0B_VAL,TIM0_COUNT;
//Timer0 模式23 捕获中断A
if(TRUE == Bt_GetIntFlag(TIM0, BtCA0Irq))
{
Bt_ClearIntFlag(TIM0,BtCA0Irq); //清除中断标志
}
// //Timer0 模式23 捕获中断B
if(TRUE == Bt_GetIntFlag(TIM0, BtCB0Irq))
{
Bt_ClearIntFlag(TIM0,BtCB0Irq); //清除中断标志
}
TIM0_COUNT = Bt_M23_Cnt16Get(TIM0);
BtCCR0B_VAL = Bt_M23_CCR_Get(TIM0,BtCCR0B);
BtCCR0A_VAL = Bt_M23_CCR_Get(TIM0,BtCCR0A);
if(TIM0_COUNT%4 == 0)
{
if((BtCCR0B_VAL+1 == TIM0_COUNT)&&(BtCCR0A_VAL + 1 == BtCCR0B_VAL))
{
if(ENCODER_CNT < 10)ENCODER_CNT++;
}
if((BtCCR0A_VAL - 1 == TIM0_COUNT)&&(BtCCR0B_VAL - 1 == BtCCR0A_VAL))
{
if(ENCODER_CNT > 0)ENCODER_CNT--;
}
}
}