当前位置: 首页 > 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.jsqmd.com/news/982982/

相关文章:

  • 5分钟掌握OpenStitching:免费全景图生成的完整Python教程
  • 飞思卡尔K50引脚复用全解析:从硬件规划到软件配置实战
  • IPATool深度解析:如何用命令行工具高效下载iOS应用包
  • 梦幻西游与大话西游本地资源处理合集:WDF解包、WAS音效编辑、地图查看与素材染色一体化工具
  • UVa 436 Arbitrage (II)
  • ARM Cortex-M4 MCU实战:K20系列低功耗与高性能嵌入式设计指南
  • i.MX 93高速接口时序设计:HS200/SDR104与RGMII的硬件避坑指南
  • 有哪些AI论文写作软件是真的契合专业内容,而不是通用套壳?
  • IDM永久激活完整指南:安全免费解锁下载神器
  • AI 应用基础设施构建:可观测性体系如何让大模型服务“透明运行“
  • PPPwn深度技术解析:从FreeBSD内核漏洞到PlayStation 4远程代码执行
  • 再见Navicat!高颜值、内置 AI,这款开源的数据库工具杀疯了。。
  • 微信小程序反编译技术深度解析:wxapkg-convertor实战指南
  • 嵌入式设计核心:从K12外设电气特性到高精度ADC与Flash应用
  • K20微控制器电气规格深度解析:从VREF到通信接口的硬件设计实践
  • GitCode个人技术开发者总结完整使用指南
  • Vue+Spring Boot双端可运行的学生信息管理项目(含前后端独立模块与启动说明)
  • 终极指南:如何轻松解密和提取RPG Maker游戏资源文件
  • 给到夯,Claude Code重磅更新:Auto Mode 与 ultracode 是个什么东西
  • MC68HC908MR24 ADC数据寄存器与时钟配置实战解析
  • 嵌入式硬件设计:Kinetis K53引脚复用与LQFP/MAPBGA封装对比实战
  • 从“对话”到“执行”:企业级AI智能体如何重塑业务全链路闭环
  • 小米把 1T 模型干到 1000 TPS?这事 Groq 看了得沉默
  • 四步解决Xbox手柄在macOS上的连接与兼容问题:从基础到专家的完整指南
  • 告别CNN与RNN:用SpectralFormer(Transformer)为高光谱图像分类打开新思路
  • 从WebLogo到MEME:手把手教你挖掘多序列比对结果中的保守区域与功能基序
  • NXP IW623P Wi-Fi 6/蓝牙5.x组合芯片硬件设计与调试实战指南
  • OmenSuperHub终极指南:三步掌握惠普游戏本性能完全控制权
  • WechatBakTool:基于C的微信聊天记录备份与数据库解密技术方案
  • 【零基础实操】 五分钟完成 OpenClaw 可视化部署配置(含安装包)