当前位置: 首页 > news >正文

单片机通用定时器编码器接口实验

单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31

HSE 为8MHZ
HSI为16MHZ

原理图:

一、编码器接口一:

主函数:

int main(void) { uint8_t i = 0; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */ delay_init(168); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ gtim_timx_encoder_chy_init(0XFFFF, 0); /* 不分频直接84M的计数频率 */ while (1) { i++; if( i % 10 == 0) { LED0_TOGGLE(); } printf("编码器的计数值为:%d\r\n",gtim_get_encode()); delay_ms(10); } }

配置:

#define GTIM_TIMX_ENCODER_CH1_GPIO_PORT GPIOC #define GTIM_TIMX_ENCODER_CH1_GPIO_PIN GPIO_PIN_6 #define GTIM_TIMX_ENCODER_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ #define GTIM_TIMX_ENCODER_CH2_GPIO_PORT GPIOC #define GTIM_TIMX_ENCODER_CH2_GPIO_PIN GPIO_PIN_7 #define GTIM_TIMX_ENCODER_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ /* TIMX 引脚复用设置 * 因为PC6、PC7默认并不是TIM3的功能脚, 必须开启复用, 才能用作TIM3的编码器功能引脚 */ #define GTIM_TIMX_ENCODERCH1_GPIO_AF GPIO_AF2_TIM3 /* 端口复用到TIM3 */ #define GTIM_TIMX_ENCODERCH2_GPIO_AF GPIO_AF2_TIM3 #define GTIM_TIMX_ENCODER TIM3 /* TIM3 */ #define GTIM_TIMX_ENCODER_INT_IRQn TIM3_IRQn #define GTIM_TIMX_ENCODER_INT_IRQHandler TIM3_IRQHandler #define GTIM_TIMX_ENCODER_CH1 TIM_CHANNEL_1 /* 通道Y, 1<= Y <=4 */ #define GTIM_TIMX_ENCODER_CH1_CLK_ENABLE() do{ __HAL_RCC_TIM3_CLK_ENABLE(); }while(0) /* TIM3 时钟使能 */ #define GTIM_TIMX_ENCODER_CH2 TIM_CHANNEL_2 /* 通道Y, 1<= Y <=4 */ #define GTIM_TIMX_ENCODER_CH2_CLK_ENABLE() do{ __HAL_RCC_TIM3_CLK_ENABLE(); }while(0) /* TIM3 时钟使能 */
void gtim_timx_encoder_chy_init(uint16_t arr, uint16_t psc) { GPIO_InitTypeDef gpio_init_struct; TIM_Encoder_InitTypeDef g_timx_encoder_chy_handle; GTIM_TIMX_ENCODER_CH1_GPIO_CLK_ENABLE(); /* 开启通道1的IO时钟 */ GTIM_TIMX_ENCODER_CH2_GPIO_CLK_ENABLE(); /* 开启通道2的IO时钟 */ GTIM_TIMX_ENCODER_CH1_CLK_ENABLE(); /* 开启通道1定时器时钟 */ GTIM_TIMX_ENCODER_CH2_CLK_ENABLE(); /* 开启通道2定时器时钟 */ gpio_init_struct.Pin = GTIM_TIMX_ENCODER_CH1_GPIO_PIN; /* 通道1的IO口,即编码器的A相 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_NOPULL; /* 不上下拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ gpio_init_struct.Alternate = GTIM_TIMX_ENCODERCH1_GPIO_AF; /* IO复用,把IO作为定时器3功能 */ HAL_GPIO_Init(GTIM_TIMX_ENCODER_CH1_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Alternate = GTIM_TIMX_ENCODERCH2_GPIO_AF; gpio_init_struct.Pin = GTIM_TIMX_ENCODER_CH2_GPIO_PIN; /* 通道2的IO口,即编码器的B相 */ HAL_GPIO_Init(GTIM_TIMX_ENCODER_CH2_GPIO_PORT, &gpio_init_struct); g_timx_encode_chy_handle.Instance = GTIM_TIMX_ENCODER; /* 定时器3 */ g_timx_encode_chy_handle.Init.Prescaler = psc; /* 定时器分频 */ g_timx_encode_chy_handle.Init.Period = arr; /* 自动重装载值 */ g_timx_encode_chy_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.EncoderMode = TIM_ENCODERMODE_TI12; /* TI1,TI2都检测 */ g_timx_encoder_chy_handle.IC1Polarity = TIM_ICPOLARITY_RISING; /* 边沿检测器设置,非反向 */ g_timx_encoder_chy_handle.IC1Selection = TIM_ICSELECTION_DIRECTTI; /* 通道1映射到IC1*/ g_timx_encoder_chy_handle.IC1Prescaler = TIM_ICPSC_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.IC1Filter = 10; /* 滤波器设置 */ g_timx_encoder_chy_handle.IC2Polarity = TIM_ICPOLARITY_RISING; /* 边沿检测器设置,非反向 */ g_timx_encoder_chy_handle.IC2Selection = TIM_ICSELECTION_DIRECTTI; /* 通道2映射到IC2 */ g_timx_encoder_chy_handle.IC2Prescaler = TIM_ICPSC_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.IC2Filter = 10; /* 滤波器设置 */ HAL_TIM_Encoder_Init(&g_timx_encode_chy_handle, &g_timx_encoder_chy_handle); HAL_TIM_Encoder_Start(&g_timx_encode_chy_handle,GTIM_TIMX_ENCODER_CH1); /* 开启编码器通道1 */ HAL_TIM_Encoder_Start(&g_timx_encode_chy_handle,GTIM_TIMX_ENCODER_CH2); /* 开启编码器通道2 */ HAL_NVIC_SetPriority(GTIM_TIMX_ENCODER_INT_IRQn, 2, 0); /* 抢占优先级2,响应优先级0 */ HAL_NVIC_EnableIRQ(GTIM_TIMX_ENCODER_INT_IRQn); /* 开启定时器3中断 */ __HAL_TIM_CLEAR_FLAG(&g_timx_encode_chy_handle,TIM_IT_UPDATE); /* 清除更新中断 */ __HAL_TIM_ENABLE_IT(&g_timx_encode_chy_handle,TIM_IT_UPDATE); /* 开启更新中断 */ }

中断:

void GTIM_TIMX_ENCODER_INT_IRQHandler(void) { HAL_TIM_IRQHandler(&g_timx_encode_chy_handle); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&g_timx_encode_chy_handle)) /* 判断CR1的DIR位 */ { g_timx_encode_count--; /* DIR位为1,也就是递减计数 */ } else { g_timx_encode_count++; /* DIR位为0,也就是递增计数 */ } } int32_t gtim_get_encode(void) { /* 计算当前总计数值,当前总计数值 = 计数器当前值 + 溢出次数*65536 */ return ( int32_t )(__HAL_TIM_GET_COUNTER(&g_timx_encode_chy_handle) + g_timx_encode_count * 65536); }

