打印
[其他ST产品]

STM32应用霍尔转速传感器基于输入捕获

[复制链接]
795|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
霍尔转速传感器基本介绍
霍尔传感器分类和原理
我用的是开关型常开PNP型的霍尔传感器

开关型的有2种分类,一种是常开,另外一种就是常闭了
关于什么常开常闭,请看下图


常开通俗来讲,就是霍尔传感器没有检测到磁铁的时候开关就是断开的,常闭相反


使用特权

评论回复
沙发
有何不可0365|  楼主 | 2024-1-30 16:12 | 只看该作者
霍尔传感器具体分类

图片来自淘宝

使用特权

评论回复
板凳
有何不可0365|  楼主 | 2024-1-30 16:14 | 只看该作者
说明

DC-直流
AC交流
NO-常开
NC-常闭
关于为什么选用开关型常开PNP型霍尔传感器
单片机只能接收高低电平,0或者是1,
开关型常开的霍尔传感器刚好符合单片机的这个特性
检测到磁铁的时候就输出高电平或者低电平,
PNP型就是检测到磁铁的时候的输出高电平,没有检测到的时候就是低电平
实验中,给霍尔传感器5V供电,检测到磁铁,霍尔传感器就输入5V,没有检测到就是0V了

使用特权

评论回复
地板
有何不可0365|  楼主 | 2024-1-30 16:14 | 只看该作者

使用特权

评论回复
5
有何不可0365|  楼主 | 2024-1-30 16:15 | 只看该作者
STM32程序实现
程序介绍
单片机STM32F103ZE
霍尔5V供电,传感器数据输出线接PA6
定时器3 通道1 输入捕获模式

使用特权

评论回复
6
有何不可0365|  楼主 | 2024-1-30 16:15 | 只看该作者
程序源码
TIM3_CAP.H
#ifndef __TIM3_CAP_H
#define __TIM3_CAP_H
#include "sys.h"


extern u32 TIM3_RES;//保存2次高电平之间的时间
extern u16 TIM3_CAP;//保存第二次捕获高电平时候的计数器的数值
extern u8 TIM3_FLAG;//逻辑标志


void tim3_cap_init(u16 arr,u16 psc);


#endif

使用特权

评论回复
7
有何不可0365|  楼主 | 2024-1-30 16:15 | 只看该作者
TIM3_CAP.H解读
定时器只能在捕获到高电平的时候,把当前计数器的数值保存下次,由于我们需要计算2次高电平的时间,所有需要一个逻辑位TIM3_FLAG
TIM3_CAP用于保存第2次定时器捕获高电平时候的计数器的数值
TIM3_RES是2次高电平总的计数器的数值
TIM3_RES乘以计数器每计一个数的时间就是总的时间了

使用特权

评论回复
8
有何不可0365|  楼主 | 2024-1-30 16:15 | 只看该作者
TIM3_CAP.C

#include "TIM3_CAP.h"


//定时器3  通道1  输入捕获模式

u32 TIM3_RES;//保存2次高电平之间的时间
u16 TIM3_CAP;//保存第二次捕获高电平时候的计数器的数值
u8 TIM3_FLAG;//逻辑标志

void tim3_cap_init(u16 arr,u16 psc)
{
        RCC->APB1ENR|=1<<1;//开启定时器3的时钟
        RCC->APB2ENR|=1<<2;//开启PA时钟
        GPIOA->CRL&=0XF0FFFFFF;//PA6配置清零
        GPIOA->CRL|=0X08080000;//PA6下拉输入 默认下拉
        GPIOA->ODR|=0<<6;//PA6下拉
       
        TIM3->ARR=arr;//设置自动重载值
        TIM3->PSC=psc;//设置预分频值
        //*********通道1设置
        TIM3->CCMR1|=1<<0;//选择输入端 IC1 映射到 TI1 上
        TIM3->CCMR1|=0<<2;//输入不分频
        TIM3->CCMR1|=0<<4;//不滤波
       
        TIM3->CCER|=1<<0;//允许通道1捕获计数器的值到捕获寄存器中
        TIM3->CCER|=0<<1;//通道1上升沿捕获
       
        TIM3->DIER|=1<<0;//允许更新中断
        TIM3->DIER|=1<<1;//允许通道1捕获中断
        MY_NVIC_Init(2,0,TIM3_IRQn,2);//抢占2,子优先级0,组2
       
        TIM3->CR1|=1<<0;//开启定时器3
}

void TIM3_IRQHandler(void)
{
        if((TIM3_FLAG&0X80)==0)//还未成功捕获       
        {
                if(TIM3->SR&0X01)//溢出
                {            
                        if(TIM3_FLAG&0X40)//已经捕获到高电平了
                        {
                                if((TIM3_FLAG&0X3F)==0X3F)//高电平太长了
                                {
                                        TIM3_FLAG|=0X80;//标记成功捕获了一次
                                        TIM3_CAP=0XFFFF;
                                }else TIM3_FLAG++;
                        }         
                }
                if(TIM3->SR&0x02)//捕获1发生捕获事件
                {       
                        if(TIM3_FLAG&0X40)                //捕获到一个上升沿                
                        {                                 
                                TIM3_FLAG|=0X80;                //标记成功捕获到一次高电平脉宽
                            TIM3_CAP=TIM3->CCR1;        //获取当前的捕获值.
                        }else//还未开始,第一次捕获上升沿
                        {
                                TIM3_FLAG=0;                        //清空
                                TIM3_CAP=0;
                                TIM3_FLAG|=0X40;                //标记捕获到了上升沿
                                 TIM3->CNT=0;        //计数器清空
                        }                    
                }                                                                                   
        }
        TIM3->SR=0;//清除中断标志位
}

