В этой статье я расскажу про вывод символов на светодиодную панель, собранную из нескольких матриц на основе драйвера MAX7219. Ранее, в статье про подключение драйвера, я упоминал готовые модули с матрицами 8×8, которые можно соединять друг с другом, и тем самым получить панель различной длины. Драйверы при этом соединяются каскадно, при загрузке данные смещаются от одного драйвера к другому.
Модули можно заказать тут. Я приобрел 5 модулей в виде конструктора, спаял их и соединил вместе. Также в продаже имеется цельная панель на 4 матрицы. Схема одного модуля представлена на картинке ниже:
Способ вывода данных на матрицы
При каскадном включении, выход DOUT предыдущего драйвера соединяется с входом DIN следующего драйвера, группы выводов CS и CLK соединяются параллельно. При загрузке данных информация сдвигается побитно, сначала загружаются данные предназначенные для последнего драйвера в цепочке, затем остальные по очереди. Для одного драйвера пакет состоит из 2 байт, это адресный байт и байт данных.
Печатная плата модуля спроектирована так, что данные загружаемые в регистры драйвера Digit0-Digit7 отображаются в строках матрицы (горизонтально), ниже приведена поясняющая картинка:
Для вывода символов я решил взять стандартную таблицу со шрифтом 5×7, которую использовал для графического дисплея Nokia 5110. Но в этой таблице байты символов упакованы по-другому, каждый байт предназначен для вертикального отображения в столбец, таким образом, просто передавать байты на драйвер не получится. Можно конечно переписать всю таблицу символов, но это слишком утомительно. В данном случае необходимо переворачивать символы, извлекая данные побитно.
Данные проще записать за один сеанс, предварительно подготовив пакеты байтов для всех матриц, то есть сразу заполнить одну строку на всю длину панели, затем остальные строки в последующих сеансах (всего 8 сток). Для 5-ти матриц за сеанс передается 10 байт данных, для всей панели соответственно получим 80 байт.
Можно конечно использовать пустой регистр No-Op (адрес 0x00), предназначенный для обращения к отдельному драйверу в цепочке, но при этом также придется отправлять байты на всю длину строки. В этом случае только один пакет будет записан в конкретный драйвер, для остальных драйверов данные запишутся в регистры No-Op, не повлияв на их функционирование. Такой способ нельзя назвать рациональным, так как увеличивается количество передаваемых данных, что замедляет процесс вывода информации.
Подключение матриц MAX7219 к микроконтроллеру
Я подключил светодиодную панель из 5 матриц к микроконтроллеру PIC16F628A, схема представлена на следующей картинке:
Часть кода программы приведена ниже (полный код в конце статьи):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #include <P16F628A.INC> LIST p=16F628A __CONFIG H'3F10' ;Конфигурация микроконтроллера Sec equ 0020h ;регистры хранения временных данных для Sec1 equ 0021h ;подпрограмм паузы Sec2 equ 0022h ; scetbit equ 0023h ;регистр счета битов для передачи по протоколу spi dat_ind equ 0024h ;регистр хранения данных для передачи по протоколу spi adr_ind equ 0025h ;регистр хранения адреса для передачи по протоколу spi adr_tmp equ 0026h ;промежуточный адресный регистр для передачи по протоколу spi shet equ 0027h ;вспомогательный регистр счета tmp_symb equ 0028h ;вспомогательный регистр счета tmp_bit equ 0029h ;вспомогательный регистр счета tmp_bit1 equ 002Ah ;вспомогательный регистр счета symbol equ 002Bh ;регистр хранения байтов символа kol_matr equ 002Ch ;регистр количества используемых матриц kol_symb equ 002Dh ;регистр количества отображаемых символов tmp_tab equ 002Eh ;регистр хранения номера таблицы nomer equ 002Fh ;регистр хранения кода ascii символа temp equ 0030h ;вспомогательный регистр счета FSR_symb equ 0031h ;регистр хранения текущего символа для косвенной аддресации FSR_viv equ 0032h ;регистр хранения адреса для косвенной аддресации data_symb equ 0033h ;начальный регистр хранения символов для отображения data_viv equ 003Ah ;начальный регистр для передачи данных на драйвер #DEFINE din PORTB,5 ;линия входа данных драйвера #DEFINE cs PORTB,6 ;линия выбора драйвера #DEFINE clk PORTB,7 ;линия тактирования драйвера ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start movlw b'01000000' ;установка выходных защелок порта B movwf PORTB ; movlw b'00000111' ;выключение компараторов movwf CMCON ; bsf STATUS,RP0 ;выбрать 1-й банк movlw b'00011111' ;настройка линий ввода\вывода порта B movwf TRISB ;RB0-RB4 на вход, остальные на выход bcf STATUS,RP0 ;выбрать 0-й банк movlw .6 ; movwf kol_symb ;запись количества выводимых символов movlw .5 ; movwf kol_matr ;запись количества используемых матриц call init_lcd ;вызов подпрограммы инициализации драйверов ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Последовательная запись символов для вывода на светодиодную панель met_1 movlw data_symb ;установка начального регистра хранения символов для отображения movwf FSR ; movlw 'П' ;запись 1-го символа 'П' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'р' ;запись 2-го символа 'р' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'и' ;запись 3-го символа 'и' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'м' ;запись 4-го символа 'м' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'е' ;запись 5-го символа 'е' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'р' ;запись 6-го символа 'р' movwf INDF ; call vivod ;вызов подпрограммы вывода данных на матрицу call paus_2s ;вызов подпрограммы паузы 2 сек movlw data_symb ;установка начального регистра хранения символов для отображения movwf FSR ; movlw '+' ;запись 1-го символа '+' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw '2' ;запись 2-го символа '2' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw '3' ;запись 3-го символа '3' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw '.' ;запись 4-го символа '.' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw '9' ;запись 5-го символа '9' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw .176 ;запись 6-го символа размерности температуры, угла movwf INDF ; ; call vivod ;вызов подпрограммы вывода данных на матрицу call paus_2s ;вызов подпрограммы паузы 2 сек movlw data_symb ;установка начального регистра хранения символов для отображения movwf FSR ; movlw 'R' ;запись 1-го символа '+' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'a' ;запись 2-го символа '2' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'd' ;запись 3-го символа '3' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'i' ;запись 4-го символа '.' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw 'o' ;запись 5-го символа '9' movwf INDF ; incf FSR,F ;инкремент регистра FSR movlw '!' ;запись 6-го символа '9' movwf INDF ; call vivod ;вызов подпрограммы вывода данных на матрицу call paus_2s ;вызов подпрограммы паузы 2 сек goto met_1 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма вывода группы символов на светодиодную панель из матриц vivod movlw .1 ;запись адреса 1-го регистра драйвера, используется как счетчик movwf adr_ind ;выводимых строк на группу драйверов viv_3 movlw data_viv ;запись адреса начального регистра для передачи данных на драйверы movwf FSR_viv ; movlw .8 ;запись счетчика бит для подготовки регистров одной строки movwf tmp_bit1 ;на группу драйверов movf kol_symb,W ;копирование кол-ва выводимых символов movwf tmp_symb ;в регистр счетчика символов movlw data_symb ;установка начального регистра хранения символов для отображения movwf FSR ; decf FSR,F ; viv_1 incf FSR,F ; movf INDF,W ;копирование символа в регистр nomer movwf nomer ; call viv_symb ;вызов подпрограммы извлечения битов символа decfsz tmp_symb,F ;декремент счетчика символов goto viv_1 ; movlw .8 ;проверка пустой области в конце строки на последней матрице xorwf tmp_bit1,W ; btfsc STATUS,Z ; goto viv_2 ; movf FSR_viv,W ;восстановление адреса текущего регистра вывода данных на драйвера movwf FSR ; rlf INDF,F ;заполнение нулями пустой области в конце стрки для последнй bcf INDF,0 ;матрицы decfsz tmp_bit1,F ; goto $-3 ; viv_2 call send ;вызов подпрограммы отправки данных строки на группу драйверов incf adr_ind,F ;инкремент счетчика выводимых строк и проверка на факт передачи movlw .9 ;8-ми строк xorwf adr_ind,W ; btfss STATUS,Z ; goto viv_3 ; return ;выход из подпрограммы вывода символов ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Здесь выполняется поиск символа в таблицах данных viv_symb movwf nomer ; movlw .32 ; subwf nomer,W ; btfss STATUS,C ; return ;значение символа менее 32: выход из подпрограммы movf nomer,W ; sublw .82 ; btfss STATUS,C ; goto viv_symb_1 ;значение символа более 82: переход на метку viv_symb_1 movlw .32 ;значение символа более 31 и менее 83: символ в таблице tab_symb_1 subwf nomer,F ;вычитание числа 32 из ASCII кода символа, получаем movlw .1 ;преобразованное значение символа movwf tmp_tab ;запись номера таблицы (1) в регистр tmp_tab goto symb_lcd ; viv_symb_1 movf nomer,W ; sublw .126 ; btfss STATUS,C ; goto viv_symb_2 ;значение символа более 126: переход на метку viv_symb_2 movlw .83 ;значение символа более 82 и менее 127: символ в таблице tab_symb_2 subwf nomer,F ;вычитание числа 83 из ASCII кода символа, получаем movlw .2 ;преобразованное значение символа movwf tmp_tab ;запись номера таблицы (2) в регистр tmp_tab goto symb_lcd ; viv_symb_2 movf nomer,W ; sublw .191 ; btfss STATUS,C ; goto viv_symb_3 ;значение символа более 191: переход на метку viv_symb_3 movlw .176 ;проверка регистра nomer на совпадение с числом 176 xorwf nomer,W ;176 - ascii код символа размерности температры, угла btfss STATUS,Z ; return ;значение не совпадает: выход из подпрограммы movlw .13 ;значение символа равно 176, символ размерности температуры, угла movwf nomer ;устанавливаем вручную преобраз. значение символа movlw .4 ; movwf tmp_tab ;запись номера таблицы (4) в регистр tmp_tab goto symb_lcd ; viv_symb_3 movf nomer,W ; sublw .242 ; btfss STATUS,C ; goto viv_symb_4 ;значение символа более 242: переход на метку viv_symb_4 movlw .192 ;значение символа более 191 и менее 243: символ в таблице tab_symb_3 subwf nomer,F ;вычитание числа 192 из ASCII кода символа, получаем movlw .3 ;преобразованное значение символа movwf tmp_tab ;запись номера таблицы (3) в регистр tmp_tab goto symb_lcd ; viv_symb_4 movlw .243 ;значение символа более 242: символ в таблице tab_symb_4 subwf nomer,F ; movlw .4 ; movwf tmp_tab ;запись номера таблицы (4) в регистр tmp_tab ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;здесь выполняется извлечения битов символа symb_lcd movf nomer,W ;умножение преобразованного значения символа на 5 addwf nomer,F ; addwf nomer,F ; addwf nomer,F ; addwf nomer,F ; movlw .5 ; movwf temp ;запись счетчика для вывода 5 байт символа movf FSR,W ;сохранение адреса текущего символа для косвенной аддресации movwf FSR_symb ;и восстановление адреса регистра для передачи данных на драйверы movf FSR_viv,W ; movwf FSR ; symb_1 movlw .1 ;определение ранее записанного номера талицы xorwf tmp_tab,W ;для вызова соответствующей таблицы btfss STATUS,Z ; goto symb_m1 ; call tab_symb_1 ; goto symb_2 ; symb_m1 movlw .2 ; xorwf tmp_tab,W ; btfss STATUS,Z ; goto symb_m2 ; call tab_symb_2 ; goto symb_2 ; symb_m2 movlw .3 ; xorwf tmp_tab,W ; btfss STATUS,Z ; goto symb_m3 ; call tab_symb_3 ; goto symb_2 ; symb_m3 call tab_symb_4 ; symb_2 movwf symbol ;сохранение байта символа в регистр symbol movf adr_ind,W ;определение номера строки для вывода данных а также movwf tmp_bit ;выборка соответствующего бита из байта символа rlf symbol,F ; rrf symbol,F ; decfsz tmp_bit,F ; goto $-2 ; rlf INDF,F ;загрузка бита символа в регистры данных строки btfsc symbol,0 ;для передачи на группу драйверов bsf INDF,0 ; btfss symbol,0 ; bcf INDF,0 ; decfsz tmp_bit1,F ; goto symb_3 ; movlw .8 ; movwf tmp_bit1 ; incf FSR,F ; symb_3 incf nomer,F ;инкремент счетчика байтов для одного символа decfsz temp,F ;декремент счетчика байтов символа goto symb_1 ; rlf INDF,F ;запись нуля, разделителя символов bcf INDF,0 ; decfsz tmp_bit1,F ;декремент счетчика битов для подготовки регистров одной строки goto symb_4 ; movlw .8 ;очередной регистр заполнен битами символов, повторная установка movwf tmp_bit1 ;счетчика incf FSR,F ; symb_4 movf FSR,W ;сохранение адреса регистра для передачи данных на драйверы movwf FSR_viv ;и восстановление адреса текущего символа для косвенной аддресации movf FSR_symb,W ; movwf FSR ; return ;выход из подпрограммы извлечения битов символа ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма инициализации для драйверов MAX7219 включенных каскадно init_lcd call pauslcd ;вызов подпрограммы паузы 2 мс movlw 0x0F ;выключить тестовый режим movwf adr_ind ; movlw 0x00 ; call send_dat ; movlw 0x0C ;включить драйвер в рабочий режим movwf adr_ind ; movlw 0x01 ; call send_dat ; movlw 0x0A ;установить интенсивность свечения 11/32 movwf adr_ind ; movlw 0x05 ; call send_dat ; movlw 0x09 ;отключить декодирование для всех индикаторов movwf adr_ind ; movlw 0x00 ; call send_dat ; movlw 0x0B ;использовать 8 индикаторов movwf adr_ind ; movlw 0x07 ; call send_dat ; return ;выход из подпрограммы send_dat movwf dat_ind ;сохранение данных в регистре dat_ind movlw data_viv ;установка первого регистра данных для передачи movwf FSR ; movf kol_matr,W ;копирование числа используемых драйверов в счетчик shet movwf shet ; init_1 movf dat_ind,W ;копирование данных для передачи в регистр INDF movwf INDF ; incf FSR,F ;инкремент регистра FSR, подготовка следующего байта для передачи decfsz shet,F ;декремент счетчика используемых драйверов goto init_1 ; call send ;вызов подпрограммы передачи данных на дрйвер return ;выход из подпрограммы ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма передачи данных по протоколу SPI на драйвера MAX7219 включенных каскадно send bcf cs ;Сбросить линию выбора драйвера CS movlw data_viv ;установка первого регистра данных для передачи movwf FSR ; movf kol_matr,W ;копирование числа используемых драйверов в счетчик shet movwf shet ; povtr2 movlw .8 ;Отправка содержимого адресного байта adr_ind на драйвер movwf scetbit ; movf adr_ind,W ;копирование данных для передачи в промежуточный регистр movwf adr_tmp ; povtor bcf clk ; btfsc adr_tmp,7 ; bsf din ; btfss adr_tmp,7 ; bcf din ; bsf clk ; rlf adr_tmp,F ; decfsz scetbit,F ; goto povtor ; movlw .8 ;Отправка содержимого регистра INDF на драйвер movwf scetbit ; povtr1 bcf clk ; btfsc INDF,7 ; bsf din ; btfss INDF,7 ; bcf din ; bsf clk ; rlf INDF,F ; decfsz scetbit,F ; goto povtr1 ; ; incf FSR,F ;инкремент регистра FSR, подготовка следующего байта для передачи decfsz shet,F ;декремент счетчика используемых драйверов goto povtr2 ; ; bcf clk ; bsf cs ;установить в 1 линию выбора драйвера CS return ;выход из подпрограммы ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
В коде программы заложены таблицы, содержащие специальные знаки, цифры, латинский и кириллический алфавит. Каждый символ по ширине занимает 6 столбцов, включая пустой разделительный столбец, соответственно на панель из 5 матриц поместится 6 символов и еще останется 4 столбца. Можно подключить еще одну матрицу, тогда на панель уместится ровно 8 символов.
В программе на этапе первоначальной настройки, в регистр kol_symb необходимо записать число символов помещающихся на панели, а в регистр kol_matr число подключенных матриц. Далее в основной программе с помощью косвенной адресации записать последовательно шесть ASCII символов, которые нужно вывести на панель, начиная с адреса data_symb. В моем примере на панель последовательно с паузой 2 секунды выводятся надписи “Пример”, “+23.6⁰”, “Radio!”.
Для вывода группы символов вызывается подпрограмма vivod, где с помощью косвенной адресации заполняются 5 регистров (начиная с адреса data_viv) составляющих одну строку на панели. Заполнение регистров выполняется побитно, путем извлечения байтов каждого символа из таблиц данных. После заполнения, содержимое регистров передается на драйверы с помощью подпрограммы send, затем также подготавливаются данные для второй строки и т.д. Неиспользованные столбцы в конце панели заполняются нулями. Для тактовой частоты в 4 МГц, вывод данных на панель из 5 матриц занимает 22,5 мс.
В статье про подключение драйвера MAX7219 можно почитать более подробную информацию об этой микросхеме.
Игорь
14 Ноя 2016Осталось объединить “DS3231 – подключение часов реального времени” и “Подключение светодиодных матриц на MAX7219” и получатся “супер часы”, 😉 Возможно ли сие действо?
picasafire
3 Дек 2016Здравствуйте, а как сделать бегущую строку?
admin
3 Дек 2016Приветствую, для бегущей строки надо дорабатывать прошивку, я пока не занимался этим вопросом.
picasafire
3 Дек 2016Нужно перерабатывать подпрограмму vivod?
admin
3 Дек 2016да, кроме этого надо реализовать кольцевой буфер на определенное количество символов, которые будут перемещаться в виде бегущей строки, еще прикинуть хватит ли скорости микроконтроллера, скорее всего придется увеличивать тактовую частоту.
Илья
8 Дек 2016Приветствую, не подскажите при подаче питания на матрицу загораются сигменты по 9точек (3на3) и какую бы прошивку не пробовал эти сигменты горят постоянно. Что можно сделать?
admin
8 Дек 2016Здравствуйте, а какую прошивку использовали, матрица только одна?
Игорь
8 Дек 2016Здравствуйте.
Попробуйте перевернуть матрицу на плате на 180гр
Алла
9 Окт 2017Библиотека LedControl library может работать как с 7-ми сегментными светодиодными дисплеями, так и со светодиодными матрицами. В нашем случае будут использоваться методы для работы со светодиодными матрицами.