NodeMcu(ESP8266)+LedControl库实现32x8点阵滚动显示

前言

想着搞一个32x8的点阵时钟,过程中就想着要让显示内容动起来,然后搞了一天终于搞出来,分享给大家!

视频展示

废话不多说,先发一个效果视频。

硬件接线

接线可参考如下接线图(不擅长画图,随便画一画):

代码

这个主要是代码太绕了,脑子转不过来,这个代码主要还是使用了LedControl库,所以理论上只要能用这个库的arduino板子都是可以使用这段代码的(需要简单修改一下)

秉承不重复造轮子的思想(其实是不想自己去摸索),驱动max7219我们使用了LedControl库;这个库默认是没有的, 需要自己到库文件管理中搜索(工具->管理库->搜索LedControl->选第一个);

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <LedControl.h>

const int DIN = D7;
const int CS = D6;
const int CLK = D5;

// 示例化对象 4:表示4个点阵屏幕
LedControl lc = LedControl(DIN, CLK, CS, 4);


unsigned char templatedata[10][8] = {
{0x0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0x0, 0x0},// 0
{0x0, 0x40, 0xC0, 0x40, 0x40, 0xE0, 0x0, 0x0},// 1
{0x0, 0xE0, 0x20, 0xE0, 0x80, 0xE0, 0x0, 0x0},// 2
{0x0, 0xE0, 0x20, 0xE0, 0x20, 0xE0, 0x0, 0x0},// 3
{0x0, 0xA0, 0xA0, 0xE0, 0x20, 0x20, 0x0, 0x0},// 4
{0x0, 0xE0, 0x80, 0xE0, 0x20, 0xE0, 0x0, 0x0},// 5
{0x0, 0xE0, 0x80, 0xE0, 0xA0, 0xE0, 0x0, 0x0},// 6
{0x0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0},// 7
{0x0, 0xE0, 0xA0, 0xE0, 0xA0, 0xE0, 0x0, 0x0},// 8
{0x0, 0xE0, 0xA0, 0xE0, 0x20, 0xE0, 0x0, 0x0}// 9
};

unsigned char writedata[4][8];

/**
获取需要显示的数字
*/
unsigned char * getshownum(uint8_t nums) {
unsigned char *ten = templatedata[(nums / 10)], *one = templatedata[nums % 10];
unsigned char *arr = new uint8_t [8];
for (int i = 0; i < 8; i++) {
arr[i] = *ten + ((*one & 0xE0) >> 4);
ten++;
one++;
}
return arr;
}


/**
显示数字

@param index 点阵屏序号
@param nums 需要显示的数字
*/
void shownum(int nums, int index) {
unsigned char *xs = getshownum(nums);
for (uint8_t i = 0; i < 8; i++) {
writedata[index][i] = *xs;
xs++;
}
}

/**
初始化写入数据
*/
void inits() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 8; j++) {
writedata[i][j] = 0x0;
}
}
}

/**
向左移动
*/
void rightMove() {
for (int i = 0; i < 8; i++) {
// 先获取第一个点阵的第一列数据
unsigned char first = writedata[0][i] & 0x80;
// 向右位移数据
first >>= 7;
// 从第二个点阵开始处理
for (int j = 1; j < 4; j++) {
// 获取点阵第一列数据
unsigned char temp = writedata[j][i] & 0x80;
// 向右位移数据
temp >>= 7;
// 清空最后一列的数据
writedata[j][i] &= 0x7F;
// 向左位移
writedata[j][i] <<= 1;
// 加上获取到的前一个点阵的第一列数据
writedata[j][i] += first;
first = temp;
// 这里单独为第一个点阵处理
if (j == (4 - 1)) {
// 清空最后一列的数据
writedata[0][i] &= 0x7F;
// 向左位移
writedata[0][i] <<= 1;
// 加上获取到的最后一个点阵的第一列数据
writedata[0][i] += first;
}
}
}
}

void Move1() {
for (int8_t i = 0; i < 4; i++) {
bool isbreadk = false;
for (int8_t j = 0; j < 8; j++) {
if (writedata[i][j] == 0xff) {
continue;
}
if (writedata[i][j] == 0x00) {
writedata[i][j] = 0x01;
isbreadk = true;
break;
}
writedata[i][j] += ((writedata[i][j] ^ (writedata[i][j] >> 1)) << 1);
}
if (isbreadk) {
break;
}
}
}

/**
动态显示数字
*/
void sliderNum(uint8_t index, uint8_t nums) {
// 保存原来的数字
unsigned char *xs = getshownum(nums);
bool ten = false, one = false;
// 这里的做法待优化,主要是判断个位或者十位部分是否改变,来判断是否需要刷新数字
for (uint8_t j = 0; j < 8; j++) {
// 判断十位部分是否变动
if ((writedata[index][j] & 0xf0) != (xs[j] & 0xf0)) {
ten = true;
}
// 判断个位部分是否变动
if ((writedata[index][j] & 0xf) != (xs[j] & 0xf)) {
one = true;
}
}
for (uint8_t i = 0; i < 8; i++) {
if (one) {
// 刷新个位部分数字
slideDown(index, xs[abs(i - 7)], true);
}
if (ten) {
// 刷线十位部分数字
slideDown(index, xs[abs(i - 7)], false);
}
showLed();
delay(80);
}
}


/**
刷新数字
*/
void slideDown(uint8_t index, unsigned char first, bool isright) {
unsigned char f = isright ? 0xf : 0xf << 4, f1 = isright ? 0xf0 : 0xf0 >> 4;
for (uint8_t k = 7; k > 0; k--) {
writedata[index][k] = (((writedata[index][k] & f1) + (writedata[index][k - 1] & f)) & f) + (writedata[index][k] & f1);
}
writedata[index][0] = ((first & f) & f) + (writedata[index][0] & f1);
}

void showLed() {
for (int j = 0; j < 8; j++) {
for (int i = 0; i < 4; i++) {
lc.setRow(i, j, writedata[i][j]);
}
}
}


void setup() {
//启用点阵
lc.shutdown(0, false);
lc.shutdown(1, false);
lc.shutdown(2, false);
lc.shutdown(3, false);
// 将亮度设置为最低
lc.setIntensity(0, 0);
lc.setIntensity(1, 0);
lc.setIntensity(2, 0);
lc.setIntensity(3, 0);
// 初始化数组
inits();
// 初始化数值
shownum(12, 2);
shownum(34, 1);
shownum(56, 0);
}

void loop() {
// 数字滚动显示
for (int j = 0; j < 8; j++) {
for (int i = 0; i < 4; i++) {
lc.setRow(i, j, writedata[i][j]);
}
}
// 整体移动函数
rightMove();
delay(150);

// 数字下滑显示

// for (uint8_t j = 0; j <= 99; j++) {
// sliderNum(0,j);
// sliderNum(1,j);
// sliderNum(2,j);
// sliderNum(3,j);
// delay(1000);
// }
}

结尾

这里我提供一个8x832x8点阵的在线取模工具,做的比较粗糙,如果有需要改进的地方欢迎在评论区留言。

8x8点阵的在线取模工具
32x8点阵的在线取模工具