初始化提交
@@ -0,0 +1,260 @@
|
||||
MD_MAX72XX::fontType_t fontBG[] =
|
||||
{
|
||||
0, // 0
|
||||
0, // 1
|
||||
0, // 2
|
||||
0, // 3
|
||||
0, // 4
|
||||
0, // 5
|
||||
0, // 6
|
||||
0, // 7
|
||||
0, // 8
|
||||
0, // 9
|
||||
0, // 10
|
||||
0, // 11
|
||||
0, // 12
|
||||
0, // 13
|
||||
0, // 14
|
||||
0, // 15
|
||||
0, // 16
|
||||
0, // 17
|
||||
0, // 18
|
||||
0, // 19
|
||||
0, // 20
|
||||
0, // 21
|
||||
0, // 22
|
||||
0, // 23
|
||||
0, // 24
|
||||
0, // 25
|
||||
0, // 26
|
||||
0, // 27
|
||||
0, // 28
|
||||
0, // 29
|
||||
0, // 30
|
||||
0, // 31
|
||||
0, // 32
|
||||
0, // 33
|
||||
0, // 34
|
||||
0, // 35
|
||||
0, // 36
|
||||
0, // 37
|
||||
0, // 38
|
||||
0, // 39
|
||||
0, // 40
|
||||
0, // 41
|
||||
0, // 42
|
||||
0, // 43
|
||||
0, // 44
|
||||
0, // 45
|
||||
0, // 46
|
||||
0, // 47
|
||||
0, // 48
|
||||
0, // 49
|
||||
0, // 50
|
||||
0, // 51
|
||||
0, // 52
|
||||
0, // 53
|
||||
0, // 54
|
||||
0, // 55
|
||||
0, // 56
|
||||
0, // 57
|
||||
0, // 58
|
||||
0, // 59
|
||||
0, // 60
|
||||
0, // 61
|
||||
0, // 62
|
||||
0, // 63
|
||||
0, // 64
|
||||
0, // 65
|
||||
0, // 66
|
||||
0, // 67
|
||||
0, // 68
|
||||
0, // 69
|
||||
0, // 70
|
||||
0, // 71
|
||||
0, // 72
|
||||
0, // 73
|
||||
0, // 74
|
||||
0, // 75
|
||||
0, // 76
|
||||
0, // 77
|
||||
0, // 78
|
||||
0, // 79
|
||||
0, // 80
|
||||
0, // 81
|
||||
0, // 82
|
||||
0, // 83
|
||||
0, // 84
|
||||
0, // 85
|
||||
0, // 86
|
||||
0, // 87
|
||||
0, // 88
|
||||
0, // 89
|
||||
0, // 90
|
||||
0, // 91
|
||||
0, // 92
|
||||
0, // 93
|
||||
0, // 94
|
||||
0, // 95
|
||||
0, // 96
|
||||
0, // 97
|
||||
0, // 98
|
||||
0, // 99
|
||||
0, // 100
|
||||
0, // 101
|
||||
0, // 102
|
||||
0, // 103
|
||||
0, // 104
|
||||
0, // 105
|
||||
0, // 106
|
||||
0, // 107
|
||||
0, // 108
|
||||
0, // 109
|
||||
0, // 110
|
||||
0, // 111
|
||||
0, // 112
|
||||
0, // 113
|
||||
0, // 114
|
||||
0, // 115
|
||||
0, // 116
|
||||
0, // 117
|
||||
0, // 118
|
||||
0, // 119
|
||||
0, // 120
|
||||
0, // 121
|
||||
0, // 122
|
||||
0, // 123
|
||||
0, // 124
|
||||
0, // 125
|
||||
0, // 126
|
||||
0, // 127
|
||||
0, // 128
|
||||
0, // 129
|
||||
0, // 130
|
||||
0, // 131
|
||||
0, // 132
|
||||
0, // 133
|
||||
0, // 134
|
||||
0, // 135
|
||||
0, // 136
|
||||
0, // 137
|
||||
0, // 138
|
||||
0, // 139
|
||||
0, // 140
|
||||
0, // 141
|
||||
0, // 142
|
||||
0, // 143
|
||||
0, // 144
|
||||
0, // 145
|
||||
0, // 146
|
||||
0, // 147
|
||||
0, // 148
|
||||
0, // 149
|
||||
0, // 150
|
||||
0, // 151
|
||||
0, // 152
|
||||
0, // 153
|
||||
0, // 154
|
||||
0, // 155
|
||||
0, // 156
|
||||
0, // 157
|
||||
0, // 158
|
||||
0, // 159
|
||||
0, // 160
|
||||
0, // 161
|
||||
0, // 162
|
||||
0, // 163
|
||||
0, // 164
|
||||
0, // 165
|
||||
0, // 166
|
||||
0, // 167
|
||||
0, // 168
|
||||
0, // 169
|
||||
0, // 170
|
||||
0, // 171
|
||||
0, // 172
|
||||
0, // 173
|
||||
0, // 174
|
||||
0, // 175
|
||||
0, // 176
|
||||
0, // 177
|
||||
0, // 178
|
||||
0, // 179
|
||||
0, // 180
|
||||
0, // 181
|
||||
0, // 182
|
||||
0, // 183
|
||||
0, // 184
|
||||
0, // 185
|
||||
0, // 186
|
||||
0, // 187
|
||||
0, // 188
|
||||
0, // 189
|
||||
0, // 190
|
||||
0, // 191
|
||||
5, 0x7e, 0x11, 0x11, 0x11, 0x7e, // 192 - '?' x0c0
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x31, // 193 - '?' x0c1
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x36, // 194 - 'B' x0c2
|
||||
5, 0x7f, 0x01, 0x01, 0x01, 0x03, // 195 - '?' x0c3
|
||||
6, 0xc0, 0x7e, 0x41, 0x41, 0x7e, 0xc0, // 196 - '?' x0c4
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x41, // 197 - 'E' x0c5
|
||||
5, 0x77, 0x08, 0x7f, 0x08, 0x77, // 198 - '?' x0c6
|
||||
5, 0x41, 0x49, 0x49, 0x49, 0x36, // 199 - '?' x0c7
|
||||
5, 0x7f, 0x10, 0x08, 0x04, 0x7f, // 200 - '?' x0c8
|
||||
5, 0x7f, 0x10, 0x09, 0x04, 0x7f, // 201 - '?' x0c9
|
||||
5, 0x7f, 0x08, 0x14, 0x22, 0x41, // 202 - 'K' x0ca
|
||||
5, 0x40, 0x3e, 0x01, 0x01, 0x7f, // 203 - '?' x0cb
|
||||
5, 0x7f, 0x02, 0x0c, 0x02, 0x7f, // 204 - 'M' x0cc
|
||||
5, 0x7f, 0x08, 0x08, 0x08, 0x7f, // 205 - 'H' x0cd
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x3e, // 206 - 'O' x0ce
|
||||
5, 0x7f, 0x01, 0x01, 0x01, 0x7f, // 207 - '?' x0cf
|
||||
5, 0x7f, 0x09, 0x09, 0x09, 0x06, // 208 - '?' x0d0
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x22, // 209 - 'C' x0d1
|
||||
5, 0x03, 0x01, 0x7f, 0x01, 0x03, // 210 - 'T' x0d2
|
||||
5, 0x27, 0x48, 0x48, 0x48, 0x3f, // 211 - '?' x0d3
|
||||
7, 0x1c, 0x22, 0x22, 0x7f, 0x22, 0x22, 0x1c, // 212 - '?' x0d4
|
||||
5, 0x63, 0x14, 0x08, 0x14, 0x63, // 213 - 'X' x0d5
|
||||
6, 0x7f, 0x40, 0x40, 0x40, 0x7f, 0xc0, // 214 - '?' x0d6
|
||||
5, 0x07, 0x08, 0x08, 0x08, 0x7f, // 215 - '?' x0d7
|
||||
5, 0x7f, 0x40, 0x7f, 0x40, 0x7f, // 216 - '?' x0d8
|
||||
6, 0x7f, 0x40, 0x7f, 0x40, 0x7f, 0xc0, // 217 - '?' x0d9
|
||||
7, 0x01, 0x01, 0x7f, 0x48, 0x48, 0x48, 0x30, // 218 - '?' x0da
|
||||
5, 0x7f, 0x48, 0x48, 0x30, 0x7f, // 219 - '?' x0db
|
||||
5, 0x7f, 0x48, 0x48, 0x48, 0x30, // 220 - '?' x0dc
|
||||
5, 0x22, 0x41, 0x49, 0x49, 0x3e, // 221 - '?' x0dd
|
||||
6, 0x7f, 0x08, 0x3e, 0x41, 0x41, 0x3e, // 222 - '?' x0de
|
||||
5, 0x46, 0x29, 0x19, 0x09, 0x7f, // 223 - '?' x0df
|
||||
5, 0x20, 0x54, 0x54, 0x54, 0x78, // 224 - '?' x0e0
|
||||
5, 0x3c, 0x4a, 0x4a, 0x49, 0x31, // 225 - '?' x0e1
|
||||
5, 0x7c, 0x54, 0x54, 0x54, 0x28, // 226 - '?' x0e2
|
||||
4, 0x7c, 0x04, 0x04, 0x0c, // 227 - '?' x0e3
|
||||
6, 0xc0, 0x78, 0x44, 0x44, 0x78, 0xc0, // 228 - '?' x0e4
|
||||
5, 0x38, 0x54, 0x54, 0x54, 0x18, // 229 - 'e' x0e5
|
||||
5, 0x6c, 0x10, 0x7c, 0x10, 0x6c, // 230 - '?' x0e6
|
||||
5, 0x44, 0x54, 0x54, 0x54, 0x28, // 231 - '?' x0e7
|
||||
5, 0x7c, 0x20, 0x10, 0x08, 0x7c, // 232 - '?' x0e8
|
||||
5, 0x7c, 0x40, 0x26, 0x10, 0x7c, // 233 - '?' x0e9
|
||||
5, 0x7c, 0x10, 0x10, 0x28, 0x44, // 234 - '?' x0ea
|
||||
5, 0x40, 0x38, 0x04, 0x04, 0x7c, // 235 - '?' x0eb
|
||||
5, 0x7c, 0x08, 0x10, 0x08, 0x7c, // 236 - '?' x0ec
|
||||
5, 0x7c, 0x10, 0x10, 0x10, 0x7c, // 237 - '?' x0ed
|
||||
5, 0x38, 0x44, 0x44, 0x44, 0x38, // 238 - 'o' x0ee
|
||||
5, 0x7c, 0x04, 0x04, 0x04, 0x7c, // 239 - '?' x0ef
|
||||
5, 0xfc, 0x24, 0x24, 0x24, 0x18, // 240 - '?' x0f0
|
||||
4, 0x38, 0x44, 0x44, 0x44, // 241 - '?' x0f1
|
||||
5, 0x04, 0x04, 0x7c, 0x04, 0x04, // 242 - '?' x0f2
|
||||
5, 0x0c, 0x90, 0x90, 0x90, 0x7c, // 243 - '?' x0f3
|
||||
7, 0x10, 0x28, 0x28, 0xfc, 0x28, 0x28, 0x10, // 244 - '?' x0f4
|
||||
5, 0x44, 0x28, 0x10, 0x28, 0x44, // 245 - 'x' x0f5
|
||||
5, 0x7c, 0x40, 0x40, 0x7c, 0xc0, // 246 - '?' x0f6
|
||||
5, 0x0c, 0x10, 0x10, 0x10, 0x7c, // 247 - '?' x0f7
|
||||
5, 0x7c, 0x40, 0x7c, 0x40, 0x7c, // 248 - '?' x0f8
|
||||
6, 0x7c, 0x40, 0x7c, 0x40, 0x7c, 0xc0, // 249 - '?' x0f9
|
||||
6, 0x04, 0x7c, 0x50, 0x50, 0x50, 0x20, // 250 - '?' x0fa
|
||||
5, 0x7c, 0x50, 0x50, 0x20, 0x7c, // 251 - '?' x0fb
|
||||
5, 0x7c, 0x50, 0x50, 0x50, 0x20, // 252 - '?' x0fc
|
||||
5, 0x28, 0x44, 0x54, 0x54, 0x38, // 253 - '?' x0fd
|
||||
6, 0x7c, 0x10, 0x38, 0x44, 0x44, 0x38, // 254 - '?' x0fe
|
||||
5, 0x48, 0x34, 0x14, 0x14, 0x7c // 255 - '?' x0ff
|
||||
};
|
||||
#endif
|
||||
3
arduino-cli/libraries/MD_MAX72XX/Font Builder/README.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The file txt2font.executable is a windows .exe file. Please rename if you want to run this, otherwise you can simply remake the executable.
|
||||
|
||||
Arduino library manager policy prevents a .exe file from being part of the distribution.
|
||||
2449
arduino-cli/libraries/MD_MAX72XX/Font Builder/arabic_var_single.txt
Normal file
@@ -0,0 +1,680 @@
|
||||
.NAME greek_var_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 0
|
||||
.CHAR 32
|
||||
.NOTE 'space'
|
||||
.WIDTH 2
|
||||
|
||||
.CHAR 33
|
||||
.WIDTH 0
|
||||
.CHAR 128
|
||||
.NOTE 'ALPHA'
|
||||
*
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 129
|
||||
.NOTE 'BETA'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 130
|
||||
.NOTE 'GAMMA'
|
||||
*****
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 131
|
||||
.NOTE 'DELTA'
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 132
|
||||
.NOTE 'EPSILON'
|
||||
*****
|
||||
*
|
||||
*
|
||||
****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 133
|
||||
.NOTE 'ZETA'
|
||||
*****
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 134
|
||||
.NOTE 'ETA'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 135
|
||||
.NOTE 'THETA'
|
||||
***
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 136
|
||||
.NOTE 'IOTA'
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 137
|
||||
.NOTE 'KAPPA'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
**
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 138
|
||||
.NOTE 'LAMBDA'
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 139
|
||||
.NOTE 'MU'
|
||||
* *
|
||||
** **
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 140
|
||||
.NOTE 'NU'
|
||||
* *
|
||||
** *
|
||||
* * *
|
||||
* **
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 141
|
||||
.NOTE 'XI'
|
||||
*****
|
||||
* *
|
||||
|
||||
***
|
||||
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 142
|
||||
.NOTE 'OMICRON'
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 143
|
||||
.NOTE 'PI'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 144
|
||||
.NOTE 'RHO'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 145
|
||||
.NOTE 'SIGMA'
|
||||
*****
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 146
|
||||
.NOTE 'TAU'
|
||||
*****
|
||||
* * *
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 147
|
||||
.NOTE 'UPSILON'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 148
|
||||
.NOTE 'PHI'
|
||||
***
|
||||
*
|
||||
***
|
||||
* * *
|
||||
***
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 149
|
||||
.NOTE 'CHI'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 150
|
||||
.NOTE 'PSI'
|
||||
* * *
|
||||
* * *
|
||||
* * *
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 151
|
||||
.NOTE 'OMEGA'
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
.CHAR 152
|
||||
.NOTE 'alpha'
|
||||
|
||||
|
||||
*
|
||||
* * *
|
||||
* *
|
||||
* *
|
||||
** *
|
||||
|
||||
.CHAR 153
|
||||
.NOTE 'beta'
|
||||
|
||||
|
||||
**
|
||||
* *
|
||||
***
|
||||
* *
|
||||
***
|
||||
*
|
||||
.CHAR 154
|
||||
.NOTE 'gamma'
|
||||
|
||||
* *
|
||||
* *
|
||||
*
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 155
|
||||
.NOTE 'delta'
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
* *
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 156
|
||||
.NOTE 'epsilon'
|
||||
|
||||
|
||||
***
|
||||
*
|
||||
**
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 157
|
||||
.NOTE 'zeta'
|
||||
|
||||
****
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
*
|
||||
**
|
||||
.CHAR 158
|
||||
.NOTE 'eta'
|
||||
|
||||
|
||||
* *
|
||||
** *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
.CHAR 159
|
||||
.NOTE 'theta'
|
||||
|
||||
|
||||
***
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 160
|
||||
.NOTE 'iota'
|
||||
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 161
|
||||
.NOTE 'kappa'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
**
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 162
|
||||
.NOTE 'lambda'
|
||||
**
|
||||
* *
|
||||
*
|
||||
** *
|
||||
* **
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 163
|
||||
.NOTE 'mu'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
* **
|
||||
*** *
|
||||
* *
|
||||
*
|
||||
.CHAR 164
|
||||
.NOTE 'nu'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 165
|
||||
.NOTE 'xi'
|
||||
|
||||
***
|
||||
*
|
||||
***
|
||||
*
|
||||
***
|
||||
*
|
||||
*
|
||||
.CHAR 166
|
||||
.NOTE 'omicron'
|
||||
|
||||
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 167
|
||||
.NOTE 'pi'
|
||||
|
||||
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 168
|
||||
.NOTE 'rho'
|
||||
|
||||
|
||||
**
|
||||
* *
|
||||
* *
|
||||
***
|
||||
*
|
||||
*
|
||||
.CHAR 169
|
||||
.NOTE 'sigma'
|
||||
|
||||
|
||||
****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 170
|
||||
.NOTE 'sigma (final)'
|
||||
|
||||
|
||||
****
|
||||
*
|
||||
***
|
||||
*
|
||||
****
|
||||
|
||||
.CHAR 171
|
||||
.NOTE 'tau'
|
||||
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 172
|
||||
.NOTE 'upsilon'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 173
|
||||
.NOTE 'phi'
|
||||
|
||||
*
|
||||
* * *
|
||||
* * *
|
||||
***
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 174
|
||||
.NOTE 'chi'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
*
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 175
|
||||
.NOTE 'psi'
|
||||
|
||||
|
||||
* * *
|
||||
* * *
|
||||
***
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 224
|
||||
.NOTE 'omega'
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
|
||||
.CHAR 225
|
||||
.NOTE 'alpha tonos'
|
||||
*
|
||||
|
||||
*
|
||||
* * *
|
||||
* *
|
||||
* *
|
||||
** *
|
||||
|
||||
.CHAR 226
|
||||
.NOTE 'epsilon tonos'
|
||||
*
|
||||
|
||||
***
|
||||
*
|
||||
**
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 227
|
||||
.NOTE 'eta tonos'
|
||||
*
|
||||
|
||||
* *
|
||||
** *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
.CHAR 228
|
||||
.NOTE 'iota dialytika'
|
||||
* *
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 229
|
||||
.NOTE 'iota tonos'
|
||||
*
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 230
|
||||
.NOTE 'omicron tonos'
|
||||
*
|
||||
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 231
|
||||
.NOTE 'upsilon tonos'
|
||||
*
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 232
|
||||
.NOTE 'upsilon dialytika'
|
||||
* *
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 233
|
||||
.NOTE 'omega tonos'
|
||||
*
|
||||
|
||||
* *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
|
||||
.CHAR 234
|
||||
.NOTE 'ALPHA tonos'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 235
|
||||
.NOTE 'EPSILON'
|
||||
*****
|
||||
*
|
||||
*
|
||||
****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 236
|
||||
.NOTE 'ETA tonos'
|
||||
** *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 237
|
||||
.NOTE 'IOTA tonos'
|
||||
* **
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 238
|
||||
.NOTE 'OMICRON tonos'
|
||||
* **
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 239
|
||||
.NOTE 'UPSILON tonos'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 240
|
||||
.NOTE 'OMEGA tonos'
|
||||
* ***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
.CHAR 244
|
||||
.NOTE 'IOTA dialytika'
|
||||
* *
|
||||
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 245
|
||||
.NOTE 'UPSILON dialytika'
|
||||
* *
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
|
||||
.END
|
||||
@@ -0,0 +1,907 @@
|
||||
.NAME katakana_var_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 0
|
||||
.CHAR 32
|
||||
.WIDTH 2
|
||||
.NOTE 'space'
|
||||
|
||||
.CHAR 33
|
||||
.WIDTH 0
|
||||
.CHAR 161
|
||||
|
||||
|
||||
|
||||
|
||||
***
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 162
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 163
|
||||
|
||||
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 164
|
||||
|
||||
|
||||
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 165
|
||||
.NOTE 'Center dot'
|
||||
|
||||
|
||||
**
|
||||
**
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 166
|
||||
.NOTE 'wo'
|
||||
|
||||
*****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 167
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
**
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 168
|
||||
|
||||
*
|
||||
*
|
||||
**
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 169
|
||||
|
||||
|
||||
*
|
||||
*****
|
||||
* *
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 170
|
||||
|
||||
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 171
|
||||
|
||||
|
||||
*
|
||||
*****
|
||||
**
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 172
|
||||
|
||||
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 173
|
||||
|
||||
|
||||
|
||||
***
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 174
|
||||
|
||||
|
||||
*****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 175
|
||||
|
||||
|
||||
|
||||
* * *
|
||||
* * *
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 176
|
||||
.NOTE 'Extender'
|
||||
|
||||
|
||||
|
||||
*****
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 177
|
||||
.NOTE 'a'
|
||||
*****
|
||||
*
|
||||
* *
|
||||
**
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 178
|
||||
.NOTE 'i'
|
||||
*
|
||||
*
|
||||
*
|
||||
**
|
||||
* *
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 179
|
||||
.NOTE 'u'
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 180
|
||||
.NOTE 'e'
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 181
|
||||
.NOTE 'o'
|
||||
*
|
||||
*****
|
||||
*
|
||||
**
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 182
|
||||
.NOTE 'ka'
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 183
|
||||
.NOTE 'ki'
|
||||
*
|
||||
*****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 184
|
||||
.NOTE 'ku'
|
||||
|
||||
****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 185
|
||||
.NOTE 'ke'
|
||||
*
|
||||
****
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 186
|
||||
.NOTE 'ko'
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 187
|
||||
.NOTE 'sa'
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 188
|
||||
.NOTE 'shi'
|
||||
|
||||
**
|
||||
*
|
||||
** *
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 189
|
||||
.NOTE 'su'
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 190
|
||||
.NOTE 'se'
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 191
|
||||
.NOTE 'so'
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 192
|
||||
.NOTE 'ta'
|
||||
|
||||
****
|
||||
* *
|
||||
* * *
|
||||
**
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 193
|
||||
.NOTE 'chi'
|
||||
*
|
||||
***
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 194
|
||||
.NOTE 'tsu'
|
||||
|
||||
* * *
|
||||
* * *
|
||||
* * *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 195
|
||||
.NOTE 'te'
|
||||
***
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 196
|
||||
.NOTE 'to'
|
||||
*
|
||||
*
|
||||
*
|
||||
**
|
||||
* *
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 197
|
||||
.NOTE 'na'
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 198
|
||||
.NOTE 'ni'
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
*****
|
||||
|
||||
|
||||
.CHAR 199
|
||||
.NOTE 'nu'
|
||||
|
||||
*****
|
||||
*
|
||||
* *
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 200
|
||||
.NOTE 'ne'
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
***
|
||||
* * *
|
||||
*
|
||||
|
||||
.CHAR 201
|
||||
.NOTE 'no'
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 202
|
||||
.NOTE 'ha'
|
||||
|
||||
*
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 203
|
||||
.NOTE 'hi'
|
||||
*
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
*
|
||||
****
|
||||
|
||||
.CHAR 204
|
||||
.NOTE 'fu'
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
.CHAR 205
|
||||
.NOTE 'he'
|
||||
|
||||
*
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
|
||||
.CHAR 206
|
||||
.NOTE 'ho'
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
* * *
|
||||
* * *
|
||||
*
|
||||
|
||||
.CHAR 207
|
||||
.NOTE 'ma'
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
* *
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 208
|
||||
.NOTE 'mi'
|
||||
|
||||
****
|
||||
|
||||
****
|
||||
*
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 209
|
||||
.NOTE 'mu'
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
*****
|
||||
*
|
||||
|
||||
.CHAR 210
|
||||
.NOTE 'me'
|
||||
|
||||
*
|
||||
*
|
||||
* *
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 211
|
||||
.NOTE 'mo'
|
||||
|
||||
*****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 212
|
||||
.NOTE 'ye'
|
||||
*
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 213
|
||||
.NOTE 'yu'
|
||||
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
******
|
||||
|
||||
.CHAR 214
|
||||
.NOTE 'yo'
|
||||
|
||||
*****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 215
|
||||
.NOTE 'ra'
|
||||
***
|
||||
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 216
|
||||
.NOTE 'ri'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 217
|
||||
.NOTE 'ru'
|
||||
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
* **
|
||||
|
||||
.CHAR 218
|
||||
.NOTE 're'
|
||||
|
||||
*
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 219
|
||||
.NOTE 'ro'
|
||||
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 220
|
||||
.NOTE 'wa'
|
||||
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 221
|
||||
.NOTE 'n'
|
||||
|
||||
**
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 222
|
||||
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 223
|
||||
|
||||
***
|
||||
* *
|
||||
***
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 224
|
||||
|
||||
|
||||
* *
|
||||
* * *
|
||||
* *
|
||||
* *
|
||||
** *
|
||||
|
||||
.CHAR 225
|
||||
* *
|
||||
|
||||
***
|
||||
*
|
||||
****
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 226
|
||||
|
||||
***
|
||||
* *
|
||||
****
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
.CHAR 227
|
||||
|
||||
|
||||
***
|
||||
*
|
||||
**
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 228
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
* **
|
||||
*** *
|
||||
*
|
||||
*
|
||||
.CHAR 229
|
||||
|
||||
|
||||
****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 230
|
||||
|
||||
|
||||
**
|
||||
* *
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
.CHAR 231
|
||||
|
||||
|
||||
|
||||
****
|
||||
* *
|
||||
****
|
||||
*
|
||||
***
|
||||
.CHAR 232
|
||||
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 233
|
||||
|
||||
*
|
||||
** *
|
||||
*
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 234
|
||||
|
||||
*
|
||||
|
||||
**
|
||||
*
|
||||
*
|
||||
* *
|
||||
**
|
||||
.CHAR 235
|
||||
* *
|
||||
*
|
||||
* *
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 236
|
||||
|
||||
*
|
||||
***
|
||||
* *
|
||||
* * *
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 237
|
||||
*
|
||||
*
|
||||
***
|
||||
*
|
||||
***
|
||||
*
|
||||
****
|
||||
|
||||
.CHAR 238
|
||||
***
|
||||
|
||||
* **
|
||||
** *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 239
|
||||
* *
|
||||
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 240
|
||||
|
||||
|
||||
* **
|
||||
** *
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
.CHAR 241
|
||||
|
||||
|
||||
** *
|
||||
* **
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
.CHAR 242
|
||||
***
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 243
|
||||
|
||||
|
||||
|
||||
* **
|
||||
* * *
|
||||
** *
|
||||
|
||||
|
||||
.CHAR 244
|
||||
|
||||
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
.CHAR 245
|
||||
* *
|
||||
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* **
|
||||
** *
|
||||
|
||||
.CHAR 246
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 247
|
||||
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* **
|
||||
|
||||
.CHAR 248
|
||||
*****
|
||||
|
||||
* *
|
||||
* *
|
||||
*
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 249
|
||||
|
||||
|
||||
|
||||
* *
|
||||
* *
|
||||
****
|
||||
*
|
||||
***
|
||||
.CHAR 250
|
||||
|
||||
*
|
||||
****
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 251
|
||||
.NOTE 'Exit (jap)'
|
||||
|
||||
|
||||
*****
|
||||
*
|
||||
****
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 252
|
||||
.NOTE 'Entrance (jap)'
|
||||
|
||||
|
||||
*****
|
||||
* * *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 253
|
||||
.NOTE 'divide'
|
||||
|
||||
*
|
||||
|
||||
*****
|
||||
|
||||
*
|
||||
|
||||
|
||||
.CHAR 255
|
||||
.NOTE '5x7 block'
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
.END
|
||||
11
arduino-cli/libraries/MD_MAX72XX/Font Builder/make_font.bat
Normal file
@@ -0,0 +1,11 @@
|
||||
txt2font arabic_var_single
|
||||
txt2font greek_var_single
|
||||
txt2font katakana_var_single
|
||||
txt2font LCD5x7_fixed_single
|
||||
txt2font modernArabic_var_single
|
||||
txt2font seg7_fixed_double
|
||||
txt2font seg7_fixed_single
|
||||
txt2font symbol_var_single
|
||||
txt2font sys_fixed_single
|
||||
txt2font sys_var_double
|
||||
txt2font sys_var_single
|
||||
@@ -0,0 +1,457 @@
|
||||
.NAME seg7_fixed_double
|
||||
.HEIGHT 2
|
||||
.WIDTH 2
|
||||
.CHAR 32
|
||||
.NOTE 'Space'
|
||||
|
||||
.CHAR 46
|
||||
.NOTE '.'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**
|
||||
**
|
||||
|
||||
|
||||
.CHAR 58
|
||||
.NOTE ':'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**
|
||||
**
|
||||
|
||||
|
||||
**
|
||||
**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 124
|
||||
.NOTE '|'
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
.CHAR 48
|
||||
.WIDTH 10
|
||||
.NOTE '0'
|
||||
******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 49
|
||||
.NOTE '1'
|
||||
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 50
|
||||
.NOTE '2'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
*******
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 51
|
||||
.NOTE '3'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 52
|
||||
.NOTE '4'
|
||||
|
||||
* *
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
*******
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 53
|
||||
.NOTE '5'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
*******
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 54
|
||||
.NOTE '6'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 55
|
||||
.NOTE '7'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 56
|
||||
.NOTE '8'
|
||||
******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 57
|
||||
.NOTE '9'
|
||||
******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
*******
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 65
|
||||
.NOTE 'A'
|
||||
******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
* *
|
||||
|
||||
.CHAR 66
|
||||
.NOTE 'B'
|
||||
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 67
|
||||
.NOTE 'C'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 68
|
||||
.NOTE 'D'
|
||||
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 69
|
||||
.NOTE 'E'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 70
|
||||
.NOTE 'F'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 97
|
||||
.NOTE 'a'
|
||||
******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
* *
|
||||
|
||||
.CHAR 98
|
||||
.NOTE 'b'
|
||||
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 99
|
||||
.NOTE 'c'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 100
|
||||
.NOTE 'd'
|
||||
*
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*******
|
||||
********
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
********
|
||||
******
|
||||
.CHAR 101
|
||||
.NOTE 'e'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
******
|
||||
.CHAR 102
|
||||
.NOTE 'f'
|
||||
******
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
********
|
||||
********
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*
|
||||
|
||||
.END
|
||||
@@ -0,0 +1,258 @@
|
||||
.NAME seg7_fixed_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 1
|
||||
.CHAR 32
|
||||
.NOTE 'Space'
|
||||
|
||||
.CHAR 46
|
||||
.NOTE '.'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
.CHAR 58
|
||||
.NOTE ':'
|
||||
|
||||
|
||||
*
|
||||
|
||||
*
|
||||
|
||||
|
||||
|
||||
.CHAR 124
|
||||
.NOTE '|'
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 48
|
||||
.WIDTH 5
|
||||
.NOTE '0'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 49
|
||||
.NOTE '1'
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 50
|
||||
.NOTE '2'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 51
|
||||
.NOTE '3'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 52
|
||||
.NOTE '4'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 53
|
||||
.NOTE '5'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 54
|
||||
.NOTE '6'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 55
|
||||
.NOTE '7'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 56
|
||||
.NOTE '8'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
.CHAR 57
|
||||
.NOTE '9'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 65
|
||||
.NOTE 'A'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 66
|
||||
.NOTE 'B'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 67
|
||||
.NOTE 'C'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 68
|
||||
.NOTE 'D'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 69
|
||||
.NOTE 'E'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 70
|
||||
.NOTE 'F'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 97
|
||||
.NOTE 'a'
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
|
||||
.CHAR 98
|
||||
.NOTE 'b'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 99
|
||||
.NOTE 'c'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 100
|
||||
.NOTE 'd'
|
||||
****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 101
|
||||
.NOTE 'e'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
|
||||
.CHAR 102
|
||||
.NOTE 'f'
|
||||
*****
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.END
|
||||
@@ -0,0 +1,276 @@
|
||||
// Font 2 Text for MD_MAX72xx library
|
||||
//
|
||||
// Quick and not very robust code to create a font defintion text file
|
||||
// from an existing font data table. This is considered a one-off task
|
||||
// followed by some manual editing of the file.
|
||||
// The file is expected to be in the similar format to the output from
|
||||
// txt2font. Specifically, it is expected that each character is on one
|
||||
// data line in order to recognise specific parts, like comments.
|
||||
//
|
||||
// The shared header file means that some elements in this
|
||||
// code are reversed (eg, the IN file extension is used as the OUT file
|
||||
// extension). Each font element is output as it is completed, without
|
||||
// buffering the while ASCII set.
|
||||
//
|
||||
#include "txt2font.h"
|
||||
|
||||
// Global data ---------------
|
||||
Global_t G;
|
||||
ASCIIDef_t font = { 0 };
|
||||
|
||||
// Code ----------------------
|
||||
void usage(void)
|
||||
{
|
||||
printf("\nusage: font2txt <root_name>\n");
|
||||
printf("\n\ninput file <root_name>.h");
|
||||
printf("\noutput file <root_name>.txt");
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int cmdLine(int argc, char *argv[])
|
||||
// process the command line parameter
|
||||
{
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
strcpy(G.fileRoot, argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int initialise(void)
|
||||
// one time initiualisation code
|
||||
{
|
||||
char szFile[FILE_NAME_SIZE];
|
||||
|
||||
// we have no font definition
|
||||
font.comment[0] = NUL;
|
||||
font.size = 0;
|
||||
font.buf = malloc(100*sizeof(font.buf[0])); // pick a big number...
|
||||
|
||||
// open the file for reading
|
||||
strcpy(szFile, G.fileRoot);
|
||||
strcat(szFile, OUT_FILE_EXT);
|
||||
if ((G.fpIn = fopen(szFile, "r")) == NULL)
|
||||
{
|
||||
printf("\nCannot open input ""%s\n""", szFile);
|
||||
return(2);
|
||||
}
|
||||
|
||||
// open the file for writing
|
||||
strcpy(szFile, G.fileRoot);
|
||||
strcat(szFile, IN_FILE_EXT);
|
||||
if ((G.fpOut = fopen(szFile, "w")) == NULL)
|
||||
{
|
||||
printf("\nCannot open output ""%s\n""", szFile);
|
||||
return(3);
|
||||
}
|
||||
|
||||
// other stuff
|
||||
G.name[0] = NUL;
|
||||
G.doubleHeight = 0;
|
||||
G.bufSize = SINGLE_HEIGHT;
|
||||
G.fixedWidth = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void trimBuffer(char *buf)
|
||||
// trim the buffer specified of all trailing white space
|
||||
{
|
||||
int i = strlen(buf)-1;
|
||||
|
||||
while (i > 0 && isspace(buf[i]))
|
||||
buf[i--] = NUL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void padBuffer(char *buf, unsigned int len)
|
||||
// pad the supplied buffer with spaces up to the length specified
|
||||
{
|
||||
if (strlen(buf) < len)
|
||||
{
|
||||
for (unsigned int j=strlen(buf); j<len; j++)
|
||||
buf[j] = SPACE;
|
||||
}
|
||||
buf[len] = NUL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normaliseBuffers(void)
|
||||
// normalise all the input buffers to the same size
|
||||
{
|
||||
unsigned int max = 0;
|
||||
|
||||
if (G.fixedWidth == 0)
|
||||
{
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
max = max < strlen(G.buf[i]) ? max = strlen(G.buf[i]) : max;
|
||||
}
|
||||
else
|
||||
max = G.fixedWidth;
|
||||
|
||||
// now make them all the same size
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
{
|
||||
padBuffer(G.buf[i], max);
|
||||
}
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
char *getToken(char *buf)
|
||||
// isolate the first token in the buffer and return a pointer to the next non white space after the token
|
||||
{
|
||||
while (isspace(*buf) || ispunct(*buf))
|
||||
buf++;
|
||||
while (!isspace(*buf) && !ispunct(*buf))
|
||||
buf++;
|
||||
*buf++ = NUL;
|
||||
while (isspace(*buf) || ispunct(*buf))
|
||||
buf++;
|
||||
|
||||
return(buf);
|
||||
}
|
||||
|
||||
void saveOutputHeader(void)
|
||||
// save the current definition as a font definition header file
|
||||
{
|
||||
fprintf(G.fpOut, "%c%s %s\n", DOT, CMD_NAME, G.fileRoot);
|
||||
fprintf(G.fpOut, "%c%s %d\n", DOT, CMD_HEIGHT, (G.doubleHeight ? 2: 1));
|
||||
fprintf(G.fpOut, "%c%s %d\n", DOT, CMD_WIDTH, G.fixedWidth);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void saveOutputFooter(void)
|
||||
// save the current definition as a font definition header file
|
||||
{
|
||||
fprintf(G.fpOut, "%c%s\n", DOT, CMD_END);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void saveOutputChar(void)
|
||||
// Save a single character definition
|
||||
{
|
||||
fprintf(G.fpOut, "%c%s %d\n", DOT, CMD_CHAR, G.curCode);
|
||||
fprintf(G.fpOut, "%c%s %s\n", DOT, CMD_NOTE, font.comment);
|
||||
|
||||
if (G.bufSize != 0)
|
||||
{
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
{
|
||||
trimBuffer(G.buf[i]);
|
||||
fprintf(G.fpOut, "%s\n", G.buf[i]);
|
||||
}
|
||||
}
|
||||
else // need at least one line
|
||||
fprintf(G.fpOut, "\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void createFontData(char *cp)
|
||||
// the font defintions strings are column data columns, so each byte will be a 'vertical'
|
||||
// stripe of the input buffers. Format is the size followed by size bytes of column data,
|
||||
// separated by commas. The comment is found after the data in a '//' comment and following
|
||||
// the first '-'.
|
||||
{
|
||||
char *cpNext;
|
||||
|
||||
cpNext = getToken(cp);
|
||||
font.size = atoi(cp);
|
||||
cp = cpNext;
|
||||
|
||||
// get all the data from the input into the font defintion
|
||||
for (unsigned int i=0; i<font.size; i++)
|
||||
{
|
||||
// get the data
|
||||
cpNext = getToken(cp);
|
||||
font.buf[i] = atoi(cp);
|
||||
cp = cpNext;
|
||||
}
|
||||
|
||||
// unpack the column data into the text strings
|
||||
// create each input string [j] in turn from the column definition [i] for the char
|
||||
for (unsigned int i=0; i<SINGLE_HEIGHT; i++)
|
||||
{
|
||||
for (unsigned int j=0; j<font.size; j++)
|
||||
G.buf[i][j] = (font.buf[j] & (1<<i)) ? STAR : SPACE;
|
||||
G.buf[i][font.size] = NUL; // terminate the string
|
||||
}
|
||||
|
||||
// save the comment - first search up to after the first '-'
|
||||
while ((*cp != '-') && (*cp != NUL))
|
||||
cp++;
|
||||
if (cp != NUL) cp++;
|
||||
strcpy(font.comment, cp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void processInput(void)
|
||||
// read the input file and process line by line
|
||||
{
|
||||
char c, inLine[INPUT_BUFFER_SIZE];
|
||||
|
||||
// skip to the opening brace then skip end of line
|
||||
do
|
||||
c = getc(G.fpIn);
|
||||
while ((c != EOF) && (c != '{'));
|
||||
do
|
||||
c = getc(G.fpIn);
|
||||
while ((c == '\n') || (c == '\r'));
|
||||
|
||||
// now read each line in turn
|
||||
while (!feof(G.fpIn) && (G.curCode < ASCII_SIZE))
|
||||
{
|
||||
fgets(inLine, sizeof(inLine), G.fpIn);
|
||||
|
||||
// if we have a blank line, get another one
|
||||
trimBuffer(inLine);
|
||||
if (strlen(inLine) == 0) continue;
|
||||
|
||||
// process the buffers into a font definition and write out what we have created
|
||||
createFontData(inLine);
|
||||
saveOutputChar();
|
||||
|
||||
// reset the font and character buffers, increment current ASCII code
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
G.buf[i][0] = NUL;
|
||||
font.size = 0;
|
||||
G.curCode++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cmdLine(argc, argv))
|
||||
{
|
||||
usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if ((ret = initialise()) != 0)
|
||||
return(ret);
|
||||
|
||||
saveOutputHeader();
|
||||
processInput();
|
||||
saveOutputFooter();
|
||||
|
||||
|
||||
// close files and exit
|
||||
fclose(G.fpIn);
|
||||
fclose(G.fpOut);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
// Text 2 Font for MD_MAX72xx library
|
||||
//
|
||||
// Quick and not very robust code to create a font defintion data table for the
|
||||
// MD_MAX72xx library from a text file representation. The text file has '.' commands
|
||||
// to direct how the defintion is structured.
|
||||
//
|
||||
#include "txt2font.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define DECIMAL_DATA 0 // decimal or hex data selection in font tables
|
||||
|
||||
// Global data ---------------
|
||||
Global_t G;
|
||||
ASCIIDef_t font[ASCII_SIZE] = { 0 };
|
||||
|
||||
// Code ----------------------
|
||||
void usage(void)
|
||||
{
|
||||
printf("\nusage: txt2font <root_name>\n");
|
||||
printf("\n\ninput file <root_name>.txt");
|
||||
printf("\noutput file <root_name>.h");
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int cmdLine(int argc, char *argv[])
|
||||
// process the command line parameter
|
||||
{
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
strcpy(G.fileRoot, argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int initialise(void)
|
||||
// one time initialisation code
|
||||
{
|
||||
char szFile[FILE_NAME_SIZE];
|
||||
|
||||
// we have no font definition
|
||||
for (int i=0; i<ASCII_SIZE; i++)
|
||||
{
|
||||
font[i].comment[0] = NUL;
|
||||
font[i].size = 0;
|
||||
font[i].buf = NULL;
|
||||
}
|
||||
|
||||
// open the file for reading
|
||||
strcpy(szFile, G.fileRoot);
|
||||
strcat(szFile, IN_FILE_EXT);
|
||||
if ((G.fpIn = fopen(szFile, "r")) == NULL)
|
||||
{
|
||||
printf("\nCannot open input ""%s\n""", szFile);
|
||||
return(2);
|
||||
}
|
||||
|
||||
// open the file for writing
|
||||
strcpy(szFile, G.fileRoot);
|
||||
strcat(szFile, OUT_FILE_EXT);
|
||||
if ((G.fpOut = fopen(szFile, "w")) == NULL)
|
||||
{
|
||||
printf("\nCannot open output ""%s\n""", szFile);
|
||||
return(3);
|
||||
}
|
||||
|
||||
// other stuff
|
||||
G.name[0] = NUL;
|
||||
G.doubleHeight = 0;
|
||||
G.bufSize = SINGLE_HEIGHT;
|
||||
G.fixedWidth = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void trimBuffer(char *buf)
|
||||
// trim the buffer specified of all trailing white space
|
||||
{
|
||||
int i = strlen(buf)-1;
|
||||
|
||||
while (i > 0 && isspace(buf[i]))
|
||||
buf[i--] = NUL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void padBuffer(char *buf, unsigned int len)
|
||||
// pad the supplied buffer with spaces up to the length specified
|
||||
{
|
||||
if (strlen(buf) < len)
|
||||
{
|
||||
for (unsigned int j=strlen(buf); j<len; j++)
|
||||
buf[j] = SPACE;
|
||||
}
|
||||
buf[len] = NUL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normaliseBuffers(void)
|
||||
// normalise all the input buffers to the same size
|
||||
{
|
||||
unsigned int max = 0;
|
||||
|
||||
if (G.fixedWidth == 0)
|
||||
{
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
max = max < strlen(G.buf[i]) ? max = strlen(G.buf[i]) : max;
|
||||
}
|
||||
else
|
||||
max = G.fixedWidth;
|
||||
|
||||
// now make them all the same size
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
{
|
||||
padBuffer(G.buf[i], max);
|
||||
}
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
char *getToken(char *buf)
|
||||
// isolate the first token in the buffer and return a pointer to the next non white space after the token
|
||||
{
|
||||
while (!isspace(*buf))
|
||||
buf++;
|
||||
*buf++ = NUL;
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
|
||||
return(buf);
|
||||
}
|
||||
|
||||
void createFontChar(void)
|
||||
// the font defintion strings are created as columns, so each byte will be a 'vertical'
|
||||
// stripe of the input buffers.
|
||||
{
|
||||
font[G.curCode].size = normaliseBuffers(); // make everything the same length; this is the width of the character
|
||||
|
||||
// allocate memory for the font data
|
||||
if (font[G.curCode].buf != NULL)
|
||||
free(font[G.curCode].buf);
|
||||
font[G.curCode].buf = malloc(font[G.curCode].size * sizeof(*font[0].buf));
|
||||
|
||||
// if double height, check the upper buffers and also copy the font data across
|
||||
if (G.doubleHeight)
|
||||
{
|
||||
if (font[G.curCode+DOUBLE_HEIGHT_OFFSET].buf != NULL)
|
||||
free(font[G.curCode+DOUBLE_HEIGHT_OFFSET].buf);
|
||||
font[G.curCode+DOUBLE_HEIGHT_OFFSET].buf = malloc(font[G.curCode].size * sizeof(*font[0].buf));
|
||||
|
||||
font[G.curCode+DOUBLE_HEIGHT_OFFSET].size = font[G.curCode].size;
|
||||
strcpy(font[G.curCode+DOUBLE_HEIGHT_OFFSET].comment, font[G.curCode].comment);
|
||||
}
|
||||
|
||||
// process the input strings in parallel [j] to create the column definition [i] for the first character
|
||||
for (unsigned int i=0; i<font[G.curCode].size; i++)
|
||||
{
|
||||
unsigned int colL, colH;
|
||||
|
||||
if (G.doubleHeight) // if we are double height, write lower and upper halves separately
|
||||
{
|
||||
colL = colH = 0;
|
||||
// high half of character stored in upper ASCII value, but in low buffers
|
||||
// low half of character stored in lower ASCII value, but in high buffers
|
||||
for (unsigned int j=0; j<SINGLE_HEIGHT; j++)
|
||||
{
|
||||
colH |= (G.buf[j][i] == SPACE) ? 0 : (1 << j);
|
||||
colL |= (G.buf[j+SINGLE_HEIGHT][i] == SPACE) ? 0 : (1 << j);
|
||||
}
|
||||
font[G.curCode+DOUBLE_HEIGHT_OFFSET].buf[i] = colH;
|
||||
font[G.curCode].buf[i] = colL;
|
||||
}
|
||||
else
|
||||
{
|
||||
colL = 0;
|
||||
for (unsigned int j=0; j<SINGLE_HEIGHT; j++)
|
||||
colL |= (G.buf[j][i] == SPACE) ? 0 : (1 << j);
|
||||
// save the column data
|
||||
font[G.curCode].buf[i] = colL;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void readInput(void)
|
||||
// read the input file and process line by line
|
||||
{
|
||||
char c, *cp, inLine[INPUT_BUFFER_SIZE];
|
||||
|
||||
cp = inLine;
|
||||
|
||||
while ((c = getc(G.fpIn)) != EOF)
|
||||
{
|
||||
if (c != '\n' && c != '\r') // not end of line
|
||||
{
|
||||
*cp++ = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we are at end of line, process the line
|
||||
*cp = NUL;
|
||||
trimBuffer(inLine);
|
||||
if (inLine[0] != DOT) // not a command? must be a chr definition line
|
||||
{
|
||||
if (G.curBuf < (SINGLE_HEIGHT*2))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("\nC%02x L%d\t%s", G.curCode, G.curBuf, inLine);
|
||||
#endif
|
||||
strcpy(G.buf[G.curBuf++], inLine); // save the buffer
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cp = getToken(&inLine[1]);
|
||||
#ifdef DEBUG
|
||||
printf("\nToken: '%s' - '%s'", inLine, cp);
|
||||
#endif
|
||||
if (strcmp(&inLine[1], CMD_NAME) == 0)
|
||||
{
|
||||
strcpy(G.name, cp);
|
||||
#ifdef DEBUG
|
||||
printf("\tfont name: '%s'", G.name);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(&inLine[1], CMD_HEIGHT) == 0)
|
||||
{
|
||||
G.doubleHeight = (*cp=='1' ? 0 : 1);
|
||||
G.bufSize = (*cp=='1' ? SINGLE_HEIGHT : SINGLE_HEIGHT*2);
|
||||
#ifdef DEBUG
|
||||
printf("\tdouble height: %d", G.doubleHeight);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(&inLine[1], CMD_WIDTH) == 0)
|
||||
{
|
||||
G.fixedWidth = abs(atoi(cp));
|
||||
#ifdef DEBUG
|
||||
printf("\twidth: %d", G.fixedWidth);
|
||||
#endif
|
||||
}
|
||||
else if ((strcmp(&inLine[1], CMD_CHAR) == 0) ||
|
||||
(strcmp(&inLine[1], CMD_END) == 0))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("\tend char %02x", G.curCode);
|
||||
#endif
|
||||
if (G.curBuf != 0) // we have buffers
|
||||
{
|
||||
// process the buffers into a font definition
|
||||
createFontChar();
|
||||
|
||||
// reset the character buffers
|
||||
for (unsigned int i=0; i<G.bufSize; i++)
|
||||
G.buf[i][0] = NUL;
|
||||
}
|
||||
|
||||
// set up the new character if not at the end
|
||||
if (strcmp(&inLine[1], CMD_END) != 0)
|
||||
{
|
||||
G.curBuf = 0;
|
||||
G.curCode = atoi(cp);
|
||||
#ifdef DEBUG
|
||||
printf("\t set up %02x", G.curCode);
|
||||
#endif
|
||||
if (G.curCode >= (G.doubleHeight ? ASCII_SIZE/2 : ASCII_SIZE))
|
||||
{
|
||||
G.curCode = 0;
|
||||
#ifdef DEBUG
|
||||
printf("\t - boundary check fail");
|
||||
#endif
|
||||
}
|
||||
font[G.curCode].comment[0] = NUL;
|
||||
font[G.curCode].size = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
printf("\tend of definition");
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(&inLine[1], CMD_NOTE) == 0)
|
||||
{
|
||||
strcpy(font[G.curCode].comment, cp);
|
||||
#ifdef DEBUG
|
||||
printf("\tnote '%s' for char %02x", font[G.curCode].comment, G.curCode);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
// reset for next line
|
||||
cp = inLine;
|
||||
memset(inLine, NUL, sizeof(inLine));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void saveOutput(void)
|
||||
// save the current definition as a font definition header file
|
||||
{
|
||||
fprintf(G.fpOut, "// Autogenerated font - '%s'\n", G.name);
|
||||
fprintf(G.fpOut, "// %s height, ", (G.doubleHeight ? "Double" : "Single"));
|
||||
if (G.fixedWidth == 0)
|
||||
fprintf(G.fpOut, "Variable spaced");
|
||||
else
|
||||
fprintf(G.fpOut, "Fixed width (%d)", G.fixedWidth);
|
||||
fprintf(G.fpOut, "\n\n");
|
||||
|
||||
fprintf(G.fpOut, "#pragma once\n\n");
|
||||
fprintf(G.fpOut, "const uint8_t PROGMEM _%s[] = \n{\n", (G.name[0] == NUL) ? "font" : G.name);
|
||||
|
||||
for (int i=0; i<ASCII_SIZE; i++)
|
||||
{
|
||||
fprintf(G.fpOut, "\t%d,", font[i].size);
|
||||
if (font[i].buf != NULL)
|
||||
{
|
||||
for (unsigned int j=0; j<font[i].size; j++)
|
||||
fprintf(G.fpOut, (DECIMAL_DATA ? "%d," : "0x%02x,"), font[i].buf[j]);
|
||||
}
|
||||
fprintf(G.fpOut, "\t// %d", i);
|
||||
if (font[i].comment[0] != NUL)
|
||||
fprintf(G.fpOut," - %s", font[i].comment);
|
||||
fprintf(G.fpOut, "\n");
|
||||
}
|
||||
|
||||
fprintf(G.fpOut, "}\n\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cmdLine(argc, argv))
|
||||
{
|
||||
usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if ((ret = initialise()) != 0)
|
||||
return(ret);
|
||||
|
||||
// read the input file
|
||||
readInput();
|
||||
|
||||
// write the output file
|
||||
saveOutput();
|
||||
|
||||
// close files and exit
|
||||
fclose(G.fpIn);
|
||||
fclose(G.fpOut);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Text 2 Font for MD_MAX72xx library
|
||||
|
||||
Quick and not very robust code to create a font defintion data table for the
|
||||
MD_MAX72xx library from a text file representation. The text file has '.' commands
|
||||
to direct how the defintion is structured.
|
||||
|
||||
This is a console application witten in standard C.
|
||||
Original target is Win32, but no OS dependencies, so should be portable to other OS.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define NAME_SIZE 50
|
||||
#define FILE_NAME_SIZE 200 // may include path
|
||||
#define FONT_NAME_SIZE 50
|
||||
#define COMMENT_SIZE 40
|
||||
#define ASCII_SIZE 256
|
||||
#define INPUT_BUFFER_SIZE 200
|
||||
|
||||
#define SINGLE_HEIGHT 8
|
||||
#define DOUBLE_HEIGHT_OFFSET (ASCII_SIZE/2) // ASCII code offset
|
||||
|
||||
#define IN_FILE_EXT ".txt"
|
||||
#define OUT_FILE_EXT ".h"
|
||||
|
||||
#define SPACE ' '
|
||||
#define STAR '*'
|
||||
#define NUL '\0'
|
||||
#define DOT '.'
|
||||
|
||||
#define CMD_NAME "NAME"
|
||||
#define CMD_HEIGHT "HEIGHT"
|
||||
#define CMD_WIDTH "WIDTH"
|
||||
#define CMD_CHAR "CHAR"
|
||||
#define CMD_NOTE "NOTE"
|
||||
#define CMD_END "END"
|
||||
|
||||
// Data types ----------------
|
||||
typedef struct
|
||||
{
|
||||
// file handling
|
||||
FILE *fpIn;
|
||||
FILE *fpOut;
|
||||
char fileRoot[FILE_NAME_SIZE];
|
||||
|
||||
// font definition header
|
||||
char name[FONT_NAME_SIZE];
|
||||
unsigned int doubleHeight; // 0 or 1
|
||||
unsigned int fixedWidth; // 0 for variable, width otherwise
|
||||
|
||||
// input buffers and tracking
|
||||
unsigned int curCode; // the current ASCII character being processed
|
||||
unsigned int curBuf; // the current buffer we are up to
|
||||
unsigned int bufSize; // the number of buffers used
|
||||
char buf[SINGLE_HEIGHT*2][INPUT_BUFFER_SIZE];
|
||||
|
||||
} Global_t, *pGlobal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char comment[COMMENT_SIZE]; // comment for this character
|
||||
unsigned int size; // number of valid
|
||||
unsigned int *buf; // size bytes allocated from memory
|
||||
|
||||
} ASCIIDef_t, *pASCIIDef_t;
|
||||
|
||||
@@ -0,0 +1,994 @@
|
||||
.NAME symbol_var_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 0
|
||||
.CHAR 0
|
||||
.NOTE 'Arrow bent BL'
|
||||
|
||||
*
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
.CHAR 1
|
||||
.NOTE 'Arrow bent BR'
|
||||
|
||||
*
|
||||
*
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
*
|
||||
*
|
||||
.CHAR 2
|
||||
.NOTE 'Arrow bent TL'
|
||||
*
|
||||
*
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 3
|
||||
.NOTE 'Arrow bent TR'
|
||||
*
|
||||
*
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 4
|
||||
.NOTE 'Arrow big L'
|
||||
*
|
||||
**
|
||||
*******
|
||||
********
|
||||
*******
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 5
|
||||
.NOTE 'Arrow big R'
|
||||
*
|
||||
**
|
||||
*******
|
||||
********
|
||||
*******
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 6
|
||||
.NOTE 'Arrow empty head L'
|
||||
*
|
||||
**
|
||||
* **
|
||||
*
|
||||
* **
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 7
|
||||
.NOTE 'Arrow empty head R'
|
||||
*
|
||||
**
|
||||
** *
|
||||
*
|
||||
** *
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 8
|
||||
.NOTE 'Arrow empty shaft'
|
||||
|
||||
|
||||
**
|
||||
|
||||
|
||||
**
|
||||
|
||||
|
||||
.CHAR 9
|
||||
.NOTE 'Arrow filled head L'
|
||||
*
|
||||
**
|
||||
****
|
||||
*****
|
||||
****
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 10
|
||||
.NOTE 'Arrow filled head R'
|
||||
*
|
||||
**
|
||||
****
|
||||
*****
|
||||
****
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 11
|
||||
.NOTE 'Arrow shaft'
|
||||
|
||||
|
||||
|
||||
********
|
||||
********
|
||||
|
||||
|
||||
|
||||
.CHAR 12
|
||||
.NOTE 'Arrow simple E'
|
||||
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
|
||||
|
||||
.CHAR 13
|
||||
.NOTE 'Arrow simple N'
|
||||
|
||||
*
|
||||
***
|
||||
* * *
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 14
|
||||
.NOTE 'Arrow simple NE'
|
||||
|
||||
****
|
||||
**
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
|
||||
.CHAR 15
|
||||
.NOTE 'Arrow simple NS'
|
||||
*
|
||||
***
|
||||
* * *
|
||||
*
|
||||
* * *
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 16
|
||||
.NOTE 'Arrow simple NW'
|
||||
|
||||
****
|
||||
**
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
|
||||
.CHAR 17
|
||||
.NOTE 'Arrow simple S'
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
* * *
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 18
|
||||
.NOTE 'Arrow simple SE'
|
||||
|
||||
*
|
||||
* *
|
||||
* *
|
||||
**
|
||||
****
|
||||
|
||||
|
||||
.CHAR 19
|
||||
.NOTE 'Arrow simple SW'
|
||||
|
||||
*
|
||||
* *
|
||||
* *
|
||||
**
|
||||
****
|
||||
|
||||
|
||||
.CHAR 20
|
||||
.NOTE 'Arrow simple W'
|
||||
|
||||
*
|
||||
*
|
||||
*****
|
||||
*
|
||||
*
|
||||
|
||||
|
||||
.CHAR 21
|
||||
.NOTE 'Arrow simple WE'
|
||||
|
||||
* *
|
||||
* *
|
||||
*******
|
||||
* *
|
||||
* *
|
||||
|
||||
|
||||
.CHAR 22
|
||||
.NOTE 'Arrow tail closure'
|
||||
|
||||
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
|
||||
|
||||
.CHAR 23
|
||||
.NOTE 'Arrow tail L'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
******
|
||||
******
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
.CHAR 24
|
||||
.NOTE 'Arrow tail R'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
.CHAR 25
|
||||
.NOTE 'Ball empty'
|
||||
|
||||
****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 26
|
||||
.NOTE 'Ball filled'
|
||||
|
||||
****
|
||||
******
|
||||
******
|
||||
******
|
||||
******
|
||||
****
|
||||
|
||||
.CHAR 27
|
||||
.NOTE 'Bullet Point empty'
|
||||
|
||||
|
||||
*
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
|
||||
.CHAR 28
|
||||
.NOTE 'Bullet Point empty rev'
|
||||
*****
|
||||
*****
|
||||
** **
|
||||
* * *
|
||||
* * *
|
||||
** **
|
||||
*****
|
||||
*****
|
||||
.CHAR 29
|
||||
.NOTE 'Bullet Point filled'
|
||||
|
||||
|
||||
*
|
||||
***
|
||||
***
|
||||
*
|
||||
|
||||
|
||||
.CHAR 30
|
||||
.NOTE 'Bullet Point filled rev'
|
||||
*****
|
||||
*****
|
||||
** **
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
*****
|
||||
*****
|
||||
.CHAR 31
|
||||
.NOTE 'Deg C'
|
||||
**
|
||||
**
|
||||
***
|
||||
*
|
||||
*
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 32
|
||||
.NOTE 'Deg F'
|
||||
**
|
||||
**
|
||||
****
|
||||
*
|
||||
***
|
||||
*
|
||||
*
|
||||
|
||||
.CHAR 33
|
||||
.NOTE 'Diamond empty'
|
||||
*
|
||||
***
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 34
|
||||
.NOTE 'Diamond filled'
|
||||
*
|
||||
***
|
||||
*****
|
||||
*******
|
||||
*****
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 35
|
||||
.NOTE 'Icon bullet L'
|
||||
*
|
||||
*******
|
||||
* *****
|
||||
* *****
|
||||
* *****
|
||||
*******
|
||||
*
|
||||
|
||||
.CHAR 36
|
||||
.NOTE 'Icon bullet R'
|
||||
*
|
||||
*******
|
||||
***** *
|
||||
***** *
|
||||
***** *
|
||||
*******
|
||||
*
|
||||
|
||||
.CHAR 37
|
||||
.NOTE 'Icon cactus'
|
||||
**
|
||||
**
|
||||
*****
|
||||
********
|
||||
***** **
|
||||
** ** **
|
||||
** **
|
||||
**
|
||||
.CHAR 38
|
||||
.NOTE 'Icon card clubs'
|
||||
***
|
||||
* *
|
||||
*****
|
||||
* * *
|
||||
*****
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 39
|
||||
.NOTE 'Icon card diamond'
|
||||
|
||||
*
|
||||
***
|
||||
*****
|
||||
*****
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 40
|
||||
.NOTE 'Icon card heart'
|
||||
|
||||
* *
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
***
|
||||
*
|
||||
|
||||
.CHAR 41
|
||||
.NOTE 'Icon card spades'
|
||||
*
|
||||
***
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*
|
||||
***
|
||||
|
||||
.CHAR 42
|
||||
.NOTE 'Icon gun'
|
||||
|
||||
|
||||
* *****
|
||||
******
|
||||
****
|
||||
*****
|
||||
** *
|
||||
**
|
||||
.CHAR 43
|
||||
.NOTE 'Icon gun bullets'
|
||||
*
|
||||
*
|
||||
|
||||
** ** **
|
||||
** ** **
|
||||
|
||||
*
|
||||
*
|
||||
.CHAR 44
|
||||
.NOTE 'Icon house'
|
||||
|
||||
**
|
||||
****
|
||||
******
|
||||
********
|
||||
**********
|
||||
*** ***
|
||||
*** ***
|
||||
.CHAR 45
|
||||
.NOTE 'Icon pacman'
|
||||
*****
|
||||
* *
|
||||
* * *
|
||||
* *
|
||||
* *
|
||||
* **
|
||||
* *
|
||||
*****
|
||||
.CHAR 46
|
||||
.NOTE 'Icon pacman ghost'
|
||||
*****
|
||||
* *
|
||||
* * * *
|
||||
* *
|
||||
* *
|
||||
*******
|
||||
* * * *
|
||||
* * * *
|
||||
.CHAR 47
|
||||
.NOTE 'Icon rocket'
|
||||
*
|
||||
***
|
||||
* *
|
||||
***
|
||||
***
|
||||
*****
|
||||
*****
|
||||
* * *
|
||||
.CHAR 48
|
||||
.NOTE 'Icon sex female'
|
||||
***
|
||||
* *
|
||||
* *
|
||||
***
|
||||
*
|
||||
*****
|
||||
*
|
||||
|
||||
.CHAR 49
|
||||
.NOTE 'Icon sex male'
|
||||
|
||||
***
|
||||
**
|
||||
*** *
|
||||
* *
|
||||
* *
|
||||
**
|
||||
|
||||
.CHAR 50
|
||||
.NOTE 'Icon smiley happy'
|
||||
***
|
||||
*****
|
||||
* * *
|
||||
*****
|
||||
* *
|
||||
** **
|
||||
***
|
||||
|
||||
.CHAR 51
|
||||
.NOTE 'Icon smiley sad'
|
||||
***
|
||||
*****
|
||||
* * *
|
||||
*****
|
||||
** **
|
||||
* *
|
||||
***
|
||||
|
||||
.CHAR 52
|
||||
.NOTE 'Icon snowflake'
|
||||
* * *
|
||||
** * **
|
||||
****
|
||||
** * *
|
||||
* * **
|
||||
****
|
||||
** * **
|
||||
* * *
|
||||
.CHAR 53
|
||||
.NOTE 'Icon telephone 1'
|
||||
|
||||
**
|
||||
**
|
||||
*
|
||||
*
|
||||
** *
|
||||
***
|
||||
|
||||
.CHAR 54
|
||||
.NOTE 'Icon telephone 2'
|
||||
*****
|
||||
** **
|
||||
** *** **
|
||||
* * *
|
||||
* *** *
|
||||
* * *
|
||||
*******
|
||||
|
||||
.CHAR 55
|
||||
.NOTE 'Icon tetris'
|
||||
*
|
||||
**** * *
|
||||
**
|
||||
* *
|
||||
* ***
|
||||
* *
|
||||
* **
|
||||
** * **
|
||||
.CHAR 56
|
||||
.NOTE 'Music note 1'
|
||||
****
|
||||
* *
|
||||
****
|
||||
*
|
||||
*
|
||||
**
|
||||
**
|
||||
|
||||
.CHAR 57
|
||||
.NOTE 'Music note 2'
|
||||
****
|
||||
* *
|
||||
****
|
||||
* *
|
||||
* **
|
||||
** **
|
||||
**
|
||||
|
||||
.CHAR 58
|
||||
.NOTE 'Music note 3'
|
||||
*
|
||||
**
|
||||
* *
|
||||
* *
|
||||
**
|
||||
***
|
||||
**
|
||||
|
||||
.CHAR 59
|
||||
.NOTE 'Pattern block bottom'
|
||||
|
||||
|
||||
|
||||
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
.CHAR 60
|
||||
.NOTE 'Pattern block full'
|
||||
********
|
||||
********
|
||||
********
|
||||
********
|
||||
********
|
||||
********
|
||||
********
|
||||
********
|
||||
.CHAR 61
|
||||
.NOTE 'Pattern block L'
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
.CHAR 62
|
||||
.NOTE 'Pattern block R'
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
.CHAR 63
|
||||
.NOTE 'Pattern block top'
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
|
||||
|
||||
|
||||
|
||||
.CHAR 64
|
||||
.NOTE 'Pattern box in box'
|
||||
********
|
||||
* *
|
||||
* **** *
|
||||
* * * *
|
||||
* * * *
|
||||
* **** *
|
||||
* *
|
||||
********
|
||||
.CHAR 65
|
||||
.NOTE 'Pattern carrots L'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
.CHAR 66
|
||||
.NOTE 'Pattern carrots R'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
.CHAR 67
|
||||
.NOTE 'Pattern chain link'
|
||||
|
||||
****
|
||||
* *
|
||||
*** ***
|
||||
*** ***
|
||||
* *
|
||||
****
|
||||
|
||||
.CHAR 68
|
||||
.NOTE 'Pattern check big'
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
.CHAR 69
|
||||
.NOTE 'Pattern check edge big'
|
||||
** **
|
||||
** **
|
||||
|
||||
|
||||
|
||||
|
||||
** **
|
||||
** **
|
||||
.CHAR 70
|
||||
.NOTE 'Pattern check edge small'
|
||||
* * * *
|
||||
* * * *
|
||||
|
||||
|
||||
|
||||
|
||||
* * * *
|
||||
* * * *
|
||||
.CHAR 71
|
||||
.NOTE 'Pattern check small'
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
.CHAR 72
|
||||
.NOTE 'Pattern round'
|
||||
* ** *
|
||||
* *
|
||||
* *
|
||||
* ** *
|
||||
* ** *
|
||||
* *
|
||||
* *
|
||||
* ** *
|
||||
.CHAR 73
|
||||
.NOTE 'Pattern spiral'
|
||||
********
|
||||
*
|
||||
****** *
|
||||
* * *
|
||||
* * * *
|
||||
* **** *
|
||||
* *
|
||||
********
|
||||
.CHAR 74
|
||||
.NOTE 'Pattern stripes diag L'
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
.CHAR 75
|
||||
.NOTE 'Pattern stripes diag R'
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
* *
|
||||
* * *
|
||||
* * *
|
||||
.CHAR 76
|
||||
.NOTE 'Pattern stripes H'
|
||||
********
|
||||
|
||||
********
|
||||
|
||||
********
|
||||
|
||||
********
|
||||
|
||||
.CHAR 77
|
||||
.NOTE 'Pattern stripes V'
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
.CHAR 78
|
||||
.NOTE 'Pattern X'
|
||||
* *
|
||||
** **
|
||||
* *
|
||||
**
|
||||
**
|
||||
* *
|
||||
** **
|
||||
* *
|
||||
.CHAR 79
|
||||
.NOTE 'Pointer big E'
|
||||
*
|
||||
**
|
||||
***
|
||||
****
|
||||
***
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 80
|
||||
.NOTE 'Pointer big S'
|
||||
|
||||
|
||||
*******
|
||||
*****
|
||||
***
|
||||
*
|
||||
|
||||
|
||||
.CHAR 81
|
||||
.NOTE 'Pointer big up'
|
||||
|
||||
|
||||
*
|
||||
***
|
||||
*****
|
||||
*******
|
||||
|
||||
|
||||
.CHAR 82
|
||||
.NOTE 'Pointer big W'
|
||||
*
|
||||
**
|
||||
***
|
||||
****
|
||||
***
|
||||
**
|
||||
*
|
||||
|
||||
.CHAR 83
|
||||
.NOTE 'Pointer small E'
|
||||
|
||||
*
|
||||
**
|
||||
***
|
||||
**
|
||||
*
|
||||
|
||||
|
||||
.CHAR 84
|
||||
.NOTE 'Pointer small N'
|
||||
|
||||
|
||||
*
|
||||
***
|
||||
*****
|
||||
|
||||
|
||||
|
||||
.CHAR 85
|
||||
.NOTE 'Pointer small S'
|
||||
|
||||
|
||||
*****
|
||||
***
|
||||
*
|
||||
|
||||
|
||||
|
||||
.CHAR 86
|
||||
.NOTE 'Pointer small W'
|
||||
|
||||
*
|
||||
**
|
||||
***
|
||||
**
|
||||
*
|
||||
|
||||
|
||||
.CHAR 87
|
||||
.NOTE 'Wave Sine'
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
**
|
||||
.CHAR 88
|
||||
.NOTE 'Wave square'
|
||||
*** **
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
.CHAR 89
|
||||
.NOTE 'Wave triangle'
|
||||
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
|
||||
.CHAR 90
|
||||
.NOTE 'Pattern bars V 1'
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
.CHAR 91
|
||||
.NOTE 'Pattern bars V 2'
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
.CHAR 92
|
||||
.NOTE 'Pattern bars V 3'
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
.CHAR 93
|
||||
.NOTE 'Pattern bars V 4'
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
.CHAR 94
|
||||
.NOTE 'Pattern bars V 5'
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
*****
|
||||
.CHAR 95
|
||||
.NOTE 'Pattern bars V 6'
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
****
|
||||
.CHAR 96
|
||||
.NOTE 'Pattern bars V 7'
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
.CHAR 97
|
||||
.NOTE 'Pattern bars V 8'
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
.CHAR 98
|
||||
.NOTE 'Pattern bars V 9'
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
.END
|
||||
2542
arduino-cli/libraries/MD_MAX72XX/Font Builder/sys_fixed_single.txt
Normal file
1683
arduino-cli/libraries/MD_MAX72XX/Font Builder/sys_var_double.txt
Normal file
2260
arduino-cli/libraries/MD_MAX72XX/Font Builder/sys_var_single.txt
Normal file
11
arduino-cli/libraries/MD_MAX72XX/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# MAX72xx LED Matrix Display Library
|
||||
|
||||
<i>IMPORTANT NOTE: Please make sure that you find and read the html documentation that comes with the library (open "docs/index.html") or use the link below. <b>You will need to edit the MAX72xx.h file to configure the type of matrix you are using</b>. This is the most asked support question so avoid frustration and READ THE MANUAL in the docs subfolder.</i>
|
||||
|
||||
The library implements functions that allow the MAX72xx to be used for LED matrices (64 individual LEDs), allowing the programmer to use the LED matrix as a pixel device, displaying graphics elements much like any other pixel addressable display.
|
||||
|
||||
In this scenario, it is convenient to abstract out the concept of the hardware device and create a uniform and consistent pixel address space, with the libraries determining device and device-element address. Similarly, control of the devices is uniform and abstracted to a system level.
|
||||
|
||||
The library still retains flexibility for device level control, should the developer require, through the use of overloaded class methods.
|
||||
|
||||
[Library Documentation](https://majicdesigns.github.io/MD_MAX72XX/)
|
||||
@@ -0,0 +1,389 @@
|
||||
// Use the MD_MAX72XX library to scroll text on the display
|
||||
// received through the ESP8266 WiFi interface.
|
||||
//
|
||||
// Demonstrates the use of the callback function to control what
|
||||
// is scrolled on the display text. User can enter text through
|
||||
// a web browser and this will display as a scrolling message on
|
||||
// the display.
|
||||
//
|
||||
// IP address for the ESP8266 is displayed on the scrolling display
|
||||
// after startup initialisation and connected to the WiFi network.
|
||||
//
|
||||
// Connections for ESP8266 hardware SPI are:
|
||||
// Vcc 3v3 LED matrices seem to work at 3.3V
|
||||
// GND GND GND
|
||||
// DIN D7 HSPID or HMOSI
|
||||
// CS or LD D8 HSPICS or HCS
|
||||
// CLK D5 CLK or HCLK
|
||||
//
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define PRINT_CALLBACK 0
|
||||
#define DEBUG 0
|
||||
#define LED_HEARTBEAT 0
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
#define PRINTS(s) { Serial.print(F(s)); }
|
||||
#else
|
||||
#define PRINT(s, v)
|
||||
#define PRINTS(s)
|
||||
#endif
|
||||
|
||||
|
||||
#if LED_HEARTBEAT
|
||||
#define HB_LED D2
|
||||
#define HB_LED_TIME 500 // in milliseconds
|
||||
#endif
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
#define CLK_PIN D5 // or SCK
|
||||
#define DATA_PIN D7 // or MOSI
|
||||
#define CS_PIN D8 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// WiFi login parameters - network name and password
|
||||
const char* ssid = "";
|
||||
const char* password = "";
|
||||
|
||||
// WiFi Server object and parameters
|
||||
WiFiServer server(80);
|
||||
|
||||
// Global message buffers shared by Wifi and Scrolling functions
|
||||
const uint8_t MESG_SIZE = 255;
|
||||
const uint8_t CHAR_SPACING = 1;
|
||||
const uint8_t SCROLL_DELAY = 75;
|
||||
|
||||
char curMessage[MESG_SIZE];
|
||||
char newMessage[MESG_SIZE];
|
||||
bool newMessageAvailable = false;
|
||||
|
||||
char WebResponse[] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
|
||||
|
||||
char WebPage[] =
|
||||
"<!DOCTYPE html>" \
|
||||
"<html>" \
|
||||
"<head>" \
|
||||
"<title>MajicDesigns Test Page</title>" \
|
||||
|
||||
"<script>" \
|
||||
"strLine = \"\";" \
|
||||
|
||||
"function SendText()" \
|
||||
"{" \
|
||||
" nocache = \"/&nocache=\" + Math.random() * 1000000;" \
|
||||
" var request = new XMLHttpRequest();" \
|
||||
" strLine = \"&MSG=\" + document.getElementById(\"txt_form\").Message.value;" \
|
||||
" request.open(\"GET\", strLine + nocache, false);" \
|
||||
" request.send(null);" \
|
||||
"}" \
|
||||
"</script>" \
|
||||
"</head>" \
|
||||
|
||||
"<body>" \
|
||||
"<p><b>MD_MAX72xx set message</b></p>" \
|
||||
|
||||
"<form id=\"txt_form\" name=\"frmText\">" \
|
||||
"<label>Msg:<input type=\"text\" name=\"Message\" maxlength=\"255\"></label><br><br>" \
|
||||
"</form>" \
|
||||
"<br>" \
|
||||
"<input type=\"submit\" value=\"Send Text\" onclick=\"SendText()\">" \
|
||||
"</body>" \
|
||||
"</html>";
|
||||
|
||||
char *err2Str(wl_status_t code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case WL_IDLE_STATUS: return("IDLE"); break; // WiFi is in process of changing between statuses
|
||||
case WL_NO_SSID_AVAIL: return("NO_SSID_AVAIL"); break; // case configured SSID cannot be reached
|
||||
case WL_CONNECTED: return("CONNECTED"); break; // successful connection is established
|
||||
case WL_CONNECT_FAILED: return("CONNECT_FAILED"); break; // password is incorrect
|
||||
case WL_DISCONNECTED: return("CONNECT_FAILED"); break; // module is not configured in station mode
|
||||
default: return("??");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t htoi(char c)
|
||||
{
|
||||
c = toupper(c);
|
||||
if ((c >= '0') && (c <= '9')) return(c - '0');
|
||||
if ((c >= 'A') && (c <= 'F')) return(c - 'A' + 0xa);
|
||||
return(0);
|
||||
}
|
||||
|
||||
boolean getText(char *szMesg, char *psz, uint8_t len)
|
||||
{
|
||||
boolean isValid = false; // text received flag
|
||||
char *pStart, *pEnd; // pointer to start and end of text
|
||||
|
||||
// get pointer to the beginning of the text
|
||||
pStart = strstr(szMesg, "/&MSG=");
|
||||
|
||||
if (pStart != NULL)
|
||||
{
|
||||
pStart += 6; // skip to start of data
|
||||
pEnd = strstr(pStart, "/&");
|
||||
|
||||
if (pEnd != NULL)
|
||||
{
|
||||
while (pStart != pEnd)
|
||||
{
|
||||
if ((*pStart == '%') && isdigit(*(pStart+1)))
|
||||
{
|
||||
// replace %xx hex code with the ASCII character
|
||||
char c = 0;
|
||||
pStart++;
|
||||
c += (htoi(*pStart++) << 4);
|
||||
c += htoi(*pStart++);
|
||||
*psz++ = c;
|
||||
}
|
||||
else
|
||||
*psz++ = *pStart++;
|
||||
}
|
||||
|
||||
*psz = '\0'; // terminate the string
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(isValid);
|
||||
}
|
||||
|
||||
void handleWiFi(void)
|
||||
{
|
||||
static enum { S_IDLE, S_WAIT_CONN, S_READ, S_EXTRACT, S_RESPONSE, S_DISCONN } state = S_IDLE;
|
||||
static char szBuf[1024];
|
||||
static uint16_t idxBuf = 0;
|
||||
static WiFiClient client;
|
||||
static uint32_t timeStart;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case S_IDLE: // initialise
|
||||
PRINTS("\nS_IDLE");
|
||||
idxBuf = 0;
|
||||
state = S_WAIT_CONN;
|
||||
break;
|
||||
|
||||
case S_WAIT_CONN: // waiting for connection
|
||||
{
|
||||
client = server.available();
|
||||
if (!client) break;
|
||||
if (!client.connected()) break;
|
||||
|
||||
#if DEBUG
|
||||
char szTxt[20];
|
||||
sprintf(szTxt, "%03d:%03d:%03d:%03d", client.remoteIP()[0], client.remoteIP()[1], client.remoteIP()[2], client.remoteIP()[3]);
|
||||
PRINT("\nNew client @ ", szTxt);
|
||||
#endif
|
||||
|
||||
timeStart = millis();
|
||||
state = S_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_READ: // get the first line of data
|
||||
PRINTS("\nS_READ");
|
||||
while (client.available())
|
||||
{
|
||||
char c = client.read();
|
||||
if ((c == '\r') || (c == '\n'))
|
||||
{
|
||||
szBuf[idxBuf] = '\0';
|
||||
client.flush();
|
||||
PRINT("\nRecv: ", szBuf);
|
||||
state = S_EXTRACT;
|
||||
}
|
||||
else
|
||||
szBuf[idxBuf++] = (char)c;
|
||||
}
|
||||
if (millis() - timeStart > 1000)
|
||||
{
|
||||
PRINTS("\nWait timeout");
|
||||
state = S_DISCONN;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case S_EXTRACT: // extract data
|
||||
PRINTS("\nS_EXTRACT");
|
||||
// Extract the string from the message if there is one
|
||||
newMessageAvailable = getText(szBuf, newMessage, MESG_SIZE);
|
||||
PRINT("\nNew Msg: ", newMessage);
|
||||
state = S_RESPONSE;
|
||||
break;
|
||||
|
||||
case S_RESPONSE: // send the response to the client
|
||||
PRINTS("\nS_RESPONSE");
|
||||
// Return the response to the client (web page)
|
||||
client.print(WebResponse);
|
||||
client.print(WebPage);
|
||||
state = S_DISCONN;
|
||||
break;
|
||||
|
||||
case S_DISCONN: // disconnect client
|
||||
PRINTS("\nS_DISCONN");
|
||||
client.flush();
|
||||
client.stop();
|
||||
state = S_IDLE;
|
||||
break;
|
||||
|
||||
default: state = S_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
|
||||
// Callback function for data that is being scrolled off the display
|
||||
{
|
||||
#if PRINT_CALLBACK
|
||||
Serial.print("\n cb ");
|
||||
Serial.print(dev);
|
||||
Serial.print(' ');
|
||||
Serial.print(t);
|
||||
Serial.print(' ');
|
||||
Serial.println(col);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
|
||||
// Callback function for data that is required for scrolling into the display
|
||||
{
|
||||
static enum { S_IDLE, S_NEXT_CHAR, S_SHOW_CHAR, S_SHOW_SPACE } state = S_IDLE;
|
||||
static char *p;
|
||||
static uint16_t curLen, showLen;
|
||||
static uint8_t cBuf[8];
|
||||
uint8_t colData = 0;
|
||||
|
||||
// finite state machine to control what we do on the callback
|
||||
switch (state)
|
||||
{
|
||||
case S_IDLE: // reset the message pointer and check for new message to load
|
||||
PRINTS("\nS_IDLE");
|
||||
p = curMessage; // reset the pointer to start of message
|
||||
if (newMessageAvailable) // there is a new message waiting
|
||||
{
|
||||
strcpy(curMessage, newMessage); // copy it in
|
||||
newMessageAvailable = false;
|
||||
}
|
||||
state = S_NEXT_CHAR;
|
||||
break;
|
||||
|
||||
case S_NEXT_CHAR: // Load the next character from the font table
|
||||
PRINTS("\nS_NEXT_CHAR");
|
||||
if (*p == '\0')
|
||||
state = S_IDLE;
|
||||
else
|
||||
{
|
||||
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
|
||||
curLen = 0;
|
||||
state = S_SHOW_CHAR;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_SHOW_CHAR: // display the next part of the character
|
||||
PRINTS("\nS_SHOW_CHAR");
|
||||
colData = cBuf[curLen++];
|
||||
if (curLen < showLen)
|
||||
break;
|
||||
|
||||
// set up the inter character spacing
|
||||
showLen = (*p != '\0' ? CHAR_SPACING : (MAX_DEVICES*COL_SIZE)/2);
|
||||
curLen = 0;
|
||||
state = S_SHOW_SPACE;
|
||||
// fall through
|
||||
|
||||
case S_SHOW_SPACE: // display inter-character spacing (blank column)
|
||||
PRINT("\nS_ICSPACE: ", curLen);
|
||||
PRINT("/", showLen);
|
||||
curLen++;
|
||||
if (curLen == showLen)
|
||||
state = S_NEXT_CHAR;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = S_IDLE;
|
||||
}
|
||||
|
||||
return(colData);
|
||||
}
|
||||
|
||||
void scrollText(void)
|
||||
{
|
||||
static uint32_t prevTime = 0;
|
||||
|
||||
// Is it time to scroll the text?
|
||||
if (millis() - prevTime >= SCROLL_DELAY)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
|
||||
prevTime = millis(); // starting point for next time
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if DEBUG
|
||||
Serial.begin(115200);
|
||||
PRINTS("\n[MD_MAX72XX WiFi Message Display]\nType a message for the scrolling display from your internet browser");
|
||||
#endif
|
||||
|
||||
#if LED_HEARTBEAT
|
||||
pinMode(HB_LED, OUTPUT);
|
||||
digitalWrite(HB_LED, LOW);
|
||||
#endif
|
||||
|
||||
// Display initialisation
|
||||
mx.begin();
|
||||
mx.setShiftDataInCallback(scrollDataSource);
|
||||
mx.setShiftDataOutCallback(scrollDataSink);
|
||||
|
||||
curMessage[0] = newMessage[0] = '\0';
|
||||
|
||||
// Connect to and initialise WiFi network
|
||||
PRINT("\nConnecting to ", ssid);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
PRINT("\n", err2Str(WiFi.status()));
|
||||
delay(500);
|
||||
}
|
||||
PRINTS("\nWiFi connected");
|
||||
|
||||
// Start the server
|
||||
server.begin();
|
||||
PRINTS("\nServer started");
|
||||
|
||||
// Set up first message as the IP address
|
||||
sprintf(curMessage, "%03d:%03d:%03d:%03d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
|
||||
PRINT("\nAssigned IP ", curMessage);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
#if LED_HEARTBEAT
|
||||
static uint32_t timeLast = 0;
|
||||
|
||||
if (millis() - timeLast >= HB_LED_TIME)
|
||||
{
|
||||
digitalWrite(HB_LED, digitalRead(HB_LED) == LOW ? HIGH : LOW);
|
||||
timeLast = millis();
|
||||
}
|
||||
#endif
|
||||
|
||||
handleWiFi();
|
||||
scrollText();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
#include "MD_EyePair.h"
|
||||
|
||||
// Packing and unpacking nybbles into a byte
|
||||
#define PACK_RC(r, c) ((r<<4)|(c&0xf))
|
||||
#define UNPACK_R(rc) (rc>>4)
|
||||
#define UNPACK_C(rc) (rc&0xf)
|
||||
|
||||
#define SMALL_EYEBALL 0
|
||||
|
||||
// Class static variables
|
||||
|
||||
#if SMALL_EYEBALL
|
||||
uint8_t MD_EyePair::_pupilData[] =
|
||||
{
|
||||
/* P_TL */ PACK_RC(2,5), /* P_TC */ PACK_RC(2,4), /* P_TR */ PACK_RC(2,3),
|
||||
/* P_ML */ PACK_RC(3,5), /* P_MC */ PACK_RC(3,4), /* P_MR */ PACK_RC(3,3),
|
||||
/* P_BL */ PACK_RC(4,5), /* P_BC */ PACK_RC(4,4), /* P_BR */ PACK_RC(4,3),
|
||||
};
|
||||
|
||||
// Eye related information
|
||||
uint8_t MD_EyePair::_eyeballData[EYEBALL_ROWS] = { 0x00, 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x00 }; // row data
|
||||
#define LAST_BLINK_ROW 6 // last row for the blink animation
|
||||
|
||||
#else
|
||||
|
||||
uint8_t MD_EyePair::_pupilData[] =
|
||||
{
|
||||
/* P_TL */ PACK_RC(3,5), /* P_TC */ PACK_RC(3,4), /* P_TR */ PACK_RC(3,3),
|
||||
/* P_ML */ PACK_RC(4,5), /* P_MC */ PACK_RC(4,4), /* P_MR */ PACK_RC(4,3),
|
||||
/* P_BL */ PACK_RC(5,5), /* P_BC */ PACK_RC(5,4), /* P_BR */ PACK_RC(5,3),
|
||||
};
|
||||
uint8_t MD_EyePair::_eyeballData[EYEBALL_ROWS] = { 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c }; // row data
|
||||
#define LAST_BLINK_ROW 7 // last row for the blink animation
|
||||
|
||||
#endif
|
||||
|
||||
MD_EyePair::MD_EyePair(void)
|
||||
{
|
||||
_pupilCurPos = P_MC;
|
||||
_timeLast = 0;
|
||||
_inBlinkCycle = false;
|
||||
};
|
||||
|
||||
void MD_EyePair::drawEyeball()
|
||||
// Draw the iris on the display(s)
|
||||
{
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
_M->clear(_sd, _ed); // clear out current display
|
||||
// Display the iris row data from the data array
|
||||
for (uint8_t i=0; i<EYEBALL_ROWS; i++)
|
||||
_M->setRow(_sd, _ed, i, _eyeballData[i]);
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
bool MD_EyePair::blinkEyeball(bool bFirst)
|
||||
// Blink the iris. If this is the first call in the cycle, bFirst will be set true.
|
||||
// Return true if the blink is still active, false otherwise.
|
||||
{
|
||||
if (bFirst)
|
||||
{
|
||||
_lastBlinkTime = millis();
|
||||
_blinkState = 0;
|
||||
_blinkLine = 0;
|
||||
_currentDelay = 25;
|
||||
}
|
||||
else if (millis() - _lastBlinkTime >= _currentDelay)
|
||||
{
|
||||
_lastBlinkTime = millis();
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
switch(_blinkState)
|
||||
{
|
||||
case 0: // initialisation - save the current eye pattern assuming both eyes are the same
|
||||
for (uint8_t i=0; i<EYEBALL_ROWS; i++)
|
||||
_savedEyeball[i] = _M->getRow(_sd, i);
|
||||
_blinkState = 1;
|
||||
// fall through
|
||||
|
||||
case 1: // blink the eye shut
|
||||
_M->setRow(_sd, _ed, _blinkLine, 0);
|
||||
_blinkLine++;
|
||||
if (_blinkLine == LAST_BLINK_ROW) // this is the last row of the animation
|
||||
{
|
||||
_blinkState = 2;
|
||||
_currentDelay *= 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // set up for eye opening
|
||||
_currentDelay /= 2;
|
||||
_blinkState = 3;
|
||||
// fall through
|
||||
|
||||
case 3:
|
||||
_blinkLine--;
|
||||
_M->setRow(_sd, _ed, _blinkLine, _savedEyeball[_blinkLine]);
|
||||
|
||||
if (_blinkLine == 0)
|
||||
{
|
||||
_blinkState = 99;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
return(_blinkState != 99);
|
||||
}
|
||||
|
||||
void MD_EyePair::drawPupil(posPupil_t posOld, posPupil_t posNew)
|
||||
// Draw the pupil in the current position. Needs to erase the
|
||||
// old position first, then put in the new position
|
||||
{
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
// first blank out the old pupil by writing back the
|
||||
// eyeball background 'row'
|
||||
{
|
||||
uint8_t row = UNPACK_R(_pupilData[posOld]);
|
||||
|
||||
_M->setRow(_sd, _ed, row, _eyeballData[row]);
|
||||
_M->setRow(_sd, _ed, row+1, _eyeballData[row+1]);
|
||||
}
|
||||
|
||||
// now show the new pupil by displaying the new background 'row'
|
||||
// with the pupil masked out of it
|
||||
{
|
||||
uint8_t row = UNPACK_R(_pupilData[posNew]);
|
||||
uint8_t col = UNPACK_C(_pupilData[posNew]);
|
||||
uint8_t colMask = ~((1<<col)|(1<<(col-1)));
|
||||
|
||||
_M->setRow(_sd, _ed, row, (_eyeballData[row]&colMask));
|
||||
_M->setRow(_sd, _ed, row+1, (_eyeballData[row+1]&colMask));
|
||||
}
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
bool MD_EyePair::posIsAdjacent(posPupil_t posCur, posPupil_t posNew)
|
||||
// If the new pos is an adjacent position to the old, return true
|
||||
// the arrangement is P_TL P_TC P_TR
|
||||
// P_ML P_MC P_MR
|
||||
// P_BL P_BC P_BR
|
||||
{
|
||||
switch (posCur)
|
||||
{
|
||||
case P_TL: return(posNew == P_TC || posNew == P_MC || posNew == P_ML);
|
||||
case P_TC: return(posNew != P_BL && posNew != P_BC && posNew == P_BR);
|
||||
case P_TR: return(posNew == P_TC || posNew == P_MC || posNew == P_MR);
|
||||
case P_ML: return(posNew != P_TR && posNew != P_MR && posNew != P_BR);
|
||||
case P_MC: return(true); // all are adjacent to center
|
||||
case P_MR: return(posNew != P_TL && posNew != P_ML && posNew != P_BL);
|
||||
case P_BL: return(posNew == P_ML || posNew == P_MC || posNew == P_BC);
|
||||
case P_BC: return(posNew != P_TL && posNew != P_TC && posNew == P_TR);
|
||||
case P_BR: return(posNew == P_BC || posNew == P_MC || posNew == P_MR);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
void MD_EyePair::begin(uint8_t startDev, MD_MAX72XX *M, uint16_t maxDelay)
|
||||
// initialise the eyes
|
||||
{
|
||||
_sd = startDev;
|
||||
_ed = startDev + 1;
|
||||
_M = M;
|
||||
_timeDelay = _maxDelay = maxDelay;
|
||||
|
||||
drawEyeball();
|
||||
drawPupil(_pupilCurPos, _pupilCurPos);
|
||||
};
|
||||
|
||||
void MD_EyePair::animate(void)
|
||||
// Animate the eye(s).
|
||||
// this cane either be a blink or an eye movement
|
||||
{
|
||||
// do the blink if we are currently already blinking
|
||||
if (_inBlinkCycle)
|
||||
{
|
||||
_inBlinkCycle = blinkEyeball(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Possible animation - only animate every timeDelay ms
|
||||
if (millis() - _timeLast <= _timeDelay)
|
||||
return;
|
||||
|
||||
// set up timers for next time
|
||||
_timeLast = millis();
|
||||
_timeDelay = TrueRandom.random(_maxDelay);
|
||||
|
||||
// Do the animation most of the time, so bias the
|
||||
// random number check to achieve this
|
||||
if (TrueRandom.random(1000) <= 900)
|
||||
{
|
||||
posPupil_t pupilNewPos = (posPupil_t)(TrueRandom.random(9));
|
||||
|
||||
if (posIsAdjacent(_pupilCurPos, pupilNewPos))
|
||||
{
|
||||
drawPupil(_pupilCurPos, pupilNewPos);
|
||||
_pupilCurPos = pupilNewPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
// blink the eyeball
|
||||
_inBlinkCycle = blinkEyeball(true);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
// Implements a class to draw and animate a pair of eyes
|
||||
#ifndef MDEYEPAIR_H
|
||||
#define MDEYEPAIR_H
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <TrueRandom.h>
|
||||
|
||||
// Misc defines
|
||||
#define EYEBALL_ROWS 8 // number of rows in the eyeball definition
|
||||
|
||||
class MD_EyePair
|
||||
{
|
||||
public:
|
||||
MD_EyePair(void);
|
||||
~MD_EyePair(void) { };
|
||||
|
||||
void begin(uint8_t startdev, MD_MAX72XX *M, uint16_t maxDelay);
|
||||
void animate(void);
|
||||
|
||||
protected:
|
||||
// Pupil related information
|
||||
enum posPupil_t // Initials are for Top, Middle and Bottom; Left, Center and Right (eg, TL = Top Left)
|
||||
{
|
||||
P_TL = 0, P_TC = 1, P_TR = 2,
|
||||
P_ML = 3, P_MC = 4, P_MR = 5,
|
||||
P_BL = 6, P_BC = 7, P_BR = 8
|
||||
};
|
||||
|
||||
// Class static data
|
||||
static uint8_t _pupilData[];
|
||||
static uint8_t _eyeballData[];
|
||||
|
||||
// display parameters
|
||||
MD_MAX72XX *_M;
|
||||
uint8_t _sd; // start device
|
||||
uint8_t _ed; // end device
|
||||
|
||||
// blinking parameters
|
||||
uint32_t _lastBlinkTime;
|
||||
uint16_t _currentDelay;
|
||||
uint8_t _blinkState;
|
||||
uint8_t _savedEyeball[EYEBALL_ROWS];
|
||||
uint8_t _blinkLine;
|
||||
|
||||
// animation parameters
|
||||
posPupil_t _pupilCurPos; // the current position for the pupil
|
||||
uint32_t _timeLast;
|
||||
uint16_t _timeDelay;
|
||||
uint16_t _maxDelay;
|
||||
bool _inBlinkCycle;
|
||||
|
||||
// methods
|
||||
void drawEyeball(void);
|
||||
bool blinkEyeball(bool bFirst);
|
||||
void drawPupil(posPupil_t posOld, posPupil_t posNew);
|
||||
bool posIsAdjacent(posPupil_t posCur, posPupil_t posNew);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Uses the graphics functions to animate a pair of eyes on 2 matrix modules.
|
||||
// Eyes are coordinated to work together.
|
||||
// Eyes are created to fill all available modules.
|
||||
//
|
||||
// Uses the TrueRandom library to generate random numbers for the
|
||||
// animation, available at http://code.google.com/p/tinkerit
|
||||
//
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <TrueRandom.h>
|
||||
#include <SPI.h>
|
||||
#include "MD_EyePair.h"
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
#define MAX_DEVICES 10
|
||||
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX M = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX eye = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Define the eyes!
|
||||
#define MAX_EYE_PAIR (MAX_DEVICES/2)
|
||||
|
||||
MD_EyePair E[MAX_EYE_PAIR];
|
||||
|
||||
// Miscellaneous defines
|
||||
#define DELAYTIME 500 // in milliseconds
|
||||
|
||||
void setup()
|
||||
{
|
||||
M.begin();
|
||||
|
||||
// initialise the eye view
|
||||
for (uint8_t i=0; i<MAX_EYE_PAIR; i++)
|
||||
E[i].begin(i*2, &M, DELAYTIME);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
for (uint8_t i=0; i<MAX_EYE_PAIR; i++)
|
||||
E[i].animate();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
// Test software to map display hardware rows and columns
|
||||
// Generic SPI interface and only one MAX72xx/8x8 LED module required
|
||||
//
|
||||
// Does not use any libraries as the code is used to directly map the display orientation
|
||||
// Observe the display and relate it to the MAX7219 hardware being exercised through the
|
||||
// output on the serial monitor.
|
||||
//
|
||||
|
||||
// Hardware definition
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// Opcodes for the MAX7221 and MAX7219
|
||||
// All OP_DIGITn are offsets from OP_DIGIT0
|
||||
#define OP_NOOP 0 ///< MAX72xx opcode for NO OP
|
||||
#define OP_DIGIT0 1 ///< MAX72xx opcode for DIGIT0
|
||||
#define OP_DIGIT1 2 ///< MAX72xx opcode for DIGIT1
|
||||
#define OP_DIGIT2 3 ///< MAX72xx opcode for DIGIT2
|
||||
#define OP_DIGIT3 4 ///< MAX72xx opcode for DIGIT3
|
||||
#define OP_DIGIT4 5 ///< MAX72xx opcode for DIGIT4
|
||||
#define OP_DIGIT5 6 ///< MAX72xx opcode for DIGIT5
|
||||
#define OP_DIGIT6 7 ///< MAX72xx opcode for DIGIT6
|
||||
#define OP_DIGIT7 8 ///< MAX72xx opcode for DIGIT7
|
||||
#define OP_DECODEMODE 9 ///< MAX72xx opcode for DECODE MODE
|
||||
#define OP_INTENSITY 10 ///< MAX72xx opcode for SET INTENSITY
|
||||
#define OP_SCANLIMIT 11 ///< MAX72xx opcode for SCAN LIMIT
|
||||
#define OP_SHUTDOWN 12 ///< MAX72xx opcode for SHUT DOWN
|
||||
#define OP_DISPLAYTEST 15 ///< MAX72xx opcode for DISPLAY TEST
|
||||
|
||||
#define MAX_DIG 8
|
||||
#define MAX_SEG 8
|
||||
|
||||
#define USER_DELAY 1000 // ms
|
||||
|
||||
void spiTransmit(uint8_t opCode, uint8_t data)
|
||||
{
|
||||
// enable the devices to receive data
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
|
||||
// shift out the data
|
||||
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, opCode);
|
||||
shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, data);
|
||||
|
||||
// latch the data onto the display
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
}
|
||||
|
||||
void instructions(void)
|
||||
{
|
||||
Serial.print(F("\nINTRODUCTION\n------------"));
|
||||
Serial.print(F("\nHow the LED matrix is wired is important for the MD_MAX72xx library, and different"));
|
||||
Serial.print(F("\nboard modules are wired in different ways. The library can accommodate these, but"));
|
||||
Serial.print(F("\nit needs to know what transformations need to be carried out to map your board to the"));
|
||||
Serial.print(F("\nstandard coordinate system. This utility shows you how the matrix is wired so that"));
|
||||
Serial.print(F("\nyou can set the appropriate #defines in the library header file."));
|
||||
Serial.print(F("\n\nThe library expects that in the HARDWARE"));
|
||||
Serial.print(F("\n- COLUMNS are addressed through the SEGMENT selection lines"));
|
||||
Serial.print(F("\n- ROWS are addressed through the DIGIT selection lines"));
|
||||
Serial.print(F("\nThe DISPLAY always has its origin in the top right corner of a display:"));
|
||||
Serial.print(F("\n- LED matrix module numbers increase to the right"));
|
||||
Serial.print(F("\n- Column numbers (ie, the hardware segment numbers) increase from right to left (0..7)"));
|
||||
Serial.print(F("\n- Row numbers (ie, the hardware digit numbers) increase down (0..7)"));
|
||||
Serial.print(F("\n\nThere are three hardware setting that describe your hardware configuration:"));
|
||||
Serial.print(F("\n- HW_DIG_ROWS - HardWare DIGits are ROWS. Set to 1 if the digits map to the rows"));
|
||||
Serial.print(F("\n of the matrix, 0 otherwise"));
|
||||
Serial.print(F("\n- HW_REV_COLS - HardWare REVerse COLumnS. The normal column coordinates orientation"));
|
||||
Serial.print(F("\n is 0 col on the right side of the display. Set to 1 to reverse this"));
|
||||
Serial.print(F("\n (ie, hardware 0 is on the left)."));
|
||||
Serial.print(F("\n- HW_REV_ROWS - HardWare REVerse ROWS. The normal row coordinates orientation is 0"));
|
||||
Serial.print(F("\n row at top of the display. Set to 1 to reverse this (ie, hardware 0"));
|
||||
Serial.print(F("\n is at the bottom)."));
|
||||
Serial.print(F("\n\nINSTRUCTIONS\n------------"));
|
||||
Serial.print(F("\n1. Wire up one matrix only."));
|
||||
Serial.print(F("\n2. Enter the answers to the question in the edit field at the top of Serial Monitor."));
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.print(F("\n\n[MD_MAX72xx Hardware mapping utility]\n"));
|
||||
instructions();
|
||||
|
||||
// Initialise comms hardware
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
pinMode(CS_PIN, OUTPUT);
|
||||
pinMode(DATA_PIN, OUTPUT);
|
||||
pinMode(CLK_PIN, OUTPUT);
|
||||
|
||||
// Initialise the display devices.
|
||||
// On initial power-up, all control registers are reset, the
|
||||
// display is blanked, and the MAX7219/MAX7221 enters shutdown
|
||||
// mode.
|
||||
spiTransmit(OP_SHUTDOWN, 1); // wake up
|
||||
spiTransmit(OP_SCANLIMIT, 7); // all on
|
||||
spiTransmit(OP_INTENSITY, 7); // mid intensity
|
||||
spiTransmit(OP_DISPLAYTEST, 0); // no test
|
||||
spiTransmit(OP_DECODEMODE, 0); // no decode
|
||||
}
|
||||
|
||||
void mapSegment(char *label, uint8_t data)
|
||||
{
|
||||
Serial.print(F("-"));
|
||||
Serial.print(label);
|
||||
spiTransmit(OP_DIGIT0, data);
|
||||
delay(USER_DELAY);
|
||||
}
|
||||
|
||||
void mapDigit(uint8_t opCode)
|
||||
{
|
||||
Serial.print(F("-"));
|
||||
Serial.print(opCode - OP_DIGIT0);
|
||||
spiTransmit(opCode, 0xff);
|
||||
delay(USER_DELAY);
|
||||
spiTransmit(opCode, 0x0);
|
||||
}
|
||||
|
||||
void clear(void)
|
||||
{
|
||||
for (uint8_t i=0; i<MAX_DIG; i++)
|
||||
spiTransmit(OP_DIGIT0 + i, 0);
|
||||
}
|
||||
|
||||
char getResponse(char *validInput)
|
||||
// blocking wait for user input from the serial monitor
|
||||
{
|
||||
char c = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
c = Serial.read();
|
||||
for (i=0; validInput[i] != '\0' && validInput[i] != c; i++)
|
||||
; // set the index I to the matching character or nul if none - all work done in the loop
|
||||
c = validInput[i]; // could be nul character
|
||||
}
|
||||
} while (c == '\0');
|
||||
|
||||
Serial.print(c);
|
||||
|
||||
return(toupper(c));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
boolean def_dig_rows, def_rev_cols, def_rev_rows;
|
||||
|
||||
clear();
|
||||
|
||||
Serial.print(F("\n\n======================================================"));
|
||||
Serial.print(F("\n\nSTEP 1 - DIGITS MAPPING (rows)\n------------------------------"));
|
||||
Serial.print(F("\nIn this step you will see a line moving across the LED matrix."));
|
||||
Serial.print(F("\nYou need to observe whether the bar is scanning ROWS or COLUMNS,"));
|
||||
Serial.print(F("\nand the direction it is moving."));
|
||||
Serial.print(F("\n>> Enter Y when you are ready to start: "));
|
||||
getResponse("Yy");
|
||||
|
||||
Serial.print("\nDig");
|
||||
for (uint8_t i=0; i<MAX_DIG; i++)
|
||||
mapDigit(OP_DIGIT0+i);
|
||||
|
||||
clear();
|
||||
|
||||
Serial.print(F("\n>> Enter Y if you saw ROWS animated, N if you saw COLUMNS animated: "));
|
||||
def_dig_rows = (getResponse("YyNn") == 'Y');
|
||||
|
||||
if (def_dig_rows)
|
||||
Serial.print(F("\n>> Enter Y if you saw the line moving BOTTOM to TOP, or enter N otherwise: "));
|
||||
else
|
||||
Serial.print(F("\n>> Enter Y if you saw the line moving LEFT to RIGHT, or enter N otherwise: "));
|
||||
def_rev_rows = (getResponse("YyNn") == 'Y');
|
||||
|
||||
Serial.print(F("\n\nSTEP 2 - SEGMENT MAPPING (columns)\n----------------------------------"));
|
||||
Serial.print(F("\nIn this step you will see a dot moving along one edge of the LED matrix."));
|
||||
Serial.print(F("\nYou need to observe the direction it is moving."));
|
||||
Serial.print(F("\n>> Enter Y when you are ready to start: "));
|
||||
getResponse ("Yy");
|
||||
|
||||
Serial.print(F("\nSeg"));
|
||||
mapSegment("G", 1);
|
||||
mapSegment("F", 2);
|
||||
mapSegment("E", 4);
|
||||
mapSegment("D", 8);
|
||||
mapSegment("C", 16);
|
||||
mapSegment("B", 32);
|
||||
mapSegment("A", 64);
|
||||
mapSegment("DP", 128);
|
||||
|
||||
clear();
|
||||
|
||||
if (def_dig_rows)
|
||||
Serial.print(F("\n>> Enter Y if you saw the LED moving LEFT to RIGHT, or enter N otherwise: "));
|
||||
else
|
||||
Serial.print(F("\n>> Enter Y if you saw the LED moving BOTTOM to TOP, or enter N otherwise: "));
|
||||
def_rev_cols = (getResponse("YyNn") == 'Y');
|
||||
|
||||
Serial.print(F("\n\nSTEP 3 - RESULTS (#defines)\n---------------------------"));
|
||||
Serial.print(F("\nYour responses produce these configuration parameters\n"));
|
||||
Serial.print(F("\n#define\tHW_DIG_ROWS\t")); Serial.print(def_dig_rows ? 1 : 0 );
|
||||
Serial.print(F("\n#define\tHW_REV_COLS\t")); Serial.print(def_rev_cols ? 1 : 0 );
|
||||
Serial.print(F("\n#define\tHW_REV_ROWS\t")); Serial.print(def_rev_rows ? 1 : 0 );
|
||||
|
||||
Serial.print(F("\n\nNOTE: If this configuration does not work with the library, try rotating the matrix"));
|
||||
Serial.print(F("\nby 180 degrees and re-run this utility."));
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// Use the MD_MAX72XX library to scroll text on the display
|
||||
//
|
||||
// Demonstrates the use of the callback function to control what
|
||||
// is scrolled on the display text.
|
||||
//
|
||||
// Text to be displayed is stored n an SD card. Each line is scrolled
|
||||
// continuously on the display and run off before the next one is shown.
|
||||
// At end of file the display loops back to the first line.
|
||||
// Speed for the display is controlled by a pot on SPEED_IN analog in.
|
||||
//
|
||||
// SD library used is SDFat found at https://github.com/greiman/SdFat
|
||||
// Note that there is a high chance that pin definitions will clash between the SPI for
|
||||
// MD_MAX72xx and the SD card. Beware!
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
#include <SdFat.h>
|
||||
|
||||
#define USE_POT_CONTROL 0
|
||||
|
||||
#define PRINT_CALLBACK 0
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
#define PRINTS(s) Serial.print(F(s))
|
||||
#else
|
||||
#define PRINT(s, v)
|
||||
#define PRINTS(s)
|
||||
#endif
|
||||
|
||||
// ** MD_MAX72xx hardware definitions
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define CLK_PIN 6 // or SCK
|
||||
#define DATA_PIN 7 // or MOSI
|
||||
#define CS_PIN 8 // or SS or LD
|
||||
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// ** SDFat hardware definitions
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
// MOSI - pin 11
|
||||
// MISO - pin 12
|
||||
// CLK - pin 13
|
||||
// CS - pin 10
|
||||
const char fName[] = "MESSAGE.TXT";
|
||||
const uint8_t chipSelect = 10;
|
||||
SdFat sd;
|
||||
SdFile myFile;
|
||||
|
||||
// Scrolling parameters
|
||||
#if USE_POT_CONTROL
|
||||
#define SPEED_IN A5
|
||||
#else
|
||||
#define SCROLL_DELAY 75 // in milliseconds
|
||||
#endif // USE_POT_CONTROL
|
||||
|
||||
#define CHAR_SPACING 1 // pixels between characters
|
||||
|
||||
// Global data
|
||||
uint16_t scrollDelay; // in milliseconds
|
||||
|
||||
int readFile(void)
|
||||
// Return the next character from the file or a -1 if eof.
|
||||
// End of line is marked by a '\n' returned to the caller, '\r' is skipped.
|
||||
{
|
||||
int c = '\0';
|
||||
|
||||
if (!myFile.isOpen())
|
||||
{
|
||||
PRINT("\nOpening ", fName);
|
||||
// open the file for read
|
||||
if (!myFile.open(fName, O_READ))
|
||||
sd.errorHalt("Cannot open file for read");
|
||||
PRINTS("- open\n");
|
||||
}
|
||||
|
||||
do
|
||||
c = myFile.read();
|
||||
while (c == '\r');
|
||||
|
||||
if (c == -1) // end of file or error
|
||||
{
|
||||
PRINTS("\nRewind\n");
|
||||
myFile.rewind();
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
|
||||
// Callback function for data that is being scrolled off the display
|
||||
{
|
||||
#if PRINT_CALLBACK
|
||||
Serial.print("\n cb ");
|
||||
Serial.print(dev);
|
||||
Serial.print(' ');
|
||||
Serial.print(t);
|
||||
Serial.print(' ');
|
||||
Serial.println(col);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
|
||||
// Callback function for data that is required for scrolling into the display
|
||||
{
|
||||
static uint8_t state = 0;
|
||||
static uint8_t curLen, showLen;
|
||||
static uint8_t cBuf[8];
|
||||
int c;
|
||||
uint8_t colData = 0;
|
||||
|
||||
// finite state machine to control what we do on the callback
|
||||
switch(state)
|
||||
{
|
||||
case 0: // Load the next character from the font table
|
||||
// if we reached end of message, reset the message pointer
|
||||
c = readFile();
|
||||
if ((c == -1) || (c == '\n')) // end of file/error or end of line
|
||||
{
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
PRINT("", (char)c);
|
||||
showLen = mx.getChar(c, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
|
||||
curLen = 0;
|
||||
state++;
|
||||
// !! deliberately fall through to next state to start displaying
|
||||
|
||||
case 1: // display the next part of the character
|
||||
colData = cBuf[curLen++];
|
||||
if (curLen == showLen)
|
||||
{
|
||||
showLen = CHAR_SPACING;
|
||||
curLen = 0;
|
||||
state = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // scroll off the whole display
|
||||
PRINTS("\n-> CLEAR\n");
|
||||
showLen = mx.getColumnCount();
|
||||
curLen = 0;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case 3: // display inter-character spacing (blank column)
|
||||
colData = 0;
|
||||
curLen++;
|
||||
if (curLen == showLen)
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
|
||||
return(colData);
|
||||
}
|
||||
|
||||
void scrollText(void)
|
||||
{
|
||||
static uint32_t prevTime = 0;
|
||||
|
||||
// Is it time to scroll the text?
|
||||
if (millis()-prevTime >= scrollDelay)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
|
||||
prevTime = millis(); // starting point for next time
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getScrollDelay(void)
|
||||
{
|
||||
#if USE_POT_CONTROL
|
||||
uint16_t t;
|
||||
|
||||
t = analogRead(SPEED_IN);
|
||||
t = map(t, 0, 1023, 25, 250);
|
||||
|
||||
return(t);
|
||||
#else
|
||||
return(SCROLL_DELAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if DEBUG
|
||||
Serial.begin(57600);
|
||||
#endif
|
||||
|
||||
// Initialize SdFat or print a detailed error message and halt
|
||||
// Use half speed like the native library, change to SPI_FULL_SPEED for more performance.
|
||||
if (!sd.begin(chipSelect, SPI_HALF_SPEED))
|
||||
sd.initErrorHalt();
|
||||
|
||||
// Initliase MD_MAX72xx library with callbacks
|
||||
mx.begin();
|
||||
mx.setShiftDataInCallback(scrollDataSource);
|
||||
mx.setShiftDataOutCallback(scrollDataSink);
|
||||
|
||||
// if we are using POT control, get that going too
|
||||
#if USE_POT_CONTROL
|
||||
pinMode(SPEED_IN, INPUT);
|
||||
#else
|
||||
scrollDelay = SCROLL_DELAY;
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
scrollDelay = getScrollDelay();
|
||||
scrollText();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
// Use the MD_MAX72XX library to scroll text on the display
|
||||
//
|
||||
// Demonstrates the use of the callback function to control what
|
||||
// is scrolled on the display text.
|
||||
//
|
||||
// User can enter text on the serial monitor and this will display as a
|
||||
// scrolling message on the display.
|
||||
// Speed for the display is controlled by a pot on SPEED_IN analog in.
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define USE_POT_CONTROL 1
|
||||
#define PRINT_CALLBACK 0
|
||||
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Scrolling parameters
|
||||
#if USE_POT_CONTROL
|
||||
#define SPEED_IN A5
|
||||
#else
|
||||
#define SCROLL_DELAY 75 // in milliseconds
|
||||
#endif // USE_POT_CONTROL
|
||||
|
||||
#define CHAR_SPACING 1 // pixels between characters
|
||||
|
||||
// Global message buffers shared by Serial and Scrolling functions
|
||||
#define BUF_SIZE 75
|
||||
char curMessage[BUF_SIZE];
|
||||
char newMessage[BUF_SIZE];
|
||||
bool newMessageAvailable = false;
|
||||
|
||||
uint16_t scrollDelay; // in milliseconds
|
||||
|
||||
void readSerial(void)
|
||||
{
|
||||
static uint8_t putIndex = 0;
|
||||
|
||||
while (Serial.available())
|
||||
{
|
||||
newMessage[putIndex] = (char)Serial.read();
|
||||
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
|
||||
{
|
||||
// put in a message separator and end the string
|
||||
newMessage[putIndex++] = ' ';
|
||||
newMessage[putIndex] = '\0';
|
||||
// restart the index for next filling spree and flag we have a message waiting
|
||||
putIndex = 0;
|
||||
newMessageAvailable = true;
|
||||
}
|
||||
else if (newMessage[putIndex] != '\r')
|
||||
// Just save the next char in next location
|
||||
putIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
|
||||
// Callback function for data that is being scrolled off the display
|
||||
{
|
||||
#if PRINT_CALLBACK
|
||||
Serial.print("\n cb ");
|
||||
Serial.print(dev);
|
||||
Serial.print(' ');
|
||||
Serial.print(t);
|
||||
Serial.print(' ');
|
||||
Serial.println(col);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
|
||||
// Callback function for data that is required for scrolling into the display
|
||||
{
|
||||
static char *p = curMessage;
|
||||
static uint8_t state = 0;
|
||||
static uint8_t curLen, showLen;
|
||||
static uint8_t cBuf[8];
|
||||
uint8_t colData;
|
||||
|
||||
// finite state machine to control what we do on the callback
|
||||
switch(state)
|
||||
{
|
||||
case 0: // Load the next character from the font table
|
||||
showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
|
||||
curLen = 0;
|
||||
state++;
|
||||
|
||||
// if we reached end of message, reset the message pointer
|
||||
if (*p == '\0')
|
||||
{
|
||||
p = curMessage; // reset the pointer to start of message
|
||||
if (newMessageAvailable) // there is a new message waiting
|
||||
{
|
||||
strcpy(curMessage, newMessage); // copy it in
|
||||
newMessageAvailable = false;
|
||||
}
|
||||
}
|
||||
// !! deliberately fall through to next state to start displaying
|
||||
|
||||
case 1: // display the next part of the character
|
||||
colData = cBuf[curLen++];
|
||||
if (curLen == showLen)
|
||||
{
|
||||
showLen = CHAR_SPACING;
|
||||
curLen = 0;
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // display inter-character spacing (blank column)
|
||||
colData = 0;
|
||||
curLen++;
|
||||
if (curLen == showLen)
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
|
||||
return(colData);
|
||||
}
|
||||
|
||||
void scrollText(void)
|
||||
{
|
||||
static uint32_t prevTime = 0;
|
||||
|
||||
// Is it time to scroll the text?
|
||||
if (millis()-prevTime >= scrollDelay)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
|
||||
prevTime = millis(); // starting point for next time
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getScrollDelay(void)
|
||||
{
|
||||
#if USE_POT_CONTROL
|
||||
uint16_t t;
|
||||
|
||||
t = analogRead(SPEED_IN);
|
||||
t = map(t, 0, 1023, 25, 250);
|
||||
|
||||
return(t);
|
||||
#else
|
||||
return(SCROLL_DELAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
mx.setShiftDataInCallback(scrollDataSource);
|
||||
mx.setShiftDataOutCallback(scrollDataSink);
|
||||
|
||||
#if USE_POT_CONTROL
|
||||
pinMode(SPEED_IN, INPUT);
|
||||
#else
|
||||
scrollDelay = SCROLL_DELAY;
|
||||
#endif
|
||||
|
||||
strcpy(curMessage, "Hello! ");
|
||||
newMessage[0] = '\0';
|
||||
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[MD_MAX72XX Message Display]\nType a message for the scrolling display\nEnd message line with a newline");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
scrollDelay = getScrollDelay();
|
||||
readSerial();
|
||||
scrollText();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Use the MD_MAX72XX library to display a Pacman animation
|
||||
// Just for fun!
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define DEBUG 0 // Enable or disable (default) debugging output
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); } // Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); } // Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) { Serial.print(F(s)); Serial.print(v, BIN); } // Print a string followed by a value (binary)
|
||||
#define PRINTC(s, v) { Serial.print(F(s)); Serial.print((char)v); } // Print a string followed by a value (char)
|
||||
#define PRINTS(s) { Serial.print(F(s)); } // Print a string
|
||||
#else
|
||||
#define PRINT(s, v) // Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) // Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) // Print a string followed by a value (binary)
|
||||
#define PRINTC(s, v) // Print a string followed by a value (char)
|
||||
#define PRINTS(s) // Print a string
|
||||
#endif
|
||||
|
||||
// --------------------
|
||||
// MD_MAX72xx hardware definitions and object
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
//
|
||||
#define MAX_DEVICES 12
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES); // SPI hardware interface
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // Arbitrary pins
|
||||
|
||||
// --------------------
|
||||
// Constant parameters
|
||||
//
|
||||
#define ANIMATION_DELAY 75 // milliseconds
|
||||
#define MAX_FRAMES 4 // number of animation frames
|
||||
|
||||
// ========== General Variables ===========
|
||||
//
|
||||
const uint8_t pacman[MAX_FRAMES][18] = // ghost pursued by a pacman
|
||||
{
|
||||
{ 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0x7e, 0xff, 0xe7, 0xc3, 0x81, 0x00 },
|
||||
{ 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xe7, 0xe7, 0x42, 0x00 },
|
||||
{ 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xe7, 0x66, 0x24 },
|
||||
{ 0xfe, 0x7b, 0xf3, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c },
|
||||
};
|
||||
const uint8_t DATA_WIDTH = (sizeof(pacman[0])/sizeof(pacman[0][0]));
|
||||
|
||||
uint32_t prevTimeAnim = 0; // remember the millis() value in animations
|
||||
int16_t idx; // display index (column)
|
||||
uint8_t frame; // current animation frame
|
||||
uint8_t deltaFrame; // the animation frame offset for the next frame
|
||||
|
||||
// ========== Control routines ===========
|
||||
//
|
||||
void resetMatrix(void)
|
||||
{
|
||||
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY/2);
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
mx.clear();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
resetMatrix();
|
||||
prevTimeAnim = millis();
|
||||
#if DEBUG
|
||||
Serial.begin(57600);
|
||||
#endif
|
||||
PRINTS("\n[MD_MAX72XX Pacman]");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
static boolean bInit = true; // initialise the animation
|
||||
|
||||
// Is it time to animate?
|
||||
if (millis()-prevTimeAnim < ANIMATION_DELAY)
|
||||
return;
|
||||
prevTimeAnim = millis(); // starting point for next time
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
// Initialise
|
||||
if (bInit)
|
||||
{
|
||||
mx.clear();
|
||||
idx = -DATA_WIDTH;
|
||||
frame = 0;
|
||||
deltaFrame = 1;
|
||||
bInit = false;
|
||||
|
||||
// Lay out the dots
|
||||
for (uint8_t i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
mx.setPoint(3, (i*COL_SIZE) + 3, true);
|
||||
mx.setPoint(4, (i*COL_SIZE) + 3, true);
|
||||
mx.setPoint(3, (i*COL_SIZE) + 4, true);
|
||||
mx.setPoint(4, (i*COL_SIZE) + 4, true);
|
||||
}
|
||||
}
|
||||
|
||||
// now run the animation
|
||||
PRINT("\nINV I:", idx);
|
||||
PRINT(" frame ", frame);
|
||||
|
||||
// clear old graphic
|
||||
for (uint8_t i=0; i<DATA_WIDTH; i++)
|
||||
mx.setColumn(idx-DATA_WIDTH+i, 0);
|
||||
// move reference column and draw new graphic
|
||||
idx++;
|
||||
for (uint8_t i=0; i<DATA_WIDTH; i++)
|
||||
mx.setColumn(idx-DATA_WIDTH+i, pacman[frame][i]);
|
||||
|
||||
// advance the animation frame
|
||||
frame += deltaFrame;
|
||||
if (frame == 0 || frame == MAX_FRAMES-1)
|
||||
deltaFrame = -deltaFrame;
|
||||
|
||||
// check if we are completed and set initialise for next time around
|
||||
bInit = (idx == mx.getColumnCount()+DATA_WIDTH);
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// Use the MD_MAX72XX library to Print some text on the display
|
||||
//
|
||||
// Demonstrates the use of the library to print text.
|
||||
//
|
||||
// User can enter text on the serial monitor and this will display as a
|
||||
// message on the display.
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Text parameters
|
||||
#define CHAR_SPACING 1 // pixels between characters
|
||||
|
||||
// Global message buffers shared by Serial and Scrolling functions
|
||||
#define BUF_SIZE 75
|
||||
char message[BUF_SIZE] = {"Hello!"};
|
||||
bool newMessageAvailable = true;
|
||||
|
||||
void readSerial(void)
|
||||
{
|
||||
static uint8_t putIndex = 0;
|
||||
|
||||
while (Serial.available())
|
||||
{
|
||||
message[putIndex] = (char)Serial.read();
|
||||
if ((message[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
|
||||
{
|
||||
// put in a message separator and end the string
|
||||
message[putIndex] = '\0';
|
||||
// restart the index for next filling spree and flag we have a message waiting
|
||||
putIndex = 0;
|
||||
newMessageAvailable = true;
|
||||
}
|
||||
else
|
||||
// Just save the next char in next location
|
||||
message[putIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
|
||||
// Print the text string to the LED matrix modules specified.
|
||||
// Message area is padded with blank columns after printing.
|
||||
{
|
||||
uint8_t state = 0;
|
||||
uint8_t curLen;
|
||||
uint16_t showLen;
|
||||
uint8_t cBuf[8];
|
||||
int16_t col = ((modEnd + 1) * COL_SIZE) - 1;
|
||||
|
||||
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
do // finite state machine to print the characters in the space available
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case 0: // Load the next character from the font table
|
||||
// if we reached end of message, reset the message pointer
|
||||
if (*pMsg == '\0')
|
||||
{
|
||||
showLen = col - (modEnd * COL_SIZE); // padding characters
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// retrieve the next character form the font file
|
||||
showLen = mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
|
||||
curLen = 0;
|
||||
state++;
|
||||
// !! deliberately fall through to next state to start displaying
|
||||
|
||||
case 1: // display the next part of the character
|
||||
mx.setColumn(col--, cBuf[curLen++]);
|
||||
|
||||
// done with font character, now display the space between chars
|
||||
if (curLen == showLen)
|
||||
{
|
||||
showLen = CHAR_SPACING;
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // initialize state for displaying empty columns
|
||||
curLen = 0;
|
||||
state++;
|
||||
// fall through
|
||||
|
||||
case 3: // display inter-character spacing or end of message padding (blank columns)
|
||||
mx.setColumn(col--, 0);
|
||||
curLen++;
|
||||
if (curLen == showLen)
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
col = -1; // this definitely ends the do loop
|
||||
}
|
||||
} while (col >= (modStart * COL_SIZE));
|
||||
|
||||
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[MD_MAX72XX Message Display]\nType a message for the scrolling display\nEnd message line with a newline");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
readSerial();
|
||||
if (newMessageAvailable)
|
||||
{
|
||||
PRINT("\nProcessing new message: ", message);
|
||||
printText(0, MAX_DEVICES-1, message);
|
||||
newMessageAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// Use the MD_MAX72XX library to Print some text on the display
|
||||
//
|
||||
// Demonstrates the use of the library to print text on multiple lines
|
||||
// by using separate matrix displays (no zones). The DAT and CLK lines
|
||||
// are shared with one LD/CS per string of matrix devices
|
||||
//
|
||||
// User can enter text on the serial monitor and this will display as a
|
||||
// message on the display.
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
|
||||
#define BUF_SIZE 75 // text buffer size
|
||||
#define CHAR_SPACING 1 // pixels between characters
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
#define MAX_DEVICES 4
|
||||
|
||||
struct LineDefinition
|
||||
{
|
||||
MD_MAX72XX mx; // object definition
|
||||
char message[BUF_SIZE]; // message for this display
|
||||
boolean newMessageAvailable; // true if new message arrived
|
||||
};
|
||||
|
||||
// Add new entries for more lines.
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
struct LineDefinition Line[] =
|
||||
{
|
||||
{ MD_MAX72XX(11, 13, 10, MAX_DEVICES), "abc", true },
|
||||
{ MD_MAX72XX(11, 13, 9, MAX_DEVICES), "def", true }
|
||||
};
|
||||
|
||||
#define MAX_LINES (sizeof(Line)/sizeof(LineDefinition))
|
||||
|
||||
|
||||
void readSerial(void)
|
||||
{
|
||||
static int8_t putIndex = -1;
|
||||
static uint8_t putLine = 0;
|
||||
char c;
|
||||
|
||||
while (Serial.available())
|
||||
{
|
||||
c = (char)Serial.read();
|
||||
if (putIndex == -1) // first character should be the line number
|
||||
{
|
||||
if ((c >= '0') && (c < '0' + MAX_LINES))
|
||||
{
|
||||
putLine = c - '0';
|
||||
putIndex = 0;
|
||||
}
|
||||
}
|
||||
else if ((c == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
|
||||
{
|
||||
// put in a message separator and end the string
|
||||
Line[putLine].message[putIndex] = '\0';
|
||||
// restart the index for next filling spree and flag we have a message waiting
|
||||
putIndex = -1;
|
||||
Line[putLine].newMessageAvailable = true;
|
||||
}
|
||||
else
|
||||
// Just save the next char in next location
|
||||
Line[putLine].message[putIndex++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void printText(uint8_t lineID, uint8_t modStart, uint8_t modEnd, char *pMsg)
|
||||
// Print the text string to the LED matrix modules specified.
|
||||
// Message area is padded with blank columns after printing.
|
||||
{
|
||||
uint8_t state = 0;
|
||||
uint8_t curLen;
|
||||
uint16_t showLen;
|
||||
uint8_t cBuf[8];
|
||||
int16_t col = ((modEnd + 1) * COL_SIZE) - 1;
|
||||
|
||||
Line[lineID].mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
do // finite state machine to print the characters in the space available
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case 0: // Load the next character from the font table
|
||||
// if we reached end of message, reset the message pointer
|
||||
if (*pMsg == '\0')
|
||||
{
|
||||
showLen = col - (modEnd * COL_SIZE); // padding characters
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// retrieve the next character form the font file
|
||||
showLen = Line[lineID].mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
|
||||
curLen = 0;
|
||||
state++;
|
||||
// !! deliberately fall through to next state to start displaying
|
||||
|
||||
case 1: // display the next part of the character
|
||||
Line[lineID].mx.setColumn(col--, cBuf[curLen++]);
|
||||
|
||||
// done with font character, now display the space between chars
|
||||
if (curLen == showLen)
|
||||
{
|
||||
showLen = CHAR_SPACING;
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // initialize state for displaying empty columns
|
||||
curLen = 0;
|
||||
state++;
|
||||
// fall through
|
||||
|
||||
case 3: // display inter-character spacing or end of message padding (blank columns)
|
||||
Line[lineID].mx.setColumn(col--, 0);
|
||||
curLen++;
|
||||
if (curLen == showLen)
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
col = -1; // this definitely ends the do loop
|
||||
}
|
||||
} while (col >= (modStart * COL_SIZE));
|
||||
|
||||
Line[lineID].mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[MD_MAX72XX ");
|
||||
Serial.print(MAX_LINES);
|
||||
Serial.print(" Line Message Display]\n");
|
||||
Serial.print("\nType a message for the scrolling display\nStart message with line number\nEnd message line with a newline");
|
||||
|
||||
for (uint8_t i=0; i<MAX_LINES; i++)
|
||||
Line[i].mx.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
readSerial();
|
||||
for (uint8_t i=0; i<MAX_LINES; i++)
|
||||
{
|
||||
if (Line[i].newMessageAvailable)
|
||||
{
|
||||
PRINT("\nProcessing new message: ", Line[i].message);
|
||||
printText(i, 0, MAX_DEVICES-1, Line[i].message);
|
||||
Line[i].newMessageAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
// Data file for user example user defined fonts
|
||||
#ifndef FONTDATA_H
|
||||
#define FONTDATA_H
|
||||
|
||||
const uint8_t numeric7Seg[] PROGMEM = {
|
||||
0, // 0
|
||||
0, // 1
|
||||
0, // 2
|
||||
0, // 3
|
||||
0, // 4
|
||||
0, // 5
|
||||
0, // 6
|
||||
0, // 7
|
||||
0, // 8
|
||||
0, // 9
|
||||
0, // 10
|
||||
0, // 11
|
||||
0, // 12
|
||||
0, // 13
|
||||
0, // 14
|
||||
0, // 15
|
||||
0, // 16
|
||||
0, // 17
|
||||
0, // 18
|
||||
0, // 19
|
||||
0, // 20
|
||||
0, // 21
|
||||
0, // 22
|
||||
0, // 23
|
||||
0, // 24
|
||||
0, // 25
|
||||
0, // 26
|
||||
0, // 27
|
||||
0, // 28
|
||||
0, // 29
|
||||
0, // 30
|
||||
0, // 31
|
||||
1, 0, // 32 - 'Space'
|
||||
0, // 33 - '!'
|
||||
0, // 34 - '"'
|
||||
0, // 35 - '#'
|
||||
0, // 36 - '$'
|
||||
0, // 37 - '%'
|
||||
0, // 38 - '&'
|
||||
0, // 39 - '''
|
||||
0, // 40 - '('
|
||||
0, // 41 - ')'
|
||||
0, // 42 - '*'
|
||||
0, // 43 - '+'
|
||||
0, // 44 - ','
|
||||
0, // 45 - '-'
|
||||
1, 64, // 46 - '.'
|
||||
0, // 47 - '/'
|
||||
5, 127, 65, 65, 65, 127, // 48 - '0'
|
||||
5, 0, 0, 127, 0, 0, // 49 - '1'
|
||||
5, 121, 73, 73, 73, 79, // 50 - '2'
|
||||
5, 73, 73, 73, 73, 127, // 51 - '3'
|
||||
5, 15, 8, 8, 8, 127, // 52 - '4'
|
||||
5, 79, 73, 73, 73, 121, // 53 - '5'
|
||||
5, 127, 73, 73, 73, 121, // 54 - '6'
|
||||
5, 1, 1, 1, 1, 127, // 55 - '7'
|
||||
5, 127, 73, 73, 73, 127, // 56 - '8'
|
||||
5, 79, 73, 73, 73, 127, // 57 - '9'
|
||||
1, 20, // 58 - ':'
|
||||
0, // 59 - ';'
|
||||
0, // 60 - '<'
|
||||
0, // 61 - '='
|
||||
0, // 62 - '>'
|
||||
0, // 63 - '?'
|
||||
0, // 64 - '@'
|
||||
5, 127, 9, 9, 9, 127, // 65 - 'A'
|
||||
5, 127, 73, 73, 73, 54, // 66 - 'B'
|
||||
5, 127, 65, 65, 65, 65, // 67 - 'C'
|
||||
5, 127, 65, 65, 65, 62, // 68 - 'D'
|
||||
5, 127, 73, 73, 73, 73, // 69 - 'E'
|
||||
5, 127, 9, 9, 9, 9, // 70 - 'F'
|
||||
0, // 71 - 'G'
|
||||
0, // 72 - 'H'
|
||||
0, // 73 - 'I'
|
||||
0, // 74 - 'J'
|
||||
0, // 75 - 'K'
|
||||
0, // 76 - 'L'
|
||||
0, // 77 - 'M'
|
||||
0, // 78 - 'N'
|
||||
0, // 79 - 'O'
|
||||
0, // 80 - 'P'
|
||||
0, // 81 - 'Q'
|
||||
0, // 82 - 'R'
|
||||
0, // 83 - 'S'
|
||||
0, // 84 - 'T'
|
||||
0, // 85 - 'U'
|
||||
0, // 86 - 'V'
|
||||
0, // 87 - 'W'
|
||||
0, // 88 - 'X'
|
||||
0, // 89 - 'Y'
|
||||
0, // 90 - 'Z'
|
||||
0, // 91 - '['
|
||||
0, // 92 - '\'
|
||||
0, // 93 - ']'
|
||||
0, // 94 - '^'
|
||||
0, // 95 - '_'
|
||||
0, // 96 - '`'
|
||||
5, 127, 9, 9, 9, 127, // 97 - 'a'
|
||||
5, 127, 73, 73, 73, 54, // 98 - 'b'
|
||||
5, 127, 65, 65, 65, 65, // 99 - 'c'
|
||||
5, 127, 65, 65, 65, 62, // 100 - 'd'
|
||||
5, 127, 73, 73, 73, 73, // 101 - 'e'
|
||||
5, 127, 9, 9, 9, 9, // 102 - 'f'
|
||||
0, // 103 - 'g'
|
||||
0, // 104 - 'h'
|
||||
0, // 105 - 'i'
|
||||
0, // 106 - 'j'
|
||||
0, // 107 - 'k'
|
||||
0, // 108 - 'l'
|
||||
0, // 109 - 'm'
|
||||
0, // 110 - 'n'
|
||||
0, // 111 - 'o'
|
||||
0, // 112 - 'p'
|
||||
0, // 113 - 'q'
|
||||
0, // 114 - 'r'
|
||||
0, // 115 - 's'
|
||||
0, // 116 - 't'
|
||||
0, // 117 - 'u'
|
||||
0, // 118 - 'v'
|
||||
0, // 119 - 'w'
|
||||
0, // 120 - 'x'
|
||||
0, // 121 - 'y'
|
||||
0, // 122 - 'z'
|
||||
0, // 123 - '{'
|
||||
1, 127, // 124 - '|'
|
||||
0, // 125
|
||||
0, // 126
|
||||
0, // 127
|
||||
0, // 128
|
||||
0, // 129
|
||||
0, // 130
|
||||
0, // 131
|
||||
0, // 132
|
||||
0, // 133
|
||||
0, // 134
|
||||
0, // 135
|
||||
0, // 136
|
||||
0, // 137
|
||||
0, // 138
|
||||
0, // 139
|
||||
0, // 140
|
||||
0, // 141
|
||||
0, // 142
|
||||
0, // 143
|
||||
0, // 144
|
||||
0, // 145
|
||||
0, // 146
|
||||
0, // 147
|
||||
0, // 148
|
||||
0, // 149
|
||||
0, // 150
|
||||
0, // 151
|
||||
0, // 152
|
||||
0, // 153
|
||||
0, // 154
|
||||
0, // 155
|
||||
0, // 156
|
||||
0, // 157
|
||||
0, // 158
|
||||
0, // 159
|
||||
0, // 160
|
||||
0, // 161
|
||||
0, // 162
|
||||
0, // 163
|
||||
0, // 164
|
||||
0, // 165
|
||||
0, // 166
|
||||
0, // 167
|
||||
0, // 168
|
||||
0, // 169
|
||||
0, // 170
|
||||
0, // 171
|
||||
0, // 172
|
||||
0, // 173
|
||||
0, // 174
|
||||
0, // 175
|
||||
0, // 176
|
||||
0, // 177
|
||||
0, // 178
|
||||
0, // 179
|
||||
0, // 180
|
||||
0, // 181
|
||||
0, // 182
|
||||
0, // 183
|
||||
0, // 184
|
||||
0, // 185
|
||||
0, // 186
|
||||
0, // 187
|
||||
0, // 188
|
||||
0, // 189
|
||||
0, // 190
|
||||
0, // 191
|
||||
0, // 192
|
||||
0, // 193
|
||||
0, // 194
|
||||
0, // 195
|
||||
0, // 196
|
||||
0, // 197
|
||||
0, // 198
|
||||
0, // 199
|
||||
0, // 200
|
||||
0, // 201
|
||||
0, // 202
|
||||
0, // 203
|
||||
0, // 204
|
||||
0, // 205
|
||||
0, // 206
|
||||
0, // 207
|
||||
0, // 208
|
||||
0, // 209
|
||||
0, // 210
|
||||
0, // 211
|
||||
0, // 212
|
||||
0, // 213
|
||||
0, // 214
|
||||
0, // 215
|
||||
0, // 216
|
||||
0, // 217
|
||||
0, // 218
|
||||
0, // 219
|
||||
0, // 220
|
||||
0, // 221
|
||||
0, // 222
|
||||
0, // 223
|
||||
0, // 224
|
||||
0, // 225
|
||||
0, // 226
|
||||
0, // 227
|
||||
0, // 228
|
||||
0, // 229
|
||||
0, // 230
|
||||
0, // 231
|
||||
0, // 232
|
||||
0, // 233
|
||||
0, // 234
|
||||
0, // 235
|
||||
0, // 236
|
||||
0, // 237
|
||||
0, // 238
|
||||
0, // 239
|
||||
0, // 240
|
||||
0, // 241
|
||||
0, // 242
|
||||
0, // 243
|
||||
0, // 244
|
||||
0, // 245
|
||||
0, // 246
|
||||
0, // 247
|
||||
0, // 248
|
||||
0, // 249
|
||||
0, // 250
|
||||
0, // 251
|
||||
0, // 252
|
||||
0, // 253
|
||||
0, // 254
|
||||
0, // 255
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,224 @@
|
||||
// Use the MD_MAX72XX library to create an mechanical pushwheel type display
|
||||
// When numbers change they are scrolled up or down as if on a cylinder
|
||||
//
|
||||
// 'Speed' displayed is read from pot on SPEED_IN analog in.
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
#include "Font_Data.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); }
|
||||
#define PRINTS(s) Serial.print(F(s));
|
||||
#else
|
||||
#define PRINT(s, v)
|
||||
#define PRINTS(s)
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 4
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Analog input pin for the input value
|
||||
#define SPEED_IN A5
|
||||
|
||||
// Display and animation parameters
|
||||
#define CHAR_SPACING 1 // pixels between characters
|
||||
#define CHAR_COLS 5 // should match the fixed width character columns
|
||||
#define ANIMATION_FRAME_DELAY 30 // in milliseconds
|
||||
|
||||
// Structure to hold the data for each character to be displayed and animated
|
||||
// this could be expanded to include other charactyer specific data (eg, column
|
||||
// where it starts if display is spaced irregularly).
|
||||
struct digitData
|
||||
{
|
||||
uint8_t oldValue, newValue; // ascii value for the character
|
||||
uint8_t index; // animation progession index
|
||||
uint32_t timeLastFrame; // time the last frame started animating
|
||||
uint8_t charCols; // number of valid in the charMap
|
||||
uint8_t charMap[CHAR_COLS]; // character font bitmap
|
||||
};
|
||||
|
||||
void updateDisplay(uint16_t numDigits, struct digitData *d)
|
||||
// do the necessary to display current bitmap buffer to the LED display
|
||||
{
|
||||
uint8_t curCol = 0;
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
mx.clear();
|
||||
|
||||
for (int8_t i = numDigits - 1; i >= 0; i--)
|
||||
{
|
||||
for (int8_t j = d[i].charCols - 1; j >= 0; j--)
|
||||
{
|
||||
mx.setColumn(curCol++, d[i].charMap[j]);
|
||||
}
|
||||
curCol += CHAR_SPACING;
|
||||
}
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
boolean displayValue(uint16_t value)
|
||||
// Display the required value on the LED matrix and return true if an animation is current
|
||||
// Finite state machine will ignore new values while animations are underway.
|
||||
// Needs to be called repeatedly to ensure animations are completed smoothly.
|
||||
{
|
||||
const uint8_t DIGITS_SIZE = 3;
|
||||
static struct digitData digit[DIGITS_SIZE];
|
||||
|
||||
const uint8_t ST_INIT = 0, ST_WAIT = 1, ST_ANIM = 2;
|
||||
static uint8_t state = ST_INIT;
|
||||
|
||||
// finite state machine to control what we do
|
||||
switch(state)
|
||||
{
|
||||
case ST_INIT: // Initialise the display - done once only on first call
|
||||
PRINTS("\nST_INIT");
|
||||
for (int8_t i = DIGITS_SIZE - 1; i >= 0; i--)
|
||||
{
|
||||
// separate digits
|
||||
digit[i].oldValue = '0' + value % 10;
|
||||
value = value / 10;
|
||||
}
|
||||
|
||||
// Display the starting number
|
||||
for (int8_t i = DIGITS_SIZE - 1; i >= 0; i--)
|
||||
{
|
||||
digit[i].charCols = mx.getChar(digit[i].oldValue, CHAR_COLS, digit[i].charMap);
|
||||
}
|
||||
updateDisplay(DIGITS_SIZE, digit);
|
||||
|
||||
// Now we wait for a change
|
||||
state = ST_WAIT;
|
||||
break;
|
||||
|
||||
case ST_WAIT: // not animating - save new vaue digits and check if we need to animate
|
||||
PRINTS("\nST_WAIT");
|
||||
for (int8_t i = DIGITS_SIZE - 1; i >= 0; i--)
|
||||
{
|
||||
// separate digits
|
||||
digit[i].newValue = '0' + value % 10;
|
||||
value = value / 10;
|
||||
|
||||
if (digit[i].newValue != digit[i].oldValue)
|
||||
{
|
||||
// a change has been found - we will be animating something
|
||||
state = ST_ANIM;
|
||||
// initialise animation parameters for this digit
|
||||
digit[i].index = 0;
|
||||
digit[i].timeLastFrame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == ST_WAIT) // no changes - keep waiting
|
||||
break;
|
||||
// else fall through as we ned to animate from now
|
||||
|
||||
case ST_ANIM: // currently animating a change
|
||||
// work out the new intermediate bitmap for each character
|
||||
// 1. Get the 'new' character bitmap into temp buffer
|
||||
// 2. Shift this buffer down or up by current index amount
|
||||
// 3. Shift the current character by one pixel up or down
|
||||
// 4. Combine the new partial character and the existing character to produce an frame
|
||||
for (int8_t i = DIGITS_SIZE - 1; i >= 0; i--)
|
||||
{
|
||||
if ((digit[i].newValue != digit[i].oldValue) && // values are different
|
||||
(millis() - digit[i].timeLastFrame >= ANIMATION_FRAME_DELAY)) // timer has expired
|
||||
{
|
||||
uint8_t newChar[CHAR_COLS] = { 0 };
|
||||
|
||||
PRINT("\nST_ANIM Digit ", i);
|
||||
PRINT(" from '", (char)digit[i].oldValue);
|
||||
PRINT("' to '", (char)digit[i].newValue);
|
||||
PRINT("' index ", digit[i].index);
|
||||
|
||||
mx.getChar(digit[i].newValue, CHAR_COLS, newChar);
|
||||
if (((digit[i].newValue > digit[i].oldValue) || // incrementing
|
||||
(digit[i].oldValue == '9' && digit[i].newValue == '0')) && // wrapping around on increase
|
||||
!(digit[i].oldValue == '0' && digit[i].newValue == '9')) // not wrapping around on decrease
|
||||
{
|
||||
// scroll down
|
||||
for (uint8_t j = 0; j < digit[i].charCols; j++)
|
||||
{
|
||||
newChar[j] = newChar[j] >> (COL_SIZE - 1 - digit[i].index);
|
||||
digit[i].charMap[j] = digit[i].charMap[j] << 1;
|
||||
digit[i].charMap[j] |= newChar[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// scroll up
|
||||
for (uint8_t j = 0; j < digit[i].charCols; j++)
|
||||
{
|
||||
newChar[j] = newChar[j] << (COL_SIZE - 1 - digit[i].index);
|
||||
digit[i].charMap[j] = digit[i].charMap[j] >> 1;
|
||||
digit[i].charMap[j] |= newChar[j];
|
||||
}
|
||||
}
|
||||
|
||||
// set new parameters for next animation and check if we are done
|
||||
digit[i].index++;
|
||||
digit[i].timeLastFrame = millis();
|
||||
if (digit[i].index >= COL_SIZE )
|
||||
digit[i].oldValue = digit[i].newValue; // done animating
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay(DIGITS_SIZE, digit); // show new display
|
||||
|
||||
// are we done animating?
|
||||
{
|
||||
boolean allDone = true;
|
||||
|
||||
for (uint8_t i = 0; allDone && (i < DIGITS_SIZE); i++)
|
||||
{
|
||||
allDone = allDone && (digit[i].oldValue == digit[i].newValue);
|
||||
}
|
||||
|
||||
if (allDone) state = ST_WAIT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
state = 0;
|
||||
}
|
||||
|
||||
return(state == ST_WAIT); // animation has ended
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if DEBUG
|
||||
Serial.begin(57600);
|
||||
#endif // DEBUG
|
||||
PRINTS("\n[MD_MAX72xx PushWheel]")
|
||||
|
||||
mx.begin();
|
||||
mx.setFont(numeric7Seg);
|
||||
|
||||
pinMode(SPEED_IN, INPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int16_t value = analogRead(SPEED_IN)/10; // remove jitters
|
||||
|
||||
displayValue(value);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Uses a sequence of bitmaps defined as a font to display animations of eyes to convey emotion.
|
||||
// Eyes are coordinated to work together.
|
||||
//
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
#include "MD_RobotEyes.h"
|
||||
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 2
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX M = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX M = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
MD_RobotEyes E;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[7];
|
||||
MD_RobotEyes::emotion_t e;
|
||||
uint16_t timePause; // in milliseconds
|
||||
} sampleItem_t;
|
||||
|
||||
const sampleItem_t eSeq[] =
|
||||
{
|
||||
{ "Nutral", MD_RobotEyes::E_NEUTRAL, 20000 },
|
||||
{ "Blink" , MD_RobotEyes::E_BLINK, 1000 },
|
||||
{ "Wink" , MD_RobotEyes::E_WINK, 1000 },
|
||||
{ "Left" , MD_RobotEyes::E_LOOK_L, 1000 },
|
||||
{ "Right" , MD_RobotEyes::E_LOOK_R, 1000 },
|
||||
{ "Up" , MD_RobotEyes::E_LOOK_U, 1000 },
|
||||
{ "Down" , MD_RobotEyes::E_LOOK_D, 1000 },
|
||||
{ "Angry" , MD_RobotEyes::E_ANGRY, 1000 },
|
||||
{ "Sad" , MD_RobotEyes::E_SAD, 1000 },
|
||||
{ "Evil" , MD_RobotEyes::E_EVIL, 1000 },
|
||||
{ "Evil2" , MD_RobotEyes::E_EVIL2, 1000 },
|
||||
{ "Squint", MD_RobotEyes::E_SQUINT, 1000 },
|
||||
{ "Dead" , MD_RobotEyes::E_DEAD, 1000 },
|
||||
{ "ScanV" , MD_RobotEyes::E_SCAN_UD, 1000 },
|
||||
{ "ScanH" , MD_RobotEyes::E_SCAN_LR, 1000 },
|
||||
};
|
||||
|
||||
void setup()
|
||||
{
|
||||
M.begin();
|
||||
E.begin(&M);
|
||||
E.setText("RobotEyes");
|
||||
do { } while (!E.runAnimation()); // wait for the text to finish
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t timeStartDelay;
|
||||
static uint8_t index = ARRAY_SIZE(eSeq);
|
||||
static enum { S_IDLE, S_TEXT, S_ANIM, S_PAUSE } state = S_IDLE;
|
||||
|
||||
bool b = E.runAnimation(); // always run the animation
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case S_IDLE:
|
||||
index++;
|
||||
if (index >= ARRAY_SIZE(eSeq))
|
||||
index = 0;
|
||||
E.setText(eSeq[index].name);
|
||||
state = S_TEXT;
|
||||
break;
|
||||
|
||||
case S_TEXT: // wait for the text to finish
|
||||
if (b) // text animation is finished
|
||||
{
|
||||
E.setAnimation(eSeq[index].e, true);
|
||||
state = S_ANIM;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ANIM: // checking animation is completed
|
||||
if (b) // animation is finished
|
||||
{
|
||||
timeStartDelay = millis();
|
||||
state = S_PAUSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_PAUSE: // non blocking waiting for a period between animations
|
||||
if (millis() - timeStartDelay >= eSeq[index].timePause)
|
||||
state = S_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = S_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
#include "MD_RobotEyes.h"
|
||||
#include "MD_RobotEyes_Data.h"
|
||||
|
||||
// Debugging macros
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define PRINTS(s) { Serial.print(F(s)); }
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(F("0x")); Serial.print(v, HEX); }
|
||||
#else
|
||||
#define PRINTS(s)
|
||||
#define PRINT(s, v)
|
||||
#define PRINTX(s, v)
|
||||
#endif
|
||||
|
||||
MD_RobotEyes::MD_RobotEyes(void) :
|
||||
_nextEmotion(E_NEUTRAL), _animState(S_IDLE),
|
||||
_autoBlink(true), _timeBlinkMinimum(5000)
|
||||
{
|
||||
};
|
||||
|
||||
void MD_RobotEyes::loadEye(uint8_t module, uint8_t ch)
|
||||
{
|
||||
uint8_t buf[EYE_COL_SIZE];
|
||||
uint8_t size;
|
||||
|
||||
size = _M->getChar(ch, EYE_COL_SIZE, buf);
|
||||
|
||||
for (uint8_t i = 0; i < EYE_COL_SIZE; i++)
|
||||
{
|
||||
_M->setColumn(module, i, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void MD_RobotEyes::drawEyes(uint8_t L, uint8_t R)
|
||||
// Draw the left and right eyes
|
||||
{
|
||||
MD_MAX72XX::fontType_t *savedFont = _M->getFont();
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
_M->setFont(_RobotEyes_Font);
|
||||
|
||||
_M->clear(_sd, _sd+1); // clear out display modules
|
||||
|
||||
// Load the data and show it
|
||||
loadEye(_sd+LEFT_MODULE_OFFSET, L);
|
||||
loadEye(_sd+RIGHT_MODULE_OFFSET, R);
|
||||
|
||||
_M->setFont(savedFont);
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void MD_RobotEyes::dumpSequence(const animFrame_t* pBuf, uint8_t numElements)
|
||||
// Debugging routine to display an animation table in PROGMEM
|
||||
{
|
||||
for (uint8_t i = 0; i < numElements; i++)
|
||||
{
|
||||
animFrame_t f;
|
||||
|
||||
memcpy_P(&f, &pBuf[i], sizeof(animFrame_t));
|
||||
PRINT("\n[", i);
|
||||
PRINT("]: L:", f.eyeData[LEFT_EYE_INDEX]);
|
||||
PRINT(" R:", f.eyeData[RIGHT_EYE_INDEX]);
|
||||
PRINT(" T:", f.timeFrame);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t MD_RobotEyes::loadSequence(emotion_t e)
|
||||
// Load the next emotion from the static data.
|
||||
// Set global variables to the required values
|
||||
{
|
||||
// run through the lookuptable to find the sequence data
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(lookupTable); i++)
|
||||
{
|
||||
memcpy_P(&_animEntry, &lookupTable[i], sizeof(animTable_t));
|
||||
if (_animEntry.e == e)
|
||||
{
|
||||
#if DEBUG
|
||||
dumpSequence(_animEntry.seq, _animEntry.size);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set up the current index depending on direction of animation
|
||||
if (_animReverse) _animIndex = _animEntry.size - 1; else _animIndex = 0;
|
||||
|
||||
return(_animEntry.size);
|
||||
}
|
||||
|
||||
void MD_RobotEyes::loadFrame(animFrame_t* pBuf)
|
||||
// Load the idx'th frame from the frame sequence PROGMEM to normal memory pBuf
|
||||
{
|
||||
memcpy_P(pBuf, &_animEntry.seq[_animIndex], sizeof(animFrame_t));
|
||||
}
|
||||
|
||||
void MD_RobotEyes::showText(bool bInit)
|
||||
// Print the text string to the LED matrix modules specified.
|
||||
// Message area is padded with blank columns after printing.
|
||||
{
|
||||
static enum { S_LOAD, S_SHOW, S_SPACE } state;
|
||||
static uint8_t curLen, showLen;
|
||||
static uint8_t cBuf[EYE_COL_SIZE];
|
||||
|
||||
if (bInit)
|
||||
{
|
||||
PRINT("\nText: ", _pText);
|
||||
_timeLastAnimation = millis();
|
||||
_M->clear(_sd, _sd + 1);
|
||||
state = S_LOAD;
|
||||
}
|
||||
|
||||
// Is it time to scroll the text?
|
||||
if (millis() - _timeLastAnimation < FRAME_TIME/2)
|
||||
return;
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
// Now scroll the text
|
||||
_M->transform(_sd, _sd+1, MD_MAX72XX::TSL); // scroll along by one place
|
||||
_timeLastAnimation = millis(); // starting time for next scroll
|
||||
|
||||
// Now work out what's next using finite state machine to control what we do
|
||||
switch (state)
|
||||
{
|
||||
case S_LOAD: // Load the next character from the font table
|
||||
// if we reached end of message or empty string, reset the message pointer
|
||||
if (*_pText == '\0')
|
||||
{
|
||||
_pText = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise load the character
|
||||
showLen = _M->getChar(*_pText++, ARRAY_SIZE(cBuf), cBuf);
|
||||
curLen = 0;
|
||||
state = S_SHOW;
|
||||
// fall through to the next state
|
||||
|
||||
case S_SHOW: // display the next part of the character
|
||||
_M->setColumn(_sd, 0, cBuf[curLen++]);
|
||||
if (curLen == showLen)
|
||||
{
|
||||
showLen = (*_pText == '\0' ? 2*EYE_COL_SIZE : 1); // either 1 space or pad to the end of the display if finished
|
||||
curLen = 0;
|
||||
state = S_SPACE;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_SPACE: // display inter-character spacing (blank columns)
|
||||
_M->setColumn(_sd, 0, 0);
|
||||
curLen++;
|
||||
if (curLen >= showLen)
|
||||
state = S_LOAD;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = S_LOAD;
|
||||
}
|
||||
|
||||
_M->control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void MD_RobotEyes::begin(MD_MAX72XX *M, uint8_t moduleStart)
|
||||
// initialise other stuff after libraries have started
|
||||
{
|
||||
#if DEBUG
|
||||
Serial.begin(57600);
|
||||
#endif
|
||||
PRINTS("\n[MD_RobotEyes Debug]");
|
||||
|
||||
_M = M;
|
||||
_sd = moduleStart;
|
||||
|
||||
setAnimation(E_NEUTRAL, false);
|
||||
};
|
||||
|
||||
bool MD_RobotEyes::runAnimation(void)
|
||||
// Animate the eyes
|
||||
// Return true if there is no animation happening
|
||||
{
|
||||
static animFrame_t thisFrame;
|
||||
|
||||
switch (_animState)
|
||||
{
|
||||
case S_IDLE: // no animation running - wait for a new one or blink if time to do so
|
||||
if (_pText != nullptr) // there is some text to show
|
||||
{
|
||||
PRINTS("\nIDLE: showing text");
|
||||
showText(true);
|
||||
_animState = S_TEXT;
|
||||
break;
|
||||
}
|
||||
// otherwise fall through and try for an animation
|
||||
|
||||
case S_RESTART: // back to start of current animation
|
||||
if (_nextEmotion != E_NONE) // check if we have an animation in the queue
|
||||
{
|
||||
PRINTS("\nRESRT: showing animation");
|
||||
_timeLastAnimation = millis();
|
||||
|
||||
// set up the next animation
|
||||
loadSequence(_nextEmotion);
|
||||
_nextEmotion = E_NONE;
|
||||
_animState = S_ANIMATE;
|
||||
}
|
||||
else if (_autoBlink) // check if we should be blinking
|
||||
{
|
||||
if (((millis() - _timeLastAnimation) >= _timeBlinkMinimum) && (random(1000) > 700))
|
||||
{
|
||||
PRINTS("\nRESRT: forcing blink");
|
||||
setAnimation(E_BLINK, true);
|
||||
_animState = S_RESTART;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ANIMATE: // process the next frame for this sequence
|
||||
PRINT("\nPROCESS: Frame:", _animIndex);
|
||||
loadFrame(&thisFrame);
|
||||
drawEyes(thisFrame.eyeData[LEFT_EYE_INDEX], thisFrame.eyeData[RIGHT_EYE_INDEX]);
|
||||
if (_animReverse) _animIndex--; else _animIndex++;
|
||||
|
||||
_timeStartPause = millis();
|
||||
_animState = S_PAUSE;
|
||||
break;
|
||||
|
||||
case S_PAUSE: // pause this frame for the required time
|
||||
{
|
||||
if ((millis() - _timeStartPause) < thisFrame.timeFrame)
|
||||
break;
|
||||
|
||||
// check if this is the end of animation
|
||||
if ((!_animReverse && _animIndex >= _animEntry.size) ||
|
||||
(_animReverse && _animIndex < 0))
|
||||
{
|
||||
PRINTS("\nPAUSE: Animation end")
|
||||
if (_autoReverse) // set up the same emotion but in reverse
|
||||
{
|
||||
PRINTS(" & auto reverse");
|
||||
_nextEmotion = _animEntry.e;
|
||||
_animReverse = true; // set this flag for the restart state
|
||||
_autoReverse = false; // clear the flag for this animation sequence
|
||||
_animState = S_RESTART;
|
||||
}
|
||||
else
|
||||
_animState = S_IDLE;
|
||||
}
|
||||
else
|
||||
_animState = S_ANIMATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_TEXT: // currently displaying text
|
||||
{
|
||||
showText();
|
||||
if (_pText == nullptr)
|
||||
_animState = S_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // something is wrong - reset the FSM
|
||||
_animState = S_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return(_animState == S_IDLE);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
// Implements a class to draw and animate a pair of 'emotive' eyes for a robot
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
|
||||
// Misc defines
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) ///< number of elements in an array
|
||||
#define EYE_COL_SIZE 8 ///< number of columns in one eye
|
||||
|
||||
// Module offsets from first module specified
|
||||
#define LEFT_MODULE_OFFSET 1 ///< offset from the base LED module for the left eye
|
||||
#define RIGHT_MODULE_OFFSET 0 ///< offset from the base LED module for the right eye
|
||||
|
||||
// Array references for eyeData array below
|
||||
#define LEFT_EYE_INDEX 1 ///< array reference in the eye data for the left eye
|
||||
#define RIGHT_EYE_INDEX 0 ///< array reference in the eye data for the right eye
|
||||
|
||||
// Basic unit of time a frame is displayed
|
||||
#define FRAME_TIME 100 ///< minimum animation time
|
||||
|
||||
/**
|
||||
* Robot Eyes Class.
|
||||
* This class manages the displayed of animated eyes using LED matrices using the functions
|
||||
* provided by the MD_MAX72xx library.
|
||||
*/
|
||||
class MD_RobotEyes
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Emotions enumerated type.
|
||||
*
|
||||
* This enumerated type defines the emotion animations
|
||||
* availabel in the class for the eyes display
|
||||
*/
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
E_NONE, ///< placeholder for no emotions, not user selectable
|
||||
E_NEUTRAL, ///< eyes in neutral position (no animation)
|
||||
E_BLINK, ///< both eyes blink
|
||||
E_WINK, ///< one eye blink
|
||||
E_LOOK_L, ///< both eyes look left
|
||||
E_LOOK_R, ///< both eyes look right
|
||||
E_LOOK_U, ///< both eyes look up
|
||||
E_LOOK_D, ///< both eyes look down
|
||||
E_ANGRY, ///< eyes look angry (symmetrical)
|
||||
E_SAD, ///< eyes look sad (symmetrical)
|
||||
E_EVIL, ///< eyes look evil (symmetrical)
|
||||
E_EVIL2, ///< eyes look evil (asymmetrical)
|
||||
E_SQUINT, ///< both eye squint
|
||||
E_DEAD, ///< eyes indicate dead (different)
|
||||
E_SCAN_UD, ///< both eyes scanning Up/Down
|
||||
E_SCAN_LR, ///< both eyes scanning Left/Right
|
||||
} emotion_t;
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* Instantiate a new instance of the class.
|
||||
*/
|
||||
MD_RobotEyes(void);
|
||||
|
||||
/**
|
||||
* Class Destructor.
|
||||
*
|
||||
* Released any allocated memory and does the necessary to clean
|
||||
* up once the object is no longer required.
|
||||
*/
|
||||
~MD_RobotEyes(void) { };
|
||||
|
||||
/**
|
||||
* Initialize the object.
|
||||
*
|
||||
* Initialise the object data. This needs to be called during setup() to initialise new
|
||||
* data for the class that cannot be done during the object creation.
|
||||
*
|
||||
* Outside of the class, the MD_MAX72xx library should be initialised and the pointer
|
||||
* to the MD_MAX72xx object passed to the parameter. Also, as the eyes could be in the
|
||||
* middle of a string of LED modules, the first 'eye' module can be specified.
|
||||
*
|
||||
* /param M pointer to the MD_MAX72xx library object.
|
||||
* /param moduleStart the first 'eye' LED module. Defaults to 0 if not specified.
|
||||
*/
|
||||
void begin(MD_MAX72XX *M, uint8_t moduleStart = 0);
|
||||
|
||||
/**
|
||||
* Set the animation type and parameters.
|
||||
*
|
||||
* Set the next animations to the specified. Additionally, set whether the animation should
|
||||
* auto reverse the action (eg, blink down then back up again) and whether the animation
|
||||
* should be run in reverse.
|
||||
*
|
||||
* Animations are generally symmetric, so only half the anmation needs to be specified.
|
||||
* If an animated expression needs to be held, the animation should be run without auto
|
||||
* reverse, which holds the animation at the end point, and then later run the animation
|
||||
* in reverse from the last position to return to the idle state.
|
||||
*
|
||||
* \param e the type of emotion to be displayed, one of the emotion_T enumerated values.
|
||||
* \param r if true, run auto reverse.
|
||||
* \param b if true, start the animation from the end of the sequence.
|
||||
*/
|
||||
inline void setAnimation(emotion_t e, bool r, bool b = false) { _nextEmotion = e; _autoReverse = r; _animReverse = b; };
|
||||
|
||||
/**
|
||||
* Set the blink time.
|
||||
*
|
||||
* When no animation is running and AutoBlink is set, the eyes will occasionally blink.
|
||||
* Set the minimum time period between blinks. A blink will occur a random time after this.
|
||||
*
|
||||
* \param t the minimum time between blinkins actions in milliseconds.
|
||||
*/
|
||||
inline void setBlinkTime(uint16_t t) { _timeBlinkMinimum = t; };
|
||||
|
||||
/**
|
||||
* Set or reset auto blink mode.
|
||||
*
|
||||
* When no animation is running and AutoBlink is set, the eyes will loccasionally blink.
|
||||
*
|
||||
* \param b set auto blink if true, reset auto blink if false.
|
||||
*/
|
||||
inline void setAutoBlink(bool b) { _autoBlink = b; };
|
||||
|
||||
/**
|
||||
* Display a text message.
|
||||
*
|
||||
* At the end of the cuurent animation, the text will be scrolled across the 'eyes'
|
||||
* and then the eyes are returned to the neutral expression
|
||||
*
|
||||
* \param p a pointer to a char aarray containing a nul terminated string.
|
||||
The string must remain in scope while the message is being dispayed.
|
||||
*/
|
||||
inline bool setText(char *pText) { if (_pText != nullptr) return(false); else _pText = pText; return(true); };
|
||||
|
||||
/**
|
||||
* Animate the display.
|
||||
*
|
||||
* This method needs to be invoked as often as possible to ensure smooth animation.
|
||||
*
|
||||
* The calling program should monitor the return value for 'true' in order to know when
|
||||
* the animation has concluded. A 'true' return value means that the animation is complete.
|
||||
*
|
||||
* \return bool true if the animation has completed, false otherwise.
|
||||
*/
|
||||
bool runAnimation(void);
|
||||
|
||||
protected:
|
||||
// Animations FSM state
|
||||
typedef enum
|
||||
{
|
||||
S_IDLE,
|
||||
S_RESTART,
|
||||
S_ANIMATE,
|
||||
S_PAUSE,
|
||||
S_TEXT,
|
||||
} animState_t;
|
||||
|
||||
// Define an animation frame
|
||||
typedef struct animFrame_t
|
||||
{
|
||||
uint8_t eyeData[2]; // [LEFT_MODULE_OFFSET] and [RIGHT_MODULE_OFFSET] eye character from font data
|
||||
uint16_t timeFrame; // time for this frame in milliseconds
|
||||
};
|
||||
|
||||
// Define an entry in the animation sequence lookup table
|
||||
typedef struct
|
||||
{
|
||||
emotion_t e;
|
||||
animFrame_t *seq;
|
||||
uint8_t size;
|
||||
} animTable_t;
|
||||
|
||||
// Display parameters
|
||||
MD_MAX72XX *_M;
|
||||
uint16_t _sd; // start module for the display
|
||||
|
||||
// Animation parameters
|
||||
uint32_t _timeStartPause;
|
||||
uint32_t _timeLastAnimation;
|
||||
uint16_t _timeBlinkMinimum;
|
||||
animState_t _animState;
|
||||
bool _autoBlink;
|
||||
uint16_t _scrollDelay;
|
||||
|
||||
// Animation control data
|
||||
animTable_t _animEntry; // record with animation sequence parameters
|
||||
int8_t _animIndex; // current index in the animation sequence
|
||||
bool _animReverse; // true = reverse sequence, false = normal sequence
|
||||
bool _autoReverse; // true = always play the reverse, false = slected direction only
|
||||
emotion_t _nextEmotion; // the next emotion to display
|
||||
char * _pText; // pointer to text data in user code. Not null means there is text to print
|
||||
|
||||
// Methods
|
||||
void loadEye(uint8_t module, uint8_t ch);
|
||||
void drawEyes(uint8_t L, uint8_t R);
|
||||
uint8_t loadSequence(emotion_t e); // return the size of the sequence
|
||||
void loadFrame(animFrame_t* pBuf);
|
||||
void showText(bool bInit = false);
|
||||
|
||||
void dumpSequence(const animFrame_t* pBuf, uint8_t numElements); // debugging routine only
|
||||
|
||||
// Static data tables
|
||||
static const animFrame_t seqBlink[], seqWink[];
|
||||
static const animFrame_t seqLeft[], seqRight[], seqUp[], seqDown[];
|
||||
static const animFrame_t seqAngry[], seqSad[], seqEvil[], seqEvil2[];
|
||||
static const animFrame_t seqSquint[], seqDead[];
|
||||
static const animFrame_t seqScanUpDown[], seqScanLeftRight[];
|
||||
|
||||
// Lookup table to find animation
|
||||
static const animTable_t lookupTable[];
|
||||
};
|
||||
@@ -0,0 +1,406 @@
|
||||
// EmotiveEye class static variables
|
||||
#pragma once
|
||||
|
||||
#include "MD_RobotEyes.h"
|
||||
|
||||
// Sequences for animations
|
||||
// Note: must add this to the lookupTable below as well so that the animation
|
||||
// can be found by the animation engine.
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqBlink[] PROGMEM =
|
||||
{
|
||||
{ { 0, 0 }, FRAME_TIME/2 },
|
||||
{ { 1, 1 }, FRAME_TIME/2 },
|
||||
{ { 2, 2 }, FRAME_TIME/2 },
|
||||
{ { 3, 3 }, FRAME_TIME/2 },
|
||||
{ { 4, 4 }, FRAME_TIME/2 },
|
||||
{ { 5, 5 }, FRAME_TIME },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqWink[] PROGMEM =
|
||||
{
|
||||
{ { 0, 0 }, FRAME_TIME/2 },
|
||||
{ { 1, 0 }, FRAME_TIME/2 },
|
||||
{ { 2, 0 }, FRAME_TIME/2 },
|
||||
{ { 3, 0 }, FRAME_TIME/2 },
|
||||
{ { 4, 0 }, FRAME_TIME/2 },
|
||||
{ { 5, 0 }, FRAME_TIME * 2 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqRight[] PROGMEM =
|
||||
{
|
||||
{ { 0, 0 }, FRAME_TIME },
|
||||
{ { 6, 6 }, FRAME_TIME },
|
||||
{ { 7, 7 }, FRAME_TIME * 5 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqLeft[] PROGMEM =
|
||||
{
|
||||
{ { 0, 0 }, FRAME_TIME },
|
||||
{ { 8, 8 }, FRAME_TIME },
|
||||
{ { 9, 9 }, FRAME_TIME * 5 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqUp[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 11, 11 }, FRAME_TIME },
|
||||
{ { 12, 12 }, FRAME_TIME },
|
||||
{ { 13, 13 }, FRAME_TIME * 5 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqDown[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 14, 14 }, FRAME_TIME },
|
||||
{ { 15, 15 }, FRAME_TIME },
|
||||
{ { 16, 16 }, FRAME_TIME * 5 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqAngry[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 22, 17 }, FRAME_TIME },
|
||||
{ { 23, 18 }, FRAME_TIME },
|
||||
{ { 24, 19 }, FRAME_TIME },
|
||||
{ { 25, 20 }, 2000 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqSad[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 32, 27 }, FRAME_TIME },
|
||||
{ { 33, 28 }, FRAME_TIME },
|
||||
{ { 34, 29 }, 2000 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqEvil[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 39, 37 }, FRAME_TIME },
|
||||
{ { 40, 38 }, 2000 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqEvil2[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 54, 17 }, FRAME_TIME },
|
||||
{ { 55, 18 }, FRAME_TIME },
|
||||
{ { 56, 19 }, FRAME_TIME },
|
||||
{ { 57, 20 }, 2000 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqSquint[] PROGMEM =
|
||||
{
|
||||
{ { 00, 00 }, FRAME_TIME },
|
||||
{ { 54, 54 }, FRAME_TIME },
|
||||
{ { 55, 55 }, FRAME_TIME },
|
||||
{ { 56, 56 }, FRAME_TIME },
|
||||
{ { 57, 57 }, 2000 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqDead[] PROGMEM =
|
||||
{
|
||||
{ { 52, 52 }, FRAME_TIME * 4 },
|
||||
{ { 53, 53 }, FRAME_TIME * 4 },
|
||||
{ { 52, 52 }, FRAME_TIME * 2 },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqScanLeftRight[] PROGMEM =
|
||||
{
|
||||
{ { 41, 41 }, FRAME_TIME * 2 },
|
||||
{ { 42, 42 }, FRAME_TIME },
|
||||
{ { 43, 43 }, FRAME_TIME },
|
||||
{ { 44, 44 }, FRAME_TIME },
|
||||
};
|
||||
|
||||
const MD_RobotEyes::animFrame_t MD_RobotEyes::seqScanUpDown[] PROGMEM =
|
||||
{
|
||||
{ { 46, 46 }, FRAME_TIME * 2 },
|
||||
{ { 47, 47 }, FRAME_TIME },
|
||||
{ { 48, 48 }, FRAME_TIME },
|
||||
{ { 49, 49 }, FRAME_TIME },
|
||||
{ { 50, 50 }, FRAME_TIME },
|
||||
{ { 51, 51 }, FRAME_TIME },
|
||||
};
|
||||
|
||||
// Lookup table to find animation sequences
|
||||
// Table associates the data for an emotion with the sequence table and it's size
|
||||
static const MD_RobotEyes::animTable_t MD_RobotEyes::lookupTable[] PROGMEM =
|
||||
{
|
||||
{ MD_RobotEyes::E_NEUTRAL, MD_RobotEyes::seqBlink, 1 }, // special case, fixed neutral stare
|
||||
{ MD_RobotEyes::E_BLINK, MD_RobotEyes::seqBlink, ARRAY_SIZE(MD_RobotEyes::seqBlink) },
|
||||
{ MD_RobotEyes::E_WINK, MD_RobotEyes::seqWink, ARRAY_SIZE(MD_RobotEyes::seqWink) },
|
||||
{ MD_RobotEyes::E_LOOK_L, MD_RobotEyes::seqLeft, ARRAY_SIZE(MD_RobotEyes::seqLeft) },
|
||||
{ MD_RobotEyes::E_LOOK_R, MD_RobotEyes::seqRight, ARRAY_SIZE(MD_RobotEyes::seqRight) },
|
||||
{ MD_RobotEyes::E_LOOK_U, MD_RobotEyes::seqUp, ARRAY_SIZE(MD_RobotEyes::seqUp) },
|
||||
{ MD_RobotEyes::E_LOOK_D, MD_RobotEyes::seqDown, ARRAY_SIZE(MD_RobotEyes::seqDown) },
|
||||
{ MD_RobotEyes::E_ANGRY, MD_RobotEyes::seqAngry, ARRAY_SIZE(MD_RobotEyes::seqAngry) },
|
||||
{ MD_RobotEyes::E_SAD, MD_RobotEyes::seqSad, ARRAY_SIZE(MD_RobotEyes::seqSad) },
|
||||
{ MD_RobotEyes::E_EVIL, MD_RobotEyes::seqEvil, ARRAY_SIZE(MD_RobotEyes::seqEvil) },
|
||||
{ MD_RobotEyes::E_EVIL2, MD_RobotEyes::seqEvil2, ARRAY_SIZE(MD_RobotEyes::seqEvil2) },
|
||||
{ MD_RobotEyes::E_SQUINT, MD_RobotEyes::seqSquint, ARRAY_SIZE(MD_RobotEyes::seqSquint) },
|
||||
{ MD_RobotEyes::E_DEAD, MD_RobotEyes::seqDead, ARRAY_SIZE(MD_RobotEyes::seqDead) },
|
||||
{ MD_RobotEyes::E_SCAN_LR, MD_RobotEyes::seqScanLeftRight, ARRAY_SIZE(MD_RobotEyes::seqScanLeftRight) },
|
||||
{ MD_RobotEyes::E_SCAN_UD, MD_RobotEyes::seqScanUpDown, ARRAY_SIZE(MD_RobotEyes::seqScanUpDown) },
|
||||
};
|
||||
|
||||
// Font file (bitmaps for emotion animation frames)
|
||||
MD_MAX72XX::fontType_t _RobotEyes_Font[] PROGMEM =
|
||||
{
|
||||
8, 0, 126, 129, 177, 177, 129, 126, 0, // 0 - 'Rest Position'
|
||||
8, 0, 124, 130, 178, 178, 130, 124, 0, // 1 - 'Blink 1'
|
||||
8, 0, 120, 132, 180, 180, 132, 120, 0, // 2 - 'Blink 2'
|
||||
8, 0, 48, 72, 120, 120, 72, 48, 0, // 3 - 'Blink 3'
|
||||
8, 0, 32, 80, 112, 112, 80, 32, 0, // 4 - 'Blink 4'
|
||||
8, 0, 32, 96, 96, 96, 96, 32, 0, // 5 - 'Blink 5'
|
||||
8, 0, 126, 129, 129, 177, 177, 126, 0, // 6 - 'Right 1'
|
||||
8, 0, 0, 126, 129, 129, 177, 177, 126, // 7 - 'Right 2'
|
||||
8, 0, 126, 177, 177, 129, 129, 126, 0, // 8 - 'Left 1'
|
||||
8, 126, 177, 177, 129, 129, 126, 0, 0, // 9 - 'Left 2'
|
||||
0, // 10
|
||||
8, 0, 126, 129, 153, 153, 129, 126, 0, // 11 - 'Up 1'
|
||||
8, 0, 126, 129, 141, 141, 129, 126, 0, // 12 - 'Up 2'
|
||||
8, 0, 126, 129, 135, 135, 129, 126, 0, // 13 - 'Up 3'
|
||||
8, 0, 126, 129, 225, 225, 129, 126, 0, // 14 - 'Down 1'
|
||||
8, 0, 126, 129, 193, 193, 129, 126, 0, // 15 - 'Down 2'
|
||||
8, 0, 124, 130, 194, 194, 130, 124, 0, // 16 - 'Down 3'
|
||||
8, 0, 124, 130, 177, 177, 129, 126, 0, // 17 - 'Angry L 1'
|
||||
8, 0, 120, 132, 178, 177, 129, 126, 0, // 18 - 'Angry L 2'
|
||||
8, 0, 112, 136, 164, 178, 129, 126, 0, // 19 - 'Angry L 3'
|
||||
8, 0, 96, 144, 168, 180, 130, 127, 0, // 20 - 'Angry L 4'
|
||||
0, // 21
|
||||
8, 0, 126, 129, 177, 177, 130, 124, 0, // 22 - 'Angry R 1'
|
||||
8, 0, 126, 129, 177, 178, 132, 120, 0, // 23 - 'Angry R 2'
|
||||
8, 0, 126, 129, 178, 164, 136, 112, 0, // 24 - 'Angry R 3'
|
||||
8, 0, 127, 130, 180, 168, 144, 96, 0, // 25 - 'Angry R 4'
|
||||
0, // 26
|
||||
8, 0, 62, 65, 153, 153, 130, 124, 0, // 27 - 'Sad L 1'
|
||||
8, 0, 30, 33, 89, 154, 132, 120, 0, // 28 - 'Sad L 2'
|
||||
8, 0, 14, 17, 41, 90, 132, 120, 0, // 29 - 'Sad L 3'
|
||||
0, // 30
|
||||
0, // 31
|
||||
8, 0, 124, 130, 153, 153, 65, 62, 0, // 32 - 'Sad R 1'
|
||||
8, 0, 120, 132, 154, 89, 33, 30, 0, // 33 - 'Sad R 2'
|
||||
8, 0, 120, 132, 90, 41, 17, 14, 0, // 34 - 'Sad R 3'
|
||||
0, // 35
|
||||
0, // 36
|
||||
8, 0, 124, 194, 177, 177, 193, 126, 0, // 37 - 'Evil L 1'
|
||||
8, 0, 56, 68, 178, 177, 66, 60, 0, // 38 - 'Evil L 2'
|
||||
8, 0, 126, 193, 177, 177, 194, 124, 0, // 39 - 'Evil R 1'
|
||||
8, 0, 60, 66, 177, 178, 68, 56, 0, // 40 - 'Evil R 2'
|
||||
8, 0, 126, 129, 129, 129, 189, 126, 0, // 41 - 'Scan H 1'
|
||||
8, 0, 126, 129, 129, 189, 129, 126, 0, // 42 - 'Scan H 2'
|
||||
8, 0, 126, 129, 189, 129, 129, 126, 0, // 43 - 'Scan H 3'
|
||||
8, 0, 126, 189, 129, 129, 129, 126, 0, // 44 - 'Scan H 4'
|
||||
0, // 45
|
||||
8, 0, 126, 129, 131, 131, 129, 126, 0, // 46 - 'Scan V 1'
|
||||
8, 0, 126, 129, 133, 133, 129, 126, 0, // 47 - 'Scan V 2'
|
||||
8, 0, 126, 129, 137, 137, 129, 126, 0, // 48 - 'Scan V 3'
|
||||
8, 0, 126, 129, 145, 145, 129, 126, 0, // 49 - 'Scan V 4'
|
||||
8, 0, 126, 129, 161, 161, 129, 126, 0, // 50 - 'Scan V 5'
|
||||
8, 0, 126, 129, 193, 193, 129, 126, 0, // 51 - 'Scan V 6'
|
||||
8, 0, 126, 137, 157, 137, 129, 126, 0, // 52 - 'RIP 1'
|
||||
8, 0, 126, 129, 145, 185, 145, 126, 0, // 53 - 'RIP 2'
|
||||
8, 0, 60, 66, 114, 114, 66, 60, 0, // 54 - 'Peering 1'
|
||||
8, 0, 56, 68, 116, 116, 68, 56, 0, // 55 - 'Peering 2'
|
||||
8, 0, 48, 72, 120, 120, 72, 48, 0, // 56 - 'Peering 3'
|
||||
8, 0, 32, 80, 112, 112, 80, 32, 0, // 57 - 'Peering 4'
|
||||
0, // 58
|
||||
0, // 59 - 'Unused'
|
||||
0, // 60 - 'Unused'
|
||||
0, // 61 - 'Unused'
|
||||
0, // 62 - 'Unused'
|
||||
0, // 63 - 'Unused'
|
||||
0, // 64 - 'Unused'
|
||||
0, // 65 - 'Unused'
|
||||
0, // 66 - 'Unused'
|
||||
0, // 67 - 'Unused'
|
||||
0, // 68 - 'Unused'
|
||||
0, // 69 - 'Unused'
|
||||
0, // 70 - 'Unused'
|
||||
0, // 71 - 'Unused'
|
||||
0, // 72 - 'Unused'
|
||||
0, // 73 - 'Unused'
|
||||
0, // 74 - 'Unused'
|
||||
0, // 75 - 'Unused'
|
||||
0, // 76 - 'Unused'
|
||||
0, // 77 - 'Unused'
|
||||
0, // 78 - 'Unused'
|
||||
0, // 79 - 'Unused'
|
||||
0, // 80 - 'Unused'
|
||||
0, // 81 - 'Unused'
|
||||
0, // 82 - 'Unused'
|
||||
0, // 83 - 'Unused'
|
||||
0, // 84 - 'Unused'
|
||||
0, // 85 - 'Unused'
|
||||
0, // 86 - 'Unused'
|
||||
0, // 87 - 'Unused'
|
||||
0, // 88 - 'Unused'
|
||||
0, // 89 - 'Unused'
|
||||
0, // 90 - 'Unused'
|
||||
0, // 91 - 'Unused'
|
||||
0, // 92 - 'Unused'
|
||||
0, // 93 - 'Unused'
|
||||
0, // 94 - 'Unused'
|
||||
0, // 95 - 'Unused'
|
||||
0, // 96 - 'Unused'
|
||||
0, // 97 - 'Unused'
|
||||
0, // 98 - 'Unused'
|
||||
0, // 99 - 'Unused'
|
||||
0, // 100 - 'Unused'
|
||||
0, // 101 - 'Unused'
|
||||
0, // 102 - 'Unused'
|
||||
0, // 103 - 'Unused'
|
||||
0, // 104 - 'Unused'
|
||||
0, // 105 - 'Unused'
|
||||
0, // 106 - 'Unused'
|
||||
0, // 107 - 'Unused'
|
||||
0, // 108 - 'Unused'
|
||||
0, // 109 - 'Unused'
|
||||
0, // 110 - 'Unused'
|
||||
0, // 111 - 'Unused'
|
||||
0, // 112 - 'Unused'
|
||||
0, // 113 - 'Unused'
|
||||
0, // 114 - 'Unused'
|
||||
0, // 115 - 'Unused'
|
||||
0, // 116 - 'Unused'
|
||||
0, // 117 - 'Unused'
|
||||
0, // 118 - 'Unused'
|
||||
0, // 119 - 'Unused'
|
||||
0, // 120 - 'Unused'
|
||||
0, // 121 - 'Unused'
|
||||
0, // 122 - 'Unused'
|
||||
0, // 123 - 'Unused'
|
||||
0, // 124 - 'Unused'
|
||||
0, // 125 - 'Unused'
|
||||
0, // 126 - 'Unused'
|
||||
0, // 127 - 'Unused'
|
||||
0, // 128 - 'Unused'
|
||||
0, // 129 - 'Unused'
|
||||
0, // 130 - 'Unused'
|
||||
0, // 131 - 'Unused'
|
||||
0, // 132 - 'Unused'
|
||||
0, // 133 - 'Unused'
|
||||
0, // 134 - 'Unused'
|
||||
0, // 135 - 'Unused'
|
||||
0, // 136 - 'Unused'
|
||||
0, // 137 - 'Unused'
|
||||
0, // 138 - 'Unused'
|
||||
0, // 139 - 'Unused'
|
||||
0, // 140 - 'Unused'
|
||||
0, // 141 - 'Unused'
|
||||
0, // 142 - 'Unused'
|
||||
0, // 143 - 'Unused'
|
||||
0, // 144 - 'Unused'
|
||||
0, // 145 - 'Unused'
|
||||
0, // 146 - 'Unused'
|
||||
0, // 147 - 'Unused'
|
||||
0, // 148 - 'Unused'
|
||||
0, // 149 - 'Unused'
|
||||
0, // 150 - 'Unused'
|
||||
0, // 151 - 'Unused'
|
||||
0, // 152 - 'Unused'
|
||||
0, // 153 - 'Unused'
|
||||
0, // 154 - 'Unused'
|
||||
0, // 155 - 'Unused'
|
||||
0, // 156 - 'Unused'
|
||||
0, // 157 - 'Unused'
|
||||
0, // 158 - 'Unused'
|
||||
0, // 159 - 'Unused'
|
||||
0, // 160 - 'Unused'
|
||||
0, // 161 - 'Unused'
|
||||
0, // 162 - 'Unused'
|
||||
0, // 163 - 'Unused'
|
||||
0, // 164 - 'Unused'
|
||||
0, // 165 - 'Unused'
|
||||
0, // 166 - 'Unused'
|
||||
0, // 167 - 'Unused'
|
||||
0, // 168 - 'Unused'
|
||||
0, // 169 - 'Unused'
|
||||
0, // 170 - 'Unused'
|
||||
0, // 171 - 'Unused'
|
||||
0, // 172 - 'Unused'
|
||||
0, // 173 - 'Unused'
|
||||
0, // 174 - 'Unused'
|
||||
0, // 175 - 'Unused'
|
||||
0, // 176 - 'Unused'
|
||||
0, // 177 - 'Unused'
|
||||
0, // 178 - 'Unused'
|
||||
0, // 179 - 'Unused'
|
||||
0, // 180 - 'Unused'
|
||||
0, // 181 - 'Unused'
|
||||
0, // 182 - 'Unused'
|
||||
0, // 183 - 'Unused'
|
||||
0, // 184 - 'Unused'
|
||||
0, // 185 - 'Unused'
|
||||
0, // 186 - 'Unused'
|
||||
0, // 187 - 'Unused'
|
||||
0, // 188 - 'Unused'
|
||||
0, // 189 - 'Unused'
|
||||
0, // 190 - 'Unused'
|
||||
0, // 191 - 'Unused'
|
||||
0, // 192 - 'Unused'
|
||||
0, // 193 - 'Unused'
|
||||
0, // 194 - 'Unused'
|
||||
0, // 195 - 'Unused'
|
||||
0, // 196 - 'Unused'
|
||||
0, // 197 - 'Unused'
|
||||
0, // 198 - 'Unused'
|
||||
0, // 199 - 'Unused'
|
||||
0, // 200 - 'Unused'
|
||||
0, // 201 - 'Unused'
|
||||
0, // 202 - 'Unused'
|
||||
0, // 203 - 'Unused'
|
||||
0, // 204 - 'Unused'
|
||||
0, // 205 - 'Unused'
|
||||
0, // 206 - 'Unused'
|
||||
0, // 207 - 'Unused'
|
||||
0, // 208 - 'Unused'
|
||||
0, // 209 - 'Unused'
|
||||
0, // 210 - 'Unused'
|
||||
0, // 211 - 'Unused'
|
||||
0, // 212 - 'Unused'
|
||||
0, // 213 - 'Unused'
|
||||
0, // 214 - 'Unused'
|
||||
0, // 215 - 'Unused'
|
||||
0, // 216 - 'Unused'
|
||||
0, // 217 - 'Unused'
|
||||
0, // 218 - 'Unused'
|
||||
0, // 219 - 'Unused'
|
||||
0, // 220 - 'Unused'
|
||||
0, // 221 - 'Unused'
|
||||
0, // 222 - 'Unused'
|
||||
0, // 223 - 'Unused'
|
||||
0, // 224 - 'Unused'
|
||||
0, // 225 - 'Unused'
|
||||
0, // 226 - 'Unused'
|
||||
0, // 227 - 'Unused'
|
||||
0, // 228 - 'Unused'
|
||||
0, // 229 - 'Unused'
|
||||
0, // 230 - 'Unused'
|
||||
0, // 231 - 'Unused'
|
||||
0, // 232 - 'Unused'
|
||||
0, // 233 - 'Unused'
|
||||
0, // 234 - 'Unused'
|
||||
0, // 235 - 'Unused'
|
||||
0, // 236 - 'Unused'
|
||||
0, // 237 - 'Unused'
|
||||
0, // 238 - 'Unused'
|
||||
0, // 239 - 'Unused'
|
||||
0, // 240 - 'Unused'
|
||||
0, // 241 - 'Unused'
|
||||
0, // 242 - 'Unused'
|
||||
0, // 243 - 'Unused'
|
||||
0, // 244 - 'Unused'
|
||||
0, // 245 - 'Unused'
|
||||
0, // 246 - 'Unused'
|
||||
0, // 247 - 'Unused'
|
||||
0, // 248 - 'Unused'
|
||||
0, // 249 - 'Unused'
|
||||
0, // 250 - 'Unused'
|
||||
0, // 251 - 'Unused'
|
||||
0, // 252 - 'Unused'
|
||||
0, // 253 - 'Unused'
|
||||
0, // 254 - 'Unused'
|
||||
0, // 255 - 'Unused'
|
||||
};
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,158 @@
|
||||
// Use the MD_MAX72XX library to Display a Scrolling Chart
|
||||
//
|
||||
// Scroll Chart Style can be changed from line to bar chart, triggered
|
||||
// by a switch on the MODE_SWITCH pin.
|
||||
//
|
||||
// Uses the MD_UIswitch library found at https://github.com/MajicDesigns/MD_UISwitch
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
#include <MD_UISwitch.h>
|
||||
|
||||
#define DEBUG 0 // Enable or disable (default) debugging output
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); } // Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); } // Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) { Serial.print(F(s)); Serial.print(v, BIN); } // Print a string followed by a value (binary)
|
||||
#define PRINTC(s, v) { Serial.print(F(s)); Serial.print((char)v); } // Print a string followed by a value (char)
|
||||
#define PRINTS(s) { Serial.print(F(s)); } // Print a string
|
||||
#else
|
||||
#define PRINT(s, v) // Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) // Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) // Print a string followed by a value (binary)
|
||||
#define PRINTC(s, v) // Print a string followed by a value (char)
|
||||
#define PRINTS(s) // Print a string
|
||||
#endif
|
||||
|
||||
// --------------------
|
||||
// MD_MAX72xx hardware definitions and object
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
//
|
||||
#define MAX_DEVICES 8
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES); // SPI hardware interface
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // Arbitrary pins
|
||||
|
||||
// --------------------
|
||||
// Mode keyswitch parameters and object
|
||||
//
|
||||
#define MODE_SWITCH 9 // Digital Pin
|
||||
|
||||
MD_UISwitch_Digital ks = MD_UISwitch_Digital(MODE_SWITCH, LOW);
|
||||
|
||||
// --------------------
|
||||
// Constant parameters
|
||||
//
|
||||
// Various delays in milliseconds
|
||||
#define Next_POINT_DELAY 40
|
||||
|
||||
|
||||
// ========== General Variables ===========
|
||||
//
|
||||
uint32_t prevTime = 0; // Used for remembering the mills() value
|
||||
|
||||
// ========== Graphic routines ===========
|
||||
//
|
||||
bool graphDisplay(bool bInit, uint8_t nType)
|
||||
{
|
||||
static int8_t curPoint = 0;
|
||||
uint8_t curCol = 0;
|
||||
|
||||
// are we initializing?
|
||||
if (bInit)
|
||||
{
|
||||
resetDisplay();
|
||||
curPoint = 4;
|
||||
bInit = false;
|
||||
}
|
||||
else if (millis() - prevTime >= Next_POINT_DELAY)
|
||||
{
|
||||
prevTime = millis(); // rest for next time
|
||||
|
||||
// work out the new value for the height depending on the chart type
|
||||
switch (nType)
|
||||
{
|
||||
case 0: // continuous display next point should be +/-1 or 0
|
||||
curPoint += random(3) - 1;
|
||||
if (curPoint < 0) curPoint = 0;
|
||||
if (curPoint > 7) curPoint = 7;
|
||||
break;
|
||||
|
||||
case 1: // random height
|
||||
case 2:
|
||||
curPoint = random(8);
|
||||
break;
|
||||
}
|
||||
|
||||
// now work out the new column value
|
||||
switch (nType)
|
||||
{
|
||||
case 0: // just a dot
|
||||
case 1:
|
||||
curCol = (1 << curPoint);
|
||||
break;
|
||||
|
||||
case 2: // bar chart
|
||||
for (uint8_t i=0; i<8; i++)
|
||||
curCol |= (i<curPoint ? 0 : 1) << i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Shift over and insert the new column
|
||||
mx.transform(MD_MAX72XX::TSL);
|
||||
mx.setColumn(0, curCol);
|
||||
}
|
||||
|
||||
return(bInit);
|
||||
}
|
||||
|
||||
// ========== Control routines ===========
|
||||
//
|
||||
void resetDisplay(void)
|
||||
{
|
||||
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY/2);
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
mx.clear();
|
||||
prevTime = 0;
|
||||
}
|
||||
|
||||
void runAnimation(void)
|
||||
// Schedule the animations, switching to the next one when the
|
||||
// the mode switch is pressed.
|
||||
{
|
||||
static uint8_t state = 0;
|
||||
static bool bRestart = true;
|
||||
|
||||
// check if the switch is pressed and handle that first
|
||||
if (ks.read() == MD_UISwitch::KEY_PRESS)
|
||||
{
|
||||
state = (state + 1) % 3;
|
||||
bRestart = true;
|
||||
};
|
||||
|
||||
// now do whatever we do in the current state
|
||||
bRestart = graphDisplay(bRestart, state);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
ks.begin();
|
||||
|
||||
#if DEBUG
|
||||
Serial.begin(57600);
|
||||
#endif
|
||||
PRINTS("\n[MD_MAX72XX Scroll Chart]");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
runAnimation();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Test the library transformation functions
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// Use a button to transfer between transformations or just do it on a timer basis
|
||||
#define USE_SWITCH_INPUT 1
|
||||
|
||||
#define SWITCH_PIN 8 // switch pin if enabled - active LOW
|
||||
|
||||
// We always wait a bit between updates of the display
|
||||
#define DELAYTIME 500 // in milliseconds
|
||||
|
||||
// Number of times to repeat the transformation animations
|
||||
#define REPEATS_PRESET 16
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 4
|
||||
#define WRAPAROUND_MODE MD_MAX72XX::ON
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
|
||||
bool changeState(void)
|
||||
{
|
||||
bool b = false;
|
||||
|
||||
#if USE_SWITCH_INPUT
|
||||
|
||||
static int8_t lastStatus = HIGH;
|
||||
int8_t status = digitalRead(SWITCH_PIN);
|
||||
|
||||
b = (lastStatus == HIGH) && (status == LOW);
|
||||
lastStatus = status;
|
||||
#else
|
||||
static uint32_t lastTime = 0;
|
||||
static uint8_t repeatCount = 0;
|
||||
|
||||
if (repeatCount == 0)
|
||||
repeatCount = REPEATS_PRESET;
|
||||
|
||||
if (millis()-lastTime >= DELAYTIME)
|
||||
{
|
||||
lastTime = millis();
|
||||
b = (--repeatCount == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return(b);
|
||||
}
|
||||
|
||||
void transformDemo(MD_MAX72XX::transformType_t tt, bool bNew)
|
||||
{
|
||||
static uint32_t lastTime = 0;
|
||||
|
||||
if (bNew)
|
||||
{
|
||||
mx.clear();
|
||||
|
||||
for (uint8_t i=0; i<MAX_DEVICES; i++)
|
||||
mx.setChar(((i+1)*COL_SIZE)-1, 'o'+i);
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
if (millis() - lastTime >= DELAYTIME)
|
||||
{
|
||||
mx.transform(0, MAX_DEVICES-1, tt);
|
||||
lastTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
// use wraparound mode
|
||||
mx.control(MD_MAX72XX::WRAPAROUND, WRAPAROUND_MODE);
|
||||
|
||||
#if USE_SWITCH_INPUT
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
Serial.begin(57600);
|
||||
Serial.println("[Transform Test]");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static int8_t tState = -1;
|
||||
static bool bNew = true;
|
||||
|
||||
if (bNew)
|
||||
{
|
||||
tState = (tState+1) % 8;
|
||||
Serial.print("State: "); Serial.println(tState);
|
||||
}
|
||||
|
||||
switch (tState)
|
||||
{
|
||||
case 0: transformDemo(MD_MAX72XX::TSL, bNew); break;
|
||||
case 1: transformDemo(MD_MAX72XX::TSR, bNew); break;
|
||||
case 2: transformDemo(MD_MAX72XX::TSU, bNew); break;
|
||||
case 3: transformDemo(MD_MAX72XX::TSD, bNew); break;
|
||||
case 4: transformDemo(MD_MAX72XX::TFUD, bNew); break;
|
||||
case 5: transformDemo(MD_MAX72XX::TFLR, bNew); break;
|
||||
case 6: transformDemo(MD_MAX72XX::TRC, bNew); break;
|
||||
case 7: transformDemo(MD_MAX72XX::TINV, bNew); break;
|
||||
default: tState = 0; // just in case
|
||||
}
|
||||
|
||||
bNew = changeState();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Uses most of the functions in the library
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// Turn on debug statements to the serial output
|
||||
#define DEBUG 1
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
|
||||
#define PRINTS(x) Serial.print(F(x))
|
||||
#define PRINTD(x) Serial.println(x, DEC)
|
||||
|
||||
#else
|
||||
#define PRINT(s, x)
|
||||
#define PRINTS(x)
|
||||
#define PRINTD(x)
|
||||
|
||||
#endif
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
// MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// We always wait a bit between updates of the display
|
||||
#define DELAYTIME 100 // in milliseconds
|
||||
|
||||
void scrollText(char *p)
|
||||
{
|
||||
uint8_t charWidth;
|
||||
uint8_t cBuf[8]; // this should be ok for all built-in fonts
|
||||
|
||||
PRINTS("\nScrolling text");
|
||||
mx.clear();
|
||||
|
||||
while (*p != '\0')
|
||||
{
|
||||
charWidth = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
|
||||
|
||||
for (uint8_t i=0; i<charWidth + 1; i++) // allow space between characters
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSL);
|
||||
if (i < charWidth)
|
||||
mx.setColumn(0, cBuf[i]);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void zeroPointSet()
|
||||
// Demonstrates the use of setPoint and
|
||||
// show where the zero point is in the display
|
||||
{
|
||||
PRINTS("\nZero point highlight");
|
||||
mx.clear();
|
||||
|
||||
if (MAX_DEVICES > 1)
|
||||
mx.setChar((2*COL_SIZE)-1, '0');
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
mx.setPoint(i, i, true);
|
||||
mx.setPoint(0, i, true);
|
||||
mx.setPoint(i, 0, true);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
|
||||
delay(DELAYTIME*3);
|
||||
}
|
||||
|
||||
void lines()
|
||||
// Demonstrate the use of drawLine().
|
||||
// fan out lines from each corner for up to 4 device blocks
|
||||
{
|
||||
PRINTS("\nLines");
|
||||
const uint8_t stepSize = 3;
|
||||
const uint8_t maxDev = (MAX_DEVICES > 4 ? 4 : MAX_DEVICES);
|
||||
|
||||
mx.clear();
|
||||
for (uint16_t c=0; c<(maxDev*COL_SIZE)-1; c+=stepSize)
|
||||
{
|
||||
mx.drawLine(0, 0, ROW_SIZE-1, c, true);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
|
||||
mx.clear();
|
||||
for (uint16_t c=0; c<(maxDev*COL_SIZE)-1; c+=stepSize)
|
||||
{
|
||||
mx.drawLine(ROW_SIZE-1, 0, 0, c, true);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
|
||||
mx.clear();
|
||||
for (uint16_t c=0; c<(maxDev*COL_SIZE)-1; c+=stepSize)
|
||||
{
|
||||
mx.drawLine(ROW_SIZE-1, (MAX_DEVICES*COL_SIZE)-1, 0, (MAX_DEVICES*COL_SIZE)-1-c, true);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
|
||||
mx.clear();
|
||||
for (uint16_t c=0; c<(maxDev*COL_SIZE)-1; c+=stepSize)
|
||||
{
|
||||
mx.drawLine(0, (MAX_DEVICES*COL_SIZE)-1, ROW_SIZE-1, (MAX_DEVICES*COL_SIZE)-1-c, true);
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
}
|
||||
|
||||
void rows()
|
||||
// Demonstrates the use of setRow()
|
||||
{
|
||||
PRINTS("\nRows 0->7");
|
||||
mx.clear();
|
||||
|
||||
for (uint8_t row=0; row<ROW_SIZE; row++)
|
||||
{
|
||||
mx.setRow(row, 0xff);
|
||||
delay(DELAYTIME);
|
||||
mx.setRow(row, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void columns()
|
||||
// Demonstrates the use of setColumn()
|
||||
{
|
||||
PRINTS("\nCols 0->max");
|
||||
mx.clear();
|
||||
|
||||
for (uint8_t col=0; col<mx.getColumnCount(); col++)
|
||||
{
|
||||
mx.setColumn(col, 0xff);
|
||||
delay(DELAYTIME/MAX_DEVICES);
|
||||
mx.setColumn(col, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void cross()
|
||||
// Combination of setRow() and setColumn() with user controlled
|
||||
// display updates to ensure concurrent changes.
|
||||
{
|
||||
PRINTS("\nMoving cross");
|
||||
mx.clear();
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
// diagonally down the display R to L
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0xff);
|
||||
mx.setRow(j, i, 0xff);
|
||||
}
|
||||
mx.update();
|
||||
delay(3*DELAYTIME);
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0x00);
|
||||
mx.setRow(j, i, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// moving up the display on the R
|
||||
for (int8_t i=ROW_SIZE-1; i>=0; i--)
|
||||
{
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0xff);
|
||||
mx.setRow(j, ROW_SIZE-1, 0xff);
|
||||
}
|
||||
mx.update();
|
||||
delay(3*DELAYTIME);
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0x00);
|
||||
mx.setRow(j, ROW_SIZE-1, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// diagonally up the display L to R
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0xff);
|
||||
mx.setRow(j, ROW_SIZE-1-i, 0xff);
|
||||
}
|
||||
mx.update();
|
||||
delay(3*DELAYTIME);
|
||||
for (uint8_t j=0; j<MAX_DEVICES; j++)
|
||||
{
|
||||
mx.setColumn(j, i, 0x00);
|
||||
mx.setRow(j, ROW_SIZE-1-i, 0x00);
|
||||
}
|
||||
}
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void bullseye()
|
||||
// Demonstrate the use of buffer based repeated patterns
|
||||
// across all devices.
|
||||
{
|
||||
PRINTS("\nBullseye");
|
||||
mx.clear();
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
for (uint8_t n=0; n<3; n++)
|
||||
{
|
||||
byte b = 0xff;
|
||||
int i = 0;
|
||||
|
||||
while (b != 0x00)
|
||||
{
|
||||
for (uint8_t j=0; j<MAX_DEVICES+1; j++)
|
||||
{
|
||||
mx.setRow(j, i, b);
|
||||
mx.setColumn(j, i, b);
|
||||
mx.setRow(j, ROW_SIZE-1-i, b);
|
||||
mx.setColumn(j, COL_SIZE-1-i, b);
|
||||
}
|
||||
mx.update();
|
||||
delay(3*DELAYTIME);
|
||||
for (uint8_t j=0; j<MAX_DEVICES+1; j++)
|
||||
{
|
||||
mx.setRow(j, i, 0);
|
||||
mx.setColumn(j, i, 0);
|
||||
mx.setRow(j, ROW_SIZE-1-i, 0);
|
||||
mx.setColumn(j, COL_SIZE-1-i, 0);
|
||||
}
|
||||
|
||||
bitClear(b, i);
|
||||
bitClear(b, 7-i);
|
||||
i++;
|
||||
}
|
||||
|
||||
while (b != 0xff)
|
||||
{
|
||||
for (uint8_t j=0; j<MAX_DEVICES+1; j++)
|
||||
{
|
||||
mx.setRow(j, i, b);
|
||||
mx.setColumn(j, i, b);
|
||||
mx.setRow(j, ROW_SIZE-1-i, b);
|
||||
mx.setColumn(j, COL_SIZE-1-i, b);
|
||||
}
|
||||
mx.update();
|
||||
delay(3*DELAYTIME);
|
||||
for (uint8_t j=0; j<MAX_DEVICES+1; j++)
|
||||
{
|
||||
mx.setRow(j, i, 0);
|
||||
mx.setColumn(j, i, 0);
|
||||
mx.setRow(j, ROW_SIZE-1-i, 0);
|
||||
mx.setColumn(j, COL_SIZE-1-i, 0);
|
||||
}
|
||||
|
||||
i--;
|
||||
bitSet(b, i);
|
||||
bitSet(b, 7-i);
|
||||
}
|
||||
}
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void stripe()
|
||||
// Demonstrates animation of a diagonal stripe moving across the display
|
||||
// with points plotted outside the display region ignored.
|
||||
{
|
||||
const uint16_t maxCol = MAX_DEVICES*ROW_SIZE;
|
||||
const uint8_t stripeWidth = 10;
|
||||
|
||||
PRINTS("\nEach individually by row then col");
|
||||
mx.clear();
|
||||
|
||||
for (uint16_t col=0; col<maxCol + ROW_SIZE + stripeWidth; col++)
|
||||
{
|
||||
for (uint8_t row=0; row < ROW_SIZE; row++)
|
||||
{
|
||||
mx.setPoint(row, col-row, true);
|
||||
mx.setPoint(row, col-row - stripeWidth, false);
|
||||
}
|
||||
delay(DELAYTIME);
|
||||
}
|
||||
}
|
||||
|
||||
void spiral()
|
||||
// setPoint() used to draw a spiral across the whole display
|
||||
{
|
||||
PRINTS("\nSpiral in");
|
||||
int rmin = 0, rmax = ROW_SIZE-1;
|
||||
int cmin = 0, cmax = (COL_SIZE*MAX_DEVICES)-1;
|
||||
|
||||
mx.clear();
|
||||
while ((rmax > rmin) && (cmax > cmin))
|
||||
{
|
||||
// do row
|
||||
for (int i=cmin; i<=cmax; i++)
|
||||
{
|
||||
mx.setPoint(rmin, i, true);
|
||||
delay(DELAYTIME/MAX_DEVICES);
|
||||
}
|
||||
rmin++;
|
||||
|
||||
// do column
|
||||
for (uint8_t i=rmin; i<=rmax; i++)
|
||||
{
|
||||
mx.setPoint(i, cmax, true);
|
||||
delay(DELAYTIME/MAX_DEVICES);
|
||||
}
|
||||
cmax--;
|
||||
|
||||
// do row
|
||||
for (int i=cmax; i>=cmin; i--)
|
||||
{
|
||||
mx.setPoint(rmax, i, true);
|
||||
delay(DELAYTIME/MAX_DEVICES);
|
||||
}
|
||||
rmax--;
|
||||
|
||||
// do column
|
||||
for (uint8_t i=rmax; i>=rmin; i--)
|
||||
{
|
||||
mx.setPoint(i, cmin, true);
|
||||
delay(DELAYTIME/MAX_DEVICES);
|
||||
}
|
||||
cmin++;
|
||||
}
|
||||
}
|
||||
|
||||
void bounce()
|
||||
// Animation of a bouncing ball
|
||||
{
|
||||
const int minC = 0;
|
||||
const int maxC = mx.getColumnCount()-1;
|
||||
const int minR = 0;
|
||||
const int maxR = ROW_SIZE-1;
|
||||
|
||||
int nCounter = 0;
|
||||
|
||||
int r = 0, c = 2;
|
||||
int8_t dR = 1, dC = 1; // delta row and column
|
||||
|
||||
PRINTS("\nBouncing ball");
|
||||
mx.clear();
|
||||
|
||||
while (nCounter++ < 200)
|
||||
{
|
||||
mx.setPoint(r, c, false);
|
||||
r += dR;
|
||||
c += dC;
|
||||
mx.setPoint(r, c, true);
|
||||
delay(DELAYTIME/2);
|
||||
|
||||
if ((r == minR) || (r == maxR))
|
||||
dR = -dR;
|
||||
if ((c == minC) || (c == maxC))
|
||||
dC = -dC;
|
||||
}
|
||||
}
|
||||
|
||||
void intensity()
|
||||
// Demonstrates the control of display intensity (brightness) across
|
||||
// the full range.
|
||||
{
|
||||
uint8_t row;
|
||||
|
||||
PRINTS("\nVary intensity ");
|
||||
|
||||
mx.clear();
|
||||
|
||||
// Grow and get brighter
|
||||
row = 0;
|
||||
for (int8_t i=0; i<=MAX_INTENSITY; i++)
|
||||
{
|
||||
mx.control(MD_MAX72XX::INTENSITY, i);
|
||||
if (i%2 == 0)
|
||||
mx.setRow(row++, 0xff);
|
||||
delay(DELAYTIME*3);
|
||||
}
|
||||
|
||||
mx.control(MD_MAX72XX::INTENSITY, 8);
|
||||
}
|
||||
|
||||
void blinking()
|
||||
// Uses the test function of the MAX72xx to blink the display on and off.
|
||||
{
|
||||
int nDelay = 1000;
|
||||
|
||||
PRINTS("\nBlinking");
|
||||
mx.clear();
|
||||
|
||||
while (nDelay > 0)
|
||||
{
|
||||
mx.control(MD_MAX72XX::TEST, MD_MAX72XX::ON);
|
||||
delay(nDelay);
|
||||
mx.control(MD_MAX72XX::TEST, MD_MAX72XX::OFF);
|
||||
delay(nDelay);
|
||||
|
||||
nDelay -= DELAYTIME;
|
||||
}
|
||||
}
|
||||
|
||||
void scanLimit(void)
|
||||
// Uses scan limit function to restrict the number of rows displayed.
|
||||
{
|
||||
PRINTS("\nScan Limit");
|
||||
mx.clear();
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
for (uint8_t row=0; row<ROW_SIZE; row++)
|
||||
mx.setRow(row, 0xff);
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
|
||||
for (int8_t s=MAX_SCANLIMIT; s>=0; s--)
|
||||
{
|
||||
mx.control(MD_MAX72XX::SCANLIMIT, s);
|
||||
delay(DELAYTIME*5);
|
||||
}
|
||||
mx.control(MD_MAX72XX::SCANLIMIT, MAX_SCANLIMIT);
|
||||
}
|
||||
|
||||
void transformation1()
|
||||
// Demonstrates the use of transform() to move bitmaps on the display
|
||||
// In this case a user defined bitmap is created and animated.
|
||||
{
|
||||
uint8_t arrow[COL_SIZE] =
|
||||
{
|
||||
0b00001000,
|
||||
0b00011100,
|
||||
0b00111110,
|
||||
0b01111111,
|
||||
0b00011100,
|
||||
0b00011100,
|
||||
0b00111110,
|
||||
0b00000000
|
||||
};
|
||||
|
||||
MD_MAX72XX::transformType_t t[] =
|
||||
{
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TFLR,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TRC,
|
||||
MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD,
|
||||
MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD,
|
||||
MD_MAX72XX::TFUD,
|
||||
MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU,
|
||||
MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU,
|
||||
MD_MAX72XX::TINV,
|
||||
MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC,
|
||||
MD_MAX72XX::TINV
|
||||
};
|
||||
|
||||
PRINTS("\nTransformation1");
|
||||
mx.clear();
|
||||
|
||||
// use the arrow bitmap
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
for (uint8_t j=0; j<mx.getDeviceCount(); j++)
|
||||
mx.setBuffer(((j+1)*COL_SIZE)-1, COL_SIZE, arrow);
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
delay(DELAYTIME);
|
||||
|
||||
// run through the transformations
|
||||
mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON);
|
||||
for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++)
|
||||
{
|
||||
mx.transform(t[i]);
|
||||
delay(DELAYTIME*4);
|
||||
}
|
||||
mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF);
|
||||
}
|
||||
|
||||
void transformation2()
|
||||
// Demonstrates the use of transform() to move bitmaps on the display
|
||||
// In this case font characters are loaded into the display for animation.
|
||||
{
|
||||
MD_MAX72XX::transformType_t t[] =
|
||||
{
|
||||
MD_MAX72XX::TINV,
|
||||
MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC,
|
||||
MD_MAX72XX::TINV,
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
|
||||
MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
|
||||
MD_MAX72XX::TSD, MD_MAX72XX::TSU, MD_MAX72XX::TSD, MD_MAX72XX::TSU,
|
||||
MD_MAX72XX::TFLR, MD_MAX72XX::TFLR, MD_MAX72XX::TFUD, MD_MAX72XX::TFUD
|
||||
};
|
||||
|
||||
PRINTS("\nTransformation2");
|
||||
mx.clear();
|
||||
mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF);
|
||||
|
||||
// draw something that will show changes
|
||||
for (uint8_t j=0; j<mx.getDeviceCount(); j++)
|
||||
{
|
||||
mx.setChar(((j+1)*COL_SIZE)-1, '0'+j);
|
||||
}
|
||||
delay(DELAYTIME*5);
|
||||
|
||||
// run thru transformations
|
||||
for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++)
|
||||
{
|
||||
mx.transform(t[i]);
|
||||
delay(DELAYTIME*3);
|
||||
}
|
||||
}
|
||||
|
||||
void wrapText()
|
||||
// Display text and animate scrolling using auto wraparound of the buffer
|
||||
{
|
||||
PRINTS("\nwrapText");
|
||||
mx.clear();
|
||||
mx.wraparound(MD_MAX72XX::ON);
|
||||
|
||||
// draw something that will show changes
|
||||
for (uint16_t j=0; j<mx.getDeviceCount(); j++)
|
||||
{
|
||||
mx.setChar(((j+1)*COL_SIZE)-1, (j&1 ? 'M' : 'W'));
|
||||
}
|
||||
delay(DELAYTIME*5);
|
||||
|
||||
// run thru transformations
|
||||
for (uint16_t i=0; i<3*COL_SIZE*MAX_DEVICES; i++)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSL);
|
||||
delay(DELAYTIME/2);
|
||||
}
|
||||
for (uint16_t i=0; i<3*COL_SIZE*MAX_DEVICES; i++)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSR);
|
||||
delay(DELAYTIME/2);
|
||||
}
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSU);
|
||||
delay(DELAYTIME*2);
|
||||
}
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
mx.transform(MD_MAX72XX::TSD);
|
||||
delay(DELAYTIME*2);
|
||||
}
|
||||
|
||||
mx.wraparound(MD_MAX72XX::OFF);
|
||||
}
|
||||
|
||||
void showCharset(void)
|
||||
// Run through display of the the entire font characters set
|
||||
{
|
||||
mx.clear();
|
||||
mx.update(MD_MAX72XX::OFF);
|
||||
|
||||
for (uint16_t i=0; i<256; i++)
|
||||
{
|
||||
mx.clear(0);
|
||||
mx.setChar(COL_SIZE-1, i);
|
||||
|
||||
if (MAX_DEVICES >= 3)
|
||||
{
|
||||
char hex[3];
|
||||
|
||||
sprintf(hex, "%02X", i);
|
||||
|
||||
mx.clear(1);
|
||||
mx.setChar((2*COL_SIZE)-1,hex[1]);
|
||||
mx.clear(2);
|
||||
mx.setChar((3*COL_SIZE)-1,hex[0]);
|
||||
}
|
||||
|
||||
mx.update();
|
||||
delay(DELAYTIME*2);
|
||||
}
|
||||
mx.update(MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
mx.begin();
|
||||
|
||||
#if DEBUG
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
#endif
|
||||
PRINTS("\n[MD_MAX72XX Test & Demo]");
|
||||
// scrollText("MD_MAX72xx Test ");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
#if 1
|
||||
scrollText("Graphics ");
|
||||
zeroPointSet();
|
||||
lines();
|
||||
rows();
|
||||
columns();
|
||||
cross();
|
||||
stripe();
|
||||
bullseye();
|
||||
bounce();
|
||||
spiral();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
scrollText("Control ");
|
||||
intensity();
|
||||
scanLimit();
|
||||
blinking();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
scrollText("Transform ");
|
||||
transformation1();
|
||||
transformation2();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
scrollText("Charset ");
|
||||
wrapText();
|
||||
showCharset();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// Program to exercise the MD_MAX72XX library
|
||||
//
|
||||
// Test the library transformation functions with range subsets
|
||||
|
||||
#include <MD_MAX72xx.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// We always wait a bit between updates of the display
|
||||
#define DELAYTIME 300 // in milliseconds
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
// need to be adapted
|
||||
#define MAX_DEVICES 8 // 2, 4, 6, or 8 work best - see Z array
|
||||
|
||||
#define CLK_PIN 13 // or SCK
|
||||
#define DATA_PIN 11 // or MOSI
|
||||
#define CS_PIN 10 // or SS
|
||||
|
||||
// SPI hardware interface
|
||||
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary pins
|
||||
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
|
||||
|
||||
// Global variables
|
||||
uint32_t lastTime = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t startDev; // start of zone
|
||||
uint8_t endDev; // end of zone
|
||||
uint8_t ch; // character to show
|
||||
MD_MAX72XX::transformType_t tt;
|
||||
} zoneDef_t;
|
||||
|
||||
zoneDef_t Z[] =
|
||||
{
|
||||
#if MAX_DEVICES == 2
|
||||
{0, 0, 26, MD_MAX72XX::TSR },
|
||||
{1, 1, 27, MD_MAX72XX::TSL },
|
||||
#endif // MAX_DEVICES 2
|
||||
#if MAX_DEVICES == 4
|
||||
{0, 0, 26, MD_MAX72XX::TSR },
|
||||
{1, 1, 25, MD_MAX72XX::TSD },
|
||||
{2, 2, 24, MD_MAX72XX::TSU },
|
||||
{3, 3, 27, MD_MAX72XX::TSL },
|
||||
#endif // MAX_DEVICES 4
|
||||
#if MAX_DEVICES == 6
|
||||
{0, 1, 26, MD_MAX72XX::TSR },
|
||||
{2, 2, 24, MD_MAX72XX::TSU },
|
||||
{3, 3, 25, MD_MAX72XX::TSD },
|
||||
{4, 5, 27, MD_MAX72XX::TSL },
|
||||
#endif // MAX_DEVICES 6
|
||||
#if MAX_DEVICES == 8
|
||||
{0, 1, 26, MD_MAX72XX::TSR },
|
||||
{2, 2, 24, MD_MAX72XX::TSU },
|
||||
{3, 3, 25, MD_MAX72XX::TSD },
|
||||
{4, 4, 24, MD_MAX72XX::TSU },
|
||||
{5, 5, 25, MD_MAX72XX::TSD },
|
||||
{6, 7, 27, MD_MAX72XX::TSL },
|
||||
#endif // MAX_DEVICES 8
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
|
||||
|
||||
void runTransformation(void)
|
||||
{
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
|
||||
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(Z); i++)
|
||||
mx.transform(Z[i].startDev, Z[i].endDev, Z[i].tt);
|
||||
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.println("[Zone Transform Test]");
|
||||
|
||||
mx.begin();
|
||||
mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON);
|
||||
|
||||
// set up the display characters
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(Z); i ++)
|
||||
{
|
||||
mx.clear(Z[i].startDev, Z[i].endDev);
|
||||
for (uint8_t j = Z[i].startDev; j <= Z[i].endDev; j++)
|
||||
mx.setChar(((j+1)*COL_SIZE)-2, Z[i].ch);
|
||||
}
|
||||
lastTime = millis();
|
||||
|
||||
// Enable the display
|
||||
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastTime >= DELAYTIME)
|
||||
{
|
||||
runTransformation();
|
||||
lastTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
77
arduino-cli/libraries/MD_MAX72XX/keywords.txt
Normal file
@@ -0,0 +1,77 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
MD_MAX72XX KEYWORD1
|
||||
controlRequest_t KEYWORD1
|
||||
controlValue_t KEYWORD1
|
||||
transformType_t KEYWORD1
|
||||
fontType_t KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
control KEYWORD2
|
||||
getDeviceCount KEYWORD2
|
||||
getColumnCount KEYWORD2
|
||||
setShiftDataInCallback KEYWORD2
|
||||
setShiftDataOutCallback KEYWORD2
|
||||
clear KEYWORD2
|
||||
setPoint KEYWORD2
|
||||
getPoint KEYWORD2
|
||||
drawLine KEYWORD2
|
||||
getBuffer KEYWORD2
|
||||
setBuffer KEYWORD2
|
||||
getColumn KEYWORD2
|
||||
setColumn KEYWORD2
|
||||
getRow KEYWORD2
|
||||
setRow KEYWORD2
|
||||
transform KEYWORD2
|
||||
update KEYWORD2
|
||||
wraparound KEYWORD2
|
||||
getChar KEYWORD2
|
||||
setChar KEYWORD2
|
||||
getFont KEYWORD2
|
||||
setFont KEYWORD2
|
||||
getMaxFontWidth KEYWORD2
|
||||
|
||||
######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
ROW_SIZE LITERAL1
|
||||
COL_SIZE LITERAL1
|
||||
MAX_INTENSITY LITERAL1
|
||||
MAX_SCANLIMIT LITERAL1
|
||||
|
||||
# controlRequest_t
|
||||
MD_MAX72XX::SHUTDOWN LITERAL1
|
||||
MD_MAX72XX::SCANLIMIT LITERAL1
|
||||
MD_MAX72XX::INTENSITY LITERAL1
|
||||
MD_MAX72XX::TEST LITERAL1
|
||||
MD_MAX72XX::UPDATE LITERAL1
|
||||
MD_MAX72XX::WRAPAROUND LITERAL1
|
||||
|
||||
# controlValue_t
|
||||
MD_MAX72XX::ON LITERAL1
|
||||
MD_MAX72XX::OFF LITERAL1
|
||||
|
||||
# transformType_t
|
||||
MD_MAX72XX::TSL LITERAL1
|
||||
MD_MAX72XX::TSR LITERAL1
|
||||
MD_MAX72XX::TSU LITERAL1
|
||||
MD_MAX72XX::TSD LITERAL1
|
||||
MD_MAX72XX::TFLR LITERAL1
|
||||
MD_MAX72XX::TFUD LITERAL1
|
||||
MD_MAX72XX::TRC LITERAL1
|
||||
MD_MAX72XX::TINV LITERAL1
|
||||
|
||||
# fontType_t
|
||||
MD_MAX72XX::SYS_FIXED LITERAL1
|
||||
MD_MAX72XX::SYS_VAR LITERAL1
|
||||
28
arduino-cli/libraries/MD_MAX72XX/library.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "MD_MAX72XX",
|
||||
"version": "2.10.0",
|
||||
"keywords": "led, matrix, driver",
|
||||
"description": "Implements functions that allow the MAX72xx (MAX7219) to be used for LED matrices (64 individual LEDs)",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/MajicDesigns/MD_MAX72XX.git"
|
||||
},
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Marco Colli",
|
||||
"url": "http://github.com/MajicDesigns/",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"export": {
|
||||
"exclude": [
|
||||
"Font Builder",
|
||||
"docs",
|
||||
"media"
|
||||
]
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
}
|
||||
10
arduino-cli/libraries/MD_MAX72XX/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=MD_MAX72XX
|
||||
version=2.10.0
|
||||
author=majicDesigns
|
||||
maintainer=marco_c <8136821@gmail.com>
|
||||
sentence=Implements functions that allow the MAX72xx (eg, MAX7219) to be used for LED matrices (64 individual LEDs)
|
||||
paragraph= Allows the programmer to use the LED matrix as a pixel device, displaying graphics elements much like any other pixel addressable display.
|
||||
category=Device Control
|
||||
url=https://github.com/MajicDesigns/MD_MAX72XX
|
||||
architectures=*
|
||||
includes=MD_MAX72xx.h,SPI.h
|
||||
297
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains class and hardware related methods.
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements class definition and general methods
|
||||
*/
|
||||
|
||||
MD_MAX72XX::MD_MAX72XX(uint8_t dataPin, uint8_t clkPin, uint8_t csPin, uint8_t numDevices):
|
||||
_dataPin(dataPin), _clkPin(clkPin), _csPin(csPin), _maxDevices(numDevices),
|
||||
_updateEnabled(true), _hardwareSPI(false)
|
||||
{
|
||||
}
|
||||
|
||||
MD_MAX72XX::MD_MAX72XX(uint8_t csPin, uint8_t numDevices):
|
||||
_dataPin(0), _clkPin(0), _csPin(csPin), _maxDevices(numDevices),
|
||||
_updateEnabled(true), _hardwareSPI(true)
|
||||
{
|
||||
}
|
||||
|
||||
void MD_MAX72XX::begin(void)
|
||||
{
|
||||
// initialize the AVR hardware
|
||||
if (_hardwareSPI)
|
||||
{
|
||||
PRINTS("\nHardware SPI");
|
||||
SPI.begin();
|
||||
// Old mode of operations!
|
||||
//SPI.setDataMode(SPI_MODE0);
|
||||
//SPI.setBitOrder(MSBFIRST);
|
||||
//SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTS("\nBitBang SPI")
|
||||
pinMode(_dataPin, OUTPUT);
|
||||
pinMode(_clkPin, OUTPUT);
|
||||
}
|
||||
|
||||
// initialise our preferred CS pin (could be same as SS)
|
||||
digitalWrite(_csPin, HIGH);
|
||||
pinMode(_csPin, OUTPUT);
|
||||
|
||||
// object memory and internals
|
||||
setShiftDataInCallback(NULL);
|
||||
setShiftDataOutCallback(NULL);
|
||||
|
||||
_matrix = (deviceInfo_t *)malloc(sizeof(deviceInfo_t) * _maxDevices);
|
||||
_spiData = (uint8_t *)malloc(SPI_DATA_SIZE);
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
#if USE_INDEX_FONT
|
||||
_fontIndex = (uint16_t *)malloc(sizeof(uint16_t) * ASCII_INDEX_SIZE);
|
||||
#else
|
||||
_fontIndex = NULL;
|
||||
#endif
|
||||
setFont(NULL);
|
||||
#endif // INCLUDE_LOCAL_FONT
|
||||
|
||||
// Initialize the display devices. On initial power-up
|
||||
// - all control registers are reset,
|
||||
// - scan limit is set to one digit (row/col or LED),
|
||||
// - Decoding mode is off,
|
||||
// - intensity is set to the minimum,
|
||||
// - the display is blanked, and
|
||||
// - the MAX7219/MAX7221 is shut down.
|
||||
// The devices need to be set to our library defaults prior using the
|
||||
// display modules.
|
||||
control(TEST, OFF); // no test
|
||||
control(SCANLIMIT, ROW_SIZE-1); // scan limit is set to max on startup
|
||||
control(INTENSITY, MAX_INTENSITY/2); // set intensity to a reasonable value
|
||||
control(DECODE, OFF); // make sure that no decoding happens (warm boot potential issue)
|
||||
clear();
|
||||
control(SHUTDOWN, OFF); // take the modules out of shutdown mode
|
||||
}
|
||||
|
||||
MD_MAX72XX::~MD_MAX72XX(void)
|
||||
{
|
||||
if (_hardwareSPI) SPI.end(); // reset SPI mode
|
||||
|
||||
free(_matrix);
|
||||
free(_spiData);
|
||||
#if USE_LOCAL_FONT && USE_FONT_INDEX
|
||||
if (_fontIndex != NULL) free(_fontIndex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MD_MAX72XX::controlHardware(uint8_t dev, controlRequest_t mode, int value)
|
||||
// control command is for the devices, translate internal request to device bytes
|
||||
// into the transmission buffer
|
||||
{
|
||||
uint8_t opcode = OP_NOOP;
|
||||
uint8_t param = 0;
|
||||
|
||||
// work out data to write
|
||||
switch (mode)
|
||||
{
|
||||
case SHUTDOWN:
|
||||
opcode = OP_SHUTDOWN;
|
||||
param = (value == OFF ? 1 : 0);
|
||||
break;
|
||||
|
||||
case SCANLIMIT:
|
||||
opcode = OP_SCANLIMIT;
|
||||
param = (value > MAX_SCANLIMIT ? MAX_SCANLIMIT : value);
|
||||
break;
|
||||
|
||||
case INTENSITY:
|
||||
opcode = OP_INTENSITY;
|
||||
param = (value > MAX_INTENSITY ? MAX_INTENSITY : value);
|
||||
break;
|
||||
|
||||
case DECODE:
|
||||
opcode = OP_DECODEMODE;
|
||||
param = (value == OFF ? 0 : 0xff);
|
||||
break;
|
||||
|
||||
case TEST:
|
||||
opcode = OP_DISPLAYTEST;
|
||||
param = (value == OFF ? 0 : 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(dev, 0)] = opcode;
|
||||
_spiData[SPI_OFFSET(dev, 1)] = param;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::controlLibrary(controlRequest_t mode, int value)
|
||||
// control command was internal, set required parameters
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case UPDATE:
|
||||
_updateEnabled = (value == ON);
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
break;
|
||||
|
||||
case WRAPAROUND:
|
||||
_wrapAround = (value == ON);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::control(uint8_t startDev, uint8_t endDev, controlRequest_t mode, int value)
|
||||
{
|
||||
if (endDev < startDev) return(false);
|
||||
|
||||
if (mode < UPDATE) // device based control
|
||||
{
|
||||
spiClearBuffer();
|
||||
for (uint8_t i = startDev; i <= endDev; i++)
|
||||
controlHardware(i, mode, value);
|
||||
spiSend();
|
||||
}
|
||||
else // internal control function, doesn't relate to specific device
|
||||
{
|
||||
controlLibrary(mode, value);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::control(uint8_t buf, controlRequest_t mode, int value)
|
||||
// dev is zero based and needs adjustment if used
|
||||
{
|
||||
if (buf > LAST_BUFFER) return(false);
|
||||
|
||||
if (mode < UPDATE) // device based control
|
||||
{
|
||||
spiClearBuffer();
|
||||
controlHardware(buf, mode, value);
|
||||
spiSend();
|
||||
}
|
||||
else // internal control function, doesn't relate to specific device
|
||||
{
|
||||
controlLibrary(mode, value);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void MD_MAX72XX::flushBufferAll()
|
||||
// Only one data byte is sent to a device, so if there are many changes, it is more
|
||||
// efficient to send a data byte all devices at the same time, substantially cutting
|
||||
// the number of communication messages required.
|
||||
{
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++) // all data rows
|
||||
{
|
||||
bool bChange = false; // set to true if we detected a change
|
||||
|
||||
spiClearBuffer();
|
||||
|
||||
for (uint8_t dev = FIRST_BUFFER; dev <= LAST_BUFFER; dev++) // all devices
|
||||
{
|
||||
if (bitRead(_matrix[dev].changed, i))
|
||||
{
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(dev, 0)] = OP_DIGIT0+i;
|
||||
_spiData[SPI_OFFSET(dev, 1)] = _matrix[dev].dig[i];
|
||||
bChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bChange) spiSend();
|
||||
}
|
||||
|
||||
// mark everything as cleared
|
||||
for (uint8_t dev = FIRST_BUFFER; dev <= LAST_BUFFER; dev++)
|
||||
_matrix[dev].changed = ALL_CLEAR;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::flushBuffer(uint8_t buf)
|
||||
// Use this function when the changes are limited to one device only.
|
||||
// Address passed is a buffer address
|
||||
{
|
||||
PRINT("\nflushBuf: ", buf);
|
||||
PRINTS(" r");
|
||||
|
||||
if (buf > LAST_BUFFER)
|
||||
return;
|
||||
|
||||
for (uint8_t i = 0; i < ROW_SIZE; i++)
|
||||
{
|
||||
if (bitRead(_matrix[buf].changed, i))
|
||||
{
|
||||
PRINT("", i);
|
||||
spiClearBuffer();
|
||||
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(buf, 0)] = OP_DIGIT0+i;
|
||||
_spiData[SPI_OFFSET(buf, 1)] = _matrix[buf].dig[i];
|
||||
|
||||
spiSend();
|
||||
}
|
||||
}
|
||||
_matrix[buf].changed = ALL_CLEAR;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::spiClearBuffer(void)
|
||||
// Clear out the spi data array
|
||||
{
|
||||
memset(_spiData, OP_NOOP, SPI_DATA_SIZE);
|
||||
}
|
||||
|
||||
void MD_MAX72XX::spiSend()
|
||||
{
|
||||
// initialise the SPI transaction
|
||||
if (_hardwareSPI)
|
||||
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_csPin, LOW);
|
||||
|
||||
// shift out the data
|
||||
if (_hardwareSPI)
|
||||
{
|
||||
for (int i = 0; i < SPI_DATA_SIZE; i++)
|
||||
SPI.transfer(_spiData[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < SPI_DATA_SIZE; i++)
|
||||
shiftOut(_dataPin, _clkPin, MSBFIRST, _spiData[i]);
|
||||
}
|
||||
|
||||
// end the SPI transaction
|
||||
digitalWrite(_csPin, HIGH);
|
||||
if (_hardwareSPI)
|
||||
SPI.endTransaction();
|
||||
}
|
||||
955
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.h
Normal file
@@ -0,0 +1,955 @@
|
||||
/**
|
||||
\mainpage Arduino LED Matrix Library
|
||||
The Maxim 72xx LED Controller IC
|
||||
--------------------------------
|
||||
The MAX7219/MAX7221 are compact, serial input/output display drivers that
|
||||
interface microprocessors to 7-segment numeric LED displays of up to 8 digits,
|
||||
bar-graph displays, or 64 individual LEDs. Included on-chip are a BCD code-B
|
||||
decoder, multiplex scan circuitry, segment and digit drivers, and an 8x8 static
|
||||
RAM that stores each digit.
|
||||
|
||||
A 4-wire serial interface (SPI) allows the devices to be cascaded, with
|
||||
communications passed through the first device in the chain to all others. Individual
|
||||
elements may be addressed and updated without rewriting the entire display.
|
||||
|
||||
This library implements functions that allow the MAX72xx to be used
|
||||
for LED matrices (64 individual LEDs), allowing the programmer to use the LED
|
||||
matrix as a pixel device, displaying graphics elements much like any other
|
||||
pixel addressable display.
|
||||
|
||||
Topics
|
||||
------
|
||||
- \subpage pageHardware
|
||||
- \subpage pageSoftware
|
||||
- \subpage pageConnect
|
||||
- \subpage pageFontUtility
|
||||
- \subpage pageRevisionHistory
|
||||
|
||||
Copyright
|
||||
---------
|
||||
Copyright (C) 2012-16 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
\page pageRevisionHistory Revision History
|
||||
Revision History
|
||||
----------------
|
||||
Nov 2017 version 2.9.1
|
||||
- Changed SPI buffer handling and isolation of AVR specific features (eg PROGMEM)
|
||||
- Added MD_MAX72xx_Message_ESP8266 example
|
||||
- Minor source file cleanup
|
||||
- Added Extended ASCII font, vertical rotated font and RobotEyes font in fontbuilder
|
||||
- Modifed fontbuilder output code for consistency with new code
|
||||
- Added getFont(), getMaxFontWidth() methods
|
||||
- Changed example - replaced MD_KeySwitch with new MD_UISwitch library
|
||||
|
||||
Nov 2016 version 2.9.0
|
||||
- Added WordClock example
|
||||
- Deprecated USE_LIBRARY_SPI as no problems reported with new implementation
|
||||
- Changed MD_ branding to new MajicDesigns diamond
|
||||
- Small adjustments to initialisation code
|
||||
|
||||
Mar 2016 version 2.8
|
||||
- Added example _Message_SD and renamed _Message to _Message_Serial
|
||||
- Added Pacman example
|
||||
- Added PushWheel example
|
||||
- Added USE_LIBRARY_SPI to enable library SPI object
|
||||
- Modifed all examples to conditionally include <SPI.h>
|
||||
- FontBuilder modified to handle definitions for double height fonts
|
||||
- New txt2font utility for easier font creattion from a text file
|
||||
- Revised and ro-organised documentation; expanded section on fonts
|
||||
|
||||
April 2015 version 2.7
|
||||
- Changed to Daft Punk example to run without switch
|
||||
- Now supporting IDE Library Manager
|
||||
|
||||
February 2015 version 2.6
|
||||
- Improvements to HW_Mapper utility
|
||||
- Added HW_USE_FC16 for FC-16 display modules
|
||||
- Added USE_HW_OTHER for user defined hardware configuration
|
||||
- Fixed incorrect spelling for HW_REV_COLS in transformbuffer() & corresponding bug
|
||||
- Added PrintText_ML example
|
||||
|
||||
February 2015 version 2.5
|
||||
- Documented process for adding new hardware module type
|
||||
- Fixed PROGMEM definitions for IDE version 1.5.7 compile error
|
||||
- Added Daft Punk example code
|
||||
- Updated HW_Mapper example/utility with built-in instructions
|
||||
- Minor problems with Parola font setting interaction fixed
|
||||
|
||||
April 2014 version 2.4
|
||||
- Improved reliability of initialization code to remove artifacts
|
||||
+ Changed order of hardware initialization for SS, _csPin
|
||||
+ Changed initialisation sequence at begin()
|
||||
+ Fixed memset bug identified by bperrybap
|
||||
- Reworked command SPI transmissions for efficiency
|
||||
- Cleanup up compiler warnings on inline wrapper code functions
|
||||
- Cleaned up examples begin() - better defined library default values
|
||||
- Reviewed and tidied up some documentation
|
||||
|
||||
March 2014 - version 2.3
|
||||
- Extensive rework of the font system
|
||||
+ New font Microsoft Excel VBA based builder tool available
|
||||
+ Removed USE_FONT_ADJUST and related code - replace by builder tool
|
||||
+ Fixed width font has been removed from the library. Definition still available in font builder
|
||||
+ fontype_t definition changed to suit new requirements
|
||||
- Transform zoning implemented (contiguous subset of services)
|
||||
+ Transformation functions, control, clear, setRow methods overloaded with range specifier
|
||||
+ User callback for L/R rotation function syntax added a device parameter
|
||||
+ New Zones example
|
||||
- USE_*_HW hardware types now separated out for future flexibility
|
||||
+ Rework of the library to use new schema for defining hardware characteristics
|
||||
+ New utility code to map out digits and segments for unknown hardware types
|
||||
- Rechecked and reworked examples for new library
|
||||
|
||||
November 2013 - version 2.2
|
||||
- Replaced reference to SPI library with inline code to allow for different select lines
|
||||
- Obsoleted INCLUDE_HARDWARE_SPI conditional compile switch
|
||||
- Fixed legacy code function name error when USE_FONT_ADJUST switch turned on
|
||||
- Implemented USE_PAROLA_HW to allow cheaply available matrix modules to be used in ganged mode
|
||||
- Fixed reversal of bit field for set/get Row/Column functions -> flipped charset data
|
||||
- Added Eyes example program
|
||||
- Upgraded and reorganized documentation
|
||||
|
||||
June 2013 - version 2.1
|
||||
- Include the selection of hardware SPI interface (10x speed improvement)
|
||||
- Tidied up comments
|
||||
|
||||
April 2013 - version 2.0
|
||||
- Major update and rewrite of library code:
|
||||
- Improved speed and efficiency of code
|
||||
- Increased level of abstraction in the library for pixel methods
|
||||
- Increased level of abstraction for character and font methods
|
||||
- Increased number of functions and added variable sized font
|
||||
- Changed defines to enumerated types within the scope of the class
|
||||
- Updated functionality to simplify controlling multiple devices
|
||||
- Changed text and comments to be aligned to doxygen documentation generation
|
||||
|
||||
June 2012 - version 1.0
|
||||
- Incorporated elements of Arduino LedControl (Eberhard Fahle) and MAX7219 libraries
|
||||
- Easier functionality for pixel graphics treatment of 8x8 matrices
|
||||
|
||||
\page pageSoftware Software Library
|
||||
The Library
|
||||
-----------
|
||||
The library implements functions that allow the MAX72xx to be used
|
||||
for LED matrices (64 individual LEDs), allowing the programmer to use the LED
|
||||
matrix as a pixel device, displaying graphics elements much like any other
|
||||
pixel addressable display.
|
||||
|
||||
In this scenario, it is convenient to abstract out the concept of the hardware device
|
||||
and create a uniform and consistent pixel address space, with the libraries determining
|
||||
device and device-element address. Similarly, control of the devices should be uniform
|
||||
and abstracted to a system level.
|
||||
|
||||
The library still retains flexibility for device level control, should the developer
|
||||
require, through the use of overloaded class methods.
|
||||
___
|
||||
|
||||
Conditional Compilation Switches
|
||||
--------------------------------
|
||||
The library allows the run time code to be tailored through the use of compilation
|
||||
switches. The compile options start with USE_ and are documented in the section
|
||||
related to the main header file MD_MAX72xx.h.
|
||||
|
||||
_NOTE_: Compile switches must be edited in the library header file. Arduino header file
|
||||
'mashing' during compilation makes the setting of these switches from user code
|
||||
completely unreliable.
|
||||
|
||||
\page pageConnect System Connections
|
||||
Connections to the Arduino Board (SPI interface)
|
||||
------------------------------------------------
|
||||
The modules are connected through a 4-wire serial interface (SPI), and devices are cascaded,
|
||||
with communications passed through the first device in the chain to all others. The Arduino
|
||||
should be connected to the IN side of the first module in the chain.
|
||||
|
||||
The Arduino interface is implemented with either
|
||||
+ The hardware SPI interface, or
|
||||
+ 3 arbitrary digital outputs that are passed through to the class constructor.
|
||||
|
||||
The AVR hardware SPI interface is fast but fixed to predetermined output pins. The more general
|
||||
software interface uses the Arduino shiftOut() library function, making it slower but allows the
|
||||
use of arbitrary digital pins to send the data to the device. Which mode is enabled depends
|
||||
on the class constructor used.
|
||||
|
||||
The Arduino interface is implemented with 3 digital outputs that are passed through to
|
||||
the class constructor. The digital outputs define the SPI interface as follows:
|
||||
- DIN (MOSI) - the Data IN signal shifts data into the display module. Data is loaded into
|
||||
the device's internal 16-bit shift register on CLK's rising edge.
|
||||
- CLK (SCK) - the CLocK signal that is used to time the data for the device.
|
||||
- LD (SS) - the interface is active when LoaD signal is LOW. Serial data are loaded into the
|
||||
device shift register while LOAD is LOW and latched in on the rising edge.
|
||||
|
||||
The LD signal is used to select the entire device chain. This allows separate LD
|
||||
outputs to control multiple displays sharing the same DIN and CLK signals. The
|
||||
software needs to instantiate a separate object for each display.
|
||||
|
||||
The remaining interface pins are for +5V and GND. The power supply must be able to supply
|
||||
enough current for the number of connected modules.
|
||||
*/
|
||||
#ifndef MD_MAX72xx_h
|
||||
#define MD_MAX72xx_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Main header file for the MD_MAX72xx library
|
||||
*/
|
||||
|
||||
/**
|
||||
\def USE_PAROLA_HW
|
||||
Set to 1 (default) to use the Parola hardware modules. The
|
||||
software was originally designed to operate with this hardware type.
|
||||
*/
|
||||
#define USE_PAROLA_HW 0
|
||||
|
||||
/**
|
||||
\def USE_GENERIC_HW
|
||||
Set to 1 to use 'generic' hardware modules commonly available, with
|
||||
connectors at the top and bottom of the PCB, available from many sources.
|
||||
*/
|
||||
#define USE_GENERIC_HW 0
|
||||
|
||||
/**
|
||||
\def USE_ICSTATION_HW
|
||||
Set to 1 to use ICStation DIY hardware module kits available from
|
||||
http://www.icstation.com/product_info.php?products_id=2609#.UxqVJyxWGHs
|
||||
This hardware must be set up with the input on the RHS.
|
||||
*/
|
||||
#define USE_ICSTATION_HW 0
|
||||
|
||||
/**
|
||||
\def USE_FC16_HW
|
||||
Set to 1 to use FC16 hardware module kits.
|
||||
FC16 modules are similar in format to the ICStation modules but are wired differently.
|
||||
Modules are identified by a FC-16 designation on the PCB
|
||||
*/
|
||||
#define USE_FC16_HW 1
|
||||
|
||||
/**
|
||||
\def USE_OTHER_HW
|
||||
Set to 1 to use other hardware not defined above.
|
||||
Module 0 (Data In) must be set up on the RHS and the CUSTOM hardware defines
|
||||
must be set up in the MD_MAD72xx_lib.h file under for this section, using the HW_Mapper
|
||||
utility to work out what the correct values to use are.
|
||||
*/
|
||||
#define USE_OTHER_HW 0
|
||||
|
||||
/**
|
||||
\def USE_LOCAL_FONT
|
||||
Set to 1 (default) to enable local font in this library and enable
|
||||
loadChar() and related methods. If the library is just used for
|
||||
graphics some FLASH RAM can be saved by not including the code to process
|
||||
font data. The font file is stored in PROGMEM.
|
||||
*/
|
||||
#define USE_LOCAL_FONT 1
|
||||
|
||||
/**
|
||||
\def USE_INDEX_FONT
|
||||
Set to 1 to enable font indexing to speed up font lookups - usually disabled.
|
||||
This will trade off increased stack RAM usage for lookup speed if enabled.
|
||||
When disabled lookups will then become linear searches through PROGMEM.
|
||||
Uses ASCII_INDEX_SIZE elements of uint16_t (512 bytes) if enabled. For most
|
||||
purposes the increase in speed is not needed.
|
||||
|
||||
USE_LOCAL FONT must be enabled for this option to take effect.
|
||||
*/
|
||||
#define USE_INDEX_FONT 0
|
||||
|
||||
// Display parameter constants
|
||||
// Defined values that are used throughout the library to define physical limits
|
||||
#define ROW_SIZE 8 ///< The size in pixels of a row in the device LED matrix array
|
||||
#define COL_SIZE 8 ///< The size in pixels of a column in the device LED matrix array
|
||||
#define MAX_INTENSITY 0xf ///< The maximum intensity value that can be set for a LED array
|
||||
#define MAX_SCANLIMIT 7 ///< The maximum scan limit value that can be set for the devices
|
||||
|
||||
/**
|
||||
* Core object for the MD_MAX72XX library
|
||||
*/
|
||||
class MD_MAX72XX
|
||||
{
|
||||
public:
|
||||
#if USE_LOCAL_FONT
|
||||
/**
|
||||
* Font definition type.
|
||||
*
|
||||
* This type is used in the setFont() method to set the font to be used
|
||||
*/
|
||||
typedef const uint8_t fontType_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Control Request enumerated type.
|
||||
*
|
||||
* This enumerated type is used with the control() method to identify
|
||||
* the control action request.
|
||||
*/
|
||||
enum controlRequest_t
|
||||
{
|
||||
SHUTDOWN = 0, ///< Shut down the MAX72XX. Requires ON/OFF value. Library default is OFF.
|
||||
SCANLIMIT = 1, ///< Set the scan limit for the MAX72XX. Requires numeric value [0..MAX_SCANLIMIT]. Library default is all on.
|
||||
INTENSITY = 2, ///< Set the LED intensity for the MAX72XX. Requires numeric value [0..MAX_INTENSITY]. LIbrary default is MAX_INTENSITY/2.
|
||||
TEST = 3, ///< Set the MAX72XX in test mode. Requires ON/OFF value. Library default is OFF.
|
||||
DECODE = 4, ///< Set the MAX72XX 7 segment decode mode. Requires ON/OFF value. Library default is OFF.
|
||||
UPDATE = 10, ///< Enable or disable auto updates of the devices from the library. Requires ON/OFF value. Library default is ON.
|
||||
WRAPAROUND = 11 ///< Enable or disable wraparound when shifting (circular buffer). Requires ON/OFF value. Library default is OFF.
|
||||
};
|
||||
|
||||
/**
|
||||
* Control Value enumerated type.
|
||||
*
|
||||
* This enumerated type is used with the control() method as the
|
||||
* ON/OFF value for a control request. Other values may be used
|
||||
* if numeric data is required.
|
||||
*/
|
||||
enum controlValue_t
|
||||
{
|
||||
OFF = 0, ///< General OFF status request
|
||||
ON = 1 ///< General ON status request
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformation Types enumerated type.
|
||||
*
|
||||
* This enumerated type is used in the transform() methods to identify a
|
||||
* specific transformation of the display data in the device buffers.
|
||||
*/
|
||||
enum transformType_t
|
||||
{
|
||||
TSL, ///< Transform Shift Left one pixel element
|
||||
TSR, ///< Transform Shift Right one pixel element
|
||||
TSU, ///< Transform Shift Up one pixel element
|
||||
TSD, ///< Transform Shift Down one pixel element
|
||||
TFLR, ///< Transform Flip Left to Right
|
||||
TFUD, ///< Transform Flip Up to Down
|
||||
TRC, ///< Transform Rotate Clockwise 90 degrees
|
||||
TINV ///< Transform INVert (pixels inverted)
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor - arbitrary digital interface.
|
||||
*
|
||||
* Instantiate a new instance of the class. The parameters passed are used to
|
||||
* connect the software to the hardware. Multiple instances may co-exist
|
||||
* but they should not share the same hardware CS pin (SPI interface).
|
||||
*
|
||||
* \param dataPin output on the Arduino where data gets shifted out.
|
||||
* \param clkPin output for the clock signal.
|
||||
* \param csPin output for selecting the device.
|
||||
* \param numDevices number of devices connected. Default is 1 if not supplied.
|
||||
* Memory for device buffers is dynamically allocated based
|
||||
* on this parameter.
|
||||
*/
|
||||
MD_MAX72XX(uint8_t dataPin, uint8_t clkPin, uint8_t csPin, uint8_t numDevices=1);
|
||||
|
||||
/**
|
||||
* Class Constructor - SPI hardware interface.
|
||||
*
|
||||
* Instantiate a new instance of the class. The parameters passed are used to
|
||||
* connect the software to the hardware. Multiple instances may co-exist
|
||||
* but they should not share the same hardware CS pin (SPI interface).
|
||||
* The dataPin and the clockPin are defined by the Arduino hardware definition
|
||||
* (SPI MOSI and SCK signals).
|
||||
*
|
||||
* \param csPin output for selecting the device.
|
||||
* \param numDevices number of devices connected. Default is 1 if not supplied.
|
||||
* Memory for device buffers is dynamically allocated based
|
||||
* on this parameter.
|
||||
*/
|
||||
MD_MAX72XX(uint8_t csPin, uint8_t numDevices=1);
|
||||
|
||||
/**
|
||||
* Initialize the object.
|
||||
*
|
||||
* Initialise the object data. This needs to be called during setup() to initialise new
|
||||
* data for the class that cannot be done during the object creation.
|
||||
*
|
||||
* The LED hardware is initialized to the middle intensity value, all rows showing,
|
||||
* and all LEDs cleared (off). Test, shutdown and decode modes are off. Display updates
|
||||
* are on and wraparound is off.
|
||||
*/
|
||||
void begin(void);
|
||||
|
||||
/**
|
||||
* Class Destructor.
|
||||
*
|
||||
* Released allocated memory and does the necessary to clean up once the object is
|
||||
* no longer required.
|
||||
*/
|
||||
~MD_MAX72XX();
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for object and hardware control.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Set the control status of the specified parameter for the specified device.
|
||||
*
|
||||
* The device has a number of control parameters that can be set through this method.
|
||||
* The type of control action required is passed through the mode parameter and
|
||||
* should be one of the control actions defined by controlRequest_t. The value that
|
||||
* needs to be supplied on the control action required is one of the defined
|
||||
* actions in controlValue_t or a numeric parameter suitable for the control action.
|
||||
*
|
||||
* \param dev address of the device to control [0..getDeviceCount()-1].
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool control(uint8_t dev, controlRequest_t mode, int value);
|
||||
|
||||
/**
|
||||
* Set the control status of the specified parameter for all devices.
|
||||
*
|
||||
* Invokes the control function for each device in turn. as this is a wrapper for the
|
||||
* control(startDev, endDev, ...) methods, see the documentation for that method.
|
||||
*
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return No return value.
|
||||
*/
|
||||
inline void control(controlRequest_t mode, int value) { control(0, getDeviceCount()-1, mode, value); };
|
||||
|
||||
/**
|
||||
* Set the control status of the specified parameter for contiguous subset of devices.
|
||||
*
|
||||
* Invokes the control function for each device in turn for the devices in the subset.
|
||||
* See documentation for the control() method.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool control(uint8_t startDev, uint8_t endDev, controlRequest_t mode, int value);
|
||||
|
||||
/**
|
||||
* Gets the number of devices attached to this class instance.
|
||||
*
|
||||
* \return uint8_t representing the number of devices attached to this object.
|
||||
*/
|
||||
uint8_t getDeviceCount(void) { return(_maxDevices); };
|
||||
|
||||
/**
|
||||
* Gets the maximum number of columns for devices attached to this class instance.
|
||||
*
|
||||
* \return uint16_t representing the number of columns.
|
||||
*/
|
||||
uint16_t getColumnCount(void) { return(_maxDevices*COL_SIZE); };
|
||||
|
||||
/**
|
||||
* Set the Shift Data In callback function.
|
||||
*
|
||||
* The callback function is called from the library when a transform shift left
|
||||
* or shift right operation is executed and the library needs to obtain data for
|
||||
* the end element of the shift (ie, conceptually this is the new data that is
|
||||
* shifted 'into' the display). The callback function is invoked when
|
||||
* - WRAPAROUND is not active, as the data would automatically supplied within the library.
|
||||
* - the call to transform() is global (ie, not for an individual buffer).
|
||||
*
|
||||
* The callback function takes 2 parameters:
|
||||
* - the device number requesting the data [0..getDeviceCount()-1]
|
||||
* - one of the transformation types in transformType_t) that tells the callback function
|
||||
* what shift is being performed
|
||||
* The return value is the data for the column to be shifted into the display.
|
||||
*
|
||||
* \param cb the address of the function to be called from the library.
|
||||
* \return No return data
|
||||
*/
|
||||
void setShiftDataInCallback(uint8_t (*cb)(uint8_t dev, transformType_t t)) { _cbShiftDataIn = cb; };
|
||||
|
||||
/**
|
||||
* Set the Shift Data Out callback function.
|
||||
*
|
||||
* The callback function is called from the library when a transform shift left
|
||||
* or shift right operation is executed and the library is about to discard the data for
|
||||
* the first element of the shift (ie, conceptually this is the data that 'falls' off
|
||||
* the front end of the scrolling display). The callback function is invoked when
|
||||
* - WRAPAROUND is not active, as the data would automatically supplied to the tail end.
|
||||
* - the call to transform() is global (ie, not for an individual buffer).
|
||||
*
|
||||
* The callback function is with supplied 3 parameters, with no return value required:
|
||||
* - the device number that is the source of the data [0..getDeviceCount()-1]
|
||||
* - one of the transformation types transformType_t that tells the callback
|
||||
* function the type of shifting being executed
|
||||
* - the data for the column being shifted out
|
||||
*
|
||||
* \param cb the address of the function to be called from the library.
|
||||
* \return No return data
|
||||
*/
|
||||
void setShiftDataOutCallback(void (*cb)(uint8_t dev, transformType_t t, uint8_t colData)) { _cbShiftDataOut = cb; };
|
||||
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for graphics and bitmap related abstraction.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Clear all the display data on all the display devices.
|
||||
*
|
||||
* \return No return value.
|
||||
*/
|
||||
inline void clear(void) { clear(0, getDeviceCount()-1); };
|
||||
|
||||
/**
|
||||
* Clear all the display data on a subset of devices.
|
||||
*
|
||||
* endDev must be greater than or equal to startDev.
|
||||
*
|
||||
* \param startDev the first device to clear [0..getDeviceCount()-1]
|
||||
* \param endDev the last device to clear [0..getDeviceCount()-1]
|
||||
* \return No return value.
|
||||
*/
|
||||
void clear(uint8_t startDev, uint8_t endDev);
|
||||
|
||||
/**
|
||||
* Draw a line between two points on the display
|
||||
*
|
||||
* Draw a line between the specified points. The LED will be turned on or
|
||||
* off depending on the value supplied. The column number will be dereferenced
|
||||
* into the device and column within the device, allowing the LEDs to be treated
|
||||
* as a continuous pixel field.
|
||||
*
|
||||
* \param r1 starting row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c1 starting column coordinate for the point [0..getColumnCount()-1].
|
||||
* \param r2 ending row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c2 ending column coordinate for the point [0..getColumnCount())-1].
|
||||
* \param state true - switch on; false - switch off.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool drawLine(uint8_t r1, uint16_t c1, uint8_t r2, uint16_t c2, bool state);
|
||||
|
||||
/**
|
||||
* Load a bitmap from the display buffers to a user buffer.
|
||||
*
|
||||
* Allows the calling program to read bitmaps (characters or graphic)
|
||||
* elements from the library display buffers. The data buffer
|
||||
* pointer should be a block of uint8_t data of size elements that will
|
||||
* contain the returned data.
|
||||
*
|
||||
* \param col address of the display column [0..getColumnCount()-1].
|
||||
* \param size number of columns of data to return.
|
||||
* \param *pd Pointer to a data buffer [0..size-1].
|
||||
* \return false if parameter errors, true otherwise. If true, data will be in the buffer at *pd.
|
||||
*/
|
||||
bool getBuffer(uint16_t col, uint8_t size, uint8_t *pd);
|
||||
|
||||
/**
|
||||
* Get the LEDS status for the specified column.
|
||||
*
|
||||
* This method operates on a specific buffer
|
||||
*
|
||||
* This method operates on one column, getting the bit field value of
|
||||
* the LEDs in the column. The column is referenced with the absolute column
|
||||
* number (ie, the device number is inferred from the column).
|
||||
*
|
||||
* \param c column which is to be set [0..getColumnCount()-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getColumn(uint8_t c) { return getColumn((c / COL_SIZE), c % COL_SIZE); };
|
||||
|
||||
/**
|
||||
* Get the status of a single LED, addressed as a pixel.
|
||||
*
|
||||
* The method will get the status of a specific LED element based on its
|
||||
* coordinate position. The column number is dereferenced into the device
|
||||
* and column within the device, allowing the LEDs to be treated as a
|
||||
* continuous pixel field.
|
||||
*
|
||||
* \param r row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c column coordinate for the point [0..getColumnCount()-1].
|
||||
* \return true if LED is on, false if off or parameter errors.
|
||||
*/
|
||||
bool getPoint(uint8_t r, uint16_t c);
|
||||
|
||||
/**
|
||||
* Load a bitfield from the user buffer to a display buffer.
|
||||
*
|
||||
* Allows the calling program to define bitmaps (characters or graphic)
|
||||
* elements and pass them to the library for display. The data buffer
|
||||
* pointer should be a block of uint8_t data of size elements that define
|
||||
* the bitmap.
|
||||
*
|
||||
* \param col address of the display column [0..getColumnCount()-1].
|
||||
* \param size number of columns of data following.
|
||||
* \param *pd Pointer to a data buffer [0..size-1].
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setBuffer(uint16_t col, uint8_t size, uint8_t *pd);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a specific column to a new state.
|
||||
*
|
||||
* This method operates on one column, setting the value of the LEDs in
|
||||
* the column to the specified value bitfield. The column is
|
||||
* referenced with the absolute column number (ie, the device number is
|
||||
* inferred from the column). The method is useful for drawing vertical
|
||||
* lines and patterns when the display is being treated as a pixel field.
|
||||
* The least significant bit of the value is the lowest row number.
|
||||
*
|
||||
* \param c column which is to be set [0..getColumnCount()-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setColumn(uint8_t c, uint8_t value) { return setColumn((c / COL_SIZE), c % COL_SIZE, value); };
|
||||
|
||||
/**
|
||||
* Set the status of a single LED, addressed as a pixel.
|
||||
*
|
||||
* The method will set the value of a specific LED element based on its
|
||||
* coordinate position. The LED will be turned on or off depending on the
|
||||
* value supplied. The column number is dereferenced into the device and
|
||||
* column within the device, allowing the LEDs to be treated as a
|
||||
* continuous pixel field.
|
||||
*
|
||||
* \param r row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c column coordinate for the point [0..getColumnCount()-1].
|
||||
* \param state true - switch on; false - switch off.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setPoint(uint8_t r, uint16_t c, bool state);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state on all devices.
|
||||
*
|
||||
* This method operates on all devices, setting the value of the LEDs in
|
||||
* the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across on the entire display.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED on each device.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
inline bool setRow(uint8_t r, uint8_t value) { return setRow(0, getDeviceCount()-1, r, value); };
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state on contiguous subset of devices.
|
||||
*
|
||||
* This method operates on a contiguous subset of devices, setting the value
|
||||
* of the LEDs in the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across specific devices only.
|
||||
* endDev must be greater than or equal to startDev.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED on each device.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setRow(uint8_t startDev, uint8_t endDev, uint8_t r, uint8_t value);
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in all the devices.
|
||||
*
|
||||
* The buffers for all devices can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is carried across
|
||||
* device boundaries (ie, there is overflow to an adjacent devices if appropriate).
|
||||
*
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
inline bool transform(transformType_t ttype) { return transform(0, getDeviceCount()-1, ttype); };
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in contiguous subset of devices.
|
||||
*
|
||||
* The buffers for all devices in the subset can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is carried across
|
||||
* device boundaries (ie, there is overflow to an adjacent devices if appropriate).
|
||||
* endDev must be greater than or equal to startDev.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool transform(uint8_t startDev, uint8_t endDev, transformType_t ttype);
|
||||
|
||||
/**
|
||||
* Turn auto display updates on or off.
|
||||
*
|
||||
* Turn auto updates on and off, as required. When auto updates are turned OFF the
|
||||
* display will not update after each operation. Display updates can be forced at any
|
||||
* time using using a call to update() with no parameters.
|
||||
*
|
||||
* This function is a convenience wrapper for the more general control() function call.
|
||||
*
|
||||
* \param mode one of the types in controlValue_t (ON/OFF).
|
||||
* \return No return value.
|
||||
*/
|
||||
void update(controlValue_t mode) { control(UPDATE, mode); };
|
||||
|
||||
/**
|
||||
* Force an update of all devices
|
||||
*
|
||||
* Used when auto updates have been turned off through the control
|
||||
* method. This will force all buffered changes to be written to
|
||||
* all the connected devices.
|
||||
*
|
||||
* \return no return value.
|
||||
*/
|
||||
void update(void) { flushBufferAll(); };
|
||||
|
||||
/**
|
||||
* Turn display wraparound on or off.
|
||||
*
|
||||
* When shifting left or right, up or down, the outermost edge is normally lost and a blank
|
||||
* row or column inserted on the opposite side. If this options is enabled, the edge is wrapped
|
||||
* around to the opposite side.
|
||||
*
|
||||
* This function is a convenience wrapper for the more general control() function call.
|
||||
*
|
||||
* \param mode one of the types in controlValue_t (ON/OFF).
|
||||
* \return No return value.
|
||||
*/
|
||||
void wraparound(controlValue_t mode) { control(WRAPAROUND, mode); };
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for managing specific devices or display buffers.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Clear all display data in the specified buffer.
|
||||
*
|
||||
* \param buf address of the buffer to clear [0..getDeviceCount()-1].
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool clear(uint8_t buf);
|
||||
|
||||
/**
|
||||
* Get the state of the LEDs in a specific column.
|
||||
*
|
||||
* This method operates on the specific buffer, returning the bit field value of
|
||||
* the LEDs in the column.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param c column which is to be set [0..COL_SIZE-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getColumn(uint8_t buf, uint8_t c);
|
||||
|
||||
/**
|
||||
* Get the state of the LEDs in a specified row.
|
||||
*
|
||||
* This method operates on the specific buffer, returning the bit field value of
|
||||
* the LEDs in the row.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getRow(uint8_t buf, uint8_t r);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a column to a new state.
|
||||
*
|
||||
* This method operates on a specific buffer, setting the value of the LEDs in
|
||||
* the column to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines vertically on the display device.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param c column which is to be set [0..COL_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setColumn(uint8_t buf, uint8_t c, uint8_t value);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state.
|
||||
*
|
||||
* This method operates on a specific device, setting the value of the LEDs in
|
||||
* the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across the display device.
|
||||
* The least significant bit of the value is the lowest row number.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 within this byte will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setRow(uint8_t buf, uint8_t r, uint8_t value);
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in the specified device.
|
||||
*
|
||||
* The buffer for one device can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is limited to the
|
||||
* nominated device buffer only (ie, there is no overflow to an adjacent device).
|
||||
*
|
||||
* \param buf address of the display [0..getBufferCount()-1].
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool transform(uint8_t buf, transformType_t ttype);
|
||||
|
||||
/**
|
||||
* Force an update of one buffer.
|
||||
*
|
||||
* Used when auto updates have been turned off through the control()
|
||||
* method. This will force all buffered display changes to be written to
|
||||
* the specified device at the same time.
|
||||
* Note that control() messages are not buffered but cause immediate action.
|
||||
*
|
||||
* \param buf address of the display [0..getBufferCount()-1].
|
||||
* \return No return value.
|
||||
*/
|
||||
void update(uint8_t buf) { flushBuffer(buf); };
|
||||
/** @} */
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for font and characters.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Load a character from the font data into a user buffer.
|
||||
*
|
||||
* Copy the bitmap for a library font character (current font set by setFont()) and
|
||||
* return it in the data area passed by the user. If the user buffer is not large
|
||||
* enough, only the first size elements are copied to the buffer.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param c the character to retrieve.
|
||||
* \param size the size of the user buffer in unit8_t units.
|
||||
* \param buf address of the user buffer supplied.
|
||||
* \return width (in columns) of the character, 0 if parameter errors.
|
||||
*/
|
||||
uint8_t getChar(uint8_t c, uint8_t size, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Load a character from the font data starting at a specific column.
|
||||
*
|
||||
* Load a character from the font table directly into the display at the column
|
||||
* specified. The currently selected font table is used as the source.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param col column of the display in the range accepted [0..getColumnCount()-1].
|
||||
* \param c the character to display.
|
||||
* \return width (in columns) of the character, 0 if parameter errors.
|
||||
*/
|
||||
uint8_t setChar(uint16_t col, uint8_t c);
|
||||
|
||||
/**
|
||||
* Set the current font table.
|
||||
*
|
||||
* Font data is stored in PROGMEM, in the format described elsewhere in the
|
||||
* documentation. All characters retrieved or used after this call will use
|
||||
* the nominated font (default or user defined). To specify a user defined
|
||||
* character set, pass the PROGMEM address of the font table. Passing a nullptr
|
||||
* resets the font table to the library default table.
|
||||
*
|
||||
* This function also causes the font index table to be recreated if the
|
||||
* library defined value USE_INDEX_TABLE is set to 1.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param f fontType_t pointer to the table of font data in PROGMEM or nullptr.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setFont(fontType_t *f);
|
||||
|
||||
/**
|
||||
* Get the maximum width character for the font.
|
||||
*
|
||||
* Returns the number of columns for the widest character in the currently
|
||||
* selected font table. Useful to allocated buffers of the right size before
|
||||
* loading characters from the font table.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \return number of columns (width) for the widest character.
|
||||
*/
|
||||
uint8_t getMaxFontWidth(void);
|
||||
|
||||
/**
|
||||
* Get the pointer to current font table.
|
||||
*
|
||||
* Returns the pointer to the current font table. Useful if user code needs
|
||||
* to replace the current font temporarily and then restore previous font.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \return pointer to the start of the font table in PROGMEM.
|
||||
*/
|
||||
fontType_t *getFont(void) { return(_fontData); };
|
||||
#endif // USE_LOCAL_FONT
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dig[ROW_SIZE]; // data for each digit of the MAX72xx (DIG0-DIG7)
|
||||
uint8_t changed; // one bit for each digit changed ('dirty bit')
|
||||
} deviceInfo_t;
|
||||
|
||||
// SPI interface data
|
||||
uint8_t _dataPin; // DATA is shifted out of this pin ...
|
||||
uint8_t _clkPin; // ... signaled by a CLOCK on this pin ...
|
||||
uint8_t _csPin; // ... and LOADed when the chip select pin is driven HIGH to LOW
|
||||
bool _hardwareSPI; // true if SPI interface is the hardware interface
|
||||
|
||||
// Device buffer data
|
||||
uint8_t _maxDevices; // maximum number of devices in use
|
||||
deviceInfo_t* _matrix;// the current status of the LED matrix (buffers)
|
||||
uint8_t* _spiData; // data buffer for writing to SPI interface
|
||||
|
||||
// User callback function for shifting operations
|
||||
uint8_t (*_cbShiftDataIn)(uint8_t dev, transformType_t t);
|
||||
void (*_cbShiftDataOut)(uint8_t dev, transformType_t t, uint8_t colData);
|
||||
|
||||
// Control data for the library
|
||||
bool _updateEnabled; // update the display when this is true, suspend otherwise
|
||||
bool _wrapAround; // when shifting, wrap left to right and vice versa (circular buffer)
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
// Font related data
|
||||
fontType_t *_fontData; // pointer to the current font data being used
|
||||
uint16_t *_fontIndex; // font index for faster access to font table offsets
|
||||
|
||||
uint16_t getFontCharOffset(uint8_t c); // find the character in the font data
|
||||
void buildFontIndex(void); // build a font index
|
||||
#endif
|
||||
|
||||
// Private functions
|
||||
void spiSend(void); // do the actual physical communications task
|
||||
void spiClearBuffer(void); // clear the SPI send buffer
|
||||
void controlHardware(uint8_t dev, controlRequest_t mode, int value); // set hardware control commands
|
||||
void controlLibrary(controlRequest_t mode, int value); // set internal control commands
|
||||
|
||||
void flushBuffer(uint8_t buf);// determine what needs to be sent for one device and transmit
|
||||
void flushBufferAll(); // determine what needs to be sent for all devices and transmit
|
||||
|
||||
uint8_t bitReverse(uint8_t b); // reverse the order of bits in the byte
|
||||
bool transformBuffer(uint8_t buf, transformType_t ttype); // internal transform function
|
||||
|
||||
bool copyRow(uint8_t buf, uint8_t rSrc, uint8_t rDest); // copy a row from Src to Dest
|
||||
bool copyColumn(uint8_t buf, uint8_t cSrc, uint8_t cDest);// copy a row from Src to Dest
|
||||
};
|
||||
|
||||
#endif
|
||||
373
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_buf.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
This file contains methods that act on display buffers.
|
||||
|
||||
Copyright (C) 2012-13 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements buffer related methods
|
||||
*/
|
||||
|
||||
bool MD_MAX72XX::clear(uint8_t buf)
|
||||
{
|
||||
if (buf > LAST_BUFFER)
|
||||
return(false);
|
||||
|
||||
memset(_matrix[buf].dig, 0, sizeof(_matrix[buf].dig));
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::bitReverse(uint8_t b)
|
||||
// Reverse the order of bits within a byte.
|
||||
// Returns the reversed byte value.
|
||||
{
|
||||
b = ((b & 0xf0) >> 4) | ((b & 0x0f) << 4);
|
||||
b = ((b & 0xcc) >> 2) | ((b & 0x33) << 2);
|
||||
b = ((b & 0xaa) >> 1) | ((b & 0x55) << 1);
|
||||
|
||||
return(b);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::copyColumn(uint8_t buf, uint8_t cSrc, uint8_t cDest)
|
||||
#else
|
||||
bool MD_MAX72XX::copyRow(uint8_t buf, uint8_t cSrc, uint8_t cDest)
|
||||
#endif
|
||||
// Src and Dest are in pixel coordinates.
|
||||
// if we are just copying rows there is no need to repackage any data
|
||||
{
|
||||
uint8_t maskSrc = 1 << HW_COL(cSrc); // which column of bits is the column data
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ncopyCol: (", buf);
|
||||
#else
|
||||
PRINT("\ncopyRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", cSrc);
|
||||
PRINT(", ", cDest);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (cSrc >= COL_SIZE) || (cDest >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (_matrix[buf].dig[i] & maskSrc)
|
||||
bitSet(_matrix[buf].dig[i], HW_COL(cDest));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[i], HW_COL(cDest));
|
||||
}
|
||||
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
uint8_t MD_MAX72XX::getColumn(uint8_t buf, uint8_t c)
|
||||
#else
|
||||
uint8_t MD_MAX72XX::getRow(uint8_t buf, uint8_t c)
|
||||
#endif
|
||||
// c is in pixel coordinates and the return value must be in pixel coordinate order
|
||||
{
|
||||
uint8_t mask = 1 << HW_COL(c); // which column of bits is the column data
|
||||
uint8_t value = 0; // assembles data to be returned to caller
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ngetCol: (", buf);
|
||||
#else
|
||||
PRINT("\ngetRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", c);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (c >= COL_SIZE))
|
||||
return(0);
|
||||
|
||||
PRINTX("mask 0x", mask);
|
||||
|
||||
// for each digit data, pull out the column/row bit and place
|
||||
// it in value. The loop creates the data in pixel coordinate order as it goes.
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (_matrix[buf].dig[HW_ROW(i)] & mask)
|
||||
bitSet(value, i);
|
||||
}
|
||||
|
||||
PRINTX(" value 0x", value);
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::setColumn(uint8_t buf, uint8_t c, uint8_t value)
|
||||
#else
|
||||
bool MD_MAX72XX::setRow(uint8_t buf, uint8_t c, uint8_t value)
|
||||
#endif
|
||||
// c and value are in pixel coordinate order
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\nsetCol: (", buf);
|
||||
#else
|
||||
PRINT("\nsetRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", c);
|
||||
PRINTX(") 0x", value);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (value & (1 << i)) // mask off next column value passed in and set it in the dig buffer
|
||||
bitSet(_matrix[buf].dig[HW_ROW(i)], HW_COL(c));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[HW_ROW(i)], HW_COL(c));
|
||||
}
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::copyRow(uint8_t buf, uint8_t rSrc, uint8_t rDest)
|
||||
#else
|
||||
bool MD_MAX72XX::copyColumn(uint8_t buf, uint8_t rSrc, uint8_t rDest)
|
||||
#endif
|
||||
// Src and Dest are in pixel coordinates.
|
||||
// if we are just copying digits there is no need to repackage any data
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ncopyRow: (", buf);
|
||||
#else
|
||||
PRINT("\ncopyColumn: (", buf);
|
||||
#endif
|
||||
PRINT(", ", rSrc);
|
||||
PRINT(", ", rDest);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (rSrc >= ROW_SIZE) || (rDest >= ROW_SIZE))
|
||||
return(false);
|
||||
|
||||
_matrix[buf].dig[HW_ROW(rDest)] = _matrix[buf].dig[HW_ROW(rSrc)];
|
||||
bitSet(_matrix[buf].changed, HW_ROW(rDest));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
uint8_t MD_MAX72XX::getRow(uint8_t buf, uint8_t r)
|
||||
#else
|
||||
uint8_t MD_MAX72XX::getColumn(uint8_t buf, uint8_t r)
|
||||
#endif
|
||||
// r is in pixel coordinates for this buffer
|
||||
// returned value is in pixel coordinates
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ngetRow: (", buf);
|
||||
#else
|
||||
PRINT("\ngetCol: (", buf);
|
||||
#endif
|
||||
PRINT(", ", r);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE))
|
||||
return(0);
|
||||
|
||||
uint8_t value = HW_REV_COLS ? bitReverse(_matrix[buf].dig[HW_ROW(r)]) : _matrix[buf].dig[HW_ROW(r)];
|
||||
|
||||
PRINTX("0x", value);
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::setRow(uint8_t buf, uint8_t r, uint8_t value)
|
||||
#else
|
||||
bool MD_MAX72XX::setColumn(uint8_t buf, uint8_t r, uint8_t value)
|
||||
#endif
|
||||
// r and value are in pixel coordinates
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\nsetRow: (", buf);
|
||||
#else
|
||||
PRINT("\nsetCol: (", buf);
|
||||
#endif
|
||||
PRINT(", ", r);
|
||||
|
||||
PRINTX(") 0x", value);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE))
|
||||
return(false);
|
||||
|
||||
_matrix[buf].dig[HW_ROW(r)] = HW_REV_COLS ? bitReverse(value) : value;
|
||||
bitSet(_matrix[buf].changed, HW_ROW(r));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool MD_MAX72XX::transform(uint8_t buf, transformType_t ttype)
|
||||
{
|
||||
if (buf > LAST_BUFFER)
|
||||
return(false);
|
||||
|
||||
if (!transformBuffer(buf, ttype))
|
||||
return(false);
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::transformBuffer(uint8_t buf, transformType_t ttype)
|
||||
{
|
||||
uint8_t t[ROW_SIZE];
|
||||
|
||||
switch (ttype)
|
||||
{
|
||||
//--------------
|
||||
case TSL: // Transform Shift Left one pixel element
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
#if HW_REV_COLS
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#else
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#endif
|
||||
#else
|
||||
#warning HW_DIG_ROWS=0
|
||||
for (uint8_t i=ROW_SIZE; i>0; --i)
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[i-1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSR: // Transform Shift Right one pixel element
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
#if HW_REV_COLS
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#else
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#endif
|
||||
#else
|
||||
for (uint8_t i=0; i<ROW_SIZE-1; i++)
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[i+1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSU: // Transform Shift Up one pixel element
|
||||
if (_wrapAround) // save the first row or a zero row
|
||||
t[0] = getRow(buf, 0);
|
||||
else
|
||||
t[0] = 0;
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE-1; i++)
|
||||
copyRow(buf, i+1, i);
|
||||
#else
|
||||
for (int8_t i=ROW_SIZE-1; i>=0; i--)
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#endif
|
||||
setRow(buf, ROW_SIZE-1, t[0]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSD: // Transform Shift Down one pixel element
|
||||
if (_wrapAround) // save the last row or a zero row
|
||||
t[0] = getRow(buf, ROW_SIZE-1);
|
||||
else
|
||||
t[0] = 0;
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=ROW_SIZE; i>0; --i)
|
||||
copyRow(buf, i-1, i);
|
||||
#else
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#endif
|
||||
setRow(buf, 0, t[0]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
#if HW_DIG_ROWS
|
||||
case TFLR: // Transform Flip Left to Right
|
||||
#else
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
#endif
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] = bitReverse(_matrix[buf].dig[i]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
#if HW_DIG_ROWS
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
#else
|
||||
case TFLR: // Transform Flip Left to Right
|
||||
#endif
|
||||
for (uint8_t i=0; i<ROW_SIZE/2; i++)
|
||||
{
|
||||
uint8_t t = _matrix[buf].dig[i];
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[ROW_SIZE-i-1];
|
||||
_matrix[buf].dig[ROW_SIZE-i-1] = t;
|
||||
}
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TRC: // Transform Rotate Clockwise
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
t[i] = getColumn(buf, COL_SIZE-1-i);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
setRow(buf, i, t[i]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TINV: // Transform INVert
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] = ~_matrix[buf].dig[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
return(false);
|
||||
}
|
||||
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
return(true);
|
||||
}
|
||||
427
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_font.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains methods that work with the fonts and characters defined in the library
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements font definition and methods
|
||||
*/
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
// Local font handling functions if the option is enabled
|
||||
|
||||
void MD_MAX72XX::buildFontIndex(void)
|
||||
{
|
||||
uint16_t offset = 0;
|
||||
|
||||
if (_fontIndex == nullptr)
|
||||
return;
|
||||
|
||||
PRINTS("\nBuilding font index");
|
||||
for (uint16_t i=0; i<ASCII_INDEX_SIZE; i++)
|
||||
{
|
||||
_fontIndex[i] = offset;
|
||||
PRINT("\nASCII '", i);
|
||||
PRINT("' offset ", _fontIndex[i]);
|
||||
offset += pgm_read_byte(_fontData+offset);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::getMaxFontWidth(void)
|
||||
{
|
||||
uint8_t max = 0;
|
||||
uint8_t charWidth;
|
||||
uint16_t offset = 0;
|
||||
|
||||
PRINTS("\nFinding max font width");
|
||||
if (_fontData != nullptr)
|
||||
{
|
||||
for (uint16_t i = 0; i < ASCII_INDEX_SIZE; i++)
|
||||
{
|
||||
charWidth = pgm_read_byte(_fontData + offset);
|
||||
/*
|
||||
PRINT("\nASCII '", i);
|
||||
PRINT("' offset ", offset);
|
||||
PRINT("' width ", charWidth);
|
||||
*/
|
||||
if (charWidth > max)
|
||||
{
|
||||
max = charWidth;
|
||||
PRINT(":", max);
|
||||
}
|
||||
offset += charWidth; // skip character data
|
||||
offset++; // skip size byte
|
||||
}
|
||||
}
|
||||
PRINT(" max ", max);
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
uint16_t MD_MAX72XX::getFontCharOffset(uint8_t c)
|
||||
{
|
||||
PRINT("\nfontOffset ASCII ", c);
|
||||
|
||||
if (_fontIndex != nullptr)
|
||||
{
|
||||
PRINTS(" from Table");
|
||||
return(_fontIndex[c]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTS(" by Search ");
|
||||
|
||||
uint16_t offset = 0;
|
||||
|
||||
for (uint8_t i=0; i<c; i++)
|
||||
{
|
||||
PRINTS(".");
|
||||
offset += pgm_read_byte(_fontData+offset);
|
||||
offset++; // skip size byte we used above
|
||||
}
|
||||
PRINT(" searched offset ", offset);
|
||||
|
||||
return(offset);
|
||||
}
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setFont(fontType_t *f)
|
||||
{
|
||||
_fontData = (f == nullptr ? _sysfont_var : f);
|
||||
|
||||
buildFontIndex();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::getChar(uint8_t c, uint8_t size, uint8_t *buf)
|
||||
{
|
||||
PRINT("\ngetChar: '", (char)c);
|
||||
PRINT("' ASC ", c);
|
||||
PRINT(" - bufsize ", size);
|
||||
|
||||
if (buf == nullptr)
|
||||
return(0);
|
||||
|
||||
uint16_t offset = getFontCharOffset(c);
|
||||
size = min(size, pgm_read_byte(_fontData+offset));
|
||||
|
||||
offset++; // skip the size byte
|
||||
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
*buf++ = pgm_read_byte(_fontData+offset+i);
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::setChar(uint16_t col, uint8_t c)
|
||||
{
|
||||
PRINT("\nsetChar: '", c);
|
||||
PRINT("' column ", col);
|
||||
boolean b = _updateEnabled;
|
||||
|
||||
uint16_t offset = getFontCharOffset(c);
|
||||
uint8_t size = pgm_read_byte(_fontData+offset);
|
||||
|
||||
offset++; // skip the size byte
|
||||
|
||||
_updateEnabled = false;
|
||||
for (int8_t i=0; i<size; i++)
|
||||
{
|
||||
uint8_t colData = pgm_read_byte(_fontData+offset+i);
|
||||
setColumn(col--, colData);
|
||||
}
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
// Standard font - variable spacing
|
||||
MD_MAX72XX::fontType_t PROGMEM _sysfont_var[] =
|
||||
{
|
||||
0, // 0 - 'Empty Cell'
|
||||
5, 0x3e, 0x5b, 0x4f, 0x5b, 0x3e, // 1 - 'Sad Smiley'
|
||||
5, 0x3e, 0x6b, 0x4f, 0x6b, 0x3e, // 2 - 'Happy Smiley'
|
||||
5, 0x1c, 0x3e, 0x7c, 0x3e, 0x1c, // 3 - 'Heart'
|
||||
5, 0x18, 0x3c, 0x7e, 0x3c, 0x18, // 4 - 'Diamond'
|
||||
5, 0x1c, 0x57, 0x7d, 0x57, 0x1c, // 5 - 'Clubs'
|
||||
5, 0x1c, 0x5e, 0x7f, 0x5e, 0x1c, // 6 - 'Spades'
|
||||
4, 0x00, 0x18, 0x3c, 0x18, // 7 - 'Bullet Point'
|
||||
5, 0xff, 0xe7, 0xc3, 0xe7, 0xff, // 8 - 'Rev Bullet Point'
|
||||
4, 0x00, 0x18, 0x24, 0x18, // 9 - 'Hollow Bullet Point'
|
||||
5, 0xff, 0xe7, 0xdb, 0xe7, 0xff, // 10 - 'Rev Hollow BP'
|
||||
5, 0x30, 0x48, 0x3a, 0x06, 0x0e, // 11 - 'Male'
|
||||
5, 0x26, 0x29, 0x79, 0x29, 0x26, // 12 - 'Female'
|
||||
5, 0x40, 0x7f, 0x05, 0x05, 0x07, // 13 - 'Music Note 1'
|
||||
5, 0x40, 0x7f, 0x05, 0x25, 0x3f, // 14 - 'Music Note 2'
|
||||
5, 0x5a, 0x3c, 0xe7, 0x3c, 0x5a, // 15 - 'Snowflake'
|
||||
5, 0x7f, 0x3e, 0x1c, 0x1c, 0x08, // 16 - 'Right Pointer'
|
||||
5, 0x08, 0x1c, 0x1c, 0x3e, 0x7f, // 17 - 'Left Pointer'
|
||||
5, 0x14, 0x22, 0x7f, 0x22, 0x14, // 18 - 'UpDown Arrows'
|
||||
5, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, // 19 - 'Double Exclamation'
|
||||
5, 0x06, 0x09, 0x7f, 0x01, 0x7f, // 20 - 'Paragraph Mark'
|
||||
4, 0x66, 0x89, 0x95, 0x6a, // 21 - 'Section Mark'
|
||||
5, 0x60, 0x60, 0x60, 0x60, 0x60, // 22 - 'Double Underline'
|
||||
5, 0x94, 0xa2, 0xff, 0xa2, 0x94, // 23 - 'UpDown Underlined'
|
||||
5, 0x08, 0x04, 0x7e, 0x04, 0x08, // 24 - 'Up Arrow'
|
||||
5, 0x10, 0x20, 0x7e, 0x20, 0x10, // 25 - 'Down Arrow'
|
||||
5, 0x08, 0x08, 0x2a, 0x1c, 0x08, // 26 - 'Right Arrow'
|
||||
5, 0x08, 0x1c, 0x2a, 0x08, 0x08, // 27 - 'Left Arrow'
|
||||
5, 0x1e, 0x10, 0x10, 0x10, 0x10, // 28 - 'Angled'
|
||||
5, 0x0c, 0x1e, 0x0c, 0x1e, 0x0c, // 29 - 'Squashed #'
|
||||
5, 0x30, 0x38, 0x3e, 0x38, 0x30, // 30 - 'Up Pointer'
|
||||
5, 0x06, 0x0e, 0x3e, 0x0e, 0x06, // 31 - 'Down Pointer'
|
||||
1, 0x00, // 32 - 'Space'
|
||||
1, 0x5f, // 33 - '!'
|
||||
3, 0x07, 0x00, 0x07, // 34 - '"'
|
||||
5, 0x14, 0x7f, 0x14, 0x7f, 0x14, // 35 - '#'
|
||||
5, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // 36 - '$'
|
||||
5, 0x23, 0x13, 0x08, 0x64, 0x62, // 37 - '%'
|
||||
5, 0x36, 0x49, 0x56, 0x20, 0x50, // 38 - '&'
|
||||
3, 0x08, 0x07, 0x03, // 39 - '''
|
||||
3, 0x1c, 0x22, 0x41, // 40 - '('
|
||||
3, 0x41, 0x22, 0x1c, // 41 - ')'
|
||||
5, 0x2a, 0x1c, 0x7f, 0x1c, 0x2a, // 42 - '*'
|
||||
5, 0x08, 0x08, 0x3e, 0x08, 0x08, // 43 - '+'
|
||||
3, 0x80, 0x70, 0x30, // 44 - ','
|
||||
5, 0x08, 0x08, 0x08, 0x08, 0x08, // 45 - '-'
|
||||
2, 0x60, 0x60, // 46 - '.'
|
||||
5, 0x20, 0x10, 0x08, 0x04, 0x02, // 47 - '/'
|
||||
5, 0x3e, 0x51, 0x49, 0x45, 0x3e, // 48 - '0'
|
||||
3, 0x42, 0x7f, 0x40, // 49 - '1'
|
||||
5, 0x72, 0x49, 0x49, 0x49, 0x46, // 50 - '2'
|
||||
5, 0x21, 0x41, 0x49, 0x4d, 0x33, // 51 - '3'
|
||||
5, 0x18, 0x14, 0x12, 0x7f, 0x10, // 52 - '4'
|
||||
5, 0x27, 0x45, 0x45, 0x45, 0x39, // 53 - '5'
|
||||
5, 0x3c, 0x4a, 0x49, 0x49, 0x31, // 54 - '6'
|
||||
5, 0x41, 0x21, 0x11, 0x09, 0x07, // 55 - '7'
|
||||
5, 0x36, 0x49, 0x49, 0x49, 0x36, // 56 - '8'
|
||||
5, 0x46, 0x49, 0x49, 0x29, 0x1e, // 57 - '9'
|
||||
1, 0x14, // 58 - ':'
|
||||
2, 0x80, 0x68, // 59 - ';'
|
||||
4, 0x08, 0x14, 0x22, 0x41, // 60 - '<'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x14, // 61 - '='
|
||||
4, 0x41, 0x22, 0x14, 0x08, // 62 - '>'
|
||||
5, 0x02, 0x01, 0x59, 0x09, 0x06, // 63 - '?'
|
||||
5, 0x3e, 0x41, 0x5d, 0x59, 0x4e, // 64 - '@'
|
||||
5, 0x7c, 0x12, 0x11, 0x12, 0x7c, // 65 - 'A'
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x36, // 66 - 'B'
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x22, // 67 - 'C'
|
||||
5, 0x7f, 0x41, 0x41, 0x41, 0x3e, // 68 - 'D'
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x41, // 69 - 'E'
|
||||
5, 0x7f, 0x09, 0x09, 0x09, 0x01, // 70 - 'F'
|
||||
5, 0x3e, 0x41, 0x41, 0x51, 0x73, // 71 - 'G'
|
||||
5, 0x7f, 0x08, 0x08, 0x08, 0x7f, // 72 - 'H'
|
||||
3, 0x41, 0x7f, 0x41, // 73 - 'I'
|
||||
5, 0x20, 0x40, 0x41, 0x3f, 0x01, // 74 - 'J'
|
||||
5, 0x7f, 0x08, 0x14, 0x22, 0x41, // 75 - 'K'
|
||||
5, 0x7f, 0x40, 0x40, 0x40, 0x40, // 76 - 'L'
|
||||
5, 0x7f, 0x02, 0x1c, 0x02, 0x7f, // 77 - 'M'
|
||||
5, 0x7f, 0x04, 0x08, 0x10, 0x7f, // 78 - 'N'
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x3e, // 79 - 'O'
|
||||
5, 0x7f, 0x09, 0x09, 0x09, 0x06, // 80 - 'P'
|
||||
5, 0x3e, 0x41, 0x51, 0x21, 0x5e, // 81 - 'Q'
|
||||
5, 0x7f, 0x09, 0x19, 0x29, 0x46, // 82 - 'R'
|
||||
5, 0x26, 0x49, 0x49, 0x49, 0x32, // 83 - 'S'
|
||||
5, 0x03, 0x01, 0x7f, 0x01, 0x03, // 84 - 'T'
|
||||
5, 0x3f, 0x40, 0x40, 0x40, 0x3f, // 85 - 'U'
|
||||
5, 0x1f, 0x20, 0x40, 0x20, 0x1f, // 86 - 'V'
|
||||
5, 0x3f, 0x40, 0x38, 0x40, 0x3f, // 87 - 'W'
|
||||
5, 0x63, 0x14, 0x08, 0x14, 0x63, // 88 - 'X'
|
||||
5, 0x03, 0x04, 0x78, 0x04, 0x03, // 89 - 'Y'
|
||||
5, 0x61, 0x59, 0x49, 0x4d, 0x43, // 90 - 'Z'
|
||||
3, 0x7f, 0x41, 0x41, // 91 - '['
|
||||
5, 0x02, 0x04, 0x08, 0x10, 0x20, // 92 - '\'
|
||||
3, 0x41, 0x41, 0x7f, // 93 - ']'
|
||||
5, 0x04, 0x02, 0x01, 0x02, 0x04, // 94 - '^'
|
||||
5, 0x40, 0x40, 0x40, 0x40, 0x40, // 95 - '_'
|
||||
3, 0x03, 0x07, 0x08, // 96 - '`'
|
||||
5, 0x20, 0x54, 0x54, 0x78, 0x40, // 97 - 'a'
|
||||
5, 0x7f, 0x28, 0x44, 0x44, 0x38, // 98 - 'b'
|
||||
5, 0x38, 0x44, 0x44, 0x44, 0x28, // 99 - 'c'
|
||||
5, 0x38, 0x44, 0x44, 0x28, 0x7f, // 100 - 'd'
|
||||
5, 0x38, 0x54, 0x54, 0x54, 0x18, // 101 - 'e'
|
||||
4, 0x08, 0x7e, 0x09, 0x02, // 102 - 'f'
|
||||
5, 0x18, 0xa4, 0xa4, 0x9c, 0x78, // 103 - 'g'
|
||||
5, 0x7f, 0x08, 0x04, 0x04, 0x78, // 104 - 'h'
|
||||
3, 0x44, 0x7d, 0x40, // 105 - 'i'
|
||||
4, 0x40, 0x80, 0x80, 0x7a, // 106 - 'j'
|
||||
4, 0x7f, 0x10, 0x28, 0x44, // 107 - 'k'
|
||||
3, 0x41, 0x7f, 0x40, // 108 - 'l'
|
||||
5, 0x7c, 0x04, 0x78, 0x04, 0x78, // 109 - 'm'
|
||||
5, 0x7c, 0x08, 0x04, 0x04, 0x78, // 110 - 'n'
|
||||
5, 0x38, 0x44, 0x44, 0x44, 0x38, // 111 - 'o'
|
||||
5, 0xfc, 0x18, 0x24, 0x24, 0x18, // 112 - 'p'
|
||||
5, 0x18, 0x24, 0x24, 0x18, 0xfc, // 113 - 'q'
|
||||
5, 0x7c, 0x08, 0x04, 0x04, 0x08, // 114 - 'r'
|
||||
5, 0x48, 0x54, 0x54, 0x54, 0x24, // 115 - 's'
|
||||
4, 0x04, 0x3f, 0x44, 0x24, // 116 - 't'
|
||||
5, 0x3c, 0x40, 0x40, 0x20, 0x7c, // 117 - 'u'
|
||||
5, 0x1c, 0x20, 0x40, 0x20, 0x1c, // 118 - 'v'
|
||||
5, 0x3c, 0x40, 0x30, 0x40, 0x3c, // 119 - 'w'
|
||||
5, 0x44, 0x28, 0x10, 0x28, 0x44, // 120 - 'x'
|
||||
5, 0x4c, 0x90, 0x90, 0x90, 0x7c, // 121 - 'y'
|
||||
5, 0x44, 0x64, 0x54, 0x4c, 0x44, // 122 - 'z'
|
||||
3, 0x08, 0x36, 0x41, // 123 - '{'
|
||||
1, 0x77, // 124 - '|'
|
||||
3, 0x41, 0x36, 0x08, // 125 - '}'
|
||||
5, 0x02, 0x01, 0x02, 0x04, 0x02, // 126 - '~'
|
||||
5, 0x3c, 0x26, 0x23, 0x26, 0x3c, // 127 - 'Hollow Up Arrow'
|
||||
5, 0x1e, 0xa1, 0xa1, 0x61, 0x12, // 128 - 'C sedilla'
|
||||
5, 0x38, 0x42, 0x40, 0x22, 0x78, // 129 - 'u umlaut'
|
||||
5, 0x38, 0x54, 0x54, 0x55, 0x59, // 130 - 'e acute'
|
||||
5, 0x21, 0x55, 0x55, 0x79, 0x41, // 131 - 'a accent'
|
||||
5, 0x21, 0x54, 0x54, 0x78, 0x41, // 132 - 'a umlaut'
|
||||
5, 0x21, 0x55, 0x54, 0x78, 0x40, // 133 - 'a grave'
|
||||
5, 0x20, 0x54, 0x55, 0x79, 0x40, // 134 - 'a acute'
|
||||
5, 0x18, 0x3c, 0xa4, 0xe4, 0x24, // 135 - 'c sedilla'
|
||||
5, 0x39, 0x55, 0x55, 0x55, 0x59, // 136 - 'e accent'
|
||||
5, 0x38, 0x55, 0x54, 0x55, 0x58, // 137 - 'e umlaut'
|
||||
5, 0x39, 0x55, 0x54, 0x54, 0x58, // 138 - 'e grave'
|
||||
3, 0x45, 0x7c, 0x41, // 139 - 'i umlaut'
|
||||
4, 0x02, 0x45, 0x7d, 0x42, // 140 - 'i hat'
|
||||
4, 0x01, 0x45, 0x7c, 0x40, // 141 - 'i grave'
|
||||
5, 0xf0, 0x29, 0x24, 0x29, 0xf0, // 142 - 'A umlaut'
|
||||
5, 0xf0, 0x28, 0x25, 0x28, 0xf0, // 143 - 'A dot'
|
||||
4, 0x7c, 0x54, 0x55, 0x45, // 144 - 'E grave'
|
||||
7, 0x20, 0x54, 0x54, 0x7c, 0x54, 0x54, 0x08, // 145 - 'ae'
|
||||
6, 0x7c, 0x0a, 0x09, 0x7f, 0x49, 0x49, // 146 - 'AE'
|
||||
5, 0x32, 0x49, 0x49, 0x49, 0x32, // 147 - 'o hat'
|
||||
5, 0x30, 0x4a, 0x48, 0x4a, 0x30, // 148 - 'o umlaut'
|
||||
5, 0x32, 0x4a, 0x48, 0x48, 0x30, // 149 - 'o grave'
|
||||
5, 0x3a, 0x41, 0x41, 0x21, 0x7a, // 150 - 'u hat'
|
||||
5, 0x3a, 0x42, 0x40, 0x20, 0x78, // 151 - 'u grave'
|
||||
4, 0x9d, 0xa0, 0xa0, 0x7d, // 152 - 'y umlaut'
|
||||
5, 0x38, 0x45, 0x44, 0x45, 0x38, // 153 - 'O umlaut'
|
||||
5, 0x3c, 0x41, 0x40, 0x41, 0x3c, // 154 - 'U umlaut'
|
||||
5, 0x3c, 0x24, 0xff, 0x24, 0x24, // 155 - 'Cents'
|
||||
5, 0x48, 0x7e, 0x49, 0x43, 0x66, // 156 - 'Pounds'
|
||||
5, 0x2b, 0x2f, 0xfc, 0x2f, 0x2b, // 157 - 'Yen'
|
||||
5, 0xff, 0x09, 0x29, 0xf6, 0x20, // 158 - 'R +'
|
||||
5, 0xc0, 0x88, 0x7e, 0x09, 0x03, // 159 - 'f notation'
|
||||
5, 0x20, 0x54, 0x54, 0x79, 0x41, // 160 - 'a acute'
|
||||
3, 0x44, 0x7d, 0x41, // 161 - 'i acute'
|
||||
5, 0x30, 0x48, 0x48, 0x4a, 0x32, // 162 - 'o acute'
|
||||
5, 0x38, 0x40, 0x40, 0x22, 0x7a, // 163 - 'u acute'
|
||||
4, 0x7a, 0x0a, 0x0a, 0x72, // 164 - 'n accent'
|
||||
5, 0x7d, 0x0d, 0x19, 0x31, 0x7d, // 165 - 'N accent'
|
||||
5, 0x26, 0x29, 0x29, 0x2f, 0x28, // 166
|
||||
5, 0x26, 0x29, 0x29, 0x29, 0x26, // 167
|
||||
5, 0x30, 0x48, 0x4d, 0x40, 0x20, // 168 - 'Inverted ?'
|
||||
5, 0x38, 0x08, 0x08, 0x08, 0x08, // 169 - 'LH top corner'
|
||||
5, 0x08, 0x08, 0x08, 0x08, 0x38, // 170 - 'RH top corner'
|
||||
5, 0x2f, 0x10, 0xc8, 0xac, 0xba, // 171 - '1/2'
|
||||
5, 0x2f, 0x10, 0x28, 0x34, 0xfa, // 172 - '1/4'
|
||||
1, 0x7b, // 173 - '| split'
|
||||
5, 0x08, 0x14, 0x2a, 0x14, 0x22, // 174 - '<<'
|
||||
5, 0x22, 0x14, 0x2a, 0x14, 0x08, // 175 - '>>'
|
||||
5, 0xaa, 0x00, 0x55, 0x00, 0xaa, // 176 - '30% shading'
|
||||
5, 0xaa, 0x55, 0xaa, 0x55, 0xaa, // 177 - '50% shading'
|
||||
5, 0x00, 0x00, 0x00, 0x00, 0xff, // 178 - 'Right side'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0xff, // 179 - 'Right T'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0xff, // 180 - 'Right T double H'
|
||||
5, 0x10, 0x10, 0xff, 0x00, 0xff, // 181 - 'Right T double V'
|
||||
5, 0x10, 0x10, 0xf0, 0x10, 0xf0, // 182 - 'Top Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0xfc, // 183 - 'Top Right double H'
|
||||
5, 0x14, 0x14, 0xf7, 0x00, 0xff, // 184 - 'Right T double all'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xff, // 185 - 'Right side double'
|
||||
5, 0x14, 0x14, 0xf4, 0x04, 0xfc, // 186 - 'Top Right double'
|
||||
5, 0x14, 0x14, 0x17, 0x10, 0x1f, // 187 - 'Bot Right double'
|
||||
5, 0x10, 0x10, 0x1f, 0x10, 0x1f, // 188 - 'Bot Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x1f, // 189 - 'Bot Right double H'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0xf0, // 190 - 'Top Right'
|
||||
5, 0x00, 0x00, 0x00, 0x1f, 0x10, // 191 - 'Bot Left'
|
||||
5, 0x10, 0x10, 0x10, 0x1f, 0x10, // 192 - 'Bot T'
|
||||
5, 0x10, 0x10, 0x10, 0xf0, 0x10, // 193 - 'Top T'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0x10, // 194 - 'Left T'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0x10, // 195 - 'Top side'
|
||||
5, 0x10, 0x10, 0x10, 0xff, 0x10, // 196 - 'Center +'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0x14, // 197 - 'Left side double H'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xff, // 198 - 'Left side double'
|
||||
5, 0x00, 0x00, 0x1f, 0x10, 0x17, // 199 - 'Bot Left double V'
|
||||
5, 0x00, 0x00, 0xfc, 0x04, 0xf4, // 200 - 'Top Left double V'
|
||||
5, 0x14, 0x14, 0x17, 0x10, 0x17, // 201 - 'Bot T double'
|
||||
5, 0x14, 0x14, 0xf4, 0x04, 0xf4, // 202 - 'Top T double'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xf7, // 203 - 'Left Side double spl'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x14, // 204 - 'Center double'
|
||||
5, 0x14, 0x14, 0xf7, 0x00, 0xf7, // 205 - 'Center + double'
|
||||
5, 0x14, 0x14, 0x14, 0x17, 0x14, // 206 - 'Bot T double H'
|
||||
5, 0x10, 0x10, 0x1f, 0x10, 0x1f, // 207 - 'Bot Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0xf4, 0x14, // 208 - 'Top T double H'
|
||||
5, 0x10, 0x10, 0xf0, 0x10, 0xf0, // 209 - 'Top Right double V'
|
||||
5, 0x00, 0x00, 0x1f, 0x10, 0x1f, // 210 - 'Bot Left double V'
|
||||
5, 0x00, 0x00, 0x00, 0x1f, 0x14, // 211 - 'Bot Right double H'
|
||||
5, 0x00, 0x00, 0x00, 0xfc, 0x14, // 212 - 'Top Right double H'
|
||||
5, 0x00, 0x00, 0xf0, 0x10, 0xf0, // 213 - 'Top Right double V'
|
||||
5, 0x10, 0x10, 0xff, 0x10, 0xff, // 214 - 'Center + double V'
|
||||
5, 0x14, 0x14, 0x14, 0xff, 0x14, // 215 - 'Center + double H'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0x1f, // 216 - 'Bot Right'
|
||||
5, 0x00, 0x00, 0x00, 0xf0, 0x10, // 217 - 'Top Left'
|
||||
5, 0xff, 0xff, 0xff, 0xff, 0xff, // 218 - 'Full Block'
|
||||
5, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 219 - 'Half Block Bottom'
|
||||
3, 0xff, 0xff, 0xff, // 220 - 'Half Block LHS'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0xff, // 221 - 'Half Block RHS'
|
||||
5, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, // 222 - 'Half Block Top'
|
||||
5, 0x38, 0x44, 0x44, 0x38, 0x44, // 223 - 'Alpha'
|
||||
5, 0x7c, 0x2a, 0x2a, 0x3e, 0x14, // 224 - 'Beta'
|
||||
5, 0x7e, 0x02, 0x02, 0x06, 0x06, // 225 - 'Gamma'
|
||||
5, 0x02, 0x7e, 0x02, 0x7e, 0x02, // 226 - 'Pi'
|
||||
5, 0x63, 0x55, 0x49, 0x41, 0x63, // 227 - 'Sigma'
|
||||
5, 0x38, 0x44, 0x44, 0x3c, 0x04, // 228 - 'Theta'
|
||||
5, 0x40, 0x7e, 0x20, 0x1e, 0x20, // 229 - 'mu'
|
||||
5, 0x06, 0x02, 0x7e, 0x02, 0x02, // 230 - 'Tau'
|
||||
5, 0x99, 0xa5, 0xe7, 0xa5, 0x99, // 231
|
||||
5, 0x1c, 0x2a, 0x49, 0x2a, 0x1c, // 232
|
||||
5, 0x4c, 0x72, 0x01, 0x72, 0x4c, // 233
|
||||
5, 0x30, 0x4a, 0x4d, 0x4d, 0x30, // 234
|
||||
5, 0x30, 0x48, 0x78, 0x48, 0x30, // 235
|
||||
5, 0xbc, 0x62, 0x5a, 0x46, 0x3d, // 236 - 'Zero Slashed'
|
||||
4, 0x3e, 0x49, 0x49, 0x49, // 237
|
||||
5, 0x7e, 0x01, 0x01, 0x01, 0x7e, // 238
|
||||
5, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, // 239 - '3 Bar Equals'
|
||||
5, 0x44, 0x44, 0x5f, 0x44, 0x44, // 240 - '+/-'
|
||||
5, 0x40, 0x51, 0x4a, 0x44, 0x40, // 241 - '>='
|
||||
5, 0x40, 0x44, 0x4a, 0x51, 0x40, // 242 - '<='
|
||||
5, 0x00, 0x00, 0xff, 0x01, 0x03, // 243 - 'Top of Integral'
|
||||
3, 0xe0, 0x80, 0xff, // 244 - 'Bot of Integral'
|
||||
5, 0x08, 0x08, 0x6b, 0x6b, 0x08, // 245 - 'Divide'
|
||||
5, 0x36, 0x12, 0x36, 0x24, 0x36, // 246 - 'Wavy ='
|
||||
5, 0x06, 0x0f, 0x09, 0x0f, 0x06, // 247 - 'Degree'
|
||||
4, 0x00, 0x00, 0x18, 0x18, // 248 - 'Math Product'
|
||||
4, 0x00, 0x00, 0x10, 0x10, // 249 - 'Short Dash'
|
||||
5, 0x30, 0x40, 0xff, 0x01, 0x01, // 250 - 'Square Root'
|
||||
5, 0x00, 0x1f, 0x01, 0x01, 0x1e, // 251 - 'Superscript n'
|
||||
5, 0x00, 0x19, 0x1d, 0x17, 0x12, // 252 - 'Superscript 2'
|
||||
5, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, // 253 - 'Centered Square'
|
||||
5, 0xff, 0x81, 0x81, 0x81, 0xff, // 254 - 'Full Frame'
|
||||
5, 0xff, 0xff, 0xff, 0xff, 0xff, // 255 - 'Full Block'
|
||||
};
|
||||
|
||||
#endif //INCLUDE_LOCAL_FONT
|
||||
|
||||
529
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_lib.h
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains library related definitions and is not visible
|
||||
to user code.
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef MDMAX72xxLIB_H
|
||||
#define MDMAX72xxLIB_H
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Includes library definitions
|
||||
*/
|
||||
|
||||
#define MAX_DEBUG 0 ///< Enable or disable (default) debugging output from the MD_MAX72xx library
|
||||
|
||||
#if MAX_DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); } ///< Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); } ///< Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) { Serial.print(F(s)); Serial.print(v, BIN); } ///< Print a string followed by a value (binary)
|
||||
#define PRINTS(s) { Serial.print(F(s)); } ///< Print a string
|
||||
#else
|
||||
#define PRINT(s, v) ///< Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) ///< Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) ///< Print a string followed by a value (binary)
|
||||
#define PRINTS(s) ///< Print a string
|
||||
#endif
|
||||
|
||||
// Opcodes for the MAX7221 and MAX7219
|
||||
// All OP_DIGITn are offsets from OP_DIGIT0
|
||||
#define OP_NOOP 0 ///< MAX72xx opcode for NO OP
|
||||
#define OP_DIGIT0 1 ///< MAX72xx opcode for DIGIT0
|
||||
#define OP_DIGIT1 2 ///< MAX72xx opcode for DIGIT1
|
||||
#define OP_DIGIT2 3 ///< MAX72xx opcode for DIGIT2
|
||||
#define OP_DIGIT3 4 ///< MAX72xx opcode for DIGIT3
|
||||
#define OP_DIGIT4 5 ///< MAX72xx opcode for DIGIT4
|
||||
#define OP_DIGIT5 6 ///< MAX72xx opcode for DIGIT5
|
||||
#define OP_DIGIT6 7 ///< MAX72xx opcode for DIGIT6
|
||||
#define OP_DIGIT7 8 ///< MAX72xx opcode for DIGIT7
|
||||
#define OP_DECODEMODE 9 ///< MAX72xx opcode for DECODE MODE
|
||||
#define OP_INTENSITY 10 ///< MAX72xx opcode for SET INTENSITY
|
||||
#define OP_SCANLIMIT 11 ///< MAX72xx opcode for SCAN LIMIT
|
||||
#define OP_SHUTDOWN 12 ///< MAX72xx opcode for SHUT DOWN
|
||||
#define OP_DISPLAYTEST 15 ///< MAX72xx opcode for DISPLAY TEST
|
||||
|
||||
#define ALL_CHANGED 0xff ///< Mask for all rows changed in a buffer structure
|
||||
#define ALL_CLEAR 0x00 ///< Mask for all rows clear in a buffer structure
|
||||
|
||||
#define ASCII_INDEX_SIZE 256 ///< Number of characters in a font table (ASCII maximum)
|
||||
|
||||
// Shortcuts
|
||||
#define SPI_DATA_SIZE (sizeof(uint8_t)*_maxDevices*2) ///< Size of the SPI data buffers
|
||||
#define SPI_OFFSET(i,x) (((LAST_BUFFER-(i))*2)+(x)) ///< SPI data offset for buffer i, digit x
|
||||
#define FIRST_BUFFER 0 ///< First buffer number
|
||||
#define LAST_BUFFER (_maxDevices-1) ///< Last buffer number
|
||||
|
||||
// variables shared in the library
|
||||
extern const uint8_t PROGMEM _sysfont_var[]; ///< System variable pitch font table
|
||||
|
||||
/**
|
||||
\page pageHardware Hardware
|
||||
Supported Hardware
|
||||
------------------
|
||||
This library supports the Parola hardware and the more commonly available LED modules available
|
||||
from many other sources. The circuits for these modules are essentially identical except
|
||||
in the way that the LED matrix is wired to the MAX7219 IC. This difference is accounted for in
|
||||
software when the type of module is selected using the appropriate USE_*_HW compile time switch.
|
||||
|
||||
Hardware supported
|
||||
------------------
|
||||
- \subpage pageParola
|
||||
- \subpage pageGeneric
|
||||
- \subpage pageICStation
|
||||
- \subpage pageFC16
|
||||
- \subpage pageNewHardware
|
||||
|
||||
Connecting Multiple Modules
|
||||
---------------------------
|
||||
Separate modules are connected by the plugging them together edge to edge, with the
|
||||
OUT side of one module plugged to the IN side of the next. More details can be found
|
||||
at the end of each module's hardware section.
|
||||
___
|
||||
|
||||
\page pageParola Parola Custom Module
|
||||
The Parola Module
|
||||
-----------------
|
||||
These custome modules allow a 'lego-like' approach to LED matrix display, using standard 8x8 on
|
||||
LED matrices. The software supports this flexibility through a scalable approach that
|
||||
only requires the definition of the number of modules to adapt existing software to
|
||||
a new configuration.
|
||||
|
||||
![Completed Parola module with and without the LED matrix] (PCB_Actual.jpg "Parola Custom Modules")
|
||||
|
||||
Circuit Schematic
|
||||
-----------------
|
||||
The schematic is the basic application circuit that is found on the MAX7219 datasheet,
|
||||
adapted to the LED matrix. Each Module consists of an 8x8 LED matrix controlled by a
|
||||
MAX7219 LED controller and a few passive components. These controllers can be daisy
|
||||
chained, making them ideal for the purpose.
|
||||
|
||||
![Parola Circuit Schematic] (Circuit_Schematic.jpg "Parola Schematic")
|
||||
|
||||
The PCB design was executed using the autorouting facility in Eagle CAD, and the PCB was
|
||||
manufactured by SeeedStudio. The Eagle CAD files for the layout and the Gerber files
|
||||
suitable for SeeedStudio are found on the [Parola website] (https://github.com/MajicDesigns/MD_Parola).
|
||||
The final design includes edge connections that allow many modules to be connected
|
||||
together into an extended display, one LED module high.
|
||||
|
||||
![PCB layout ready for manufacture] (PCB_Layout.jpg "PCB Design")
|
||||
|
||||
Wiring your own Parola standard matrix
|
||||
--------------------------------------
|
||||
How the LED matrix is wired is important for the library. The matrix used for library
|
||||
development was labelled 1088B and is sometime referred to as a **common anode** matrix.
|
||||
Connections should be made as described in the table below to be consistent with the
|
||||
assumptions in the software library.
|
||||
- Columns are addressed through the segment selection lines
|
||||
- Rows are addressed through the digit selection lines
|
||||
|
||||
MAX Signal|MAX7219 Pin|MAX Signal|MAX7219 Pin|
|
||||
:--------:|----------:|:--------:|----------:|
|
||||
Dig0 (D0) |2 |SegDP |22 |
|
||||
Dig1 (D1) |11 |SegA |14 |
|
||||
Dig2 (D2) |6 |SegB |16 |
|
||||
Dig3 (D3) |7 |SegC |20 |
|
||||
Dig4 (D4) |3 |SegD |23 |
|
||||
Dig5 (D5) |10 |SegE |21 |
|
||||
Dig6 (D6) |5 |SegF |15 |
|
||||
Dig7 (D7) |8 |SegG |17 |
|
||||
|
||||
Segment data is packed on a per-digit basis, with segment G as the least significant bit (bit 0)
|
||||
through to A as bit 6 and DP as bit 7.
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
G F E D C B A DP
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | DIG0
|
||||
| 1 | DIG1
|
||||
| 2 | DIG2
|
||||
| 3 | DIG3
|
||||
| O 4 | DIG4
|
||||
| O O 5 | DIG5
|
||||
| O O O 6 | DIG6
|
||||
| O O O O 7 | DIG7
|
||||
+------------------------+
|
||||
Vcc ---- ---- Vcc
|
||||
DOUT <--- ---< DIN
|
||||
GND ---- ---- GND
|
||||
CS/LD <--- ---< CS/LD
|
||||
CLK <--- ---< CLK
|
||||
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
Parola modules are connected by plugging them together.
|
||||
![Connecting Parola modules] (Modules_conn.jpg "Parola Modules connected")
|
||||
____
|
||||
|
||||
\page pageGeneric Generic Module
|
||||
Generic MAX7219 Module
|
||||
------------------------
|
||||
These modules are commonly available from many suppliers (eg, eBay) at reasonable cost.
|
||||
They are characterized by IN and OUT connectors at the short ends of the rectangular PCB.
|
||||
|
||||
![Generic Module] (Generic_Module.png "Generic Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
C C D G V
|
||||
L S I N c
|
||||
K N D c
|
||||
| | | | |
|
||||
V V V | |
|
||||
D7 D6 D5 D4 D3 D2 D1 D0
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 |- DP
|
||||
| 1 |- A
|
||||
| 2 |- B
|
||||
| 3 |- C
|
||||
| O 4 |- D
|
||||
| O O 5 |- E
|
||||
| O O O 6 |- F
|
||||
| O O O O 7 |- G
|
||||
+-----+--+--+--+--+------+
|
||||
| | | | |
|
||||
V V V | |
|
||||
|
||||
C C D G V
|
||||
L S O N c
|
||||
K U D c
|
||||
T
|
||||
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
Generic modules need to be oriented with the MAX7219 IC at the top and connected using
|
||||
short patch cables in a spiral pattern. The display is oriented with the IC at the top.
|
||||
![Connecting Generic modules] (Generic_conn.jpg "Generic Modules connected")
|
||||
____
|
||||
|
||||
\page pageICStation ICStation Module
|
||||
ICStation DIY Kit Module
|
||||
------------------------
|
||||
These modules are available as kits from ICStation (http://www.icstation.com/product_info.php?products_id=2609#.UxqVJyxWGHs).
|
||||
|
||||
![ICStation Module] (ICStation_Module.jpg "ICStation Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
G F E D C B A DP
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | D7
|
||||
CLK <---| 1 | D6 <--- CLK
|
||||
CS <---| 2 | D5 <--- CS
|
||||
DOUT <---| 3 | D4 <--- DIN
|
||||
GND ----| O 4 | D3 ---- GND
|
||||
VCC ----| O O 5 | D2 ---- VCC
|
||||
| O O O 6 | D1
|
||||
| O O O O 7 | D0
|
||||
+------------------------+
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
ICStation Modules are connected using the links supplied with the hardware. The display is
|
||||
oriented with the DIN side on the right.
|
||||
|
||||
![Connecting ICStation modules] (ICStation_conn.jpg "ICStation Modules connected")
|
||||
|
||||
____
|
||||
\page pageFC16 FC-16 Module
|
||||
FC-16 DIY Kit Module
|
||||
----------------------
|
||||
These modules are available as kits from some internet suppliers such as G&C Supermarket on eBay
|
||||
(http://stores.ebay.com.au/gcsupermarkethkcoltd/). They are identifiable by the FC-16 designation
|
||||
silkscreened on the PCB. Most of the available sets of 4 modules connected as one unit are
|
||||
FC-16 type.
|
||||
|
||||
![FC-16 Module] (FC-16_Module.jpg "FC-16 Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
DP A B C D E F G
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | D0
|
||||
CLK <---| 1 | D1 <--- CLK
|
||||
CS <---| 2 | D2 <--- CS
|
||||
DOUT <---| 3 | D3 <--- DIN
|
||||
GND ----| O 4 | D4 ---- GND
|
||||
VCC ----| O O 5 | D5 ---- VCC
|
||||
| O O O 6 | D6
|
||||
| O O O O 7 | D7
|
||||
+------------------------+
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
FC-16 Modules are connected using the links supplied with the hardware. The display is
|
||||
oriented with the DIN side on the right. PCB text may appear upside down.
|
||||
|
||||
![Connecting FC-16 modules] (FC-16_conn.jpg "FC-16 Modules connected")
|
||||
|
||||
____
|
||||
\page pageNewHardware New Hardware Types
|
||||
A word on coordinate systems
|
||||
----------------------------
|
||||
|
||||
Two Cartesian coordinate systems are used in the library
|
||||
- one defines the pixels seen (_display coordinates_), and
|
||||
- an underlying _hardware coordinate_ system based on digits and segments
|
||||
mapping to the MAX72xx hardware control registers.
|
||||
|
||||
Display coordinates always have their origin in the top right corner of a display.
|
||||
- Column numbers increase to the left (as do module numbers)
|
||||
- Row numbers increase down (0..7)
|
||||
|
||||
All user functions are consistent and use display coordinates.
|
||||
|
||||
Display memory buffers are stored in hardware coordinates that depend on
|
||||
the hardware configuration (i.e. the module type). It is the job of the low level
|
||||
library functions to map display to hardware coordinates. Digit 0 is the lowest
|
||||
row/column number and Segment G is the lowest column/row number.
|
||||
|
||||
All the code to do this is in the is in the buffer and pixel modules.
|
||||
All other library modules are use the primitives made available in these modules.
|
||||
|
||||
What needs to change?
|
||||
---------------------
|
||||
|
||||
As there is no standard way of wiring a LED matrix to the MAX72xx IC, each hardware type
|
||||
definition activates a series of coordinate mapping transformations. Possible changes
|
||||
are limited to combinations (8 in total) of
|
||||
- swapping rows and column coordinates (digits and segments in MAX72xx),
|
||||
- a reversal of row indices, and
|
||||
- a reversal of column indices.
|
||||
|
||||
The hardware types defined in MD_MAX72xx.h activate different library code by defining
|
||||
appropriate values for the defines listed below, in the MD_MAX72xx_lib.h file.
|
||||
|
||||
- HW_DIG_ROWS - MAX72xx digits are mapped to rows in on the matrix. If digits are
|
||||
not rows then they are columns!
|
||||
|
||||
- HW_REV_COLS - Normal column coordinates orientation is 0 col on the right side
|
||||
of the display. Set to 1 to reverse this (0 on the left).
|
||||
|
||||
- HW_REV_ROWS - Normal row coordinates orientation is 0 row at top of the display.
|
||||
Set to 1 to reverse this (0 at the bottom).
|
||||
|
||||
Determining the type of mapping
|
||||
-------------------------------
|
||||
The library example code includes a utility called MD_MAX72xx_HW_Mapper.
|
||||
This is test software to map display hardware rows and columns. It uses a
|
||||
generic SPI interface and only one MAX72xx/8x8 LED module required. It is
|
||||
independent of the libraries as the code is used to directly map the display
|
||||
orientation by setting pixels on the display and printing to the serial monitor
|
||||
which MAX72xx hardware component (segment and digit) is being exercised.
|
||||
|
||||
By observing the LED display and the serial monitor you can build a map like the
|
||||
one below. It is worth noting the direction in which the rows and columns are
|
||||
scanned by the utility, as this is the easiest way to work out the row/column
|
||||
reversal values.
|
||||
|
||||
The result of these observations is a grid definition that looks somewhat like:
|
||||
|
||||
DIG0 D1 D2 D3 D4 D5 D6 D7
|
||||
Seg G
|
||||
Seg F
|
||||
Seg E
|
||||
Seg D
|
||||
Seg C
|
||||
Seg B
|
||||
Seg A
|
||||
Seg DP
|
||||
|
||||
From this mapping it is clear
|
||||
- MAX72xx digits map to the columns, HW_DIG_ROWS is 0.
|
||||
- DIG0 is on the left (columns were also scanned left to right), so HW_REV_COLS should be set
|
||||
to 1 to reverse it to the standard 0 on the right.
|
||||
- Seg G is at the top (rows were also top to bottom), so HW_REV_ROWS should be set to 0,
|
||||
as it is already standard with 0 on top.
|
||||
|
||||
Note that in some situations using the module 'upside down' will result in a better configuration
|
||||
than would otherwise be the case. An example of this is the generic module mapping. Also remember
|
||||
that the modules are daisy chained from right to left.
|
||||
|
||||
Having determined the values for the defines, the new mapping can be configured, or matched to
|
||||
an existing hardware type.
|
||||
___
|
||||
|
||||
\page pageFontUtility Create and Modify Fonts
|
||||
|
||||
Font Storage Format
|
||||
-------------------
|
||||
One default font is defined as part of the library in PROGMEM memory. Alternative fonts
|
||||
can be specified to the library. The font builder utilities provide a convenient way to
|
||||
modify existing or develop alternative fonts.
|
||||
|
||||
Fonts are stored as a series of contiguous bytes in the following format:
|
||||
- byte 1 - the number of bytes that form this character (could be zero)
|
||||
- byte 2..n - each byte is a column of the character to be formed, starting with the
|
||||
leftmost column of the character. The least significant bit of the byte is the bottom
|
||||
pixel position of the character matrix (row 7).
|
||||
|
||||
To find a character in the font table, the library looks at the first byte (size),
|
||||
skips 'size'+1 bytes to the next character size byte and repeat until the last or
|
||||
target character is reached.
|
||||
|
||||
The compile-time switch USE_INDEX_FONT enables indexing of the font table for faster access, at
|
||||
the expense of increased RAM usage. If indexing is enabled, a single lookup is required to
|
||||
access the character data, rather than the sequential search described above.
|
||||
|
||||
The support for fonts (methods and data) may be completely disabled if not required through
|
||||
the compile-time switch USE_LOCAL_FONT. This will also disable user defined fonts.
|
||||
|
||||
____
|
||||
|
||||
The txt2font Utility
|
||||
--------------------
|
||||
The txt2font utility is a command line application that converts a text definition of the font
|
||||
into a data file in the right format for MD_MAX72xx to use.
|
||||
|
||||
This utility is as an Win32 executable. Users with other Operating Systems will need to compile
|
||||
a version to work with their OS, using the source code supplied.
|
||||
|
||||
The application is invoked from the command line and only the root name of the file is given as a command
|
||||
line parameter (eg "txt2font fred"). The application will look for and input file with a '.txt' extension
|
||||
(fred.txt) and produce an output file with a '.h' extension (fred.h).
|
||||
|
||||
The txt2font file format is line based. Lines starting with a '.' are directives for the application, all
|
||||
other lines are data for the current character defintion. An example of the beginning of a font
|
||||
definition file is shown below.
|
||||
|
||||
.NAME sys_var_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 0
|
||||
.CHAR 0
|
||||
.NOTE 'Empty Cell'
|
||||
.CHAR 1
|
||||
.NOTE 'Sad Smiley'
|
||||
@@@
|
||||
@@@@@
|
||||
@ @ @
|
||||
@@@@@
|
||||
@@ @@
|
||||
@ @
|
||||
@@@
|
||||
.CHAR 2
|
||||
.NOTE 'Happy Smiley'
|
||||
***
|
||||
|
||||
The directives have the following meaning:
|
||||
- .NAME defines the name for the font and is used in naming the font table variable.
|
||||
The name can appear anywhere in the file. If omitted, a default name is used.
|
||||
- .HEIGHT defines the height for the font. Single height fonts are '1' and double height fonts are '2'.
|
||||
If double height fonts are specified then the range of ASCII character values is restricted to 0..127 as
|
||||
the top and botton halves of the font are stored offset by 128 positions. If omitted, the application
|
||||
assumes single height font.
|
||||
- .WIDTH specifies the width of the font for all the characters defined between this WIDTH and the
|
||||
next WIDTH defintion. 0 means variable width; any other number defines the fixed width. WIDTH may be changed
|
||||
within the file - for example to define a fixed size space (no pixels!) character in a variable width font.
|
||||
- .CHAR ends the defintion of the current character and starts the defintion for the specified ASCII value.
|
||||
Valid parameters are [0..255] for single height, and [0..127] for double height. If a character code is
|
||||
omitted in the font definition file it is assumed to be empty.
|
||||
- .NOTE is an option note that will be added as a comment for the entry in the font data table.
|
||||
|
||||
Any lines not starting with a '.' are data lines for the current character. The font characters are drawn
|
||||
using a non-space character (eg, '*' or '@') wherever a LED needs to be 'on'. The application scans from
|
||||
the top down, so any lines missing at the bottom of the character definition are assumed to be blank.
|
||||
However, blank lines at the top need to be shown. Any extra rows are ignored will cause program errors.
|
||||
|
||||
A number of font definition files are supplied as examples.
|
||||
___
|
||||
|
||||
The FontBuilder Excel/VBA application
|
||||
-------------------------------------
|
||||
FontBuilder is a Microsoft Excel spreadsheet with VBA macros to manage a GUI interface for defining
|
||||
and managing font characters. FontBuilder supports both single and double height fonts. The first tab
|
||||
in the FontBuilder spreadsheet has instructions for use.
|
||||
|
||||
As FontBuilder requires using Microsoft Office products, it does not work environments where
|
||||
these are not available.
|
||||
|
||||
*/
|
||||
|
||||
// *******************************************************************************************
|
||||
// ** Combinations not listed here have probably not been tested and may not work correctly **
|
||||
// *******************************************************************************************
|
||||
#if USE_PAROLA_HW // tested MC 8 March 2014
|
||||
//#pragma message "PAROLA HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_GENERIC_HW // tested MC 9 March 2014
|
||||
//#pragma message "GENERIC HW selected"
|
||||
#define HW_DIG_ROWS 0 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_ICSTATION_HW // tested MC 9 March 2014
|
||||
//#pragma message "ICSTATION HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 1 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_FC16_HW // tested MC 23 Feb 2015
|
||||
//#pragma message "FC16 HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 0 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_OTHER_HW // user defined custom hardware configuration
|
||||
//#pragma message "OTHER HW selected"
|
||||
#define HW_DIG_ROWS 0 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 0 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#ifndef HW_DIG_ROWS
|
||||
#error "INVALID or missing hardware selected"
|
||||
#endif
|
||||
|
||||
// Macros to map ROW and COLUMN coordinates
|
||||
#if HW_REV_ROWS
|
||||
#define HW_ROW(r) (7-r) ///< Pixel to hardware coordinate row mapping
|
||||
#else
|
||||
#define HW_ROW(r) (r) ///< Pixel to hardware coordinate row mapping
|
||||
#endif
|
||||
|
||||
#if HW_REV_COLS
|
||||
#define HW_COL(c) (7-c) ///< Pixel to hardware coordinate column mapping
|
||||
#else
|
||||
#define HW_COL(c) (c) ///< Pixel to hardware coordinate column mapping
|
||||
#endif
|
||||
|
||||
#endif
|
||||
284
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_pix.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains methods that act on the matrix as a pixel field,
|
||||
generally only acting on the visible device range of the buffered
|
||||
device field (ie, the physical pixel matrix).
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements pixel related methods
|
||||
*/
|
||||
|
||||
void MD_MAX72XX::clear(uint8_t startDev, uint8_t endDev)
|
||||
{
|
||||
if (endDev < startDev) return;
|
||||
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
{
|
||||
memset(_matrix[buf].dig, 0, sizeof(_matrix[buf].dig));
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
}
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::getBuffer(uint16_t col, uint8_t size, uint8_t *pd)
|
||||
{
|
||||
if ((col >= getColumnCount()) || (pd == NULL))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
*pd++ = getColumn(col--);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setBuffer(uint16_t col, uint8_t size, uint8_t *pd)
|
||||
{
|
||||
bool b = _updateEnabled;
|
||||
|
||||
if ((col >= getColumnCount()) || (pd == NULL))
|
||||
return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
setColumn(col--, *pd++);
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::drawLine(uint8_t r1, uint16_t c1, uint8_t r2, uint16_t c2, bool state)
|
||||
// draw a line between two points using Bresentham's line algorithm
|
||||
{
|
||||
if (r1 >= ROW_SIZE || r2 >= ROW_SIZE || c1 >= (COL_SIZE*_maxDevices) || c2 >= (COL_SIZE*_maxDevices))
|
||||
return(false);
|
||||
|
||||
if (c1 > c2)
|
||||
{
|
||||
uint16_t t;
|
||||
t = c1; c1 = c2; c2 = t; // swap c1/c2
|
||||
t = r1; r1 = r2; r2 = t; // swap r1/r2
|
||||
}
|
||||
|
||||
// Bresentham's line algorithm
|
||||
int16_t dc = abs(c2-c1);
|
||||
int16_t sc = c1<c2 ? 1 : -1;
|
||||
int16_t dr = abs(r2-r1);
|
||||
int16_t sr = r1<r2 ? 1 : -1;
|
||||
int16_t err = (dc>dr ? dc : -dr)/2;
|
||||
int16_t e2;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
setPoint(r1, c1, state);
|
||||
if (c1 == c2 && r1 == r2) break;
|
||||
e2 = err;
|
||||
if (e2 >-dc) { err -= dr; c1 += sc; }
|
||||
if (e2 < dr) { err += dc; r1 += sr; }
|
||||
}
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
// used in getPoint and setPoint!
|
||||
#if HW_DIG_ROWS
|
||||
#define R r
|
||||
#define C c
|
||||
#else
|
||||
#define R c
|
||||
#define C r
|
||||
#endif
|
||||
|
||||
bool MD_MAX72XX::getPoint(uint8_t r, uint16_t c)
|
||||
{
|
||||
uint8_t buf = c/COL_SIZE;
|
||||
|
||||
c %= COL_SIZE;
|
||||
PRINT("\ngetPoint: (", buf);
|
||||
PRINT(", ", r);
|
||||
PRINT(", ", c);
|
||||
PRINTS(")");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
return(bitRead(_matrix[buf].dig[HW_ROW(R)], HW_COL(C)) == 1);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setPoint(uint8_t r, uint16_t c, bool state)
|
||||
{
|
||||
uint8_t buf = c/COL_SIZE;
|
||||
c %= COL_SIZE;
|
||||
|
||||
PRINT("\nsetPoint: (", buf);
|
||||
PRINT(", ", r);
|
||||
PRINT(", ", c);
|
||||
PRINT(") = ", state?1:0);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
if (state)
|
||||
bitSet(_matrix[buf].dig[HW_ROW(R)], HW_COL(C));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[HW_ROW(R)], HW_COL(C));
|
||||
|
||||
bitSet(_matrix[buf].changed, HW_ROW(R));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#undef R
|
||||
#undef C
|
||||
|
||||
bool MD_MAX72XX::setRow(uint8_t startDev, uint8_t endDev, uint8_t r, uint8_t value)
|
||||
{
|
||||
bool b = _updateEnabled;
|
||||
|
||||
PRINT("\nsetRow: ", r);
|
||||
|
||||
if ((r >= ROW_SIZE) || (endDev < startDev))
|
||||
return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
for (uint8_t i = startDev; i <= endDev; i++)
|
||||
setRow(i, r, value);
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::transform(uint8_t startDev, uint8_t endDev, transformType_t ttype)
|
||||
{
|
||||
// uint8_t t[ROW_SIZE];
|
||||
uint8_t colData;
|
||||
bool b = _updateEnabled;
|
||||
|
||||
if (endDev < startDev) return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
|
||||
switch (ttype)
|
||||
{
|
||||
case TSL: // Transform Shift Left one pixel element (with overflow)
|
||||
colData = 0;
|
||||
// if we can call the user function later then we don't need to do anything here
|
||||
// however, warparound mode means we know the data so no need to request from the
|
||||
// callback at all - just save it for later
|
||||
if (_wrapAround)
|
||||
colData = getColumn(((endDev+1)*COL_SIZE)-1);
|
||||
else if (_cbShiftDataOut != NULL)
|
||||
(*_cbShiftDataOut)(endDev, ttype, getColumn(((endDev+1)*COL_SIZE)-1));
|
||||
|
||||
// shift all the buffers along
|
||||
for (int8_t buf = endDev; buf >= startDev; --buf)
|
||||
{
|
||||
transformBuffer(buf, ttype);
|
||||
// handle the boundary condition
|
||||
setColumn(buf, 0, getColumn(buf-1, COL_SIZE-1));
|
||||
}
|
||||
|
||||
// if we have a callback function, now is the time to get the data if we are
|
||||
// not in wraparound mode
|
||||
if (_cbShiftDataIn != NULL && !_wrapAround)
|
||||
colData = (*_cbShiftDataIn)(startDev, ttype);
|
||||
|
||||
setColumn((startDev*COL_SIZE), colData);
|
||||
break;
|
||||
|
||||
|
||||
case TSR: // Transform Shift Right one pixel element (with overflow)
|
||||
// if we can call the user function later then we don't need to do anything here
|
||||
// however, warparound mode means we know the data so no need to request from the
|
||||
// callback at all - just save it for later.
|
||||
colData = 0;
|
||||
if (_wrapAround)
|
||||
colData = getColumn(startDev*COL_SIZE);
|
||||
else if (_cbShiftDataOut != NULL)
|
||||
(*_cbShiftDataOut)(startDev, ttype, getColumn((startDev*COL_SIZE)));
|
||||
|
||||
// shift all the buffers along
|
||||
for (uint8_t buf=startDev; buf<=endDev; buf++)
|
||||
{
|
||||
transformBuffer(buf, ttype);
|
||||
|
||||
// handle the boundary condition
|
||||
setColumn(buf, COL_SIZE-1, getColumn(buf+1, 0));
|
||||
}
|
||||
|
||||
// if we have a callback function, now is the time to get the data if we are
|
||||
// not in wraparound mode
|
||||
if (_cbShiftDataIn != NULL && !_wrapAround)
|
||||
colData = (*_cbShiftDataIn)(endDev, ttype);
|
||||
|
||||
setColumn(((endDev+1)*COL_SIZE)-1, colData);
|
||||
break;
|
||||
|
||||
case TFLR: // Transform Flip Left to Right (use the whole field)
|
||||
// first reverse the device buffers end for end
|
||||
for (uint8_t buf = 0; buf < (endDev - startDev)/2; buf++)
|
||||
{
|
||||
deviceInfo_t t;
|
||||
|
||||
t = _matrix[startDev + buf];
|
||||
_matrix[startDev + buf] = _matrix[endDev - buf];
|
||||
_matrix[endDev - buf] = t;
|
||||
}
|
||||
|
||||
// now reverse the columns in each device
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
transformBuffer(buf, ttype);
|
||||
break;
|
||||
|
||||
// These next transformation work the same just by doing the individual devices
|
||||
case TSU: // Transform Shift Up one pixel element
|
||||
case TSD: // Transform Shift Down one pixel element
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
case TRC: // Transform Rotate Clockwise
|
||||
case TINV: // Transform INVert
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
transformBuffer(buf, ttype);
|
||||
break;
|
||||
|
||||
default:
|
||||
return(false);
|
||||
}
|
||||
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||