STM32 学习总结4 --- 编码器 旋钮式 增量编码器

  这个我实在网上找了好久找了一个可用的程序,大部分,你搜索编码器程序出来的都是电机的相关程序,而我要的是旋钮式的,PEC11-4020F-S0018型号的编码器。

  这个代码写得挺完善的,就是没有写主函数,因此调用问题上,还是费了好些神才弄出来,关键它里面的一些定义,我很久没有些程序,都不清楚了,如:

typedef struct tagspin
{
    RotateStatus rotatestatus; // 旋转状态
    KeyStatus keystatus; // 按键状态
}struspin;

  我知道struct为结构体,但是typedef就真的忘了,百度一下,就清楚了。在主函数里只需

struspin left_spin;
struspin right_spin;

在调用函数void  Init_Spin_Status(struspin *left_spin, struspin *right_spin)和void  Read_Spin(struspin *left_spin, struspin *right_spin)时,就又忘了*left_spin这是指针的,因此:

Init_Spin_Status( &left_spin , &right_spin ); 要添加&

Read_Spin(&left_spin, &right_spin);

修改相关配置,在主函数加几句调用,便可以运行了,不过至今还有几个问题:

1、目前程序的执行是旋转编码器两次才有加1或减1;

2、PEC11-4020F-S0018码编器,一圈有30个定位,实物自己转出来数的。资料里0018 = 18 Pulses per 360 ° Rotation 我的理解是一圈18个脉冲,一圈有30个定位18个脉冲,那一个定位应该有几个脉冲呢?再研究下程序,怎么会转两个定位加1操作一次;

3、我用的循环扫描的方式,编码器有按键功能,当只有扫描编码器不显示数码管时,按键的程序是要亮灯,可是实际就是闪一下没有,不过当我在主程序里加上数码管的显示,按键的灯就可以一直亮着了;

4、在主函数的while里我又添加了另外四个独立按键的扫描,按键和编码器都可以正常运行,有个问题就是每次按键时,数码管的会闪一下,就好像按键时停止了一下数码管的显示,很明显,肉眼能观察到。

主要的部分程序:

// 初始化左右旋转编码器的状态
void Init_Spin_Status(struspin *left_spin, struspin *right_spin)
{
l  eft_spin->rotatestatus = SPIN_NO_ROTATE;
  left_spin->keystatus = KEY_NO_PRESSED;
  right_spin->rotatestatus = SPIN_NO_ROTATE;
  right_spin->keystatus = KEY_NO_PRESSED;
}

