服务器主板数码管显示ff,ESP8266之旋转编码器与四位数码管模块显示圈数

模块:NodeMCU

SDK版本:ESP8266_RTOS_SDK-3.0

开发环境:wsl+vscode

外设:增量式光电编码器,四位共阳数码管模块

很久没用8266了,最近做了个绕线计数器,手头只有一块NodeMCU,使用旋转编码器(某宝36块的那个)与数码管显示模块(某宝四块八)。

编码器:

编码器统一为外径38,轴6的,脉冲600 ,电压5~24V宽电压 ,输出方式 ,线长2m。电压默认5-24v,默认是AB信号。8266不像stm32有硬件编码接口,所以只能采用软件的方式实现。首先我们来看编码器的正转与反转波形图。

3629b3c7df65cdf559c2779b152c9f09.png

一个周期内的波形变化即可判断正转与反转,假设高电平为1,低电平为0,正转时信号A与B按照“11-10-00-01-11-10-00-01....”变化

反转时信号A与B按照“11-01-00-10-11-01-00-10....”变化

若将A与B按照二进制相加得到变化顺序如下:正转:3-2-0-1-3-2-0-1....

反转:3-1-0-2-3-1-0-2....

这样我们就只需要读取A与B两个信号高低电平就好了,正转与反正的变化顺序都是不一样的,总结下思路1.初始化GPIO,设置为输入读取电平

2.记住初始状态encOld,一个周期内四次变化,记住上电时的那次,以后每个周期以此为开始

3.读取实时状态encNow,如果没有变化表示编码器没有转动

4.一个周期有四次状态变化,只要判断连续的三次符合正转或者反转的状态变化,即返回相应的值

5.主函数中while循环并记录下每一个脉冲,600个脉冲为一圈,处理数据

下面是编码器代码#include

#include

#include "driver/gpio.h"

#include "encoder.h"

#include "gpio.h"

//A为低电平,B增高,A为高电平时B降低为正转

//A为低电平时B降低,A为高电平时B增高为正转

#define pinA 14 //编码器信号A

#define pinB 12 //编码器信号B

static int encA=0,encB=0;

static int enc0=0,enc1=0;

static int encOld=0,encX=0,encY=0;

int encNow;

unsigned char Encoder(void)

{

encY=encNow;

encA=gpio_get_level(pinA);

encB=gpio_get_level(pinB);

if(enc0==0)

{

encOld=(encA?2:0)+(encB?1:0);//记住初次使用时状态

enc0=1;

}

encNow=(encA?2:0)+(encB?1:0);//根据两个IO当前状态组合成16进制的0|1|2|3

if(encY==encNow) return(0);//如果相同就没有转动

//11-10-00-01是正转

//11-01-00-10是反转

if((encOld==3&&encNow==2)||(encOld==2&&encNow==0)||(encOld==0&&encNow==1)||(encOld==1&&encNow==3))encX=encNow;

if((encOld==3&&encX==2&&encNow==0)||(encOld==2&&encX==0&&encNow==1)||(encOld==0&&encX==1&&encNow==3)||(encOld==1&&encX==3&&encNow==2))

{

encX=0;

return('R');//正转返回R

}

if((encOld==3&&encNow==1)||(encOld==1&&encNow==0)||(encOld==0&&encNow==2)||(encOld==2&&encNow==3))encX=encNow;

if((encOld==3&&encX==1&&encNow==0)||(encOld==1&&encX==0&&encNow==2)||(encOld==0&&encX==2&&encNow==3)||(encOld==2&&encX==3&&encNow==1))

{

encX=0;

return('L');//反转返回L

}

return(0);//无效返回0

}

数码管模块:

四位数码管模块采用2片595驱动数码管,需要单片机3路IO口,根据数码管动态扫描原理进行显示。店家给的例程只有51单片机和Ardiuno的,不过驱动原理很简单,需要的IO口也很少,稍微改改就能用了,这里只贴了数码管部分,还需要初始化GPIO

四位数码管的三个IO口为SCLK,RCLK,DIO,分别作用为打入信号,时钟脉冲信号,和串行数据输入信号#include

#include "freertos/FreeRTOS.h"

#include "freertos/task.h"

#include "freertos/queue.h"

#include "esp_system.h"

#include "esp_spi_flash.h"

#include "driver/gpio.h"

#include "display.h"

#include "gpio.h"