测试i结果:

二、编码器接口2

主函数:

int main(void) { uint8_t i = 0; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */ delay_init(168); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ gtim_timx_encoder_chy_init(0XFFFF, 0); /* 不分频直接84M的计数频率 */ while (1) { i++; if( i % 10 == 0) { LED0_TOGGLE(); } printf("编码器的计数值为:%d\r\n",gtim_get_encode()); delay_ms(10); } }

配置:

/* TIMX 编码器接口定义 */ #define GTIM_TIMX_ENCODER_CH1_GPIO_PORT GPIOA #define GTIM_TIMX_ENCODER_CH1_GPIO_PIN GPIO_PIN_15 #define GTIM_TIMX_ENCODER_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */ #define GTIM_TIMX_ENCODER_CH2_GPIO_PORT GPIOB #define GTIM_TIMX_ENCODER_CH2_GPIO_PIN GPIO_PIN_3 #define GTIM_TIMX_ENCODER_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */ /* TIMX 引脚复用设置 * 因为PA15、PB3默认并不是TIM2的功能脚, 必须开启复用, 才能用作TIM2的编码器功能引脚 */ #define GTIM_TIMX_ENCODERCH1_GPIO_AF GPIO_AF1_TIM2 /* 端口复用到TIM2 */ #define GTIM_TIMX_ENCODERCH2_GPIO_AF GPIO_AF1_TIM2 #define GTIM_TIMX_ENCODER TIM2 /* TIM2 */ #define GTIM_TIMX_ENCODER_INT_IRQn TIM2_IRQn #define GTIM_TIMX_ENCODER_INT_IRQHandler TIM2_IRQHandler #define GTIM_TIMX_ENCODER_CH1 TIM_CHANNEL_1 /* 通道Y, 1<= Y <=4 */ #define GTIM_TIMX_ENCODER_CH1_CLK_ENABLE() do{ __HAL_RCC_TIM2_CLK_ENABLE(); }while(0) /* TIM2 时钟使能 */ #define GTIM_TIMX_ENCODER_CH2 TIM_CHANNEL_2 /* 通道Y, 1<= Y <=4 */ #define GTIM_TIMX_ENCODER_CH2_CLK_ENABLE() do{ __HAL_RCC_TIM2_CLK_ENABLE(); }while(0) /* TIM2 时钟使能 */
void gtim_timx_encoder_chy_init(uint16_t arr, uint16_t psc) { GPIO_InitTypeDef gpio_init_struct; TIM_Encoder_InitTypeDef g_timx_encoder_chy_handle; GTIM_TIMX_ENCODER_CH1_GPIO_CLK_ENABLE(); /* 开启通道1的IO时钟 */ GTIM_TIMX_ENCODER_CH2_GPIO_CLK_ENABLE(); /* 开启通道2的IO时钟 */ GTIM_TIMX_ENCODER_CH1_CLK_ENABLE(); /* 开启通道1定时器时钟 */ GTIM_TIMX_ENCODER_CH2_CLK_ENABLE(); /* 开启通道2定时器时钟 */ gpio_init_struct.Pin = GTIM_TIMX_ENCODER_CH1_GPIO_PIN; /* 通道1的IO口,即编码器的A相 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_NOPULL; /* 不上下拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ gpio_init_struct.Alternate = GTIM_TIMX_ENCODERCH1_GPIO_AF; /* IO复用,把IO作为定时器2功能 */ HAL_GPIO_Init(GTIM_TIMX_ENCODER_CH1_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Alternate = GTIM_TIMX_ENCODERCH2_GPIO_AF; gpio_init_struct.Pin = GTIM_TIMX_ENCODER_CH2_GPIO_PIN; /* 通道2的IO口,即编码器的B相 */ HAL_GPIO_Init(GTIM_TIMX_ENCODER_CH2_GPIO_PORT, &gpio_init_struct); g_timx_encode_chy_handle.Instance = GTIM_TIMX_ENCODER; /* 定时器2 */ g_timx_encode_chy_handle.Init.Prescaler = psc; /* 定时器分频 */ g_timx_encode_chy_handle.Init.Period = arr; /* 自动重装载值 */ g_timx_encode_chy_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.EncoderMode = TIM_ENCODERMODE_TI12; /* TI1,TI2都检测 */ g_timx_encoder_chy_handle.IC1Polarity = TIM_ICPOLARITY_RISING; /* 边沿检测器设置,非反向 */ g_timx_encoder_chy_handle.IC1Selection = TIM_ICSELECTION_DIRECTTI; /* 通道1映射到IC1*/ g_timx_encoder_chy_handle.IC1Prescaler = TIM_ICPSC_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.IC1Filter = 10; /* 滤波器设置 */ g_timx_encoder_chy_handle.IC2Polarity = TIM_ICPOLARITY_RISING; /* 边沿检测器设置,非反向 */ g_timx_encoder_chy_handle.IC2Selection = TIM_ICSELECTION_DIRECTTI; /* 通道2映射到IC2 */ g_timx_encoder_chy_handle.IC2Prescaler = TIM_ICPSC_DIV1; /* 不分频 */ g_timx_encoder_chy_handle.IC2Filter = 10; /* 滤波器设置 */ HAL_TIM_Encoder_Init(&g_timx_encode_chy_handle, &g_timx_encoder_chy_handle); HAL_TIM_Encoder_Start(&g_timx_encode_chy_handle,GTIM_TIMX_ENCODER_CH1); /* 开启编码器通道1 */ HAL_TIM_Encoder_Start(&g_timx_encode_chy_handle,GTIM_TIMX_ENCODER_CH2); /* 开启编码器通道2 */ HAL_NVIC_SetPriority(GTIM_TIMX_ENCODER_INT_IRQn, 2, 0); /* 抢占优先级2,响应优先级0 */ HAL_NVIC_EnableIRQ(GTIM_TIMX_ENCODER_INT_IRQn); /* 开启定时器2中断 */ __HAL_TIM_CLEAR_FLAG(&g_timx_encode_chy_handle,TIM_IT_UPDATE); /* 清除更新中断 */ __HAL_TIM_ENABLE_IT(&g_timx_encode_chy_handle,TIM_IT_UPDATE); /* 开启更新中断 */ }

中断:

void GTIM_TIMX_ENCODER_INT_IRQHandler(void) { HAL_TIM_IRQHandler(&g_timx_encode_chy_handle); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&g_timx_encode_chy_handle)) /* 判断CR1的DIR位 */ { g_timx_encode_count--; /* DIR位为1,也就是递减计数 */ } else { g_timx_encode_count++; /* DIR位为0,也就是递增计数 */ } } int32_t gtim_get_encode(void) { /* 计算当前总计数值,当前总计数值 = 计数器当前值 + 溢出次数*65536 */ return ( int32_t )(__HAL_TIM_GET_COUNTER(&g_timx_encode_chy_handle) + g_timx_encode_count * 65536); }