////////////////////////////////////////////////////////////
// 读取 2 旋转编码器的状态
static LEVEL last_leftspinkey_level= H, last_rightspinkey_level= H; // 保存的上一次按键的电平情况
static SpinABstatus last_leftspinABst=SPIN_AB_ST3, last_rightspinABst=SPIN_AB_ST3; // 保存的上一次AB引脚的电平情况
void Read_Spin(struspin *left_spin, struspin *right_spin)
{
  LEVEL now_leftspinkey_level, now_rightspinkey_level;
  LEVEL now_leftspinA_level, now_leftspinB_level;
  LEVEL now_rightspinA_level, now_rightspinB_level;
  SpinABstatus now_leftspinABst, now_rightspinABst;
  // 先读取旋转编码器的各引脚的电平值
  if( READ_SPIN_L_KEY() ) { now_leftspinkey_level = H; } // 读取左侧旋转编码器的按键电平值
  else { now_leftspinkey_level = L; }

  if( READ_SPIN_R_KEY() ) { now_rightspinkey_level = H; } // 读取右侧旋转编码器的按键电平值
  else { now_rightspinkey_level = L; }

  if( READ_SPIN_L_A() ) { now_leftspinA_level = H; } // 读取左侧旋转编码器的 A 信号电平值
  else { now_leftspinA_level = L; }

  if( READ_SPIN_L_B() ) { now_leftspinB_level = H; } // 读取左侧旋转编码器的 B 信号电平值
  else { now_leftspinB_level = L; }

  if( READ_SPIN_R_A() ) { now_rightspinA_level = H; } // 读取右侧旋转编码器的 A 信号电平值
  else { now_rightspinA_level = L; }

  if( READ_SPIN_R_B() ) { now_rightspinB_level = H; } // 读取右侧旋转编码器的 B 信号电平值
  else { now_rightspinB_level = L; }

  // 根据 左侧旋转编码器的按键 前后 两次的电平值, 确定按键状态
  if( (last_leftspinkey_level == H) && (now_leftspinkey_level == L) ) { left_spin->keystatus = KEY_JUST_PRESSED; }
  else if((last_leftspinkey_level == H) && (now_leftspinkey_level == H) ) { left_spin->keystatus = KEY_NO_PRESSED; }
  else if((last_leftspinkey_level == L) && (now_leftspinkey_level == H) ) { left_spin->keystatus = KEY_JUST_POPUP; }
  else { left_spin->keystatus = KEY_ALREADY_PRESSED; }

  // 根据 右侧旋转编码器的按键 前后 两次的电平值, 确定按键状态
  if( (last_rightspinkey_level == H) && (now_rightspinkey_level == L) ) { right_spin->keystatus = KEY_JUST_PRESSED; }
  else if((last_rightspinkey_level == H) && (now_rightspinkey_level == H) ) { right_spin->keystatus = KEY_NO_PRESSED; }
  else if((last_rightspinkey_level == L) && (now_rightspinkey_level == H) ) { right_spin->keystatus = KEY_JUST_POPUP; }
  else { right_spin->keystatus = KEY_ALREADY_PRESSED; }

  // 根据 左侧旋转编码器的 A B 的电平值, 确定 AB 状态
  if( (now_leftspinA_level == H) && (now_leftspinB_level == H) ) { now_leftspinABst = SPIN_AB_ST3; } // A=1 B=1;
  else if((now_leftspinA_level == H) && (now_leftspinB_level == L) ) { now_leftspinABst = SPIN_AB_ST2; } // A=1 B=0;
  else if((now_leftspinA_level == L) && (now_leftspinB_level == L) ) { now_leftspinABst = SPIN_AB_ST0; } // A=0 B=0;
  else { now_leftspinABst = SPIN_AB_ST1; } // A=0 B=1;

  // 根据 右侧旋转编码器的 A B 的电平值, 确定 AB 状态
  if( (now_rightspinA_level == H) && (now_rightspinB_level == H) ) { now_rightspinABst = SPIN_AB_ST3; } // A=1 B=1;
  else if((now_rightspinA_level == H) && (now_rightspinB_level == L) ) { now_rightspinABst = SPIN_AB_ST2; } // A=1 B=0;
  else if((now_rightspinA_level == L) && (now_rightspinB_level == L) ) { now_rightspinABst = SPIN_AB_ST0; } // A=0 B=0;
  else { now_rightspinABst = SPIN_AB_ST1; } // A=0 B=1;

  // 再根据 左侧旋转编码器 前后两次 AB信号线的状态, 确定是左旋还是右旋
  if( (last_leftspinABst == SPIN_AB_ST3) && (now_leftspinABst == SPIN_AB_ST2)){ left_spin->rotatestatus = SPIN_UNTICLOCKWISE; }
  else if ((last_leftspinABst == SPIN_AB_ST3) && (now_leftspinABst == SPIN_AB_ST1)){ left_spin->rotatestatus = SPIN_CLOCKWISE; }
  else { left_spin->rotatestatus = SPIN_NO_ROTATE; }

// 再根据 右侧旋转编码器 前后两次 AB信号线的状态, 确定是左旋还是右旋
if( (last_rightspinABst== SPIN_AB_ST3) && (now_rightspinABst== SPIN_AB_ST2)){ right_spin->rotatestatus = SPIN_UNTICLOCKWISE;}
else if ((last_rightspinABst== SPIN_AB_ST3) && (now_rightspinABst== SPIN_AB_ST1)){ right_spin->rotatestatus = SPIN_CLOCKWISE; }
else { right_spin->rotatestatus = SPIN_NO_ROTATE; }

last_leftspinkey_level = now_leftspinkey_level; // 保存当前状态,作为下次状态的依据
last_rightspinkey_level = now_rightspinkey_level;
last_leftspinABst = now_leftspinABst;
last_rightspinABst = now_rightspinABst;

}

