霍尔电机的霍尔信号(转向+速度)

什么是霍尔效应?

霍尔效应是电磁效应的一种,这一现象是美国物理学家霍尔(E.H.Hall,1855—1938)于1879年在研究金属的导电机制时发现的。   当电流垂直于外磁场通过半导体时,载流子发生偏转,垂直于电流和磁场的方向会产生一附加电场,从而在半导体的两端产生电势差,这一现象就是霍尔效应,这个电势差也被称为霍尔电势差。霍尔效应使用左手定则判断

 霍尔效应符合物理课本上面的左手定则,着手磁场垂直于手心,指尖是电流方向,大拇指就是安培力的方向,所以这个力拉扯电子形成电压差。

霍尔效应应用如下图

霍尔电机的霍尔信号(转向+速度)_第1张图片

A点和B点就是产生点位差的地方, 如此可以产生一个电压。中间的铁板相当于一个霍尔传感器,电压就是相当于信号。所以有磁场就有霍尔信号。

动画详解霍尔效应原理_哔哩哔哩_bilibili

什么是霍尔电机?

利用霍尔效应驱动的电机,下面是霍尔传感器的简图:本人是搞单片机的,非结构专业不保证图是对的。

霍尔电机的霍尔信号(转向+速度)_第2张图片

以上有两个磁铁,所以必然有两个信号代表一圈;比如霍尔A得到两个脉冲电压代表转过一圈。

霍尔电机应用+制作:
霍尔无刷电机是什么工作原理?用几块磁铁做一个,原来并不复杂_哔哩哔哩_bilibili

霍尔电机单磁极:

【有刷电机霍尔和无刷电机霍尔的科普 霍尔开关,霍尔传感器】https://www.bilibili.com/video/BV15G4y1D7ik?vd_source=4e683a72f3622d9cfc92780b0923b43a

有刷电机霍尔和无刷电机霍尔的科普 霍尔开关,霍尔传感器_哔哩哔哩_bilibili

霍尔电机单片机实践——读取霍尔信号测速+转向;

首先我也没有电机的结构图;只有一个不知名霍尔电机,电机转速测速表;

电机转速测速表:uni-t ut373迷你型的电机转速表;使用方法略;使用反光纸,转一圈就反射一次;

霍尔电机有5个线的插头是霍尔信号的:判别U (黄)   V(绿)   W(蓝) 红黑是供电线5V这样;一般通用;不保证所有霍尔电机都是这样;

1、’使用示波器连接其中一个信号线;然后电机转速测速标测实际速度;

2、使用电机控制器霍尔线连接单片机再连接电机,控制器驱动高电压线连接电机

 霍尔电机的霍尔信号(转向+速度)_第3张图片

示波器&&转速表的测试表

霍尔&&实测
转把PWM 霍尔周期ms 霍尔频率 r/min(霍) 备注说明 测转速表(r/min)
0 0 0 0 0 0
10 2 到8hz (不稳定转)转一下停 120-170
20 89.9 5394 2630.1
30 135 8100 4009
40 164 9840 4900
50 166 9960 4927
60 166 9960 4927
70 167 10020 4965
80 167 10020 4965
90 167 10020 4965
100 167 10020 4965
10.1 14.5 870 390
浮动数据 浮动数据
结论:两个霍尔信号转一圈

霍尔信号与转速表成倍数2的关系

得到结论:两个方波表一圈:

单片机利用霍尔信号的测速方案:

1、利用外部中断;两个上升沿+定时器的时间*2=得到转速

2、利用捕获:上升沿捕获*2=转速

但是先上波形;霍尔信号的波形

ps如下的波形频率85*60=5100r/min符合 测试表的转把PWM的20 。如下为判定。

1、排除掉里面的频率很高杂波,如果里面的不是杂波,那么频率应该达到15.3khz。

一、转速不符合实际转速,变大了几千倍15.3k*60=918k r/min。

二、或者,测转速表转速已经和脉冲成为了千倍关系,电机里面的磁极有几千个,才符合测速表的测量转速(电机的一个磁极转一圈一个脉冲)。

所以得出结论:80hz方波里面面的为杂波;

 图霍尔信号的波形

霍尔电机的霍尔信号(转向+速度)_第4张图片

 图霍尔里面的杂波

霍尔电机的霍尔信号(转向+速度)_第5张图片

ps:由杂波频率可以知道频率为15.3khz,为了保证有低于这个15.3频率一点点的杂波出现,应该选择低筒截止频率在10khz左右。因为非干扰波,最高频率只用到1khz

截止频率运算

以上提到截止频率,怎么运算。怎么去滤波?

采用LC RC低通滤波器,这里采用RC滤波器;

怎么选取参数,360R和33nf

附上公式链接:

参考别人的

RC低通滤波器截止频率公式推导_rc低通滤波电路_月光疾風的博客-CSDN博客

自己运算的:

RC滤波分析计算——信号与系统_qq_36658033的博客-CSDN博客

如果采取光耦隔离:输入单片机的波形

就要在光耦两边都用上;具体参数按照计算方法字节选取;为了方便硬件我选取了单电容滤波;这个弊端很大;波形会变得十分的差;

如下是滤除好的波,频率越高上升沿弯曲严重;但是勉强可用;

 

计算方法还是:将电容换成频域;(不保证对不对,瞎几把写的)

c的频域为=1/jwc 

假设截至频率也是2分之根号2=|1/jwc|模;

 如截止频率运算

那么经过计算0.1的uf的大概频率截至在2.3M这样

所以经过计算和更换选用0.22uf的,其实可以选更大的选mf的试试(没试过);

速度和转向程序;

测量原理:在霍尔信号处理好没有毛刺的输入单片机情况下;用定时器的us级别作为捕获,测量一个信号的周期;因为3个极对,一个极两个信号为转一圈;测量的周期x2就得到了转一圈的时间;即r/s

转向可以通过三个霍尔来标定;比如在A发送情况后B发生,正向;A发生后C发生就反向;(是例如哦)

底层驱动文件

#include  "Drv_hall_capture.h"
#include "public.h"
#include "hk32f0xx.h"


static uint32_t  line10_counter_B = 0, line11_counter_C = 0 ,*p_get_TIM1_captrue1_counter;
static char  front_turn;
void   Drv_external_interrup_init()
{
    
  GPIO_InitTypeDef  GPIO_InitStruct;
  EXTI_InitTypeDef  EXTI_InitStruct;
  NVIC_InitTypeDef  NVIC_InitStruct;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE );
  
  GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_10 |GPIO_Pin_11 ;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN  ;
  GPIO_InitStruct.GPIO_PuPd =   GPIO_PuPd_DOWN    ;
  GPIO_InitStruct.GPIO_Speed =  GPIO_Speed_Level_3;

  GPIO_Init( GPIOA,  &GPIO_InitStruct);
  EXTI_InitStruct.EXTI_Line = /* EXTI_Line9 |*/EXTI_Line10 | EXTI_Line11;
  EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
  EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling ;
  EXTI_InitStruct.EXTI_LineCmd= ENABLE;
  
  EXTI_Init( &EXTI_InitStruct);
  
  NVIC_InitStruct.NVIC_IRQChannel = EXTI4_15_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  
  NVIC_Init( &NVIC_InitStruct);
  gx.hall_value.hall_V_B =& line10_counter_B;
  gx.hall_value.hall_W_C =& line11_counter_C;
  gx.hall_value.front_break_turn =& front_turn;
   
}

/*
    hall 外部中断处理  hall信号中断就标记,如果在捕获到A之后立即再判断一次外中断;如果外中断B就是正向,C就是反向;
    
*/
static uint32_t external_counter;
void Drv_interruo_external_PA9_PA10_PA11(void)
{
  bool A_to_next_B , A_to_next_C;
   if( EXTI_GetFlagStatus( EXTI_Line10))
  { 
    A_to_next_B = true;
    line10_counter_B++;
  }
  
   if( EXTI_GetFlagStatus( EXTI_Line11))
  {
    A_to_next_C = true;
    line11_counter_C++; 
  }
  if( external_counter != *p_get_TIM1_captrue1_counter )
  {
//      if( *p_get_TIM1_captrue1_counter >= 60000  ) { *p_get_TIM1_captrue1_counter = 0; } //防止溢出处理
      external_counter = *p_get_TIM1_captrue1_counter;
      if( A_to_next_B == true  ) 
      {  front_turn = 0; } //负向
      else if( A_to_next_C == true) 
      {  front_turn = 1; } //正
  }  
  EXTI_ClearFlag( EXTI_Line10|EXTI_Line11); 
}

void EXTI4_15_IRQHandler()
{

  Drv_interruo_external_PA9_PA10_PA11( );
  
}





/****        霍尔捕获,一个霍尔信号是方波            ***/
static uint32_t TIM1_captrue2;  //捕获ic2  
static uint32_t TIM1_period;    //捕获信号的  周期
static uint32_t TIM1_captrue2_counter; // 捕获ic2 的计数
static uint32_t TIM1_update_counter;   // 一个信号内的  更新计数累加
static uint32_t TIM1_captrue2_update_counter; // ic2捕获到了之后,记录当前更新计数;
void Drv_time1_capture_init( uint16_t prescaler ,uint16_t reload  )
{
   
   GPIO_InitTypeDef  GPIO_InitStruct;
   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
   TIM_ICInitTypeDef  TIM_ICInitStruct;
   NVIC_InitTypeDef  NVIC_InitStruct;
   
   RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA, ENABLE);
   RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
   
   GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 ;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF ;
   GPIO_InitStruct.GPIO_OType = GPIO_OType_PP ;
   GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN ;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3  ;
   
   
   GPIO_Init( GPIOA, & GPIO_InitStruct);
   
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_2 );
   
   TIM_TimeBaseInitStruct.TIM_ClockDivision =  TIM_CKD_DIV1;
   TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up ;
   TIM_TimeBaseInitStruct.TIM_Prescaler =  prescaler - 1;
   TIM_TimeBaseInitStruct.TIM_Period = reload -1;
   TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
   
   
   TIM_ICInitStruct.TIM_Channel = TIM_Channel_2 ;
   TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising  ;
   TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI ;
   TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1 ;
   TIM_ICInitStruct.TIM_ICFilter = 1  ;
      
   TIM_ICInit(TIM1, &TIM_ICInitStruct);
   TIM_ARRPreloadConfig( TIM1, ENABLE);
   
   TIM_ITConfig( TIM1, TIM_IT_CC2 , ENABLE );
   TIM_ITConfig( TIM1, TIM_IT_Update, ENABLE );

   
   NVIC_InitStruct.NVIC_IRQChannel = TIM1_CC_IRQn ;
   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
   NVIC_InitStruct.NVIC_IRQChannelPriority = 1;
   NVIC_Init( & NVIC_InitStruct);
   
   NVIC_InitStruct.NVIC_IRQChannel = TIM1_BRK_UP_TRG_COM_IRQn ;
   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
   NVIC_InitStruct.NVIC_IRQChannelPriority = 1;
   NVIC_Init( & NVIC_InitStruct);
   
   
   TIM_Cmd( TIM1, ENABLE );
   gx.TIM1_captrue.p_captrue2 = & TIM1_captrue2;
   gx.TIM1_captrue.p_captrue2_counter = &TIM1_captrue2_counter;
   p_get_TIM1_captrue1_counter        = &TIM1_captrue2_counter;  //提供给外部中断
   gx.TIM1_captrue.p_period = & TIM1_period;

    
}



/*  更新 ic2 捕获 中断处理*/

void Drv_captrue2_interrup( void );
void TIM1_CC_IRQHandler()
{
 if( TIM_GetITStatus( TIM1,TIM_IT_CC2 ) )
 {    
    Drv_captrue2_interrup(  );
 }

 TIM_ClearITPendingBit( TIM1, TIM_IT_CC2  );  
}

void TIM1_BRK_UP_TRG_COM_IRQHandler( )
{
    if( TIM_GetITStatus( TIM1,  TIM_IT_Update ) )
    {
       TIM1_update_counter++; 
       led_off_open( );
    }
    TIM_ClearITPendingBit( TIM1, TIM_IT_Update );
}

/*  捕获ic2驱动:
    跳过第一次捕获
   每次捕获都记录当前更新中断的次数,并且清零更新中断
   每次捕获完了都清除计数器;
   每次捕获清除更新次数。  
*/

void Drv_captrue2_interrup( void )
{
      static uint8_t cnt1;
      
      if(cnt1 == 0)
      { 
        cnt1 ++;
           //第一次的边沿读取,并且清零计数器;
      }
      else
      {
        TIM1_captrue2_counter++;   // 第二次捕获之后才进行捕获计数; 
        TIM1_captrue2 =  TIM_GetCapture2( TIM1);      
        TIM1_captrue2_update_counter =  TIM1_update_counter;
        TIM1_period   =  TIM1_captrue2 +( TIM1_captrue2_update_counter * TIM1_CAPTRUE_RELOAD);
      } 
      TIM_SetCounter( TIM1, 0);
      TIM1_update_counter = 0 ; //每次处理捕获1之后 都清了掉计数
}


void Drv_speed_drectiong_hall(    uint32_t  **period ,char **direction ,uint32_t **update1)
{

   *period     =& TIM1_period ;
   *direction  =& front_turn ;
   *update1    =& TIM1_captrue2_update_counter ;
   
}

 链接文件

#include "link_speed_drection.h"
#include "public.h"

static uint32_t  *period_cnt ,*p_update1,*p_revolution_s =& gx.motor_parameter.motor_revolution_s ;
static char   *direction_flag  =& gx.motor_parameter.motor_direction;


void  Link_get_revolution_speed_and_direction( void )
{
   static uint8_t cnt;
   uint32_t T_us;
   if( cnt == 0 )
   {
     cnt++;  
     Drv_speed_drectiong_hall(     &period_cnt ,  &direction_flag ,&p_update1);
     
   }else
   {
        T_us =  (*period_cnt * 2 );                  // 三个极对 ,两个周期算一圈;
        *p_revolution_s =  1000000 / T_us ;         //  f = 1 / T .现在T是us单位                                  
   }               
   
   

}

你可能感兴趣的:(硬件小记,嵌入式硬件,单片机,mcu)