news 2026/4/24 12:52:52

先楫HP6750利用QEI进行1ms内PWM脉冲计数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
先楫HP6750利用QEI进行1ms内PWM脉冲计数

说明:

测试1ms周期内的PWM信号,调焦时候,先发PWM脉冲,再根据1ms内编码器反馈的A、B相正交编码器脉冲,判断拿到脉冲反馈。

  1. 只测试1ms内PWM信号的脉冲个数,物理连接上,只需要将产生的PWM信号接入到QEI的A相输入上。使用上下计数模式qei_work_mode_ud。此时pluse_cnt = (ph/2)&0x001fffff; // 计数,UP模式。
  2. 测试1ms内脉冲电机编码器反馈的正交PWM信号的脉冲个数,物理连接上,需要将编码器A相、B相分别接到两个同一个TRGM、通道不同的管脚上。使用正交编码计数模式qei_work_mode_abz。此时pluse_cnt = (ph/4)&0x001fffff; // 计数,ABZ模式 。
  3. 3路信号,得用到3个QEI。使用时TRGM与QEI需要对应,记住trgm1对应qei1,以此类推。

// hpm在线配置软件网址 https://tools.hpmicro.com/pinmux

/* * Copyright (c) 2021 HPMicro * * SPDX-License-Identifier: BSD-3-Clause * */ #include "board.h" #include "hpm_debug_console.h" #include "hpm_qei_drv.h" #include "hpm_trgm_drv.h" #include "pinmux.h" #include "hpm_gpio_drv.h" #include "hpm_gpiom_drv.h" //#ifndef BOARD_APP_QEI_BASE //#define BOARD_APP_QEI_BASE BOARD_BLDC_QEI_BASE //#define BOARD_APP_QEI_IRQ BOARD_BLDC_QEI_IRQ //#define BOARD_APP_QEI_TRGM BOARD_BLDC_QEI_TRGM //#define BOARD_APP_QEI_TRGM_QEI_A_SRC BOARD_BLDC_QEI_TRGM_QEI_A_SRC //#define BOARD_APP_QEI_TRGM_QEI_B_SRC BOARD_BLDC_QEI_TRGM_QEI_B_SRC //#define BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV BOARD_BLDC_QEI_FOC_PHASE_COUNT_PER_REV //#endif #ifndef BOARD_APP_QEI_BASE #define BOARD_APP_QEI_BASE HPM_QEI0 #define BOARD_APP_QEI_IRQ IRQn_QEI0 #define BOARD_APP_QEI_TRGM HPM_TRGM0 #define BOARD_APP_QEI_TRGM_QEI_A_SRC HPM_TRGM0_INPUT_SRC_TRGM0_P9 #define BOARD_APP_QEI_TRGM_QEI_B_SRC HPM_TRGM0_INPUT_SRC_TRGM0_P7 #define BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV 65536U // 16384*4 //#define BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV 0x001fffff #endif ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32_t z = 0, ph = 0, spd = 0, tmr = 0 ; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) bool data_ready = false; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32_t pluse_cnt = 0; void qei_reinit(void) { qei_counter_reset_assert(BOARD_APP_QEI_BASE);/*配置CR寄存器(复位)*/ // 重置计数值 qei_counter_reset_release(BOARD_APP_QEI_BASE);/* 配置CR寄存器 */ // 重新开始计数 } void init_qei_trgm_pins_focus_axis(void) { HPM_IOC->PAD[IOC_PAD_PB08].FUNC_CTL = IOC_PB08_FUNC_CTL_TRGM0_P_09; // A相 HPM_IOC->PAD[IOC_PAD_PB09].FUNC_CTL = IOC_PB09_FUNC_CTL_TRGM0_P_07; // B相 trgm_output_t trgm0_io_config0 = {0}; trgm0_io_config0.invert = 0; // 是否对信号做逻辑反相 trgm0_io_config0.type = trgm_output_same_as_input; // 输出信号的边沿处理方式(输入有上升沿,输出就有上升沿;输入有下降沿,输出就有下降沿) trgm0_io_config0.input = HPM_TRGM0_INPUT_SRC_TRGM0_P9; // TRGM 输出的信号来源是哪一路输入 trgm_output_config(HPM_TRGM0, HPM_TRGM0_OUTPUT_SRC_QEI0_A, &trgm0_io_config0); // 编码器 A信号 trgm_output_t trgm0_io_config1 = {0}; trgm0_io_config1.invert = 0; trgm0_io_config1.type = trgm_output_same_as_input; trgm0_io_config1.input = HPM_TRGM0_INPUT_SRC_TRGM0_P7; trgm_output_config(HPM_TRGM0, HPM_TRGM0_OUTPUT_SRC_QEI0_B, &trgm0_io_config1); // 编码器 B信号 } /////////////////////////////////////////////////////////////////////////////////////////////// #include "hpm_pwm_drv.h" typedef float float32; #define uint32 uint32_t static float32 u32_fre = 0.0f; static float32 f_fre_gtimer = 0.0f; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) volatile uint32_t u32_reload = 0U; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) volatile uint32_t u32_gtreload = 0U; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32 u32_test_count[12] = {0U}; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32 u32_pwm_start_timer = 0U; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32 pulse_fre_s = 0; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32 u32_gptmr_cnt = 0; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) bool b_pulse_enable_flag = 0; uint32 get_time_cur(void) { return HPM_GPTMR1->CHANNEL[0].CNT; } void init_pwm_pins_laser(void) { // 自定义PWM0 HPM_IOC->PAD[IOC_PAD_PA23].FUNC_CTL = IOC_PA23_FUNC_CTL_PWM0_P_1; // PWM1- HPM_IOC->PAD[IOC_PAD_PA23].PAD_CTL = 0x1810U; HPM_IOC->PAD[IOC_PAD_PA24].FUNC_CTL = IOC_PA24_FUNC_CTL_PWM1_P_5; // PWM2- HPM_IOC->PAD[IOC_PAD_PA24].PAD_CTL = 0x1810U; HPM_IOC->PAD[IOC_PAD_PA08].FUNC_CTL = IOC_PA08_FUNC_CTL_GPTMR1_COMP_0;; // PWM3-:使用gptmr生成 调焦轴 HPM_IOC->PAD[IOC_PAD_PA08].PAD_CTL = 0x1810U; } #ifndef PWM #define PWM HPM_PWM0 #define PWM_CLOCK_NAME BOARD_APP_PWM_CLOCK_NAME #define PWM_OUTPUT_PIN1 BOARD_APP_PWM_OUT1 #define PWM_OUTPUT_PIN2 BOARD_APP_PWM_OUT2 #define TRGM BOARD_APP_TRGM #define TRGM_PWM_OUTPUT BOARD_APP_TRGM_PWM_OUTPUT #endif void elic_pwm_init(PWM_Type *pwm, uint8_t pwm_ch) { uint32_t u32_reload = 0U; uint32_t u32_duty = 0U; u32_fre = (float32)clock_get_frequency(PWM_CLOCK_NAME); u32_reload = (uint32_t)(u32_fre /100.0f); u32_duty = (uint32_t)((float)u32_reload * 0.5f); pwm->CHCFG[1U] = 0x02010000U;//占空比取反时0x01010002U; pwm->CMPCFG[1U] = 0x08U; pwm->CMPCFG[2U] = 0x08U; pwm->PWMCFG[1U] = 0x18200000U; pwm->FRCMD = 0;//关断时占空比为100时取0 pwm->SHCR = 0x215U; pwm->STA = 0U; pwm->RLD = (u32_reload+1U) << 4; pwm->CMP[1U] = (u32_duty+1U) << 4; pwm->CMP[2U] = (u32_reload+1U) << 4; pwm->SHLK = 0x00000000U; pwm->UNLK = PWM_UNLOCK_KEY; pwm->SHLK = 0x80000000U; pwm->GCR = 0X04100183U; } void elic_pwm_set(PWM_Type *pwm, uint32_t pwm_fre, uint32_t pwm_duty) { //static uint32_t u32_reload = 0U; uint32_t u32_duty = 0U; static uint32_t u32_fre_pre = 0U; static uint32_t u32_duty_pre = 0U; u32_test_count[1U] = u32_fre_pre; u32_test_count[2U] = pwm_fre; u32_test_count[3U] = u32_duty_pre; u32_test_count[4U] = pwm_duty; if((u32_fre_pre != pwm_fre) || (u32_duty_pre != pwm_duty)) { pwm->STA = 0U; if(pwm_fre && pwm_duty) { if(100U == pwm_duty) { pwm->PWMCFG[1U] = 0x08200000U; pwm->GCR = 0X04100102U; u32_test_count[5U]++; } else { u32_reload = (uint32_t)(u32_fre /(float)pwm_fre); u32_duty = (uint32_t)((float)u32_reload * (float)pwm_duty / 100.0f); pwm->SHLK = 0x00000000U; pwm->UNLK = PWM_UNLOCK_KEY; pwm->RLD = (u32_reload+20U) << 4U; pwm->CMP[1U] = u32_duty << 4U | 0x8U; pwm->CMP[2U] = (u32_reload+20U) << 4U; pwm->SHLK = 0x80000000U; pwm->PWMCFG[1U] = 0x18200000U; pwm->GCR = 0X04100182U; u32_test_count[6U]++; } } else { pwm->PWMCFG[1U] = 0x18200000U; pwm->GCR = 0X04100183U; u32_test_count[7U]++; } u32_fre_pre = pwm_fre; u32_duty_pre = pwm_duty; } } void board_init_DO_pins(void) { // 方向 HPM_IOC->PAD[IOC_PAD_PB17].FUNC_CTL = IOC_PB17_FUNC_CTL_GPIO_B_17; gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOB, 17, gpiom_soc_gpio0); gpio_set_pin_output(HPM_GPIO0, GPIO_OE_GPIOB, 17); gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 17, 0); // 使能 HPM_IOC->PAD[IOC_PAD_PB16].FUNC_CTL = IOC_PB16_FUNC_CTL_GPIO_B_16; gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOB, 16, gpiom_soc_gpio0); gpio_set_pin_output(HPM_GPIO0, GPIO_OE_GPIOB, 16); gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOB, 16, 0); // PWM3 24V/5V HPM_IOC->PAD[IOC_PAD_PA04].FUNC_CTL = IOC_PA04_FUNC_CTL_GPIO_A_04; gpiom_set_pin_controller(HPM_GPIOM, GPIOM_ASSIGN_GPIOA, 4, gpiom_soc_gpio0); gpio_set_pin_output(HPM_GPIO0, GPIO_OE_GPIOA, 4); gpio_write_pin(HPM_GPIO0, GPIO_DO_GPIOA, 4, 0); // 脉冲调焦5V } // qei引脚 void init_qei_pwm_cnt_pins(void) { HPM_IOC->PAD[IOC_PAD_PC16].FUNC_CTL = IOC_PC16_FUNC_CTL_TRGM2_P_02; // PWM1 HPM_IOC->PAD[IOC_PAD_PC18].FUNC_CTL = IOC_PC18_FUNC_CTL_TRGM3_P_10; // PWM2 HPM_IOC->PAD[IOC_PAD_PC17].FUNC_CTL = IOC_PC17_FUNC_CTL_TRGM0_P_00; // PWM3 } ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) volatile uint32_t z1 = 0, ph1 = 0, spd1 = 0, tmr1 = 0; #ifndef BOARD_APP_QEI_BASE_FIRST #define BOARD_APP_QEI_BASE_FIRST HPM_QEI2 #define BOARD_APP_QEI_IRQ_FIRST IRQn_QEI2 #define BOARD_APP_QEI_TRGM_FIRST HPM_TRGM2 #define BOARD_APP_QEI_TRGM_FIRST_QEI_A_SRC HPM_TRGM2_INPUT_SRC_TRGM2_P2 #define BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV_FIRST 0x001fffff #endif ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) static uint64_t pluse_cnt1 = 0; // 累积计数 ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32_t jjjflag11 = 0; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32_t freq3cnt = 3000; ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(4) uint32_t duty3cnt = 50; void qei_init(void) { init_qei_pwm_cnt_pins(); trgm_output_t config1 = {0}; config1.invert = false; config1.input = HPM_TRGM2_INPUT_SRC_TRGM2_P2;/* 接收来自TRGM的IO_6 */ trgm_output_config(HPM_TRGM2, TRGM_TRGOCFG_QEI_A, &config1); qei_set_work_mode(BOARD_APP_QEI_BASE_FIRST, qei_work_mode_ud);/* HPM_QEI2 上下计数模式 */ qei_counter_reset_assert(BOARD_APP_QEI_BASE_FIRST); /*配置CR寄存器(复位)*/ qei_phase_config(BOARD_APP_QEI_BASE_FIRST, BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV_FIRST, /*设置qei的phcnt寄存器reload为最大,0x001fffff*/ qei_z_count_inc_on_phase_count_max, false); /*配置PHCFG寄存器*/ qei_counter_reset_release(BOARD_APP_QEI_BASE);/* 配置CR寄存器 */ qei_load_counter_to_read_registers(BOARD_APP_QEI_BASE_FIRST); } /////////////////////////////////////////////////////////////////////////////////////////////// int main(void) { board_init(); //////////////////////////////////////////////////////////////////////////////////////////// board_init_DO_pins(); init_pwm_pins_laser(); qei_init(); ///* 第三路PWM 共用HPM_QEI0,同时需要配置为mode_abz模式和mode_ud模式,冲突 */ //elic_pwm_gtimer_init(HPM_GPTMR1, 0U, 0U); //// 给PWM //elic_pwm_gtimer_set(HPM_GPTMR1, 0, 5000, 50U); /* 第一路PWM生成 */ elic_pwm_init(HPM_PWM0, 1); elic_pwm_set(HPM_PWM0, 5000, 50); ////////////////////////////////////////////////////////////////////////////////////////// init_qei_trgm_pins_focus_axis(); /********************************************************************************************/ qei_set_work_mode(BOARD_APP_QEI_BASE, qei_work_mode_abz); /* HPM_QEI0 正交编码计数模式 */ //qei_set_work_mode(BOARD_APP_QEI_BASE, qei_work_mode_ud);/* HPM_QEI0 正交编码计数模式 */ qei_counter_reset_assert(BOARD_APP_QEI_BASE);/*配置CR寄存器(复位)*/ qei_phase_config(BOARD_APP_QEI_BASE, BOARD_APP_QEI_MOTOR_PHASE_COUNT_PER_REV, /*设置qei的phcnt寄存器reload为最大,0x001fffff*/ qei_z_count_inc_on_phase_count_max, false);/*配置PHCFG寄存器*/ qei_counter_reset_release(BOARD_APP_QEI_BASE);/* 配置CR寄存器 */ /*********************************************************************************************/ while(1) { /****************************************编码器计数********************************************/ // QEI 根据 phase 计数,A/B 脉冲 → 相位计数 (A/B 正转 → phase++;A/B 反转 → phase--) // phase 到达 max // ↓ // 触发内部 Z // ↓ // z_counter++ qei_load_counter_to_read_registers(BOARD_APP_QEI_BASE); // 硬件锁存数据, z = qei_get_count_on_read_event(BOARD_APP_QEI_BASE, qei_counter_type_z); // 转数(圈数) ph = qei_get_count_on_read_event(BOARD_APP_QEI_BASE, qei_counter_type_phase); // 圈内位置(相位) spd = qei_get_speed_history(BOARD_APP_QEI_BASE, qei_speed_his0) + // 速度(含方向) qei_get_speed_history(BOARD_APP_QEI_BASE, qei_speed_his1) + qei_get_speed_history(BOARD_APP_QEI_BASE, qei_speed_his2) + qei_get_speed_history(BOARD_APP_QEI_BASE, qei_speed_his3); tmr = qei_get_count_on_read_event(BOARD_APP_QEI_BASE, qei_counter_type_timer); // 测速时间基准 pluse_cnt = (ph/4)&0x001fffff; // 计数,ABZ模式 //pluse_cnt = (ph/2)&0x001fffff; // 计数,UP模式 ////////////////////////////////////////////////////////////////////////////////////////////////////// /*****************************************PWM生成计数***************************************************/ qei_counter_reset_release(BOARD_APP_QEI_BASE_FIRST); // 开始计数 qei_load_counter_to_read_registers(BOARD_APP_QEI_BASE_FIRST); ph1 = qei_get_count_on_read_event(BOARD_APP_QEI_BASE_FIRST, qei_counter_type_phase); pluse_cnt1 = (ph1 / 2) & 0x001FFFFF; // 计数,UP模式 //if(jjjflag11 == 2) //{ // qei_counter_reset_release(BOARD_APP_QEI_BASE_FIRST); // 开始计数 // qei_counter_reset_release(BOARD_APP_QEI_BASE); // 开始计数 //} //else if(jjjflag11 == 0) //{ // qei_counter_reset_assert(BOARD_APP_QEI_BASE_FIRST); // 清零 // qei_counter_reset_assert(BOARD_APP_QEI_BASE); // 清零 //} /////////////////////////////////////////////////////////////////////////////////////////////////////// } return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 12:51:22

