Skip to content

手把手教你玩转测速模块(原理+驱动)

测速是现代化测控系统中不可或缺的一部分,它通过精确测量物体或现象的速度,为众多应用领域提供了关键的数据支持。无论是车辆行驶的速度监测,还是工业自动化中的生产线控制,甚至是科学实验中的粒子速度测量,测速模块都发挥着至关重要的作用。

测速模块的工作原理基于多种物理效应和先进技术,如多普勒效应、光电传感、光耦传感等,这些技术使得测速模块能够快速、准确地捕捉到速度信息。此外,测速模块还具有响应速度快、精度高等特点,使其在各种复杂环境下都能可靠工作。

本文将深入探讨测速模块之一的电机测速模块工作原理、技术实现和应用案例,帮助您更好地了解这一模块。

1. 源码下载及前置阅读

  • STM32F103C8T6模板工程

链接:https://pan.baidu.com/s/1gJigWypYfwLo2cn2nP2DGg?pwd=yqya 提取码:yqya

  • 本文的源码

链接:https://pan.baidu.com/s/1Hm47Z_UF6zwBj5fc3IT8DQ?pwd=v1su 提取码:v1su

如果你是嵌入式开发小白,那么建议你先读读下面几篇文章。

往期教程,有兴趣的小伙伴可以看看。

2. 测速模块介绍

2.1 测速模块型号介绍

测速模块常见用途:

  1. 电机转速检测
  2. 脉冲计数
  3. 位置限位
  4. 工件计数

常见的测速模块有以下三款,大同小异,都是接三个引脚(四引脚的那款 AO 引脚不起作用),除了正负极就是数字输出(OUT)。小差别已经写在图上啦。

大家在学习和工作中可以自行选择合适的型号,这里我使用的是宽槽,光耦传感器的这个型号。

2.2 测速模块参数及引脚介绍

测速模块参数:

  • 使用进口槽型光耦传感器,槽宽度 10mm
  • 有遮挡,输出高电平;无遮挡,输出低电平
  • 有输出状态指示灯,输出高电平灯灭,输出低电平灯亮
  • 使用宽电压 LM393 比较器
  • 比较器输出,信号干净,波形好,驱动能力强,超过 15mA
  • 工作电压:3.3V ~ 5V
  • 输出形式:数字开关量输出(0 和 1)
  • 设有固定螺栓孔,方便安装
  • 小板 PCB 尺寸:2.3cm x 2cm

参考接线如下:

测速模块STM32备注
VCC3.3/5V电源正极
OUT任意 GPIO 口数字输出
GNDGND电源负极

OUT 连接:

  1. 与单片机 IO 口直接相连,检测传感器是否有遮档,如用电机码盘则可检测电机的转速。
  2. 与继电器相连,组成限位开关等功能。
  3. 与有源蜂鸣器模块相连,组成报警器。

3. 使用逻辑

接下来让我介绍一下利用测速模块测距离和测速度的逻辑。

我们知道:

  1. 测速模块槽中无遮挡时,输出低电平;遮挡时,输出高电平
  2. 圆周长,C = 2×3.14×r = 3.14×d

拿我的 TT 马达和配套的轮胎(直径6.5cm)、码盘(20个格子)举例。

码盘每经过一个格子,会遮挡(高电平)和不遮挡(低电平)。

20格的码盘转一圈就会经历20个下降沿中断,一个下降沿中断就是走了 3.14×6.5/20 = 1.0205cm,约等于一个中断走1cm。

测距离:计算中断次数,即距离。

测速度:利用定时器,1 秒内接收多少个外部中断,即每秒速度。

其他轮胎或码盘可套用公式:

测距离 = 3.14×直径/码盘格子×中断次数。

测速度 = 定时器每秒输出 3.14×直径/码盘格子×中断次数,记得重置中断次数。

4. 编程实战

实战目标:串口输出电机旋转距离(cm)和速度(cm/s)。

4.1 硬件接线

本教程使用的硬件如下:

  • 单片机:STM32F103C8T6
  • 测速模块:宽槽,光耦传感器
  • 电机:TT马达(和配套码盘)
  • 串口:USB 转 TTL
  • 烧录器:ST-LINK V2
测速模块STM32USB 转 TTL
VCC3.3/5V
OUTA4
GNDG
A10TX
A9RX
GGND

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法】。