// 右面旋转编码器,用户自己的代码
void Process_Right_Spin( struspin *rightspin)
{
  if(rightspin->keystatus == KEY_JUST_PRESSED) // 旋转编码器的按键刚按下的处理程序,用户自己填入
  {
    LED5=!LED5;

  }
  else if(rightspin->rotatestatus == SPIN_CLOCKWISE) // 旋转编码器顺时针旋转的处理程序,用户自己填入
  {
    right_NUM++;
  }
  else if(rightspin->rotatestatus == SPIN_UNTICLOCKWISE) // 旋转编码器反时针旋转的处理程序,用户自己填入
  {
    right_NUM--;
  }
}

//////////////////////////////////////////////////////
/////// 左面的旋转编码器 ///////////////
//#define RCC_LEFT_SPIN RCC_APB2Periph_GPIOC // 左面的旋转编码器使用的GPIOE时钟
//#define GPIO_SPIN_L_PORT GPIOC // 左面的旋转编码器驱动引脚所在的端口

#define SPIN_L_KEY_PIN GPIO_Pin_9 // 左面的旋转编码器 按键 引脚号
#define pinSPINleftKEY PIN9
#define SPIN_L_A_PIN GPIO_Pin_7 // 左面的旋转编码器 A 引脚号
#define pinSPINleftA PIN7
#define SPIN_L_B_PIN GPIO_Pin_8 // 左面的旋转编码器 B 引脚号
#define pinSPINleftB PIN8

#define READ_SPIN_L_KEY() PCin(pinSPINleftKEY) // PC9
#define READ_SPIN_L_A() PCin(pinSPINleftA) // PC7 读入 A 引脚的电平
#define READ_SPIN_L_B() PCin(pinSPINleftB) // PC8 读入 B 引脚的电平

///////////////////////////////////////////////////

typedef enum
{
  KEY_NO_PRESSED = 0,
  KEY_JUST_PRESSED ,
  KEY_ALREADY_PRESSED ,
  KEY_JUST_POPUP ,
}KeyStatus;

typedef enum
{
  L = 0, // 低电平
  H , // 高电平
}LEVEL;

typedef enum
{
  SPIN_NO_ROTATE = 0, // 无旋转
  SPIN_CLOCKWISE , // 顺时针旋转
  SPIN_UNTICLOCKWISE , // 反时针旋转
}RotateStatus;

typedef struct tagspin
{
  RotateStatus rotatestatus; // 旋转状态
  KeyStatus keystatus; // 按键状态
}struspin;

typedef enum
{
  SPIN_AB_ST0 = 0, // A=0 B=0;
  SPIN_AB_ST1 , // A=0 B=1;
  SPIN_AB_ST2 , // A=1 B=0;
  SPIN_AB_ST3 , // A=1 B=1;
}SpinABstatus; // 旋转编码器信号线 A B 的电平

Init_Spin_Status( &left_spin , &right_spin );
left_NUM=0;
right_NUM=0;
LED5=0;
while(1)
{
  Read_Spin(&left_spin, &right_spin);
  Process_LEFT_Spin(&left_spin);
  Process_Right_Spin( &right_spin);
  display(0,left_NUM);
  display(1,right_NUM); 
}

时间: 2024-11-05 18:51:01

STM32 学习总结4 --- 编码器 旋钮式 增量编码器的相关文章

降噪自编码器/稀疏自编码器/栈式自编码器

漫谈autoencoder:降噪自编码器/稀疏自编码器/栈式自编码器(含tensorflow实现) 2018年08月11日 20:45:14 wblgers1234 阅读数 13196更多 分类专栏: 机器学习 深度学习 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/wblgers1234/article/details/81545079 0. 前言   在非监督学习中,最典型的一类神经