从实验室岩芯到地下储层:一条地震波速度的‘溯源’之旅

从实验室岩芯到地下储层&#xff1a;一条地震波速度的‘溯源’之旅 地震波速度是勘探地球物理学的核心参数之一&#xff0c;它像一条隐形的线索&#xff0c;贯穿了从微观岩芯分析到宏观储层预测的全过程。对于石油勘探工程师、地球物理学家和地质建模师而言&#xff0c;理解这条…

作者头像 李华
网站建设 2026/4/24 12:49:39

FreeCAD - “增料放样“基础使用

创建第一个草图创建第二个草图偏置其中一个草图点击“增料放样”&#xff0c;选择其中一个草图附件&#xff0c;点击“OK”轮廓对象为上一步选择的附件&#xff0c;点击添加截面&#xff0c;选择另一草图中的轮廓点击 OK 完成操作

作者头像 李华
网站建设 2026/4/24 12:48:17

JetBrains IDE试用期重置工具:30天无限续期的终极解决方案

JetBrains IDE试用期重置工具&#xff1a;30天无限续期的终极解决方案 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter JetBrains IDE试用期重置工具&#xff08;ide-eval-resetter&#xff09;是一款专门为开发者…

作者头像 李华
网站建设 2026/4/24 12:43:32

不只是安装:用Docker在Kali上5分钟快速部署可复用的DVWA测试环境

容器化渗透测试&#xff1a;5分钟在Kali上构建DVWA靶场的最佳实践 当安全研究人员需要快速搭建一个可反复测试的Web漏洞环境时&#xff0c;传统LAMP堆栈的手动配置往往意味着长达数小时的依赖解决和版本调试。而容器化技术正在彻底改变这一现状——通过Docker&#xff0c;我们不…

作者头像 李华
网站建设 2026/4/24 12:41:58

3步掌握你的数字记忆:用WeChatMsg高效永久保存微信聊天记录

3步掌握你的数字记忆&#xff1a;用WeChatMsg高效永久保存微信聊天记录 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/…

作者头像 李华
网站建设 2026/4/24 12:39:30

DSP28335 eQEP模块的M/T法测速详解:从公式推导到代码实现

DSP28335 eQEP模块M/T法测速实战&#xff1a;从寄存器配置到误差优化 在电机控制系统中&#xff0c;精确的速度测量是实现高性能闭环控制的基础。当电机运行范围从每分钟几转到上万转时&#xff0c;传统测速方法往往难以兼顾低速精度和高速响应。TI的DSP28335通过增强型正交编码…

作者头像 李华