凌鸥081ZYKFB官方关于正交编码器的例程太过简单main函数里仅用一个value变量读取编码器计数寄存器的值/******************************************************************************* 函数名称 int main(void) 功能描述 主程序入口 输入参数 无 输出参数 无 返 回 值 无 其它说明 实验将P2.8和P1.3分别复用为TIM3_CH0和TIM3_CH1模式其中TIM3_CH0对应编码器 模式的T0信号输入口TIM3_CH1对应编码器模式的T1信号输入口。实验配置编码器工 作模式为编码器模式计数周期为4096。 运行效果为 将编码器的A B两个相线分别接入P2.8和P1.3口转动编码器通过debug查看Value查 看编码器脉冲计数值。 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- *******************************************************************************/ u32 Value 0; int main(void) { Hardware_init(); /* 硬件初始化 */ while (1) { Value UTIMER_ECD1_CNT;//读取编码器计数值 } }测试用编码器介绍该编码器从开发板5V取电A端连接P1.3B端连接P2.8硬件初始化程序/******************************************************************************* 函数名称 void Hardware_init(void) 功能描述 硬件部分初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void Hardware_init(void) { __disable_irq(); /* 关闭中断 中断总开关 */ SYS_WR_PROTECT 0x7a83; /*使能系统寄存器写操作*/ FLASH_CFG | 0x00080000; /* enable prefetch FLASH预取加速使能*/ GPIO_init(); /* GPIO初始化 */ UTimer_init(); /* UTimer初始化 */ SoftDelay(100); /* 等待硬件初始化完毕*/ NVIC_EnableIRQ(ENCODER1_IRQn); /*使能编码器1中断*/ NVIC_EnableIRQ(TIMER3_IRQn); /*使能TIME3中断X*/ SYS_WR_PROTECT 0x0; /*关闭系统寄存器写操作*/ #if POWER_MODE SYS_VolSelModuleEnableIRQ(MCU_POWER_5v0);/*MCU电源中断使能函数*/ #else SYS_VolSelModuleEnableIRQ(MCU_POWER_3v3);/*MCU电源中断使能函数*/ #endif __enable_irq(); /* 开启中断 */ } /******************************************************************************* 函数名称 void GPIO_init(void) 功能描述 GPIO硬件初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void GPIO_init(void) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(GPIO_InitStruct); //初始化结构体 //配置按键 startP2.11 stop:P2.11 GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; //GPIO输入模式 GPIO_InitStruct.GPIO_Pin GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO2, GPIO_InitStruct); //配置LED1P0.6 LED2P0.7 LED3: P0.3 GPIO_InitStruct.GPIO_Mode GPIO_Mode_OUT; //GPIO输出模式 GPIO_InitStruct.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_3; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO0, GPIO_InitStruct); /* 配置UTimer3 TIM3_CH0: P2.8 TIM3_CH1: P1.3*/ GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; GPIO_InitStruct.GPIO_Pin GPIO_Pin_8; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO2, GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; GPIO_InitStruct.GPIO_Pin GPIO_Pin_3; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO1, GPIO_InitStruct); GPIO_PinAFConfig(GPIO1, GPIO_PinSource_3, AF8_TIMER23); //复用 GPIO_PinAFConfig(GPIO2, GPIO_PinSource_8, AF8_TIMER23); //复用 } /******************************************************************************* 函数名称 void Clock_Init(void) 功能描述 时钟配置 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2023/10/23 V2.0 HuangMG 增加MCU电源检测功能 *******************************************************************************/ void Clock_Init(void) { SYS_WR_PROTECT 0x7a83; /* 解除系统寄存器写保护 */ SYS_AFE_REG5 | BIT15; /* BIT15:PLLPDN */ #if POWER_MODE SYS_VolSelModule(MCU_POWER_5v0); /* MCU供电电压15V0;3.3V*/ #else SYS_VolSelModule(MCU_POWER_3v3); /* MCU供电电压15V0;3.3V*/ #endif SoftDelay(100); /* 等待PLL稳定*/ SYS_WR_PROTECT 0x7a83; /* 解除系统寄存器写保护 */ SYS_CLK_CFG 0x000001ff; /* BIT8:0: CLK_HS,1:PLL | BIT[7:0]CLK_DIV | 1ff对应96M时钟 */ SYS_WR_PROTECT 0x0; /*关闭系统寄存器写操作*/ } /******************************************************************************* 函数名称 void SystemInit(void) 功能描述 硬件系统初始化调用时钟初始化函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2016/3/14 V1.0 Howlet Li 创建 *******************************************************************************/ void SystemInit(void) { Clock_Init(); /* 时钟初始化 */ } /******************************************************************************* 函数名称 void UTimer_init(void) 功能描述 UTimer硬件初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void UTimer_init(void) { TIM_TimerInitTypeDef TIM_InitStruct; TIM_TimerStrutInit(TIM_InitStruct); //Timer结构体初始化 TIM_InitStruct.Timer_TH 12000; /* 定时器1ms中断一次*/ TIM_InitStruct.Timer_Filter0 1; /*CH0滤波滤波宽度为Timer_Filter0*8个时钟周期*/ TIM_InitStruct.Timer_Filter1 1; TIM_InitStruct.Timer_ClockDiv TIM_Clk_Div8; //12MHz TIM_TimerInit(TIMER3, TIM_InitStruct); TIM_TimerCmd(TIMER3, ENABLE); /* Timer3 模块使能 */// time3不使能对编码器采集无影响 UTIMER_ECD1_TH 800; //计数门限,10圈溢出一次 UTIMER_ECD1_CFG (0x1 8); //编码器模式选择正交编码模式T1/T2都计数脉冲数是实际的4倍 UTIMER_IE (0x3 14);//ENC1_OF_IE1 ENC1_UF_IE1,上溢 下溢中断均使能---ZDX UTIMER_IE|BIT9;//T3_ZC_IE Timer3 计数器过 0 中断使能高电平有效 UTIMER_CFG | (1 9); //启动编码器 }中断程序/******************************************************************************* 函数名称 void TIMER3_IRQHandler(void) 功能描述 TIMER3中断处理函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2020/8/5 V1.0 Howlet Li 创建 *******************************************************************************/ u16 time3_1ms_cnt0; u16 run_1ms_cnt0; u16 second_flag0; u8 Run_start_flag0;//编码器开始转动标志 void UTIMER3_IRQHandler(void) { if (UTIMER_IF BIT9)//1MS 过零一次 { UTIMER_IFBIT9; time3_1ms_cnt; if(time3_1ms_cnt200)//200ms { second_flag; Invers_GPIO(GPIO0, GPIO_Pin_7); //LED2反转 time3_1ms_cnt0; } if(Run_start_flag) { run_1ms_cnt; } } } /******************************************************************************* 函数名称 void ENCODER0_IRQHandler(void) 功能描述 ENCODER1中断处理函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2020/8/5 V1.0 Howlet Li 创建 *******************************************************************************/ int16_t ENCODE_cnt 0; void ENCODER1_IRQHandler(void) { if (UTIMER_IF BIT14)//下溢出 { UTIMER_IFBIT14; Invers_GPIO(GPIO0, GPIO_Pin_6); //LED1反转 ENCODE_cnt--; } if (UTIMER_IF BIT15)//上溢出 { UTIMER_IFBIT15; Invers_GPIO(GPIO0, GPIO_Pin_3); //LED3反转 ENCODE_cnt; } }MAIN函数程序u32 Value 0; int32_t ROUND_Value;//采集到的总脉冲数 int16_t RPM_value;// int16_t RPM_value_ave;//转速单位RPM u8 zero_flag0;//value初始是否为0 int16_t RPM_Temp[6]{0}; int main(void) { u8 i0; Hardware_init(); /* 硬件初始化 */ GPIO_SetBits(GPIO0,GPIO_Pin_3); GPIO_SetBits(GPIO0,GPIO_Pin_6); UTIMER_IF0x00ff; Value UTIMER_ECD1_CNT; if(Value) zero_flag1; while (1) { Value UTIMER_ECD1_CNT;//读取编码器计数值编码器转一圈实际发出20个脉冲 if(zero_flag) {Value0;zero_flag0;} if(Value) { Run_start_flag1; } if(ENCODE_cnt0)//上溢出10圈溢出一次 表示正转 { ROUND_ValueENCODE_cnt*800Value; } else { ROUND_ValueENCODE_cnt*800-Value; } if(second_flag)//每200ms进入一次 { second_flag0; RPM_Temp[i]ROUND_Value; i; if(i6)//1s { i0; RPM_valueRPM_Temp[5]-RPM_Temp[0]; RPM_value_ave(RPM_value*60/80);//1分钟圈数 RPM ENCODE_cnt0;ROUND_Value0;run_1ms_cnt0;Run_start_flag0; } } } }计算编码器旋钮转速思路该编码器旋钮旋转1圈可使A、B接口均发出20个脉冲(PWM)信号UTimer模块配置为上下边沿均计数即旋钮每转1圈UTIMER_ECD1_CNT增加80个数值UTIMER_ECD1_TH800说明每旋转10圈UTIMER则进入溢出中断一次正转则进入上溢中断反转则进入下溢中断上溢一次ENCODE_cnt1下溢一次ENCODE_cnt-1。TImer3定时器配置为12Mhz频率门限值为12000则每1ms进入一次过零中断。程序运行时使用变量Value实时读取UTIMER_ECD1_CNT并通过ROUND_ValueENCODE_cnt*800Value;(正转)ROUND_ValueENCODE_cnt*800-Value; (反转)计算出持续的脉冲数Timer3定时器每1ms进入一次过零中断期间每200ms second_flag自加一次每当second_flag1时主函数里将ROUND_Value值存入RPM_Temp[i]数组内共存6次存满第6个数据即RPM_Temp[5] 时将 RPM_Temp[5]-RPM_Temp[0] 计算出1秒内ROUND_Value总增加数该数字除以4再除以20得到1秒内编码器转过的总圈数 乘以60秒表示1分钟转过的总圈数单位RPM。Debug结果参考
基于凌鸥081ZYKFB开发板的编码器测转速算法学习
凌鸥081ZYKFB官方关于正交编码器的例程太过简单main函数里仅用一个value变量读取编码器计数寄存器的值/******************************************************************************* 函数名称 int main(void) 功能描述 主程序入口 输入参数 无 输出参数 无 返 回 值 无 其它说明 实验将P2.8和P1.3分别复用为TIM3_CH0和TIM3_CH1模式其中TIM3_CH0对应编码器 模式的T0信号输入口TIM3_CH1对应编码器模式的T1信号输入口。实验配置编码器工 作模式为编码器模式计数周期为4096。 运行效果为 将编码器的A B两个相线分别接入P2.8和P1.3口转动编码器通过debug查看Value查 看编码器脉冲计数值。 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- *******************************************************************************/ u32 Value 0; int main(void) { Hardware_init(); /* 硬件初始化 */ while (1) { Value UTIMER_ECD1_CNT;//读取编码器计数值 } }测试用编码器介绍该编码器从开发板5V取电A端连接P1.3B端连接P2.8硬件初始化程序/******************************************************************************* 函数名称 void Hardware_init(void) 功能描述 硬件部分初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void Hardware_init(void) { __disable_irq(); /* 关闭中断 中断总开关 */ SYS_WR_PROTECT 0x7a83; /*使能系统寄存器写操作*/ FLASH_CFG | 0x00080000; /* enable prefetch FLASH预取加速使能*/ GPIO_init(); /* GPIO初始化 */ UTimer_init(); /* UTimer初始化 */ SoftDelay(100); /* 等待硬件初始化完毕*/ NVIC_EnableIRQ(ENCODER1_IRQn); /*使能编码器1中断*/ NVIC_EnableIRQ(TIMER3_IRQn); /*使能TIME3中断X*/ SYS_WR_PROTECT 0x0; /*关闭系统寄存器写操作*/ #if POWER_MODE SYS_VolSelModuleEnableIRQ(MCU_POWER_5v0);/*MCU电源中断使能函数*/ #else SYS_VolSelModuleEnableIRQ(MCU_POWER_3v3);/*MCU电源中断使能函数*/ #endif __enable_irq(); /* 开启中断 */ } /******************************************************************************* 函数名称 void GPIO_init(void) 功能描述 GPIO硬件初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void GPIO_init(void) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(GPIO_InitStruct); //初始化结构体 //配置按键 startP2.11 stop:P2.11 GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; //GPIO输入模式 GPIO_InitStruct.GPIO_Pin GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO2, GPIO_InitStruct); //配置LED1P0.6 LED2P0.7 LED3: P0.3 GPIO_InitStruct.GPIO_Mode GPIO_Mode_OUT; //GPIO输出模式 GPIO_InitStruct.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_3; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO0, GPIO_InitStruct); /* 配置UTimer3 TIM3_CH0: P2.8 TIM3_CH1: P1.3*/ GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; GPIO_InitStruct.GPIO_Pin GPIO_Pin_8; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO2, GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN; GPIO_InitStruct.GPIO_Pin GPIO_Pin_3; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIO1, GPIO_InitStruct); GPIO_PinAFConfig(GPIO1, GPIO_PinSource_3, AF8_TIMER23); //复用 GPIO_PinAFConfig(GPIO2, GPIO_PinSource_8, AF8_TIMER23); //复用 } /******************************************************************************* 函数名称 void Clock_Init(void) 功能描述 时钟配置 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2023/10/23 V2.0 HuangMG 增加MCU电源检测功能 *******************************************************************************/ void Clock_Init(void) { SYS_WR_PROTECT 0x7a83; /* 解除系统寄存器写保护 */ SYS_AFE_REG5 | BIT15; /* BIT15:PLLPDN */ #if POWER_MODE SYS_VolSelModule(MCU_POWER_5v0); /* MCU供电电压15V0;3.3V*/ #else SYS_VolSelModule(MCU_POWER_3v3); /* MCU供电电压15V0;3.3V*/ #endif SoftDelay(100); /* 等待PLL稳定*/ SYS_WR_PROTECT 0x7a83; /* 解除系统寄存器写保护 */ SYS_CLK_CFG 0x000001ff; /* BIT8:0: CLK_HS,1:PLL | BIT[7:0]CLK_DIV | 1ff对应96M时钟 */ SYS_WR_PROTECT 0x0; /*关闭系统寄存器写操作*/ } /******************************************************************************* 函数名称 void SystemInit(void) 功能描述 硬件系统初始化调用时钟初始化函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2016/3/14 V1.0 Howlet Li 创建 *******************************************************************************/ void SystemInit(void) { Clock_Init(); /* 时钟初始化 */ } /******************************************************************************* 函数名称 void UTimer_init(void) 功能描述 UTimer硬件初始化 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2015/11/5 V1.0 Howlet Li 创建 *******************************************************************************/ void UTimer_init(void) { TIM_TimerInitTypeDef TIM_InitStruct; TIM_TimerStrutInit(TIM_InitStruct); //Timer结构体初始化 TIM_InitStruct.Timer_TH 12000; /* 定时器1ms中断一次*/ TIM_InitStruct.Timer_Filter0 1; /*CH0滤波滤波宽度为Timer_Filter0*8个时钟周期*/ TIM_InitStruct.Timer_Filter1 1; TIM_InitStruct.Timer_ClockDiv TIM_Clk_Div8; //12MHz TIM_TimerInit(TIMER3, TIM_InitStruct); TIM_TimerCmd(TIMER3, ENABLE); /* Timer3 模块使能 */// time3不使能对编码器采集无影响 UTIMER_ECD1_TH 800; //计数门限,10圈溢出一次 UTIMER_ECD1_CFG (0x1 8); //编码器模式选择正交编码模式T1/T2都计数脉冲数是实际的4倍 UTIMER_IE (0x3 14);//ENC1_OF_IE1 ENC1_UF_IE1,上溢 下溢中断均使能---ZDX UTIMER_IE|BIT9;//T3_ZC_IE Timer3 计数器过 0 中断使能高电平有效 UTIMER_CFG | (1 9); //启动编码器 }中断程序/******************************************************************************* 函数名称 void TIMER3_IRQHandler(void) 功能描述 TIMER3中断处理函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2020/8/5 V1.0 Howlet Li 创建 *******************************************************************************/ u16 time3_1ms_cnt0; u16 run_1ms_cnt0; u16 second_flag0; u8 Run_start_flag0;//编码器开始转动标志 void UTIMER3_IRQHandler(void) { if (UTIMER_IF BIT9)//1MS 过零一次 { UTIMER_IFBIT9; time3_1ms_cnt; if(time3_1ms_cnt200)//200ms { second_flag; Invers_GPIO(GPIO0, GPIO_Pin_7); //LED2反转 time3_1ms_cnt0; } if(Run_start_flag) { run_1ms_cnt; } } } /******************************************************************************* 函数名称 void ENCODER0_IRQHandler(void) 功能描述 ENCODER1中断处理函数 输入参数 无 输出参数 无 返 回 值 无 其它说明 修改日期 版本号 修改人 修改内容 ----------------------------------------------------------------------------- 2020/8/5 V1.0 Howlet Li 创建 *******************************************************************************/ int16_t ENCODE_cnt 0; void ENCODER1_IRQHandler(void) { if (UTIMER_IF BIT14)//下溢出 { UTIMER_IFBIT14; Invers_GPIO(GPIO0, GPIO_Pin_6); //LED1反转 ENCODE_cnt--; } if (UTIMER_IF BIT15)//上溢出 { UTIMER_IFBIT15; Invers_GPIO(GPIO0, GPIO_Pin_3); //LED3反转 ENCODE_cnt; } }MAIN函数程序u32 Value 0; int32_t ROUND_Value;//采集到的总脉冲数 int16_t RPM_value;// int16_t RPM_value_ave;//转速单位RPM u8 zero_flag0;//value初始是否为0 int16_t RPM_Temp[6]{0}; int main(void) { u8 i0; Hardware_init(); /* 硬件初始化 */ GPIO_SetBits(GPIO0,GPIO_Pin_3); GPIO_SetBits(GPIO0,GPIO_Pin_6); UTIMER_IF0x00ff; Value UTIMER_ECD1_CNT; if(Value) zero_flag1; while (1) { Value UTIMER_ECD1_CNT;//读取编码器计数值编码器转一圈实际发出20个脉冲 if(zero_flag) {Value0;zero_flag0;} if(Value) { Run_start_flag1; } if(ENCODE_cnt0)//上溢出10圈溢出一次 表示正转 { ROUND_ValueENCODE_cnt*800Value; } else { ROUND_ValueENCODE_cnt*800-Value; } if(second_flag)//每200ms进入一次 { second_flag0; RPM_Temp[i]ROUND_Value; i; if(i6)//1s { i0; RPM_valueRPM_Temp[5]-RPM_Temp[0]; RPM_value_ave(RPM_value*60/80);//1分钟圈数 RPM ENCODE_cnt0;ROUND_Value0;run_1ms_cnt0;Run_start_flag0; } } } }计算编码器旋钮转速思路该编码器旋钮旋转1圈可使A、B接口均发出20个脉冲(PWM)信号UTimer模块配置为上下边沿均计数即旋钮每转1圈UTIMER_ECD1_CNT增加80个数值UTIMER_ECD1_TH800说明每旋转10圈UTIMER则进入溢出中断一次正转则进入上溢中断反转则进入下溢中断上溢一次ENCODE_cnt1下溢一次ENCODE_cnt-1。TImer3定时器配置为12Mhz频率门限值为12000则每1ms进入一次过零中断。程序运行时使用变量Value实时读取UTIMER_ECD1_CNT并通过ROUND_ValueENCODE_cnt*800Value;(正转)ROUND_ValueENCODE_cnt*800-Value; (反转)计算出持续的脉冲数Timer3定时器每1ms进入一次过零中断期间每200ms second_flag自加一次每当second_flag1时主函数里将ROUND_Value值存入RPM_Temp[i]数组内共存6次存满第6个数据即RPM_Temp[5] 时将 RPM_Temp[5]-RPM_Temp[0] 计算出1秒内ROUND_Value总增加数该数字除以4再除以20得到1秒内编码器转过的总圈数 乘以60秒表示1分钟转过的总圈数单位RPM。Debug结果参考