使用特权

评论回复
9
有何不可0365|  楼主 | 2024-1-30 16:15 | 只看该作者
TIM3_CAP.C解读
首先开启定时器3和GPIOA的时钟
        RCC->APB1ENR|=1<<1;//开启定时器3的时钟
        RCC->APB2ENR|=1<<2;//开启PA时钟

使用特权

评论回复
10
有何不可0365|  楼主 | 2024-1-30 16:16 | 只看该作者
接着设置PA6为下拉输入,为什么下拉输入,因为我们需要捕获高电平,如果你要捕获低电平,设置PA6为上拉输入,然后设置定时器下降沿捕获
        GPIOA->CRL&=0XF0FFFFFF;//PA6配置清零
        GPIOA->CRL|=0X08080000;//PA6下拉输入 默认下拉
        GPIOA->ODR|=0<<6;//PA6下拉

使用特权

评论回复
11
有何不可0365|  楼主 | 2024-1-30 16:16 | 只看该作者
设置定时器的自动重载值和预分频值
        TIM3->ARR=arr;//设置自动重载值
        TIM3->PSC=psc;//设置预分频值

使用特权

评论回复
12
有何不可0365|  楼主 | 2024-1-30 16:16 | 只看该作者
设置通道1为输入不分频,不滤波
        TIM3->CCMR1|=1<<0;//选择输入端 IC1 映射到 TI1 上
        TIM3->CCMR1|=0<<2;//输入不分频
        TIM3->CCMR1|=0<<4;//不滤波
1
2
3
关于什么是分频,什么是滤波

使用特权

评论回复
13
有何不可0365|  楼主 | 2024-1-30 16:16 | 只看该作者
滤波
首先看STM32中文参考手册中的介绍

我的理解就是输入捕获采样频率也就是速度

使用特权

评论回复
14
有何不可0365|  楼主 | 2024-1-30 16:19 | 只看该作者
分频
贴上官方介绍

就是每几个高电平触发一次捕获
如果你设置每2个事件触发一次捕获,那么检测到2次高电平的时候才会把当前的计数器的数值保存到TIM3->CCR1寄存器中

使用特权

评论回复
15
有何不可0365|  楼主 | 2024-1-30 16:20 | 只看该作者
什么是TIM3->CCR1寄存器呢
看官方的介绍就知道了



也就是保存捕获的时候计数器的数值

使用特权

评论回复
16
有何不可0365|  楼主 | 2024-1-30 16:20 | 只看该作者
计数器的值能捕获入TIM3_CCR1寄存器和设置上升沿捕获
        TIM3->CCER|=1<<0;//允许通道1捕获计数器的值到捕获寄存器中
        TIM3->CCER|=0<<1;//通道1上升沿捕获
1
2
开启定时器更新中断和通道1捕获中断
        TIM3->DIER|=1<<0;//允许更新中断
        TIM3->DIER|=1<<1;//允许通道1捕获中断
1
2
设置中断分组和优先级
        MY_NVIC_Init(2,0,TIM3_IRQn,2);//抢占2,子优先级0,组2
1
开启定时器3
        TIM3->CR1|=1<<0;//开启定时器3

使用特权

评论回复
17
有何不可0365|  楼主 | 2024-1-30 16:20 | 只看该作者
TIM3中断函数解读
TIM3_FLAG是8位的,其中第7位用于标志第一次捕获,如果检测到第一次捕获就置1,第8位用于标志第二次捕获,检测到了就置1,1~6用于在检测到第一次捕获的时候定时器更新的次数

使用特权

评论回复
18
有何不可0365|  楼主 | 2024-1-30 16:20 | 只看该作者
MAIN.C

#include "sys.h"
#include "usart.h"               
#include "delay.h"
#include "led.h"
#include "tim3_cap.h"





int main(void)
{
        Stm32_Clock_Init(9);        //系统时钟设置
        delay_init(72);                          //延时初始化
        uart_init(72,115200);         //串口初始化为115200
        tim3_cap_init(0XFFFF,72-1);//每计一个数1us   每溢出一次10ms
        led_init();                                //LED初始化
          while(1)
        {
                if(TIM3_FLAG&0X80)
                {
                        TIM3_RES=TIM3_FLAG&0X3F;
                        TIM3_RES*=65536;                                        //溢出时间总和
                        TIM3_RES+=TIM3_CAP;                //得到总的高电平时间
                        printf("%.3fs\r\n",0.000001*TIM3_RES);        //打印总的高点平时间
                        TIM3_FLAG=0;                        //开启下一次捕获
                }
                LED1=!LED1;
                delay_ms(200);
        }
}

使用特权

评论回复
19
有何不可0365|  楼主 | 2024-1-30 16:21 | 只看该作者
MAIN.C解读
主函数是检测到2次高电平就通过串口打印出高电平的时间

以下头文件中是用了原子哥的头文件

#include "sys.h"
#include "usart.h"               
#include "delay.h"

使用特权

评论回复
20
有何不可0365|  楼主 | 2024-1-30 16:21 | 只看该作者
结果
LED1每0.2s切换亮灭状态一次,故每0.4s亮一次,结果和下图一样

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

465

帖子

0

粉丝