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定时器--正交编码器模式详解

  • 相关阅读:
    Laravel 初始化
    ant design pro 左上角 logo 修改
    请求到服务端后是怎么处理的
    Websocket 知识点
    王道数据结构 (7) KMP 算法
    王道数据结构 (6) 简单的模式匹配算法
    王道数据结构 (4) 单链表 删除节点
    王道数据结构 (3) 单链表 插入节点
    王道数据结构 (2) 单链表 尾插法
    王道数据结构 (1) 单链表 头插法
  • 原文地址:https://www.cnblogs.com/WhiteTears/p/9021854.html
Copyright © 2011-2022 走看看