zoukankan      html  css  js  c++  java
  • STM32-增量式旋转编码器测量

     

    Development kit:MDK5.14

    IDE:UV4

    MCU:STM32F103C8T6

    一、增量式旋转编码器

    1、简介

    • 编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺。
    • 按照读出方式编码器可以分为接触式和非接触式两种;
    • 按照工作原理编码器可分为增量式和绝对式两类。增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。 
    • 旋转编码器是集光机电技术于一体的速度位移传感器。它将被测的角位移直接转换成数字信号(高速脉冲信号)。
    • 我们通常用的是增量型编码器,可将旋转编码器的输出脉冲信号直接输入给PLC,利用PLC的高速计数器对其脉冲信号进行计数,以获得测量结果。不同型号的旋转编码器,其输出脉冲的相数也不同,有的旋转编码器输出A、B、Z三相脉冲,有的只有A、B相两相,最简单的只有A相。A、B为相差90度的脉冲,Z相信号在编码器旋转一圈只有一个脉冲,通常用来做零点的依据,连接时要注意PLC输入的响应时间。旋转编码器还有一条屏蔽线,使用时要将屏蔽线接地,提高抗干扰性。
    • 信号输出有正弦波(电流或电压),方波(TTL、HTL),集电极开路(PNP、NPN),推拉式多种形式,其中TTL为长线差分驱动(对称A,A-;B,B-;Z,Z-),HTL也称推拉式、推挽式输出,编码器的信号接收设备接口应与编码器对应。信号连接—编码器的脉冲信号一般连接计数器、PLC、计算机,PLC和计算机连接的模块有低速模块与高速模块之分,开关频率有低有高。如单相联接,用于单方向计数,单方向测速。A.B两相联接,用于正反向计数、判断正反向和测速。A、B、Z三相联接,用于带参考位修正的位置测量。A、A-,B、B-,Z、Z-连接,由于带有对称负信号的连接,在后续的差分输入电路中,将共模噪声抑制,只取有用的差模信号,因此其抗干扰能力强,可传输较远的距离。对于TTL的带有对称负信号输出的编码器,信号传输距离可达150米。
    • 线数:旋转一周信号线输出脉冲数,也成为分辨率

    2、型号

    博主此篇文章使用的旋转编码器型号有两种。

    传感器(增量式旋转编码器)
    型号 供电电压 输出方式 分辨率 品牌/厂家 输出电平
    S20-1000型拉线位移传感器 5-24V NPN集电极开路 400 Omron/欧姆龙   

    DT100E40R1024-HI

    增量型大孔径编码器

     5-30V  HTL(推挽式)  1024

    冬莅自动化技术(上海)有限公司

    www.shdongli.cn

    高:VCC*70%

    低:1V

     

     

     

     

     

     

     

     

    二、硬件设计

       由于增量型编码器输出脉冲,可以直接接入PLC单片机,利用PLC高速计数器进行测量。将编码器接入STM32单片机需要一个定时器资源,并将定时器配置为编码器模式,稍后会简要介绍配置方法。根据传感器的输出方式,进而来判断是否需要进行信号预处理。对于集电极开路输出的传感器接入必须使用上拉电阻。注意STM32大多数引脚的输入电压都在3.3V左右,尽量不要过压。如果电压较大,最好加隔离电路,比如6N136光耦,类似下图

     

      我在这里并没有使用隔离电路,而是对传感器统一使用了5V供电,并在信号接入端人为加了3.3V上拉(上拉电阻1K),这种接口电路在我自己设计的采集板上统一留出了8个。编码器应用中并未使用Z相,仅使用了A、B两相进行编码器计数。按照线序说明接入STM32的定时器引脚,PA6、PA7对应TIM3的CH1、CH2通道,PB6、PB7对应TIM4的CH1、CH2通道。对于第二种传感器的推挽输出方式而言,实验证明这种接入电路也是可行的。(具体电路没有进行分析,只是图个方便。但是5*70%=3.5V应该是勉强可以直接接入stm32引脚的)

    三、软件设计

    1、STM32定时器编码器模式简介

      参考官方文档,摘录几个要点:

    • 编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。
    • 两个输入TI1和TI2被用来最为增量编码器的接口,TI1FP1和TI2FP2是TI1和TI2在通过滤波器和极性控制后的信号,计数器由每次在TI1FP1和TI2FP2的有效跳变驱动,根据跳变顺序,产生计数脉冲和方向信号,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应设计
    • IC1、TI1概念理解:TI1是定时器输入通道,IC1是输入捕获通道(两者可以交错)。配置CCMR1寄存器的CC1S位可以指定IC1的映射方式。可配置滤波器和预分频器。

     

    •  计数方向与编码器信号的关系

    2、软件实现

      1 /********************************************
      2 
      3 TIM3、TIM4定时器编码器模式配置
      4 
      5 *********************************************/
      6 
      7 #include "sys.h"
      8 #include "encoder.h"
      9 
     10 int TIM3ITCount=0;//中断溢出次数
     11 int TIM4ITCount=0;//中断溢出次数
     12 
     13 void TIM3_IRQHandler(void)
     14 {   
     15     if(TIM3->SR&0x0001)//溢出中断
     16     {
     17         
     18     }   
     19     TIM3->SR&=~(1<<0);//清除标志位    
     20 }
     21 
     22 void TIM4_IRQHandler(void)
     23 {   
     24     if(TIM4->SR&0x0001)//溢出中断
     25     {
     26     }   
     27     TIM4->SR&=~(1<<0);//清除标志位    
     28 }
     29 
     30 void TIM3_Encoder_Init()
     31 {
     32     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
     33     TIM_ICInitTypeDef TIM_ICInitStructure;
     34     GPIO_InitTypeDef GPIO_InitStructure;
     35     NVIC_InitTypeDef NVIC_InitStructure;
     36     
     37     //时钟使能
     38     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  //使能 TIM3 时钟
     39     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟
     40     
     41     //GPIO配置
     42     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PA6、PA7设置
     43     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
     44     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     45     GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA
     46     
     47     //定时器初始化
     48     TIM_DeInit(TIM3);
     49     TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
     50     TIM_TimeBaseStructure.TIM_Period =65535;//预装载值
     51     TIM_TimeBaseStructure.TIM_Prescaler = 0;//预分频
     52     TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
     53     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
     54     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
     55     
     56     //编码器模式配置
     57     TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);
     58     TIM_ICStructInit(&TIM_ICInitStructure);
     59     TIM_ICInitStructure.TIM_ICFilter = 6;//ICx_FILTER;
     60     TIM_ICInit(TIM3, &TIM_ICInitStructure);
     61     
     62     //初始化 NVIC 中断优先级分组
     63     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
     64     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
     65     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级
     66     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
     67     NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
     68     
     69     //中断配置
     70     TIM_ClearFlag(TIM3, TIM_FLAG_Update);
     71     TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
     72     
     73     //Reset counter
     74     TIM3->CNT = 0;
     75     //使能定时器
     76     TIM_Cmd(TIM3, ENABLE);   
     77 }
     78 
     79 void TIM4_Encoder_Init()
     80 {
     81     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
     82     TIM_ICInitTypeDef TIM_ICInitStructure;
     83     GPIO_InitTypeDef GPIO_InitStructure;
     84     NVIC_InitTypeDef NVIC_InitStructure;
     85     
     86     //时钟使能
     87     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  //使能 TIM4 时钟
     88     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能 GPIOB 时钟
     89     
     90     //GPIO配置
     91     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6、PB7设置
     92     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
     93     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     94     GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 GPIOA
     95     
     96     //定时器初始化
     97     TIM_DeInit(TIM4);
     98     TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
     99     TIM_TimeBaseStructure.TIM_Period =65535;//预装载值
    100     TIM_TimeBaseStructure.TIM_Prescaler = 0;//预分频
    101     TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
    102     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
    103     TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); 
    104     
    105     //编码器模式配置
    106     TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);
    107     TIM_ICStructInit(&TIM_ICInitStructure);
    108     TIM_ICInitStructure.TIM_ICFilter = 6;//ICx_FILTER;
    109     TIM_ICInit(TIM4, &TIM_ICInitStructure);
    110     
    111     //初始化 NVIC 中断优先级分组
    112     NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4 中断
    113     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
    114     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级 0 级
    115     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
    116     NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
    117     
    118     //中断配置
    119     TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    120     TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
    121     
    122     //Reset counter
    123     TIM4->CNT = 0;
    124     //使能定时器
    125     TIM_Cmd(TIM4, ENABLE);   
    126 }
    encoder.c

     

    3、注意事项

    • 更新中断可以不开。但是由于没有使用Z相信号,所以这里保留更新中断,实际上目前中断里什么也没做
    • 由于是双相下降沿计数,所以转一次会输出两个脉冲,转一周脉冲数为分辨率*2,注意处理。当然你也可以配置为其它计数倍数
    • 这里预装载65535,可改为线数*2,即可对转一周的位置进行严格编码
    • TIMx->CNT的值即为编码器的位置(并不一定是输出脉冲值,跟旋转方向和预装载值有关,增量编码器的零点是初始化自己定义的)
    • GPIO配置为浮空输入模式。对于集电极开路输出的编码器,如果你没有外部上拉,则使用内部上拉,配置为上拉输入模式即可。

     

    参考资料:

    1、百度百科-旋转编码器

    2、STM32定时器--正交编码器模式详解

  • 相关阅读:
    VMware Workstation安装CentOs7固定ip地址
    使用阿里云oss
    使用Yapi展示你的api接口
    .net core使用MQTT
    CentOS 7服务器安装brook和bbr加速
    博客主题
    自定义控件
    winform数据绑定
    is as 运算符
    反射
  • 原文地址:https://www.cnblogs.com/WhiteTears/p/9021854.html
Copyright © 2011-2022 走看看