STM32学习之路-LCD(2)<LCD初始化>

这些天一直在研究LCD的初始化函数,因为不过是用IO口模拟时序还是用FSMC来驱动LCD,都必须要弄好LCD的初始化 其实LCD的初始化就是跟着LCD IC的datasheet来写寄存器,大部分都使用上面的默认值,网上有很多修改的例子,这里就不 放出来了.但是我想写下一些比较重要的东西. 这是从网上下载来的一个文件的前半部分: 当然,别的型号的IC也是有这些东西的,不过可能有些地址不同而已. R0,这个命令有两个功能,如果对它写,则最低位为OSC,用于开启和关闭振荡器.而如果对它读操作, 则返回

STM32学习笔记——USART串口(向原子哥和火哥学习)

一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范围的波特率选择. STM32 的串口资源相当丰富的,功能也相当强劲.STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作.它还允许多处理器通信.

STM32学习笔记6(TIM通用模块生成PWM)

1.     TIMER输出PWM基本概念   脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术.简单一点,就是对脉冲宽度的控制.一般用来控制步进电机的速度等等. STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出. 1.1   PWM输出模式 S

STM32学习笔记(四)——串口控制LED(中断方式)

目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类型并使能串口中断 七.编写中断服务函数函数名格式为函数名格式为 USARTxIRQHandler(x 对应串口号). 八.主函数的实现. 一.时钟使能,包括GPIO的时钟和串口的时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //

STM32学习笔记——OLED屏

STM32学习笔记--OLED屏 OLED屏的特点: 1.  模块有单色和双色可选,单色为纯蓝色,双色为黄蓝双色(本人选用双色): 2.  显示尺寸为0.96寸 3.  分辨率为128*64 4.  多种接口方式,该模块提供了总共 5 种接口包括: 6800. 8080 两种并行接口方式. 3线或4线的SPI接口,IIC接口方式 5.  不需要高压,直接接3.3V就可以工作:(可以与stm32的引脚直接相接) OLED图片: OLED引脚介绍: CS:OLED片选信号 RST:OLED复位端口

STM32学习笔记4(TIM32位定时器的实现)

关于STM32的CPU为32位,定时器却为16位的探讨 STM32的通用定时器可以实现很多功能,例如:定时计数.测量外部信号脉冲宽度.产生PWM波形.测量输入的PWM波形等.在所有这些操作中,定时器的位数主要影响两个参数,一个是定时或测量的精度,另一个是定时的时间长度.下面我们以一个列表看一下定时的精度和定时的长度有多少: 关于各个预分频器的作用请参考下图的右半部分: 从表中可以看出,在最高精度下(14ns)定时长度只有0.91ms,在精度为250ns(即4MHz)时定时长度可达16.38ms.

STM32学习笔记之一(初窥STM32)

怎么做好学习笔记? 答:自我感知-->学习知识-->归纳总结-->自我升华(真正属于自己的知识是,抛开书本,运用时,你还能记得的思想) 自我感知--看到知识概念,先自我感觉那应该是个什么东西(如:寄存器---寄存东西(数据)的地方嘛) 学习知识--有了自我感知后,就需要验证自己的感知是否正确,请记住,带着自己思想的学习是最高效的学习(如:寄存器---存什么东西呢?) 归纳总结--学习了大量知识后,就该汇总汇总了(如:寄存器---存数据(通用寄存器),存命令(PC),存地址(LR)) 自我

STM32学习之路-外部中断(2)

OK,继续上篇的内容. 配置好外部中断源以后, 就得使能外部中断线了. 为了方便看再借下这个图: 对外部中断的使能其实就是配置上面这些寄存器.即使能哪EXIT线,选择上面模式,是中断还是事件,选择下降沿还是上升沿. 具体怎么写寄存器这就不研究了, = = 太麻烦了.. 直接用STM32的库就行了,来看看它的代码吧 这是EXTI结构体的初始化函数, void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct) { EXTI_InitStruct->