Драйвер светоидодов DM164.

Часто в своих устройствах хочется организовать красивую индикацию, а может устройство в принципе, по своей основной функции должно управлять большим количеством разноцветных светодиодов. В этом случае отличным, да и по сути единственным решением является использование RGB-светодиодов, которые управляются при помощи трех ШИМ сигналов (по одному на каждую цветовую составляющую — Red/Green/Blue). И вроде бы все отлично, но что если светодиодов требуется подключить, к примеру, 12 штук, и все они должны светиться по-разному. И 12 — это еще далеко не предел 😉 Получается, что нам придется под эти цели отдать как минимум 36 выводов микроконтроллера, а это, согласитесь, совсем немало. Вот как раз для таких случаев и придуманы специальные микросхемы под названием драйвер светодиодов, и об одной из них я сегодня и расскажу. Собственно, нашей задачей будет спроектировать небольшую схемку для подключения как раз-таки 12 RGB светодиодов и написать программу для управления их цветом.

Драйвер светодидов DM164

Начнем с обсуждения электронных компонентов, которые я буду использовать в работе. Итак, в качестве мозгового центра устройства будет выступать микроконтроллер STM32F103RBT6. Какой именно контроллер задействовать абсолютно непринципиально, так что это не имеет большого значения. Важным является выбор драйвера 😉 Я буду использовать (и активно использую) DM164. Светодиоды также можно использовать абсолютно разные, главное, чтобы они были с общим анодом.

Собственно, пару слов о самой микросхеме. У DM164 есть 24 выходных канала, то есть к одному драйверу мы можем подключить 8 светодиодов (по три канала на один светодиод). То есть нам для решения задачи понадобятся два драйвера (8 + 4 диодов). Для каждой цветовой составляющей мы можем задать яркость от 0 до 65536, таким образом, многообразие цветов просто фантастическое =) В зависимости от используемых диодов мы можем настроить значение выходного тока, для этого используются внешние резисторы. Максимально драйвер может выдавать 90 мА. Я не буду перечислять факты из документации на драйвер, поэтому давайте остановимся на уже упомянутых основных характеристиках драйвера и перейдем к практике.

Поскольку мы решили использовать две микросхемы, то я сразу же приведу схему для каскадного включения двух драйверов и поэтапно распишу что и зачем там используется

Схема подключения

Давайте начнем по порядку. На выводы VDD1 и VDD2 мы подаем напряжение питания — 3.3 В.

Соответственно, выводы VSSx мы заземляем. Кроме того, подключаем землю на выводы DCKPH и DOUTPH, которые отвечают за настройку протокола обмена. Вот как это выглядит:

Драйвер светодиодов DM164

В нашем случае DCKPH=DOUTPH=L 😉

К каждому из драйверов подключены три резистора. Они как раз задают выходной ток каналов DM164. Зависимость вот такая:

Зависимость выходного тока от номинала внешних резисторов

Мои светодиоды рассчитаны на ток 30 мА, поэтому, исходя из графика, я поставил резисторы номиналом 2.7 кОм.

С этим все довольно просто, переходим к управляющим выводам.

Сигнал EN_B — его мы подключаем на какую-нибудь ножку микроконтроллера, которая будет работать в режиме простого выхода. При высоком уровне на EN_B выходы драйвера отключены и светодиоды не горят, при низком, соответственно, светодиоды светятся тем цветом, который мы им передали по SPI.

Раз уж упомянул SPI, то давайте рассмотрим выводы DOUT, DCK и DIN. Собственно, это и есть выводы SPI 😉 Управление драйвером осуществляется именно по этому интерфейсу. Отправляя данные драйверу мы устанавливаем яркость для каждого из выходных каналов, а принимая данные мы можем диагностировать возникновение ошибок. Но в данном примере мы не будем использовать прием, поскольку по большому счету для стабильной работы это и не требуется.

Поскольку нам надо подключить два драйвера, а не один, то мы используем так называемое каскадное подключение. Как видно из схемы вывод DOUT первой микросхемы идет дальше, а именно на вход DIN второго драйвера. Таким образом, со стороны контроллера мы используем один модуль SPI. Яркости каждого канала соответствует 16-битное число, которое и необходимо отправить. Один светодиод — это три канала, поэтому у первого драйвера мы задействуем все 24, а у второго только половину (12) каналов. В результате нехитрых вычислений получается, что отправлять нам нужно будет 36 значений типа uint16_t 😉 Причем первые 12 из них «проскочат» первый драйвер и благодаря каскадному подключению дойдут до второго.

Двигаемся дальше по выводам микросхемы и на очереди сигнал GCK. Сюда мы должны подать ШИМ-сигнал с нашего микроконтроллера, он будет использоваться для формирования выходного сигнала каналов драйвера. Максимальная частота при напряжении питания 3.3 В составляет 36 МГц.

Вывод LATCH — «защелка». Именно подав этот сигнал мы дадим драйверу команду активировать выходы в соответствии с данными, которые мы к тому моменту уже должны будем передать.

Вывод ALARM нужен для того, чтобы диагностировать перегрев DM164, его мы тоже в примере не будем задействовать, но на схеме подключение предусмотрено — на всякий случай, для будущих нужд )

IWAVE отвечает за режим работы драйвера и на этот вход мы подадим высокий уровень (высокий — traditional Iout waveform, низкий — average separate Iout waveform).