ST-Link V2STM32
SWCLKSWCLK
SWDIOSWDIO
GNDGND
3.3V3V3

接好如下图,大家可以不用接轮胎。

4.2 初始化引脚

初始化一下测速模块的 OUT 引脚。

我们采用中断的方式计数,需要初始化和使能一下 EXTI。

c
void GPIO_Init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    SP_CLK();                                               //IO口时钟使能

    gpio_initstruct.Pin = SP_PIN;                           //OUT引脚
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING;            //下降沿触发
    gpio_initstruct.Pull = GPIO_NOPULL;                     //无电阻
    HAL_GPIO_Init(SP_GPIO, &gpio_initstruct);               //初始化OUT引脚

    HAL_NVIC_SetPriority(EXTI4_IRQn,2,0);                   //抢占优先级2,响应优先级0
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);                         //使能EXTI4
}

4.3 设计中断

我们每次检测到测速模块的下降沿,速度和距离都加1。

因为 TT 马达的轮胎搭配上码盘,刚好每格大约1cm,所以我们直接加1,大家根据硬件不同自行调整。

c
void EXTI4_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(SP_PIN);         //调用中断处理公用函数 清除中断线 的中断标志位
    __HAL_GPIO_EXTI_CLEAR_IT(SP_PIN);         //HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == SP_PIN)
        if (HAL_GPIO_ReadPin(SP_GPIO, SP_PIN) == GPIO_PIN_RESET){
            speedCnt++;
            distant++;
        }
}

4.4 设计定时器

我们使用通用定时器2,设计初始化和中断。根据实战目标,我们希望定时器每秒溢出。

当定时器溢出,输出当前速度和行驶距离,并把当前速度归零。

定时器溢出时间计算方法:

公式:Tout = ((ARR + 1) * (PSC + 1)) / Ft (单位:us)。

已知 Tout = 1s;Ft,定时器工作频率,是 72Mhz。

那么公式里还剩下两个未知数,我们一般设定 PSC,求 ARR。

为了计算方便,Ft = 72M,所以我们 PSC 取7199(可取范围1~65535)。

于是,1 = ((ARR + 1) * (7199 + 1)) / 72000000。

计算可得,ARR = 9999。

c
void TIM2_Init(void)
{
    htim2.Instance = TIM2;                          //通用定时器2
    htim2.Init.Prescaler = 7199;                    //设置预分频系数(PSC)
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;    //递增计数模式
    htim2.Init.Period = 9999;                       //自动装载值(ARR)
    HAL_TIM_Base_Init(&htim2);                      //初始化定时器2
    HAL_TIM_Base_Start_IT(&htim2);                  //使能定时器2及其更新中断
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
    if(tim_baseHandle->Instance==TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();                //定时器2时钟使能

        HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);      //抢占0,响应0
        HAL_NVIC_EnableIRQ(TIM2_IRQn);              //开启TIM2中断
    }
}

void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim2);                     //定时器中断公共处理函数
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    printf("当前速度: %d cm/s \r\n", speedCnt);
    printf("行驶距离: %d cm \r\n\r\n", distant);
    speedCnt = 0;
}

4.5 主函数

主函数如下,用的是定时器溢出和中断,所以主函数里没写什么。

c
int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    uart1_init(115200);                 /* 波特率设为115200 */
    speed_init();                       /* 定时器2初始化 */

    printf("测速模块...\r\n");
    TIM2_Init();                        /* 定时器2初始化 */
    while(1)
    {

    }
}

4.6 最终效果

串口输出如下,TT 马达的工作电压在 3~6V,这是我接单片机 3.3V 的速度,大概是 40 cm/s。

这是我接单片机 5V 的速度,大概是 55 cm/s。电压越大转速越大,测速模块工作正常。

5. 小结

测速模块作为现代科技中不可或缺的一部分,为我们提供了精确、实时的速度测量。随着技术的不断进步和创新,我们可以期待测速模块在未来的发展中发挥更重要的作用。它将继续为我们提供准确、可靠的速度测量解决方案,并为各行各业的发展做出贡献。

本文通过介绍测速模块的原理、工作方式以及应用场景,希望能够帮助大家对测速模块有更全面的了解,并激发对该技术的兴趣。感谢各位看官,peace and love!