测试结果:

http://www.rkmt.cn/news/1494721.html

相关文章:

  • IPATool深度解析:如何用命令行工具高效下载iOS应用包
  • PPPwn深度技术解析:从FreeBSD内核漏洞到PlayStation 4远程代码执行
  • i.MX 93高速接口时序设计:HS200/SDR104与RGMII的硬件避坑指南
  • 再见Navicat!高颜值、内置 AI,这款开源的数据库工具杀疯了。。
  • AI 应用基础设施构建:可观测性体系如何让大模型服务“透明运行“
  • MC68HC908MR24 ADC数据寄存器与时钟配置实战解析
  • 【零基础实操】 五分钟完成 OpenClaw 可视化部署配置(含安装包)
  • 从WebLogo到MEME:手把手教你挖掘多序列比对结果中的保守区域与功能基序
  • 3分钟掌握Borderless Gaming:告别游戏窗口边框的终极解决方案
  • 5分钟掌握YimMenu:GTA5安全增强与防崩溃解决方案
  • 企业AI算力工作站DLTM深度学习推理工作站零代码私有化重塑企业AI落地新模式
  • 告别龟速下载!3分钟掌握百度网盘高速下载神器
  • 从PCI到PCIe 4.0:图解电脑主板接口的‘高速公路’进化史(及未来展望)
  • 深度解析MusicFree:如何构建开源插件化音乐播放器的技术架构
  • 嵌入式接口时序设计:从i.MX 6ULZ核心外设到硬件调试实战
  • 如何快速掌握DDC/CI协议:MonitorControl跨架构显示器控制终极指南
  • Trelby剧本写作工具:完全免费的专业剧本创作软件终极指南
  • 0基础跨行斩获万元薪资,真正拉开差距的是破局思维
  • MonitorControl终极指南:用Mac键盘控制所有显示器亮度,完全免费!
  • 5分钟快速指南:用HoRNDIS实现Mac与Android的USB网络共享
  • 从‘php不是命令’到成功运行脚本:一个PHP新手的PowerShell环境配置踩坑实录
  • K50微控制器模拟前端与通信接口电气规格深度解析与设计指南
  • 【2026最新排行榜】免费C盘搬家哪个软件好?无损软件搬家工具(附下载链接
  • 50个Dify工作流模板:从新手到专家的AI自动化解决方案
  • 告别手动复制粘贴!用立创EDA自带拼板,5分钟搞定你的PCB阵列设计
  • DayZ单机模式实战指南:打造你的专属末日世界
  • 如何为Xshell选择最佳配色方案:250+专业主题的完整指南
  • 从‘阿帕网’到‘云服务’:分组交换是如何一步步成为互联网基石的?
  • 全能型 AI论文写作软件排名(2026 最新)
  • 粉笔事业单位和中公哪个好?事业编备考看公基、职测、综应和学习方式