В данной статье мы рассмотрим подключение матричного дисплея MAX7219 к плате ESP32 с помощью ESP-IDF. Мы начнем с краткого описания светодиодной матрицы и ее взаимодействия с платой разработки ESP32, а затем перейдем к программированию ESP32 в VS Code с помощью расширения ESP-IDF. Мы продемонстрируем, как отображать различные символы и цифры на светодиодном точечно-матричном дисплее, который представляет собой массив светодиодов, обычно используемый для отображения различных типов текста, символов и изображений в виде точек (светодиодов).
Ранее на нашем сайте мы рассматривали подключение светодиодного матричного дисплея MAX7219 к плате Arduino.
Светодиодный матричный дисплей MAX7219
Светодиодный матричный дисплей MAX7219 широко используется в электронных проектах и выпускается в двух вариантах. Один тип известен как FC-16, а другой — как универсальный модуль.

Каждый модуль матрицей светодиодов MAX7219 состоит из двух элементов: матрицы 8×8 и микросхемы драйверов MAX7219, которая является одной из самых популярных микросхем для дисплеев. Матрица 8×8 состоит из 8 светодиодов в каждой строке и столбце, что в сумме составляет 64 светодиода, где каждая «точка» представляет собой светодиод. Каждому светодиоду (точке) соответствует номер строки и столбца.
Как видно на приведенной выше схеме, модуль MAX7219 имеет 5 контактов, состоящих из двух контактов питания (VCC и GND) и трех контактов связи SPI (DIN, CS и CLK). Кроме того, модуль содержит два набора этих контактов с обеих сторон, образующих входные и выходные соединения. Оба типа модулей, FC-16 и универсальный модуль, имеют одинаковые соединения с обеих сторон.
Давайте кратко обсудим обе эти связи.
Входные соединения
Контакты входного разъема подключены к микроконтроллеру, которым в нашем случае является плата разработки ESP32.
| VCC | Это вывод, подающий питание на светодиодный матричный модуль MAX7219. Чтобы установить яркость на половину, подключите его к выводу Vin микроконтроллера ESP32. |
| GND | Общий провод (земля) |
| DIN | Это данные, поступающие на контакт, используемый в SPI-связи между микроконтроллером и светодиодным модулем. Он действует как входной контакт SPI. |
| CS | Это контакт выбора микросхемы в интерфейсе SPI. |
| CLK | Это вывод тактового сигнала последовательного интерфейса SPI. |
Теперь перейдем к выходным контактам.
Выходные соединения
Если необходимо соединить несколько модулей MAX7219 вместе, используются выходные контакты. Они предлагают тот же набор из пяти контактов, что и входные, за исключением того, что вместо входного контакта данных используется контакт вывода данных.
| VCC | Этот контакт соединен с контактом VCC следующего подключенного модуля. |
| GND | Этот контакт соединен с контактом GND следующего подключенного модуля. |
| DOUT | Это контакт данных, который соединен с контактом данных (DIN) следующего подключенного модуля. |
| CS | Этот контакт соединяется с контактом CS следующего подключенного модуля. |
| CLK | Этот контакт соединяется с контактом CLK следующего подключенного модуля. |
С распиновкой дисплея разобрались, теперь рассмотрим епе его подключить к плате ESP32.
Подключение матричного дисплея MAX7219 к плате ESP32
Для подключения платы ESP32 к светодиодному матричному модулю MAX7219 нам потребуются следующие компоненты:
- Плата ESP32.
- Модуль MAX7219.
- Соединительные провода.
Для сопряжения светодиодной матрицы MAX7219 с ESP32 мы будем использовать интерфейс SPI отладочной платы. Отладочная плата ESP32 поставляется с двумя универсальными контроллерами SPI. Эти контроллеры SPI могут быть сконфигурированы для использования в качестве ведомых узлов, управляемых внешним SPI-мастером. Они известны как SPI2 (HSPI) и SPI3 (VSPI). Оба имеют отдельные сигнальные шины. Следовательно, мы можем использовать их по отдельности как в качестве мастера, так и в качестве ведомого устройства. Каждая шина может управлять до тремя SPI-устройствами или ведомыми устройствами в режиме контроллера.
В таблице ниже показаны стандартные контакты SPI ESP32 для обоих каналов.
| SPI-канал | MOSI | MISO | SCK/CLK | CS/SS |
| VSPI | GPIO23 | GPIO19 | GPIO18 | GPIO5 |
| HSPI | GPIO13 | GPIO12 | GPIO14 | GPIO15 |
Соединения между устройствами указаны в таблице ниже:
| Контакты модуля MAX7219 | ESP32 |
| VCC | Контакт VCC будет соединен с контактом Vin (5 В) платы ESP32. |
| GND | Общий провод (земля) с ESP32 |
| DIN | Этот вывод предназначен для приема данных по протоколу SPI. Мы подключим его к GPIO23, который является стандартным выводом SPI MOSI в ESP32. |
| CS | Этот вывод — это контакт выбора микросхемы по протоколу SPI. Мы подключим его к GPIO5, который является стандартным выводом SPI CS в ESP32. |
| CLK | Этот вывод является контактом тактового сигнала последовательного интерфейса SPI. Мы подключим его к GPIO18, который является выводом тактового сигнала SPI по умолчанию в ESP32. |
Подключите модуль MAX7219 к плате разработки ESP32, как показано на схеме ниже. Здесь мы используем модуль FC-16, состоящий из четырех блоков.
Использование ESP-IDF для подключения модуля MAX7219 к ESP32
Мы создадим проект в VS Code с расширением ESP-IDF, чтобы показать, как легко программировать ESP32 с модулем MAX7219. Код будет отображать различные изображения и числа на светодиодной матрице в режиме прокрутки. Мы будем использовать библиотеку MAX7219, предоставленную UncleRus на GitHub.
Создание примера проекта
Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.
Укажите название проекта и каталог, а также плату и целевое устройство ESP-IDF. Для платы ESP-IDF мы выбрали опцию custom board ("пользовательская плата"). Для целевого устройства ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ ("Выбрать шаблон"), чтобы продолжить.
В разделе «Расширение» выберите опцию ESP-IDF:
На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’) («Создать проект, используя шаблон sample_project»).
Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это откроет проект, который мы создали на вкладке «Проводник». Внутри папки проекта находится несколько папок. Это справедливо для каждого проекта, который вы будете создавать с помощью ESP-IDF Explorer.
Для начала добавим необходимые заголовочные файлы для библиотек, требуемых для этого проекта. Создайте новую папку с названием «components» и добавьте в неё файлы, перечисленные ниже:
- max7219.c
- max7219.h
- max7219_priv.h
- CMakeLists.txt
Эти файлы можно скачать по этой ссылке на GitHub.
max7219.c
|
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 |
/* * Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of itscontributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file max7219.c * * ESP-IDF driver for MAX7219/MAX7221 * Serially Interfaced, 8-Digit LED Display Drivers * * Ported from esp-open-rtos * * Copyright (c) 2017 Ruslan V. Uss <unclerus@gmail.com> * * BSD Licensed as described in the file LICENSE */ #include "max7219.h" #include <string.h> #include <esp_log.h> #include "max7219_priv.h" static const char *TAG = "max7219"; #define ALL_CHIPS 0xff #define ALL_DIGITS 8 #define REG_DIGIT_0 (1 << 8) #define REG_DECODE_MODE (9 << 8) #define REG_INTENSITY (10 << 8) #define REG_SCAN_LIMIT (11 << 8) #define REG_SHUTDOWN (12 << 8) #define REG_DISPLAY_TEST (15 << 8) #define VAL_CLEAR_BCD 0x0f #define VAL_CLEAR_NORMAL 0x00 #define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0) #define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0) static inline uint16_t shuffle(uint16_t val) { return (val >> 8) | (val << 8); } static esp_err_t send(max7219_t *dev, uint8_t chip, uint16_t value) { uint16_t buf[MAX7219_MAX_CASCADE_SIZE] = { 0 }; if (chip == ALL_CHIPS) { for (uint8_t i = 0; i < dev->cascade_size; i++) buf[i] = shuffle(value); } else buf[chip] = shuffle(value); spi_transaction_t t; memset(&t, 0, sizeof(t)); t.length = dev->cascade_size * 16; t.tx_buffer = buf; return spi_device_transmit(dev->spi_dev, &t); } inline static uint8_t get_char(max7219_t *dev, char c) { if (dev->bcd) { if (c >= '0' && c <= '9') return c - '0'; switch (c) { case '-': return 0x0a; case 'E': case 'e': return 0x0b; case 'H': case 'h': return 0x0c; case 'L': case 'l': return 0x0d; case 'P': case 'p': return 0x0e; } return VAL_CLEAR_BCD; } return font_7seg[(c - 0x20) & 0x7f]; } /////////////////////////////////////////////////////////////////////////////// esp_err_t max7219_init_desc(max7219_t *dev, spi_host_device_t host, uint32_t clock_speed_hz, gpio_num_t cs_pin) { CHECK_ARG(dev); memset(&dev->spi_cfg, 0, sizeof(dev->spi_cfg)); dev->spi_cfg.spics_io_num = cs_pin; dev->spi_cfg.clock_speed_hz = clock_speed_hz; dev->spi_cfg.mode = 0; dev->spi_cfg.queue_size = 1; dev->spi_cfg.flags = SPI_DEVICE_NO_DUMMY; return spi_bus_add_device(host, &dev->spi_cfg, &dev->spi_dev); } esp_err_t max7219_free_desc(max7219_t *dev) { CHECK_ARG(dev); return spi_bus_remove_device(dev->spi_dev); } esp_err_t max7219_init(max7219_t *dev) { CHECK_ARG(dev); if (!dev->cascade_size || dev->cascade_size > MAX7219_MAX_CASCADE_SIZE) { ESP_LOGE(TAG, "Invalid cascade size %d", dev->cascade_size); return ESP_ERR_INVALID_ARG; } uint8_t max_digits = dev->cascade_size * ALL_DIGITS; if (dev->digits > max_digits) { ESP_LOGE(TAG, "Invalid digits count %d, max %d", dev->digits, max_digits); return ESP_ERR_INVALID_ARG; } if (!dev->digits) dev->digits = max_digits; // Shutdown all chips CHECK(max7219_set_shutdown_mode(dev, true)); // Disable test CHECK(send(dev, ALL_CHIPS, REG_DISPLAY_TEST)); // Set max scan limit CHECK(send(dev, ALL_CHIPS, REG_SCAN_LIMIT | (ALL_DIGITS - 1))); // Set normal decode mode & clear display CHECK(max7219_set_decode_mode(dev, false)); // Set minimal brightness CHECK(max7219_set_brightness(dev, 0)); // Wake up CHECK(max7219_set_shutdown_mode(dev, false)); return ESP_OK; } esp_err_t max7219_set_decode_mode(max7219_t *dev, bool bcd) { CHECK_ARG(dev); dev->bcd = bcd; CHECK(send(dev, ALL_CHIPS, REG_DECODE_MODE | (bcd ? 0xff : 0))); CHECK(max7219_clear(dev)); return ESP_OK; } esp_err_t max7219_set_brightness(max7219_t *dev, uint8_t value) { CHECK_ARG(dev); CHECK_ARG(value <= MAX7219_MAX_BRIGHTNESS); CHECK(send(dev, ALL_CHIPS, REG_INTENSITY | value)); return ESP_OK; } esp_err_t max7219_set_shutdown_mode(max7219_t *dev, bool shutdown) { CHECK_ARG(dev); CHECK(send(dev, ALL_CHIPS, REG_SHUTDOWN | !shutdown)); return ESP_OK; } esp_err_t max7219_set_digit(max7219_t *dev, uint8_t digit, uint8_t val) { CHECK_ARG(dev); if (digit >= dev->digits) { ESP_LOGE(TAG, "Invalid digit: %d", digit); return ESP_ERR_INVALID_ARG; } if (dev->mirrored) digit = dev->digits - digit - 1; uint8_t c = digit / ALL_DIGITS; uint8_t d = digit % ALL_DIGITS; ESP_LOGV(TAG, "Chip %d, digit %d val 0x%02x", c, d, val); CHECK(send(dev, c, (REG_DIGIT_0 + ((uint16_t)d << 8)) | val)); return ESP_OK; } esp_err_t max7219_clear(max7219_t *dev) { CHECK_ARG(dev); uint8_t val = dev->bcd ? VAL_CLEAR_BCD : VAL_CLEAR_NORMAL; for (uint8_t i = 0; i < ALL_DIGITS; i++) CHECK(send(dev, ALL_CHIPS, (REG_DIGIT_0 + ((uint16_t)i << 8)) | val)); return ESP_OK; } esp_err_t max7219_draw_text_7seg(max7219_t *dev, uint8_t pos, const char *s) { CHECK_ARG(dev && s); while (s && pos < dev->digits) { uint8_t c = get_char(dev, *s); if (*(s + 1) == '.') { c |= 0x80; s++; } CHECK(max7219_set_digit(dev, pos, c)); pos++; s++; } return ESP_OK; } esp_err_t max7219_draw_image_8x8(max7219_t *dev, uint8_t pos, const void *image) { CHECK_ARG(dev && image); for (uint8_t i = pos, offs = 0; i < dev->digits && offs < 8; i++, offs++) max7219_set_digit(dev, i, *((uint8_t *)image + offs)); return ESP_OK; } |
max7219.h
|
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 |
/* * Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of itscontributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file max7219.h * @defgroup max7219 max7219 * @{ * * ESP-IDF driver for MAX7219/MAX7221 * Serially Interfaced, 8-Digit LED Display Drivers * * Ported from esp-open-rtos * * Copyright (c) 2017 Ruslan V. Uss <unclerus@gmail.com> * * BSD Licensed as described in the file LICENSE */ #ifndef __MAX7219_H__ #define __MAX7219_H__ #include <stdint.h> #include <stdbool.h> #include <driver/spi_master.h> #include <driver/gpio.h> // add by nopnop2002 #include <esp_err.h> #ifdef __cplusplus extern "C" { #endif #define MAX7219_MAX_CLOCK_SPEED_HZ (10000000) // 10 MHz #define MAX7219_MAX_CASCADE_SIZE 8 #define MAX7219_MAX_BRIGHTNESS 15 /** * Display descriptor */ typedef struct { spi_device_interface_config_t spi_cfg; spi_device_handle_t spi_dev; uint8_t digits; //!< Accessible digits in 7seg. Up to cascade_size * 8 uint8_t cascade_size; //!< Up to `MAX7219_MAX_CASCADE_SIZE` MAX721xx cascaded bool mirrored; //!< true for horizontally mirrored displays bool bcd; } max7219_t; /** * @brief Initialize device descriptor * * @param dev Device descriptor * @param host SPI host * @param clock_speed_hz SPI clock speed, Hz * @param cs_pin CS GPIO number * @return `ESP_OK` on success */ esp_err_t max7219_init_desc(max7219_t *dev, spi_host_device_t host, uint32_t clock_speed_hz, gpio_num_t cs_pin); /** * @brief Free device descriptor * * @param dev Device descriptor * @return `ESP_OK` on success */ esp_err_t max7219_free_desc(max7219_t *dev); /** * @brief Initialize display * * Switch it to normal operation from shutdown mode, * set scan limit to the max and clear * * @param dev Display descriptor * @return `ESP_OK` on success */ esp_err_t max7219_init(max7219_t *dev); /** * @brief Set decode mode and clear display * * @param dev Display descriptor * @param bcd true to set BCD decode mode, false to normal * @return `ESP_OK` on success */ esp_err_t max7219_set_decode_mode(max7219_t *dev, bool bcd); /** * @brief Set display brightness * * @param dev Display descriptor * @param value Brightness value, 0..MAX7219_MAX_BRIGHTNESS * @return `ESP_OK` on success */ esp_err_t max7219_set_brightness(max7219_t *dev, uint8_t value); /** * @brief Shutdown display or set it to normal mode * * @param dev Display descriptor * @param shutdown Shutdown display if true * @return `ESP_OK` on success */ esp_err_t max7219_set_shutdown_mode(max7219_t *dev, bool shutdown); /** * @brief Write data to display digit * * @param dev Display descriptor * @param digit Digit index, 0..dev->digits - 1 * @param val Data * @return `ESP_OK` on success */ esp_err_t max7219_set_digit(max7219_t *dev, uint8_t digit, uint8_t val); /** * @brief Clear display * * @param dev Display descriptor * @return `ESP_OK` on success */ esp_err_t max7219_clear(max7219_t *dev); /** * @brief Draw text on 7-segment display * * @param dev Display descriptor * @param pos Start digit * @param s Text * @return `ESP_OK` on success */ esp_err_t max7219_draw_text_7seg(max7219_t *dev, uint8_t pos, const char *s); /** * @brief Draw 64-bit image on 8x8 matrix * * @param dev Display descriptor * @param pos Start digit * @param image 64-bit buffer with image data * @return `ESP_OK` on success */ esp_err_t max7219_draw_image_8x8(max7219_t *dev, uint8_t pos, const void *image); #ifdef __cplusplus } #endif /**@}*/ #endif /* __MAX7219_H__ */ |
max7219_priv.h
|
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 |
/* * Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of itscontributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file max7219_priv.h * * ESP-IDF driver for MAX7219/MAX7221 * Serially Interfaced, 8-Digit LED Display Drivers * * Ported from esp-open-rtos * * Copyright (c) 2017, 2018 Ruslan V. Uss <unclerus@gmail.com> * * BSD Licensed as described in the file LICENSE */ #ifndef __MAX7219_PRIV_H__ #define __MAX7219_PRIV_H__ static const uint8_t font_7seg[] = { /* ' ' ! " # $ % & ' ( ) */ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4e, 0x78, /* * + , - . / 0 1 2 3 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x7e, 0x30, 0x6d, 0x79, /* 4 5 6 7 8 9 : ; < = */ 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x00, 0x00, 0x0d, 0x09, /* > ? @ A B C D E F G */ 0x19, 0x65, 0x00, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47, 0x5e, /* H I J K L M N O P Q */ 0x37, 0x06, 0x38, 0x57, 0x0e, 0x76, 0x15, 0x1d, 0x67, 0x73, /* R S T U V W X Y Z [ */ 0x05, 0x5b, 0x0f, 0x1c, 0x3e, 0x2a, 0x49, 0x3b, 0x6d, 0x4e, /* \ ] ^ _ ` a b c d e */ 0x00, 0x78, 0x00, 0x08, 0x02, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, /* f g h i j k l m n o */ 0x47, 0x5e, 0x37, 0x06, 0x38, 0x57, 0x0e, 0x76, 0x15, 0x1d, /* p q r s t u v w x y */ 0x67, 0x73, 0x05, 0x5b, 0x0f, 0x1c, 0x3e, 0x2a, 0x49, 0x3b, /* z { | } ~ */ 0x6d, 0x4e, 0x06, 0x78, 0x00 }; #endif /* __MAX7219_PRIV_H__ */ |
CMakeLists.txt
|
1 2 3 4 5 |
idf_component_register( SRCS max7219.c INCLUDE_DIRS . REQUIRES driver log ) |
Теперь перейдите к файлу main.c. В папке main находится исходный код, то есть файл main.c будет находиться здесь. Перейдите в папку main > main.c и откройте его. Скопируйте приведенный ниже код из этого файла и сохраните его.
Код ESP32 для работы с модулем MAX7219
|
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 |
#include <stdio.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <esp_idf_version.h> #include <max7219.h> #ifndef APP_CPU_NUM #define APP_CPU_NUM PRO_CPU_NUM #endif #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0) #define HOST HSPI_HOST #else #define HOST SPI2_HOST #endif #define CASCADE_SIZE 1 #define MOSI_PIN 23 #define CS_PIN 5 #define CLK_PIN 18 static const uint64_t symbols[] = { 0x3c66666e76663c00, // digits 0-9 0x7e1818181c181800, 0x7e060c3060663c00, 0x3c66603860663c00, 0x30307e3234383000, 0x3c6660603e067e00, 0x3c66663e06663c00, 0x1818183030667e00, 0x3c66663c66663c00, 0x3c66607c66663c00 , 0x383838fe7c381000, // arrow up 0x10387cfe38383800, //arrow down 0x10307efe7e301000, //arrow right 0x1018fcfefc181000 //arrow left }; static const size_t symbols_size = sizeof(symbols) - sizeof(uint64_t) * CASCADE_SIZE; void task(void *pvParameter) { spi_bus_config_t cfg = { .mosi_io_num = MOSI_PIN, .miso_io_num = -1, .sclk_io_num = CLK_PIN, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 0, .flags = 0 }; ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1)); max7219_t dev = { .cascade_size = CASCADE_SIZE, .digits = 0, .mirrored = true }; ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, CS_PIN)); ESP_ERROR_CHECK(max7219_init(&dev)); size_t offs = 0; while (1) { for (uint8_t i=0; i<CASCADE_SIZE; i++) max7219_draw_image_8x8(&dev,i*8,(uint8_t *)symbols + i*8 + offs); vTaskDelay(pdMS_TO_TICKS(500)); if (++offs == symbols_size) offs = 0; } } void app_main() { xTaskCreatePinnedToCore(task, "task", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL, APP_CPU_NUM); } |
Этот код можно также скачать по следующей ссылке.
Как работает код?
Для начала мы подключим необходимые для этого проекта библиотеки, включая библиотеки FreeRTOS для создания задач и генерации задержек, а также библиотеку max7219 для работы с матрицей светодиодов.
|
1 2 3 4 5 |
#include <stdio.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <esp_idf_version.h> #include <max7219.h> |
Далее мы добавим несколько определений, включающих размер каскада, который мы установили равным «1», поскольку будем использовать один модуль MAX7214.
|
1 |
#define CASCADE_SIZE 1 |
Контакты SPI для MOSI, CS и CLK установлены как GPIO23, GPIO5 и GPIO18 соответственно. Это также стандартные контакты SPI VSPI ESP32.
|
1 2 3 |
#define MOSI_PIN 23 #define CS_PIN 5 #define CLK_PIN 18 |
Далее мы создаём входную матрицу в виде 64-битных чисел в шестнадцатеричном формате. В данном случае состояние светодиодной матрицы 8×8 представляется в виде беззнакового целого числа (uint64_t). Символы изображают цифры от 0 до 9, а затем стрелки, указывающие вверх, вниз, вправо и влево. Эти изображения будут отображаться на светодиодной матрице.
Для формирования массива symbols[] мы использовали онлайн-редактор светодиодных матриц. Вы также можете использовать его для отображения предпочитаемых вами анимаций.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static const uint64_t symbols[] = { 0x3c66666e76663c00, // digits 0-9 0x7e1818181c181800, 0x7e060c3060663c00, 0x3c66603860663c00, 0x30307e3234383000, 0x3c6660603e067e00, 0x3c66663e06663c00, 0x1818183030667e00, 0x3c66663c66663c00, 0x3c66607c66663c00 , 0x383838fe7c381000, // arrow up 0x10387cfe38383800, //arrow down 0x10307efe7e301000, //arrow right 0x1018fcfefc181000 //arrow left }; |
Размер символа/изображения рассчитывается путем вычитания из общего размера светодиодной матрицы размера используемых модулей (CASCADE_SIZE).
|
1 |
static const size_t symbols_size = sizeof(symbols) - sizeof(uint64_t) * CASCADE_SIZE; |
Внутри функции task() мы сначала настраиваем и инициализируем шину SPI, а затем настраиваем и инициализируем устройство MAX7219 для отображения анимации на светодиодной матрице.
|
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 |
void task(void *pvParameter) { spi_bus_config_t cfg = { .mosi_io_num = MOSI_PIN, .miso_io_num = -1, .sclk_io_num = CLK_PIN, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 0, .flags = 0 }; ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1)); max7219_t dev = { .cascade_size = CASCADE_SIZE, .digits = 0, .mirrored = true }; ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, CS_PIN)); ESP_ERROR_CHECK(max7219_init(&dev)); size_t offs = 0; while (1) { for (uint8_t i=0; i<CASCADE_SIZE; i++) max7219_draw_image_8x8(&dev,i*8,(uint8_t *)symbols + i*8 + offs); vTaskDelay(pdMS_TO_TICKS(500)); if (++offs == symbols_size) offs = 0; } } |
Для настройки шины SPI мы создаём структуру конфигурации SPI spi_bus_config_t. Она будет содержать параметры шины SPI, включая используемые контакты. После этого мы инициализируем шину SPI с помощью структуры конфигурации SPI, вызвав функцию spi_bus_initialize(). Эта функция инициализации главной шины принимает три параметра: идентификатор хоста, указатель на структуру конфигурации шины и канал DMA.
|
1 2 3 4 5 6 7 8 9 10 |
spi_bus_config_t cfg = { .mosi_io_num = MOSI_PIN, .miso_io_num = -1, .sclk_io_num = CLK_PIN, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 0, .flags = 0 }; ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1)); |
Далее мы настроим устройство MAX7219, задав параметры структуры дескриптора дисплея max7219_t. Она содержит размер каскада, доступные разряды и состояние горизонтального зеркального дисплея. После этого мы инициализируем модуль MAX7219, вызывая функции max7219_init_desc() и max7219_init() одновременно. Первая функция инициализирует устройство на шине SPI, принимая в качестве параметров указатель на структуру max7219_t, идентификатор хоста, тактовую частоту устройства и набор контактов SPI CS. Вторая функция принимает в качестве параметра указатель на структуру max7219_t.
|
1 2 3 4 5 6 7 |
max7219_t dev = { .cascade_size = CASCADE_SIZE, .digits = 0, .mirrored = true }; ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, CS_PIN)); ESP_ERROR_CHECK(max7219_init(&dev)); |
Внутри бесконечного цикла while мы будем использовать цикл for для отображения изображений на светодиодной матрице с задержкой в 0,5 секунды. Функция max7219_draw_image_8x8() вызывается внутри цикла for и в нашем случае выполняется один раз, поскольку CASCADE_SIZE установлен равным 1. Эта функция принимает три параметра: указатель на структуру max7219_t, позицию начальной цифры и 64-битный буфер с данными изображения.
|
1 2 3 4 5 6 7 8 9 10 11 |
size_t offs = 0; while (1) { for (uint8_t i=0; i<CASCADE_SIZE; i++) max7219_draw_image_8x8(&dev,i*8,(uint8_t *)symbols + i*8 + offs); vTaskDelay(pdMS_TO_TICKS(500)); if (++offs == symbols_size) offs = 0; } |
Внутри функции app_main() задача создается путем вызова функции xTaskCreatePinnedToCore().
|
1 2 3 4 |
void app_main() { xTaskCreatePinnedToCore(task, "task", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL, APP_CPU_NUM); } |
Компиляция скетча
Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.
|
1 |
idf.py -p COMX flash monitor |
После успешной прошивки кода светодиодная матрица MAX7219 Dot начинает многократно отображать различные цифры и стрелки.
1 просмотров







