霍尔转速传感器基本介绍
霍尔传感器分类和原理
我用的是开关型常开PNP型的霍尔传感器
开关型的有2种分类,一种是常开,另外一种就是常闭了
关于什么常开常闭,请看下图
常开通俗来讲,就是霍尔传感器没有检测到磁铁的时候开关就是断开的,常闭相反
霍尔传感器具体分类
图片来自淘宝链接
说明
关于为什么选用开关型常开PNP型霍尔传感器
单片机只能接收高低电平,0或者是1,
开关型常开的霍尔传感器刚好符合单片机的这个特性
检测到磁铁的时候就输出高电平或者低电平,
PNP型就是检测到磁铁的时候的输出高电平,没有检测到的时候就是低电平
实验中,给霍尔传感器5V供电,检测到磁铁,霍尔传感器就输入5V,没有检测到就是0V了
实物图
STM32程序实现
程序介绍
单片机STM32F103ZE
霍尔5V供电,传感器数据输出线接PA6
定时器3 通道1 输入捕获模式
程序源码
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
TIM3_CAP.H解读
定时器只能在捕获到高电平的时候,把当前计数器的数值保存下次,由于我们需要计算2次高电平的时间,所有需要一个逻辑位TIM3_FLAG
TIM3_CAP用于保存第2次定时器捕获高电平时候的计数器的数值
TIM3_RES是2次高电平总的计数器的数值
TIM3_RES乘以计数器每计一个数的时间就是总的时间了
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_CAP.C解读
首先开启定时器3和GPIOA的时钟
RCC->APB1ENR|=1<<1;//开启定时器3的时钟
RCC->APB2ENR|=1<<2;//开启PA时钟
接着设置PA6为下拉输入,为什么下拉输入,因为我们需要捕获高电平,如果你要捕获低电平,设置PA6为上拉输入,然后设置定时器下降沿捕获
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;//不滤波
什么是滤波
滤波
首先看STM32中文参考手册中的介绍
我的理解就是输入捕获采样频率也就是速度
分频
贴上官方介绍
就是每几个高电平触发一次捕获
如果你设置每2个事件触发一次捕获,那么检测到2次高电平的时候才会把当前的计数器的数值保存到TIM3->CCR1寄存器中
什么是TIM3->CCR1寄存器呢
看官方的介绍就知道了
也就是保存捕获的时候计数器的数值
计数器的值能捕获入TIM3_CCR1寄存器和设置上升沿捕获
TIM3->CCER|=1<<0;//允许通道1捕获计数器的值到捕获寄存器中
TIM3->CCER|=0<<1;//通道1上升沿捕获
开启定时器更新中断和通道1捕获中断
TIM3->DIER|=1<<0;//允许更新中断
TIM3->DIER|=1<<1;//允许通道1捕获中断
设置中断分组和优先级
MY_NVIC_Init(2,0,TIM3_IRQn,2);//抢占2,子优先级0,组2
开启定时器3
TIM3->CR1|=1<<0;//开启定时器3
TIM3_FLAG是8位的,其中第7位用于标志第一次捕获,如果检测到第一次捕获就置1,第8位用于标志第二次捕获,检测到了就置1,1~6用于在检测到第一次捕获的时候定时器更新的次数
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("%.3fsrn",0.000001*TIM3_RES); //打印总的高点平时间
TIM3_FLAG=0; //开启下一次捕获
}
LED1=!LED1;
delay_ms(200);
}
}
MAIN.C解读
主函数是检测到2次高电平就通过串口打印出高电平的时间
以下头文件中是用了原子哥的头文件
#include "sys.h"#include "usart.h" #include "delay.h" 结果
LED1每0.2s切换亮灭状态一次,故每0.4s亮一次,结果和下图一样
用飞线把PA6(通道1)和PE5(LED1)连接起来
工程文件
工程文件 链接
霍尔转速传感器基本介绍
霍尔传感器分类和原理
我用的是开关型常开PNP型的霍尔传感器
开关型的有2种分类,一种是常开,另外一种就是常闭了
关于什么常开常闭,请看下图
常开通俗来讲,就是霍尔传感器没有检测到磁铁的时候开关就是断开的,常闭相反
霍尔传感器具体分类
图片来自淘宝链接
说明
关于为什么选用开关型常开PNP型霍尔传感器
单片机只能接收高低电平,0或者是1,
开关型常开的霍尔传感器刚好符合单片机的这个特性
检测到磁铁的时候就输出高电平或者低电平,
PNP型就是检测到磁铁的时候的输出高电平,没有检测到的时候就是低电平
实验中,给霍尔传感器5V供电,检测到磁铁,霍尔传感器就输入5V,没有检测到就是0V了
实物图
STM32程序实现
程序介绍
单片机STM32F103ZE
霍尔5V供电,传感器数据输出线接PA6
定时器3 通道1 输入捕获模式
程序源码
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
TIM3_CAP.H解读
定时器只能在捕获到高电平的时候,把当前计数器的数值保存下次,由于我们需要计算2次高电平的时间,所有需要一个逻辑位TIM3_FLAG
TIM3_CAP用于保存第2次定时器捕获高电平时候的计数器的数值
TIM3_RES是2次高电平总的计数器的数值
TIM3_RES乘以计数器每计一个数的时间就是总的时间了
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_CAP.C解读
首先开启定时器3和GPIOA的时钟
RCC->APB1ENR|=1<<1;//开启定时器3的时钟
RCC->APB2ENR|=1<<2;//开启PA时钟
接着设置PA6为下拉输入,为什么下拉输入,因为我们需要捕获高电平,如果你要捕获低电平,设置PA6为上拉输入,然后设置定时器下降沿捕获
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;//不滤波
什么是滤波
滤波
首先看STM32中文参考手册中的介绍
我的理解就是输入捕获采样频率也就是速度
分频
贴上官方介绍
就是每几个高电平触发一次捕获
如果你设置每2个事件触发一次捕获,那么检测到2次高电平的时候才会把当前的计数器的数值保存到TIM3->CCR1寄存器中
什么是TIM3->CCR1寄存器呢
看官方的介绍就知道了
也就是保存捕获的时候计数器的数值
计数器的值能捕获入TIM3_CCR1寄存器和设置上升沿捕获
TIM3->CCER|=1<<0;//允许通道1捕获计数器的值到捕获寄存器中
TIM3->CCER|=0<<1;//通道1上升沿捕获
开启定时器更新中断和通道1捕获中断
TIM3->DIER|=1<<0;//允许更新中断
TIM3->DIER|=1<<1;//允许通道1捕获中断
设置中断分组和优先级
MY_NVIC_Init(2,0,TIM3_IRQn,2);//抢占2,子优先级0,组2
开启定时器3
TIM3->CR1|=1<<0;//开启定时器3
TIM3_FLAG是8位的,其中第7位用于标志第一次捕获,如果检测到第一次捕获就置1,第8位用于标志第二次捕获,检测到了就置1,1~6用于在检测到第一次捕获的时候定时器更新的次数
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("%.3fsrn",0.000001*TIM3_RES); //打印总的高点平时间
TIM3_FLAG=0; //开启下一次捕获
}
LED1=!LED1;
delay_ms(200);
}
}
MAIN.C解读
主函数是检测到2次高电平就通过串口打印出高电平的时间
以下头文件中是用了原子哥的头文件
#include "sys.h"#include "usart.h" #include "delay.h" 结果
LED1每0.2s切换亮灭状态一次,故每0.4s亮一次,结果和下图一样
用飞线把PA6(通道1)和PE5(LED1)连接起来
工程文件
工程文件 链接
举报