#define GPIO_BLUE_LED 2

#define DIO 5 //串行数据输入

#define RCLK 4 //时钟脉冲信号,上升沿有效

#define SCLK 0 //打入信号,上升沿有效

unsigned char LED[8]; //用于LED的8位缓存

unsigned char LED_0F[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf,0X00};

//数码管显示0123456789AbCdEF-

unsigned char LED_1F[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//带小数点的数字0.1.2.3.4.5.6.7.8.

//显示

void LED4_Display (void)

{

unsigned char *led_table; // 查表指针

unsigned char i;

//显示第1位

led_table = LED_0F + LED[0];

i = *led_table;

LED_OUT(i);

LED_OUT(0x01);

gpio_set_level(RCLK,0);

gpio_set_level(RCLK,1);

//显示第2位,带小数点

led_table = LED_1F + LED[1];

i = *led_table;

LED_OUT(i);

LED_OUT(0x02);

gpio_set_level(RCLK,0);

gpio_set_level(RCLK,1);

//显示第3位

led_table = LED_0F + LED[2];

i = *led_table;

LED_OUT(i);

LED_OUT(0x04);

gpio_set_level(RCLK,0);

gpio_set_level(RCLK,1);

//显示第4位

led_table = LED_0F + LED[3];

i = *led_table;

LED_OUT(i);

LED_OUT(0x08);

gpio_set_level(RCLK,0);

gpio_set_level(RCLK,1);

}

void LED_OUT(unsigned char X)

{

unsigned char i;

for(i=8;i>=1;i--)

{

if (X&0x80)

{

gpio_set_level(DIO,1);

}

else

{

gpio_set_level(DIO,0);

}

X<<=1;

gpio_set_level(SCLK,0);

gpio_set_level(SCLK,1);

}

}

使用的时候先给LED[]赋值,即要显示的数字,例如LED[0]=6,第四个数码管就会显示6,把函数LED4_Display ();放到while里面循环或者RTOS任务里面定时执行即可。

存在的问题:

转速过快会丢失脉冲导致不准,不过我这里的转速下是准确的,够用了。(买的时候以为精度越高越好,这下坑了自己

还有while循环中不要使用printf,这样会拖慢cpu速度。 阅读量:6423

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一种可能的C语言代码实现: #include <stdio.h> #include <stdlib.h> #include <wiringPi.h> // 引入wiringPi库 #define CLK_PIN 0 // CLK引脚 #define DT_PIN 1 // DT引脚 #define SW_PIN 2 // SW引脚 #define MAX_VALUE 9 // 数码管最大值 int main(void) { int value = 0; // 初始值为0 int clk_state, dt_state, sw_state, last_clk_state = HIGH; wiringPiSetup(); // 初始化wiringPi库 pinMode(CLK_PIN, INPUT); pinMode(DT_PIN, INPUT); pinMode(SW_PIN, INPUT); pullUpDnControl(CLK_PIN, PUD_UP); // 配置CLK引脚上拉电阻 pullUpDnControl(DT_PIN, PUD_UP); // 配置DT引脚上拉电阻 pullUpDnControl(SW_PIN, PUD_UP); // 配置SW引脚上拉电阻 while (1) { // 无限循环 clk_state = digitalRead(CLK_PIN); // 读取CLK引脚状态 dt_state = digitalRead(DT_PIN); // 读取DT引脚状态 sw_state = digitalRead(SW_PIN); // 读取SW引脚状态 if (clk_state != last_clk_state) { // 如果CLK引脚状态发生变化 if (dt_state != clk_state) { // 如果DT引脚状态与CLK引脚状态不同,即旋转方向为正 if (value < MAX_VALUE) { // 如果数码管显示的值小于最大值 value++; // 数码管值加1 } } else { // 如果DT引脚状态与CLK引脚状态相同,即旋转方向为负 if (value > 0) { // 如果数码管显示的值大于0 value--; // 数码管值减1 } } printf("Value: %d\n", value); // 输出当前数码管值 } last_clk_state = clk_state; // 记录上一次CLK引脚状态 delay(50); // 延时50毫秒,避免滤波 } return 0; } 这段代码使用了wiringPi库来读取旋转编码器的CLK和DT引脚状态,并通过判断旋转方向来递增或递减一个变量value的值。在每次变化时,它会输出当前数码管值。同时,还使用了SW引脚来实现另一个功能,可以根据需要进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值