MSEL позволяет конфигурировать драйвер — для этого его нужно перевести в состояние логической единицы.

И, наконец, ONEST — включает/отключает функцию one-shot. Мы этот режим не будем использовать, поэтому на эту ножку подаем просто низкий уровень.

IWAVE отвечает за режим работы драйвера и на этот вход мы подадим высокий уровень (высокий — traditional Iout waveform, низкий — average separate Iout waveform).

Диоды я подключил к последовательным каналам — то есть первый диод, к примеру, подключен катодами на IOUT0, IOUT1, IOUT2, а на общий анод подаем напряжение питания (3.3 В). Аналогичным образом подключаются все остальные диоды. У меня получилось, что за синюю составляющую цвета первого светодиода отвечает IOUT0, за красную — IOUT1, ну и за зеленую — IOUT2 (BGR).

Итак, вроде бы с электрическим подключением разобрались, давайте переходить к программной реализации.

Для этого проекта я буду использовать Keil и библиотеку SPL. При желании можно создать аналогичный проект при помощи STM32Cube.

Начинаем с подключения требующихся файлов:

#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_spi.h"

Далее объявим переменные:

SPI_InitTypeDef spi;
GPIO_InitTypeDef gpio;
TIM_TimeBaseInitTypeDef timer;
TIM_OCInitTypeDef timerPWM;
TIM_ICInitTypeDef timIC;
 
uint16_t currentColorData[36];
uint32_t i = 0;
uint16_t timeout;

Определим тайм-аут для передачи данных по SPI. На настройках периферии — таймеров и SPI я не буду отдельно останавливаться, поскольку все это мы уже обсуждали в статьях, посвященных этим модулям.

#define TIMEOUT_TIME                0x1000

Подключено у меня следующим образом:

  • ALARM — PB0
  • MSEL — PB1
  • LTH — PB10
  • IWAVE — PC4
  • ONEST — PC5
  • SPI_MOSI — PA7
  • SPI_CLK — PA5
  • GCK — PA3

Теперь нам нужно настроить все эти выводы и подать нужный сигнал на каждый из них, а также настроить GCK на генерацию ШИМ и модуль SPI1. GCK у нас на PA3, а это четвертый канал таймера TIM2:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
 
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_4;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio);
 
GPIO_ResetBits(GPIOC, GPIO_Pin_4);
 
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_5;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio);
 
GPIO_ResetBits(GPIOC, GPIO_Pin_5);
 
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_13;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio);
 
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_1;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio);
 
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
 
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_10;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio);
 
GPIO_ResetBits(GPIOB, GPIO_Pin_10);
 
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
gpio.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio);
 
TIM_TimeBaseStructInit(&timer);
timer.TIM_Prescaler = 1;
timer.TIM_Period = 2;
TIM_TimeBaseInit(TIM2, &timer);	
 
TIM_OCStructInit(&timerPWM);
timerPWM.TIM_Pulse = 1;
timerPWM.TIM_OCMode = TIM_OCMode_PWM1;
timerPWM.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC4Init(TIM2, &timerPWM);
 
TIM_Cmd(TIM2, ENABLE);
 
spi.SPI_Direction = SPI_Direction_1Line_Tx;
spi.SPI_DataSize = SPI_DataSize_16b;
spi.SPI_CPOL = SPI_CPOL_Low;
spi.SPI_CPHA = SPI_CPHA_1Edge;
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
spi.SPI_FirstBit = SPI_FirstBit_MSB;
spi.SPI_CRCPolynomial = 7;
spi.SPI_Mode = SPI_Mode_Master;
SPI_Init(SPI1, &spi);
 
SPI_Cmd(SPI1, ENABLE);

Подготавливаем передаваемые данные:

for (i = 0; i < 36; i += 3)
{
  currentColorData[i] = 65535;
  currentColorData[i + 1] = 0;
  currentColorData[i + 2] = 0;
}

Как вы помните, каналы у нас сгруппированы по три (каждый светодиод — 3 канала) и первый канал — это у нас синий, второй — красный, а третий зеленый цвет. Таким образом, при передаче такого массива все светодиоды должны выдать максимально яркий и чистый синий цвет 😉

Выполняем отправку:

for (i = 0; i < 36; i++)
{
  timeout = TIMEOUT_TIME;
  while ((SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) & (timeout != 0))
  {
    timeout--;
  }
  SPI_I2S_SendData(SPI1, currentColorData[i]);
  timeout = TIMEOUT_TIME;
  while ((SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) & (timeout != 0))
  {
    timeout--;
  }
}

Данные переданы — необходимо их «защелкнуть» — кратковременно подаем высокий уровень на LATCH.

GPIO_SetBits(GPIOB, GPIO_Pin_10);
GPIO_ResetBits(GPIOB, GPIO_Pin_10);

Вот и все! =) Диоды начинают светить красивым сними цветом. В общем-то можно задать любой цвет свечения, а можно разукрасить все светоидоды в разные цвета, а можно и вообще организовать красивую динамическую индикацию 😉 Все зависит от фантазии и, конечно, от задачи, которую необходмо реализовать. А мы на сегодня на этом заканчиваем, до скорой встречи!

Понравилась статья? Поделись с друзьями!

Драйвер светоидодов DM164.: 2 комментария
  1. Спасибо! Будем использовать по необходимости.
    P.S. Эта та что в корпусе LQFP48 ?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *