精华内容
下载资源
问答
  • STM32电机测速(正交或者霍尔编码器

    万次阅读 多人点赞 2020-08-19 22:41:41
    2.2 STM32电机测速(正交或者霍尔编码器) 我们这里提供左右电机测速代码,在公众号:小白学移动机器人,发送:电机测速,即可获得源码工程下载链接。 2.2.1 实现工具 STM32单片机、带编码器的直流减速电机、Keil5、...

    2.2 STM32电机测速(正交或者霍尔编码器)

    我们这里提供左右电机测速代码,在公众号:小白学移动机器人,发送:电机测速,即可获得源码工程下载链接。

    2.2.1 实现工具

    STM32单片机、带编码器的直流减速电机、Keil5、(蓝牙、串口助手)调试用

    2.2.2 编码器原理

    (1)编码器是什么?

    编码器是一种将角位移或者角速度转换成一串电数字脉冲的旋转式传感器。编码器又分为光电编码器和霍尔编码器。

    (2)编码器工作原理是什么?

    霍尔编码器是有霍尔马盘和霍尔元件组成。霍尔马盘是在一定直径的圆板上等分的布置有不同的磁极。霍尔马盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。示意图如下:

    img

    (3)带霍尔编码器的直流减速电机接线图

    img

    (4)测速原理

    单位时间内,根据脉冲走过的距离计算电机实际速度,这里采用5ms定时器中断。

    (5)采集数据方式

    通常有两种方式,第一种软件技术直接采用外部中断进行采集,根据AB相位差的不同可以判断正负。第二种硬件技术直接使用定时器的编码器模式,这里采用第二种。也是大家常说的四倍频,提高测量精度的方法。其实就是把AB相的上升沿和下降沿都采集而已,所以1变4。自己使用外部中断方式实现就比较占用资源了,所以不建议使用。

    (6)速度计算方法

    这里计算的是真实的电机轮子的物理转速

    电机转动一圈的脉冲数:num1 单位:个

    单位时间:t 单位:秒

    单位时间内捕获的脉冲变化数:num2 单位:个 (反应电机正反转)

    电机轮子半径:r 单位:m

    圆周率:pi 单位:无

    速度:speed 单位: mm/s
    speed=1000num2(2pir/num1)/t speed = 1000*num2*(2*pi*r/num1)/t

    2.2.3 部分代码分享

    主要流程:

    将编码器AB相使用的引脚设置成定时器的编码器模式,我们根据TIMx->CNT寄存器数据的变化,计算出单位时间内,脉冲的变化值。然后在定时器中断服务函数中进行速度计算,然后将速度数据通过蓝牙发送到PC的串口助手,验证数据是否正确。

    (1)编码器引脚配置以及测速代码

    #include "encoder.h"
    
    /**************************************************************************
    函数功能:把TIM2初始化为编码器接口模式
    入口参数:无
    返回  值:无
    **************************************************************************/
    void Encoder_Init_TIM2(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
    	TIM_ICInitTypeDef TIM_ICInitStructure;  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    //使能定时器2的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能PA端口时钟
    
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	//端口配置
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
    	GPIO_Init(GPIOA, &GPIO_InitStructure);					//根据设定参数初始化GPIOA
    
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_Prescaler = 0x0;              //预分频器 
    	TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;  //设定计数器自动重装值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    	
    	TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    	
    	TIM_ICStructInit(&TIM_ICInitStructure);
    	TIM_ICInitStructure.TIM_ICFilter = 10;
    	TIM_ICInit(TIM2, &TIM_ICInitStructure);
    	TIM_ClearFlag(TIM2, TIM_FLAG_Update);                   //清除TIM的更新标志位
    	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    	//Reset counter
    	TIM_SetCounter(TIM2,0);
    	//===============================================
    	TIM2->CNT = 0x7fff;
    	//===============================================
    	TIM_Cmd(TIM2, ENABLE); 
    }
    /**************************************************************************
    函数功能:把TIM4初始化为编码器接口模式
    入口参数:无
    返回  值:无
    **************************************************************************/
    void Encoder_Init_TIM4(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
    	TIM_ICInitTypeDef TIM_ICInitStructure;  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);    //使能定时器4的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   //使能PB端口时钟
    
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
    	GPIO_Init(GPIOB, &GPIO_InitStructure);					//根据设定参数初始化GPIOB
    
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_Prescaler = 0x0;              // 预分频器 
    	TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;  //设定计数器自动重装值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
    	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    	TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    	TIM_ICStructInit(&TIM_ICInitStructure);
    	TIM_ICInitStructure.TIM_ICFilter = 10;
    	TIM_ICInit(TIM4, &TIM_ICInitStructure);
    	TIM_ClearFlag(TIM4, TIM_FLAG_Update);                   //清除TIM的更新标志位
    	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
    	//Reset counter
    	TIM_SetCounter(TIM4,0);
    	//===============================================
    	TIM4->CNT = 0x7fff;
    	//===============================================
    	TIM_Cmd(TIM4, ENABLE); 
    }
    
    /**************************************************************************
    函数功能:读取编码器脉冲差值,读取单位时间内的脉冲变化值
    入口参数:TIM_TypeDef * TIMx
    返回  值:无
    **************************************************************************/
    s16 getTIMx_DetaCnt(TIM_TypeDef * TIMx)
    {
    	s16 cnt;
    	cnt = TIMx->CNT-0x7fff;
    	TIMx->CNT = 0x7fff;
    	return cnt;
    }
    
    /**************************************************************************
    函数功能:计算左右轮速
    入口参数:int *leftSpeed,int *rightSpeed
    返回  值:无
    		//计算左右车轮线速度,正向速度为正值 ,反向速度为负值,速度为乘以1000之后的速度 mm/s
    		//一定时间内的编码器变化值*转化率(转化为直线上的距离m)*200s(5ms计算一次) 得到 m/s *1000转化为int数据
    
    		一圈的脉冲数:
    			左:1560
    			右:1560
    		轮子半径:0.03m
    		轮子周长:2*pi*r
    		一个脉冲的距离:
    			左:0.000120830m
    			右:0.000120830m
    		速度分辨率:
    			左: 0.0240m/s 
    			右: 0.0240m/s 
    			200  5ms的倒数
    			1000 扩大分辨率
    **************************************************************************/
    
    void Get_Motor_Speed(int *leftSpeed,int *rightSpeed)
    {
    	//5ms测速 5ms即这里说的单位时间  	
    	*leftSpeed   = getTIMx_DetaCnt(TIM4)*1000*200*0.000120830;  
    	*rightSpeed  = getTIMx_DetaCnt(TIM2)*1000*200*0.000120830;
    }
    
    

    (2)main.c

    #include "sys.h"
    
    //====================自己加入的头文件===============================
    #include "delay.h"
    #include "led.h"
    #include "encoder.h"
    #include "usart3.h"
    #include "timer.h"
    #include <stdio.h>
    //===================================================================
    
    int leftSpeedNow  =0;
    int rightSpeedNow =0;
    
    int main(void)
    { 
    
    	GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
    	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁用JTAG 启用 SWD
    	
    	MY_NVIC_PriorityGroupConfig(2);	//=====设置中断分组
    	
    	delay_init();	    	        //=====延时函数初始化
    	LED_Init();                     //=====LED初始化    程序灯	
    	
    	usart3_init(9600);              //=====串口3初始化  蓝牙 发送调试信息
    
    	Encoder_Init_TIM2();            //=====初始化编码器1接口
    	Encoder_Init_TIM4();            //=====初始化编码器2接口
    	
    	TIM3_Int_Init(50-1,7200-1);     //=====定时器初始化 5ms一次中断
    	
    	while(1)
    	{
    		printf("L=%d,R=%d\r\n",leftSpeedNow,rightSpeedNow);
    		delay_ms(15);
    	} 
    }
    
    //5ms 定时器中断服务函数
    
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    	{
    		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);   //清除TIMx的中断待处理位:TIM 中断源 
    		
    		Get_Motor_Speed(&leftSpeedNow,&rightSpeedNow);
    		Led_Flash(100);
    	}
    }
    
    

    2.2.4 总结

    上面的一篇文章,我们实现的STM32单片机对直流减速电机的测速。再加上之前介绍的电机PWM控制,下一篇我们要结合前两篇的内容加上PID实现对电机速度的闭环控制。

    系列文章

    以往链接,点击访问。

    上一篇STM32电机PWM控制
    下一篇STM32电机PID速度控制
    系列文章从零搭建ROS机器人

    如果你感觉,我的文章比较适合你,关注我,点个赞,给你不一样的惊喜。
    在这里插入图片描述

    展开全文
  • stm32霍尔编码器

    千次阅读 2020-10-28 20:12:58
    霍尔编码器 想用一个定时器实现测速但是 TIM_Period ARR 过程中要读取cnt并置零 所以要两定时器 可用是stm32的霍尔编码功能;AB项那个上升沿先到判断cnt加减; TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI...

    霍尔编码器

    想用一个定时器实现测速但是 TIM_Period ARR 过程中要读取cnt并置零 所以要两定时器

    可用是stm32的霍尔编码功能;AB项那个上升沿先到判断cnt加减;

    TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,
                                    TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);检查全上升沿
    

    无所谓方向问题实验一下就行了而且无法确认霍尔编码器那个的AB项(我菜我也不明白)
    在这里插入图片描述
    在这里插入图片描述

    void  Speed_Init(void)
    {
    	GPIO_InitTypeDef  GPIO_Struct;
    	TIM_TimeBaseInitTypeDef  TIM_Base_Struct;
    	TIM_ICInitTypeDef TIM_IC_Struct;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	
    	GPIO_Struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Struct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    	GPIO_Init(GPIOA,&GPIO_Struct);
    	
    	TIM_DeInit(TIM3);//预防
    	TIM_Base_Struct.TIM_Period = 6000;
    	TIM_Base_Struct.TIM_Prescaler = 0;
    	TIM_Base_Struct.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_Base_Struct.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM3, &TIM_Base_Struct);
    	
    	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,
                                    TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//霍尔编码
    	
    	TIM_IC_Struct.TIM_ICFilter = 9;
    	TIM_ICInit(TIM3, &TIM_IC_Struct);
    	
        TIM_Cmd(TIM3, ENABLE);
    	
    }
    
    static  void  NVIC_Tim6_Init(void)
    {
    	NVIC_InitTypeDef  NVIC_Tim6_Struct;
    	
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    	NVIC_Tim6_Struct.NVIC_IRQChannel = TIM6_IRQn;
    	NVIC_Tim6_Struct.NVIC_IRQChannelPreemptionPriority = 1;
    	NVIC_Tim6_Struct.NVIC_IRQChannelSubPriority = 4;
    	NVIC_Tim6_Struct.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_Tim6_Struct);
    }
    
    void  TIM6_Init(void)
    {
    	TIM_TimeBaseInitTypeDef  TIM_Base_Struct;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
    	
    	TIM_DeInit(TIM6);//预防
    	TIM_Base_Struct.TIM_Period = 999;
    	TIM_Base_Struct.TIM_Prescaler = 71;//1ms
    	TIM_TimeBaseInit(TIM6, &TIM_Base_Struct);
    	
    	TIM_ClearFlag(TIM6, TIM_FLAG_Update);
    	TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
        TIM_Cmd(TIM6, ENABLE);
    	
    	NVIC_Tim6_Init();
    
    }
    

    利用ARR重装可以实现正负的判断极短的时间内计数不可能太高

    #include "usart.h"
    #include "tim_speed.h"
    #include "delay.h"
    int count = 0;
    u16  time = 0;
    float speed = 0;
    int main (void)
    {
    	
    	Speed_Init();
    	USART_Config();
    	delay_init();
    	TIM6_Init();
    	while(1){
    		if(time == 500){
    			count = (short)TIM3 -> CNT;  
    			TIM3 -> CNT=0;
    			if(count<5000){
    				speed = count/1540*3.1415*2*0.03/(time/1000);
    				printf("%5.3f\r\n",speed);
    			}else {
    				speed = (6000-count)/1540*3.1415*2*0.03/(time/1000);//由于电机年代久远搞不清楚减速比自己手动转一圈多次测试大概在1540
    				printf("-%5.3f\r\n",speed);
    			}
    			time = 0;
    		}
    			
    	}
    
    }
    void TIM6_IRQHandler(void)
    {
    	if ( TIM_GetITStatus( TIM6, TIM_IT_Update) != RESET ){	
    		time++;
    		TIM_ClearITPendingBit(TIM6 , TIM_FLAG_Update);  		
    	}		 
    }
    

    学习中。。。。。仅作参考。

    展开全文
  • 分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机。先来看一下最基本的 接线方法——- ——S1与S2连接单片机上的S(我这里用的2号和3号,是中断引脚); ——G与V连接单片机上的G与V(对着接就行...
  • 基于STM32F4的霍尔编码器解析程序,可以做辨向和解析速度
  • 霍尔编码器原理及测速--PID—arduino

    万次阅读 多人点赞 2020-03-04 17:13:28
    分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机带霍尔传感器。先来看一下最基本的 接线方法------- ------S1与S2连接单片机上的S(我这里用的2号和3号,是中断引脚); ------G与V连接单片机上...

    标题

    本人目前是一个大一菜鸟,最近在学编码器方面的知识,希望我的经验对你有些帮助。
    分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机。先来看一下最基本的
    接线方法-------
    在这里插入图片描述

    测速原理

    ##测速原理
    这里需要用到一些基本函数,大家可以去相关网站去找一下,重要的是定时器函数和中断函数
    我用的这个电机脉冲数双相300个,单相150个。(电机的型号不同可能会不一样,如果店家那没有的话可以抠出来下面一部分程序测)
    具体思路:首先使用定时器定时一个时间,我这里用的是50ms。编码器转一圈会发送脉冲,一个脉冲可以产生一个中断,在中断函数里令一个变量自加,每产生一个脉冲该变量就加1。所以该变量就是脉冲数。
    通过50ms内产生得脉冲数就可以算出速度了(这里是角速度,如果要具体算速度的话乘以轮子半径即可)。用脉冲数/150( 这里用单相或者双相都一样,我用的单相得)即可得到在这50ms内电机转动得圈数。再乘以20就是一秒内转的圈数,再乘以60就是一分钟转的圈数 。 下面是代码
    打开串口绘图器即可观察数据(打印函数一定要用 Serial.println()才可以显示哦)

    #include <TimerOne.h>
    float v;
    volatile long counter_val0=0;
    volatile long counter_val1=0;      //该变量用于存储编码器的值,所以用类型修饰符volatile;
    int j=0;                           //定时器标志;
    
    void setup()
    {
      delay(2000);
      pinMode(2, INPUT);
      pinMode(3, INPUT);                    //设置为输入模式,并且2,3号引脚是中断口0,1;
    
      Serial.begin(115200);                //初始化波特率为115200
      attachInterrupt(0, counter0, RISING);//设置编码器A相位上升沿中断
      attachInterrupt(1, counter1, RISING);//设置编码器B相位上升沿中断
      Timer1.initialize(50000);            // 设置定时器中断时间,单位微秒 ,这里是50毫秒
      Timer1.attachInterrupt( timerIsr ); // 打开定时器中断
      interrupts();                      //打开外部中断
    }
    void loop()
    {
      long lTemp = 0; //定义临时存储数据变量
      if(j==1)        //判断是否发生定时器中断,这里是50ms发生一次
       {
           j=0;       //清除标记
       }     
    }
    //外部中断处理函数
    void counter0()
    {
         counter_val0++;    //每一个中断加一
    }
    void counter1()
    {
         counter_val1++;    //每一个中断加一
    }
    //定时器中断处理函数
    void timerIsr()
    {
       j=1;                           //定时时间达到标志     
       v=60*20*counter_val0/150.0;    //这里的单位是转每分钟:r/min
       Serial.println(v);    
       counter_val0=0;
       counter_val1=0;               //清空该时间段内的脉冲数
       return v;                
    }
    

    PID

    如果有对PID算法感兴趣的我们可以讨论下,根据编码器测速写了一个控制电机速度的算法,但是参数我还没调出来。下面是源代码。如果有错误希望大佬们给我提醒一下

    #include <TimerOne.h>
    #define set_point 100
     float v;
    long counter_val0=0;
    long counter_val1=0;
    int j=0;
    
    void setup()
    {
      delay(2000);
      pinMode(2, INPUT);
      pinMode(3, INPUT);
      pinMode(8,OUTPUT);
      pinMode(9,OUTPUT);       //启用电机A的三个管脚,全部设置为输出状态
      digitalWrite(9, LOW);       //松开电机A的制动
      digitalWrite(8, HIGH);      //设置方向为正向旋转
      Serial.begin(115200);//初始化波特率为115200
      attachInterrupt(0, counter0, RISING);//设置编码器A相位上升沿中断
      attachInterrupt(1, counter1, RISING);//设置编码器B相位上升沿中断
      Timer1.initialize(50000); // 设置定时器中断时间,单位微秒
      Timer1.attachInterrupt( timerIsr ); // 打开定时器中断
      interrupts();  //打开外部中断
    }
    void loop()
    {
      long lTemp = 0; //定义临时存储数据变量
      if(j==1)   //判断是否发生定时器中断,即定时时间是否到达
       {
           j=0; }
          int v1=(int)v;
           analogWrite(9,PIDControl_L(50,v1));
           analogWrite(8,0);
           
         
    }
    //外部中断处理函数
    void counter0()
    {
         counter_val0++;    //每一个中断加一
    }
    void counter1()
    {
         counter_val1++;    //每一个中断加一
    }
    //定时器中断处理函数
    void timerIsr()
    {
       j=1;     //定时时间达到标志     
       v=1200*counter_val0/150.0;
    
             Serial.println(v);  
       
       counter_val0=0;
       counter_val1=0;
       return v;
    }
    
    
    float PIDControl_L(int SpeedSet,int speed)        //pid
    {
        float Kp=50,Ki=9,kd=0.1;
        float cap;  
       int e=0,e1=0,e2=0;       
       static float PwmControl;
        static  float  pwm;
        e2=e1; 
        e1 = e; 
        e=SpeedSet-speed;
        PwmControl+=Kp *(e-e1)+ Ki*e+kd*(e-2e1+e2); 
        pwm=map(PwmControl,0, 60, 0, 255);
             
      
        cap = pwm;             
     
        return pwm;
    }
    

    `

    展开全文
  • 霍尔旋转编码器主要由旋转磁铁组合、取样电路和信号处理电路等部分组成,如图1所示。其中,旋转磁铁组合安装在胶印机收纸辊上,霍尔旋转编码器电路部分固定在机体上,敏感面对准磁极,两者间距小于5 mm,对收纸辊的...
  • 文章目录Bill of Material演示视频控制原理接线IDE 代码(仅使用A相位)IDE ... 带霍尔编码器(增量,正交)的直流电机 x 1; 电位器 x 1; 演示视频 【Arduino 101】霍尔编码器与闭环控制(白话) 控制原理 接线


    Bill of Material

    Arduino Uno x 1; L298N 马达驱动 x 1; 带霍尔编码器(增量,正交)的直流电机 x 1; 电位器 x 1;

    演示视频

    【Arduino 101】霍尔编码器与闭环控制(白话)

    控制原理

    在这里插入图片描述

    接线

    在这里插入图片描述

    IDE 代码 I(仅使用A相位)

     /*
    Bnag Bnang Control with Encoded DC Motor(霍尔编码器与起停控制直流电机)
    Last Edited: Feb.27th.2021 by Mun Kim
    Contact: robotix.kim@gmail.com     
    */
     
    // Motor encoder output pulse per rotation (change as required)// 每圈的脉冲数量,可以从数据手册中查找
    int PPR= 3;
     
    // Encoder output to Arduino Interrupt pin// 编码器的A相位接Arduino的D2.
    int encoder_A= 2; 
     
    // L298n Motor Driver // 马达驱动接线:D5控制PWM, D6与D7控制转动方向
    int enB= 5; int in3= 6; int in4= 7;
     
    // Analog pin for potentiometer // 电位器接线:用来控制目标转速(不是PWM)
    int pot = 0;
     
    // Pulse count from encoder // 用来储存脉冲数量
    volatile long encoderCount = 0;
     
    // One-second interval for measurements // 每一秒进行一次测量与控制,可改小,ie: interval=100;
    int interval = 1000;
     
    // Counters for milliseconds during interval // 用来计算时间 
    long previousMillis = 0; long currentMillis = 0;
     
    // Variable for RPM measuerment //rpm: 实际测到的转速, setRPM:目标转速
    int rpm = 0; int setRPM=0;
     
    // Variable for PWM motor speed output // PWM初始值, 可以设为 0-255 之间的任意值
    int pwm = 50; 
     
    void setup(){
      Serial.begin(9600); 
      pinMode(encoder_A, INPUT_PULLUP);   
      attachInterrupt(digitalPinToInterrupt(encoder_A), ISR_Encoder, RISING);
      previousMillis = millis();
    }
     
    void loop(){
        // Set desired RPM // 把电位器读数转换成目标转速(2000到10000转每分钟)
        setRPM = map(analogRead(pot), 0, 1023, 2000, 10000);
        
        //Set motor direction // 马达转动方向
        digitalWrite(in3, HIGH); digitalWrite(in4,LOW);
        
    
        // Update RPM value every second // 每一秒更新一次测量转速
        currentMillis = millis();
        if (currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;
     
        // Calculate RPM // 计算
        rpm = (float)((encoderCount/PPR)*(1000/interval)*60);
     
        // 串口监视器上显示目标,Arduino 输出的 PWM, 以及测量到的RPM
          Serial.print("Set RPM: ");         Serial.print(setRPM);
          Serial.print('\t');
          Serial.print("Measured RPM: ");    Serial.print(rpm);
          Serial.print('\t');
          Serial.print("Crrent PWM: ");    Serial.println(pwm);
       
        //Bang Bang control // 起停式控制了
          if(rpm < setRPM){ pwm++; }   
          if(rpm > setRPM){ pwm--; }
          else{pwm=pwm;} 
    
        analogWrite(enB, pwm); //调整马达转速
    
        //pulse count reset // 累计脉冲数量重置,为下一秒测量做准备  
        encoderCount = 0; 
        }
      
    }
    
     // Interupt service routine.
    void ISR_Encoder(){
      encoderCount++; }
    

    IDE 代码 II(改用A & B相位)

    1. 如果测量到的RPM是负数,代表马达在逆时针旋转。
    2. 追加定义一个encoder_B.
    // Encoder output to Arduino Interrupt pin// 编码器的A相位接Arduino的D2.
    int encoder_A= 2; int encoder_B=3;
    
    1. ISR 的激发从上升沿(Trigger on RISING)改成 “CHANGE”.
      ie: 无论信号是由高到低还是由低到高,只要变化就会激发ISR。
    void setup() {
      pinMode(enoder_A, INPUT);
      pinMode(encoder_B, INPUT);
      attachInterrupt(digitalPinToInterrupt(encoder_A), ISR_EncoderA, CHANGE);
      attachInterrupt(digitalPinToInterrupt(encoder_B), ISR_EncoderB, CHANGE);
    }
    
    1. 更改Interrupt Service Routine (将代码与下面的示意图相比较会好理解一些)
      在这里插入图片描述
    void ISR_EncoderA() {
    // Phase A: Low to High // A相位从低到高
      if (digitalRead(encoder_A) == HIGH) {
        // check phase B // 观察B相位从而判断转动方向
        if (digitalRead(encoder_B) == LOW) {
          encoderCount++; }        // CW, 顺时针  
        else {
          encoderCount--; }       // CCW, 逆时针  
      }
    
      else  // Phase A: High to Low // A相位从高到低 
      {
        // check phase B // 观察B相位从而判断转动方向
        if (digitalRead(encoder_B) == HIGH) {
          encoderCount++; }         // CW   
        else {
          encoderCount--; }         // CCW
        }
     }
    
    void ISR_EncoderB() {
      if (digitalRead(encoder_B) == HIGH) {
        if (digitalRead(encoder_A) == HIGH) {
         encoderCount++;        
        }
        else {
          encoderCount--;        
        }
      }
      else {
        if (digitalRead(encoder_A) == LOW) {
          encoderCount++;}          
        else {
         encoderCount--;}         
         }
    }
    
    展开全文
  • arduino 霍尔编码器测速
  • STM32cubeMX--增量式PID调节电机速度(霍尔编码器

    千次阅读 多人点赞 2021-05-08 10:32:22
    目录前言一、直流减速电机与霍尔编码器1.1、编码器介绍与选择1.2、编码器参数1.3、编码器测速原理1.3.1、方向判断1.3.2、速度获取二、STM32cubeMX库配置编码器模式2.1、连线分析2.2、cubeMX设置2.2.1、cubeMX初始化...
  • stm32f103测脉冲数用于带霍尔编码器的电机测速

    千次阅读 多人点赞 2020-10-29 18:14:50
    在使用带霍尔编码器的电机时,需要捕获脉冲,来达到测电机的转速的目的,捕获脉冲的方式有很多,我刚开始选用的是定时器捕获,后因需要测度多个电机的速度,STM32F103的定时器感觉不够用,所以选择EXTI以达到捕获高...
  • Micropython——基于PYB的霍尔编码器电机测速与使用

    千次阅读 热门讨论 2020-07-24 19:54:23
    文章目录编码器电机简介霍尔传感器编码器电机接线编码器读取代码 编码器电机简介 霍尔传感器 编码器电机接线 DM420驱动器 PYB 编码器A相 X1(TIM2,CH1) 编码器B相 X2(TIM2,CH2) 编码器5V V+(Vin) 编码...
  • Micropython——基于PYB的霍尔编码器电机测速与使用 需要注意的是,在霍尔编码器电机的PID控制中,我们需要用到硬件模块: PYB L298N 或 TB6612 霍尔编码器电机 12V电源或可调电压源 电机的接线如下(如果是有两个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,466
精华内容 586
关键字:

霍尔编码器