Умный индикатор

Rate this item
(2 votes)

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Постановка задачи, требования к самодельному индикатору

Мы будем делать индикатор, состоящий из произвольного количества светодиодов, управляемых микроконтроллером. Основные требования к нашему индикатору:

  • низкое энергопотребление в спящем режиме

  • управление одним МК большим количеством светодиодов

  • управление каждым светодиодом независимо

  • управление яркостью

  • минимальное количество компонент — в идеале МК и светодиоды

  • одностороннее размещение на плате — для более тонкого исполнения

  • управление индикатором по одному проводу

  • диапазон питания 3-5в

Таким образом, вы сами сможете расположить светодиоды на плате как вам необходимо. Например, в форме сердечка или ёлочки. Для управления достаточно подключить 3 провода — GND, VDD, и управляющий вывод. Управлять можно будет каждым светодиодом независимо.

{product id=33}

Подбор компонентов

Светодиоды

Будем использовать обычные smd светодиоды различных цветов формата 0603. Его легко паять, он ярко светит, легко купить.

Интерфейс общения

Нам нужно минимизировать количество проводов от данного индикатора. Для передачи информации нашему индикатору будем использовать совместимый с широко распространённым протоколом 1-wire. Таким образом, нужно всего 3 провода — питание, GND и управляющий провод. Почти для всех типов МК есть примеры для работы по данному протоколу, так что проблем с подключением данного индикатора к проекту не будет.

Начинается посылка с сигнала RESET. Первый байт — служебный, перевод в спящий режим или задает яркость светодиодов. Далее нужное количество байт, по одному биту на каждый светодиод. Например, для 24 светодиодов, одна посылка занимает 400 мкс + 60мкс * 32 = 2 мс, что вполне достаточно даже для мигания светодиодами.

Микроконтроллер

Продолжаем эксплуатировать STM8. Выбираем исключительно по цене. Индикатор должен быть не дорогим. Конечно хотелось бы больше ног, но в этом случае получается дороже цена. Ну и потом, разместить большое количество светодиодов компактно, на одной стороне — не так просто. Так что, хватит самого простого МК stm8s003. Данный МК дает широкий диапазон питания от 3 до 5В.

Если бороться за энергопотребление, то лучше взять серию stm8l, но цена МК будет в два раза дороже. Также снизится напряжение питания, нельзя будет подключить напрямую от 5В.

Составляем схему

Обвязка МК стандартная. Сам МК, пару конденсаторов и все. А вот со светодиодами будем использовать чуть модернизированную методику чарлиплексинга. Выделим несколько выводов МК как управляющие. Минимум один. Остальные выводы МК рабочие, не больше 20, иначе будет низкая яркость. Каждый управляющий вывод снабдим резистором, рассчитанными на максимальную яркость светодиода из расчёта 5 вольтового питания 220Ом. Между каждым управляющим выводом, после резистора, и рабочим выводом МК разместим по 2 светодиода, навстречу друг другу разной полярностью. Получится такая схема.


Как управлять светодиодами в такой схеме? Чтобы зажечь один светодиод, необходимо на управляющем выводе подать 0, а на рабочем 1. Чтобы зажечь другой светодиод из пары, надо на управляющем подать 1, а на рабочем 0. Чтобы оба погасить, на управляющем может быть любой сигнал, а рабочий надо перевести в такое же состояние или в режим входа. Выводы PB4 и PB5 не могут иметь 1, поэтому там может быть только по одному светодиоду. Вывод PA1 во время сна переводится в input pull-up, это надо иметь ввиду. Одновременно можно зажигать только один светодиод на один управляющий вывод, иначе они могут выйти из строя. У нас 14 выводов. Итого, например, если будет 4 управляющих и 10 рабочих — то будет 80 светодиодов, а если 6 управляющих и 8 рабочих — то 96. Так что, можно считать, что ограничение — это ваше желание паять столько светодиодов и возможность разместить их на плате. Для реальных проектов хватит 20-30 светодиодов.

Вывод PRG будем использовать для управления. Он будет находится в режиме input pull-up. А общаться будем по протоколу 1-wire. Так что, это не будет мешать программированию. При такой схеме — у нас всего 1 резистор на 20 светодиодов. Очень удобно!

Примеры готовых индикаторов

Велокомпьютер

Для нашего прибора велокомпьютер, можно использовать индикатор — две шкалы, и четыре светодиода. Одна шкала красная, отражает скорость, вторая шкала зеленая отражает каденс. На второй шкале можно отражать процент потраченных калорий от запланированных. Информационные светодиоды можно использовать так: один верхний светодиод — синий, показывает состояние блютус; два верхних светодиода — красные — отражают нарушение скорости и каденса. Получается такая плата, ровно под корпус.


А так в корпусе. Под каждый светодиод сверлим отверстие 1.5 - 2 мм. Это очень легко сделать, если к корпусу приклеить распечатку платы, она будет шаблоном для сверления. Можно расточить эти отверстия в одну общую щель. На внутреннюю часть корпуса можно приклеить прозрачный пластик (например от DVD диска). Можно залить щель прозрачной эпоксидкой.

В таком формате можно разместить его на руле и будет отлично видно текущую скорость и каденс. Потребление такого индикатора в дороге будет около 2 мА. В спящем режиме добавит еще 5 мкА.

GPS трекер

Для GPS трекера индикатор будет состоять из 8 ми светодиодов красного цвета по кругу — для обозначения направления. Четыре светодиода сверху будут отображать записанные в память точки и активную точку. Размер 2х2 см. Толщина 2мм. Отлично разместится в таком небольшом корпусе.


А так он будет выглядеть в собранном приборе.

 

Ваш индикатор

Вы можете сделать любой индикатор и использовать в своих проектах. У вас будет не только уникальный прибор, но и уникальный индикатор к нему!

Примеры индикатора:

  • шкала по кругу для роторного энкодера

  • часы и минуты — два круга светодиодов 24 светодиода

  • несколько шкал громкости на разные каналы

  • отображение уровня жидкости в процентах и различные статусные светодиоды

  • компактное отображение количества подключенных датчиков

  • матрица 8 х 8 из светодиодов — отображаем динамические картинки

  • ваш логотип из светодиодов

Программа

Программу как обычно пишем в среде ST Visual Develop, на основе стандартной библиотеки.

Общая логика работы программы

Для работы программы будем использовать два таймера — один для протокола 1-wire, с минимальной градацией 8 мкс, и второй для динамической индикации, с частотой 1000 Гц и PWM режимом. Сам МК будет работать на частоте 2МГц, от внутреннего генератора.

Для управления светодиодами будем использовать механизм динамической индикации. Каждый рабочий вывод по сути будет сегментом. Итого максимальная яркость, которую мы можем получить, будет равна яркости одного светодиода поделённой на количество всех светодиодов и умноженное на количество управляющих выводов. Например, если у нас 10 светодиодов и один управляющий вывод с резистором, то яркость будет 1/10 от максимальной. Светодиоды светятся довольно ярко, так что для индикатора это вполне достаточная яркость.

Для управления каждым светодиодом создадим массив по числу светодиодов. Единица в этом массиве будет означать, что светодиод горит. Далее все просто. При включении настроим всю периферию и перейдём в спящий режим. По прерыванию, на входе 1-wire, просыпаемся, получаем посылку и начинаем управлять светодиодами. Если получили команду — спать, то выключаем все и спим.

Инициализация

Как обычно, отключим всю периферию и перейдем на частоту 2 МГц. Таймер TIM2 будем использовать для динамической индикации.

  CLK->PCKENR1 = CLK_PCKENR1_TIM4+CLK_PCKENR1_TIM2;
  CLK->PCKENR2 = 0b01110011;
 
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);
 
  TIM2_TimeBaseInit(TIM2_PRESCALER_16, 124);//1000Гц.
  TIM2_ClearFlag(TIM2_FLAG_UPDATE);
  TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
  TIM2->IER |= (uint8_t)TIM2_IT_UPDATE | TIM2_IT_CC1;
 
  TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_DISABLE,124,TIM2_OCPOLARITY_HIGH);
  TIM2_OC1PreloadConfig(ENABLE);
  TIM2_ARRPreloadConfig(ENABLE);
 

Для регулирования яркости будем использовать PWM режим таймера TIM2. Разрешение PWM нам высокое не нужно, сделаем 124 градации яркости. В начале яркость максимальная. Частота таймера 1000 Гц. Прерывания будут задействованы по обновлению таймера и по сравнению со значением PWM скважности.

Для приёма команд по протоколу 1-wire будем использовать таймер TIM4. Его задача будет отсчитать таймаут и определить первый стартовый сигнал RESET. Настраиваем его в одиночный режим, то есть по окончанию отсчёта он остановится и все. Прерывания на нем нам не нужны.

  TIM4_Cmd(DISABLE);//для приема 1-wire
  TIM4_TimeBaseInit(TIM4_PRESCALER_16, 200);//8 микросекунды один тик до 1600мкс - как таймаут!
  TIM4_SelectOnePulseMode(TIM4_OPMODE_SINGLE);//одиночныйрежим
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  TIM4->CNTR=0;
 

Сам таймер пока остановлен, значение счётчика обнулено. Максимальное значение 1600 мкс. Для корректной работы протокола 1-wire необходимо установить срабатывания прерывания на управляющем выводе на FALL_ONLY (по падению сигнала) и установить максимальный приоритет данному прерыванию, чтобы нас ничего не отвлекало при декодировании сигнала.

  EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOD,EXTI_SENSITIVITY_FALL_ONLY);//самыйвысокий приоритет имеет
  ITC_SetSoftwarePriority(ITC_IRQ_TIM2_OVF, ITC_PRIORITYLEVEL_2);
  ITC_SetSoftwarePriority(ITC_IRQ_TIM4_OVF, ITC_PRIORITYLEVEL_2);
  ITC_SetSoftwarePriority(ITC_IRQ_PORTD, ITC_PRIORITYLEVEL_3);
 

Дальше инициализируем все выводы. Ставим их как PUSH PULL и значение 0. Это самый лучший вариант для сна, наименьшее энергопотребление. Вывод для управления индикатором ставим как PULL_UP с прерываниями (этот вывод SWIM).

  //GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_IT);//приемсигнала! для тестирования!
  GPIO_Init(GPIOD,GPIO_PIN_1,GPIO_MODE_IN_PU_IT);//приемсигнала!
 
  sleep();
 

Если вы решили потестировать работу протокола обмена у индикатора, то надо выделить другой вывод для управления, потому что отладка и одновременный приём сигнала 1-wire работать не будет. Переходим в спящий режим. Используем специальную процедуру, чтобы погасить все светодиоды перед переход в спящий режим. В ней же инициализируем все выводы.

void sleep(void) {
  stoptim = 1;//чтобы не менять индикацию
  //переключаем все выводы на GND
  //переходим в спящий режим
  GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_SLOW);
  GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_LOW_SLOW);
  GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_LOW_SLOW);
  GPIO_Init(GPIOB,GPIO_PIN_4|GPIO_PIN_5,GPIO_MODE_OUT_OD_LOW_SLOW);
 
  halt();
  stoptim = 0;
}
 

Специальная переменная будет отключать на всякий случай работу таймера, чтобы не включить обратно светодиоды в момент перехода в сон.

Динамическая индикация

С динамической индикацией вы уже умеете работать. Подробно мы её рассматривали в приборе Кухонный таймер. Обработка ведётся в обработчике прерывания TIM2. В данном приборе мы будем использовать возможность данного таймера работать в PWM режиме. Это позволит нам удобно управлять яркостью светодиодов.

Давайте немного посчитаем. Допустим мы решили управлять одним управляющим выводом сразу 20 светодиодами. В случае динамической индикации нам придётся последовательно включать каждый светодиод и так пока не переберём все 20. Если частота таймера у нас будет 1000 Гц, то итоговая частота мигания одного светодиода будет 1000 / 20 = 50 Гц. Этого вполне достаточно, но ниже опускать не стоит — будет заметно мерцание. Если в этом случае поступить как мы делали в кухонном таймере, то есть добавлять пустых циклов, то для управления яркостью надо будет поднять частоту таймера до 10 000 Гц и выше. При нашей частоте процессора в 2 МГц, это становится проблемой. Поэтому самый правильный вариант использовать PWM режим. В этом случае все относительно просто. С частотой в 1000Гц мы перебираем каждый светодиод и включаем его, а потом по прерыванию Capture and Compare, мы выключаем все светодиоды. В таком выбранное максимальное число в таймере ARR = 124 будет служить нам градациями яркости. Стоит отметить, что при нашей не высокой частоте процессора, мы должны успеть обработать логику включения нужного светодиода. Минимальная яркость у нас должна быть больше чем процедура обработки. Можно подобрать опытным путем — для 20 светодиодов, например, это 8 единиц при такой настройке таймера.

Теперь перейдем к обзору самой процедуры.

INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
 {
  if (stoptim) 
  {
    TIM2->SR1 = (uint8_t)(~TIM2_IT_UPDATE);
    return;
  }  
 
    //милисекунды
    if (timedelay) timedelay--;
 
    //все выкл!
    GPIOA->DDR &= (u8) (~ (GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3));
    //GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_IN_FL_NO_IT);
    GPIOD->DDR &= (u8) (~(GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6) );
    //GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_IN_FL_NO_IT);
    GPIOC->DDR &= (u8) (~(GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7) );
    //GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_IN_FL_NO_IT);
    GPIOB->DDR &= (u8) (~ (GPIO_PIN_4|GPIO_PIN_5) );
    //GPIO_Init(GPIOB,GPIO_PIN_4|GPIO_PIN_5,GPIO_MODE_IN_FL_NO_IT);
 }
 

Сначала как обычно, сбросим бит отложенного прерывания. Выключим все светодиоды, для этого переведем в FLOAT все наши управляющие ножки. Для большей производительности будет использовать напрямую регистр DDR. Библиотечные функции вызываются очень долго. Дальше необходимо перебрать все комбинации включения светодиодов по очереди.

Все будет зависеть от вашей схемы подключения светодиодов. Разберём на примере схемы, приведённой выше (см. раздел Схема). Согласно схеме у нас 2 управляющий вывода и 3 рабочих. Значит одновременно мы можем зажечь 2 светодиода. Таким образом, наши выводы можно разбить на пары (lx_uprx) - (l1_upr1 + l2_upr2), (l1_upr2 + l2_upr1), (l3_upr1+l3_upr2). Каждую пару надо задействовать по два раза меняя полярность. Итого получается общее количество светодиодов поделить на количество управляющих выводов состояний = 6 состояний.

Необходимо в конструкции switch case перебрать их все. Получится такой код.

switch (numind) {  
 case 0:  
 if (ind[<b>0</b>] ) GPIO_Init(GPIOD,GPIO_PIN_2,GPIO_MODE_OUT_PP_<b>LOW</b>_SLOW);
 if (ind[<b>6</b>]) GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_OUT_PP_<b>LOW</b>_SLOW);
 GPIO_Init(GPIOD,GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_<b>HIGH</b>_SLOW);//все управляющие включили на HIGH
 break;
 
 case 1:
 if (ind[<b>1</b>] ) GPIO_Init(GPIOD,GPIO_PIN_2,GPIO_MODE_OUT_PP_<b>HIGH</b>_SLOW);
 if (ind[<b>7</b>]) GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_OUT_PP_<b>HIGH</b>_SLOW);
 
 GPIO_Init(GPIOD,GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_<b>LOW</b>_SLOW);//все управляющие включили на GND
 break;
 
 ….. и так далее
 }
 
 numind++;
 if (numind==6) numind=0;
 

И так для всех случаев. Обязательно проверьте, что указали все правильно. Важно, чтобы на одном управляющем выводе, не было включено одновременно больше одного светодиода, а то они могут сгореть! В конце обработчика делаем итерацию счётчика номера состояний.

Для управления яркостью, просто будем выключать все светодиоды в прерывании TIM2_CAP_COM.

INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 14)
 {
  GPIOA->DDR &amp;= (u8) (~ (GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3));
    //GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_IN_FL_NO_IT);
  GPIOD->DDR &amp;= (u8) (~(GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6) );
    //GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_IN_FL_NO_IT);
  GPIOC->DDR &amp;= (u8) (~(GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7) );
    //GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_IN_FL_NO_IT);
  GPIOB->DDR &amp;= (u8) (~ (GPIO_PIN_4|GPIO_PIN_5) );
 
  TIM2->SR1 = (uint8_t)(~TIM2_IT_CC1);
 }
 

Вот и все. Важно не запутаться и получается отличная динамическая индикация. Как нумеровать светодиоды вы можете выбрать сами. Например, если это две шкалы по 8 светодиодов, то удобнее одну шкалу с 0 до 7, потом другую с 8 до 15, потом оставшиеся 4 светодиода. Так будет проще управлять. Если у вас часы, то опять же проще 0 1 2 3 — по часовой стрелке с первого часа. Если стороны света, то как часы, по часовой стрелке.

Приём команд по протоколу 1-wire

Протокол 1-wire очень популярен. Он часто используется в приборах. Практически на всех платформах вы можете найти реализацию кода обмена по данному протоколу. Чтобы понять как он работает приведем простую диаграмму из datasheet на датчик температуры DS18B20. Протокол работает на PULL UP линии, которая поднята к VDD. Для общения, управляющий микроконтроллер (мастер) опускает линию на GND.

Для начала работы по данному протоколу требуется специальный сигнал RESET.

Мастер опускает линию на 480 мкс, а потом освобождает и она возвращается на HIGH. Датчик отвечает, что он есть, опуская линию на 240 мкс и ждёт до окончания 480 мкс. Далее идет обмен данными. Каждый бит передаётся используя тайм слот длиной в 70 мкс. Чтобы передать 1, почти весь слот должна быть 1, а чтобы передать 0, то почти весь слот должен быть 0.

Перевод линии в 0 служит начало передачи бита. Если считывать линию в середине тайм слота, то состоянии линии и будет означать 0 или 1. Биты в байте передаются от младшего к старшему. Сам протокол поддерживает адресацию и много различных функций, но мы будем использовать простой режим — один мастер, один индикатор.

Итак в начале обмена, мастер передаёт сигнал RESET. Далее 1 байт операции и далее нужное количество байт состояния светодиодов. Для реализации будем использовать прерывание по переходу в 0 состояния управляющего вывода. Сам вывод будет находится в состоянии PULL UP, так что со стороны управляющего МК можно использовать OPEN DRAIN режим вывода.

INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6)
 {
   u8 zn;
  u8 time;
 
  time = TIM4->CNTR;
  TIM4->CNTR=0;//сразу начинаем отсчётсначала!
  TIM4->CR1 |= (uint8_t)TIM4_CR1_CEN;
 
  if (dataok) return;
 
  if(time > 190) {//190*8 = 1520мкс таймаут и стартпосле прошлого пакета //тут либо 0 либо200 с прошлого раза
    waitreset=1;//какая то ошибка
  } else if (waitreset==1) {
    if (time > 50) {//50*8 = 400мкс //старт!
      numbuffind=0;
      waitreset=0;
    }
  }
 
  if (waitreset==0) {
    //10мкс - около 20 тактов до этого местаот срабатывания прервания
    _delay_us(20);
    if (GPIOC->IDR &amp; GPIO_PIN_7) buffind[numbuffind]=1;
    else buffind[numbuffind]=0;
 
    if (numbuffind>(NUMIND)) dataok=1;    
    numbuffind++;
  }
 }
 

Считываем значение счётчика таймера 4. Обнуляем его и запускаем заново. Если dataok не нулевая, значит мы еще не обработали предыдующие полученные данные, в этом случае ничего не делаем. Если счетчик больше 190 — 1500 мкс, то что- то не так, сбрасываем все в начало — устанавливаем переменную waitreset. Если мы ждем ресет и счетчик меньше 1520 мкс, но больше 400мкс, то дождались — начинаем работать. Так как прерывание у нас срабатывает только по переходу в 0, то мы его получим когда уже пойдет первый бит, поэтому сразу начинаем считывать состояние линии. Необходимо немного подождать — 20 мкс и считать состояние линии. Будет примерно половина тайм слота. МК у нас работает не очень быстро и это время по сути будет немного больше, вместо 20 мкс мы получим около 30мкс, нам это и надо. Далее записываем полученный бит в массив и ждем пока пока не получим команду плюс все данные. После этого ставим в единицу флажок dataok. Дальнейшяя обработка полученных данных идет в основном цикле.

Важно отметить что в прерываниях нельзя использовать delay, связанный с другими прерываниями. Поэтому здесь используется специально подобранный набор команд, который выполняется строго нужное количество тактов.

#define US(us) ( 2000000.0 / 3000000.0 * us ) //FCPU / 3000
#define MS(ms) US(ms * 1000) // maximum 10ms
 
#define _delay( loops ) _asm("$N: \n decw X \n jrne $L \nnop", (u16)loops);
#define _delay_us(us) _delay(US(us))
 

Для оптимизации под ваш МК этого кода, надо просто поменять частоту на нужную.

  if (dataok) {
      //обработка данных
      u8 i=0;
      for (i=0;i<10;i++) {
        ind[i] = buffind[i+8];
      };
 
      command = 0;
      for (i=0;i<8;i++) {
        command |= (buffind[i] << i);
      }
 
      if (command) {
        //первые 7 бит яркость
        u8 tyar;
 
        tyar = command &amp; 0b1111111;
        if (tyar) TIM2->CCR1L = tyar;
 
        //идем спать!
        if (command &amp; 0b1000000) sleep();
      }
 
      waitreset=1;
      dataok=0;
      numbuffind=0;
  }  
 

Записываем полученные данные в массив индикации. Собираем команду, и если пора спать, то идём спать, а если это яркость — то меняем CCR значение таймера. В конце все готовим к следующей посылке. Вот так можно передавать данные по одному проводу.

Управление индикатором со стороны прибора

На стороне управляющего МК, если у вас нет библиотек, вам надо написать примерно такой код.

 

#define IND_WIRE_1 GPIOC->ODR |=(uint8_t)GPIO_PIN_6//GPIO_WriteHigh(GPIOC,GPIO_PIN_6)
#define IND_WIRE_0 GPIOC->ODR &amp;= (uint8_t)(~GPIO_PIN_6) //GPIO_WriteLow(GPIOC,GPIO_PIN_6)
 
void sendindicator(void) {
  //reset
  u32 dd = indicator;
 
  stoptim=1;
 
  IND_WIRE_0;
  _delay_us(10);
  IND_WIRE_1;  
  _delay_us(480);
 
  {
    u8 i;
 
  for (i=0;i<32;i++) {
    if (dd &amp; 1) {
      disableInterrupts();
      IND_WIRE_0;      
      _delay_us(10);
      IND_WIRE_1;
      enableInterrupts();
      _delay_us(55);
    } else {
      IND_WIRE_0;      
      _delay_us(65);
      IND_WIRE_1;
      _delay_us(5);
    }
    dd >>= 1;
  }
  }
 
  stoptim=0;    
}  
 

Узкое место передача 1, обязательно надо чтобы в этом момент ничто нас не прерывало. Лучше отключить прерывания. Остальное не так требовательно к точности таймера.

Как изготовить индикатор

Разработка схемы в Kicad и трассировка

Вы можете взять за основу проект Kicad с github проекта. Далее вам необходимо будет доработать схему в Kicad. Потом на плате разместить светодиоды в нужной вам форме, например сердечка. Трассировка закончена.

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

  4. Вам необходимо будет подготовить трассировку платы. Доработать схему в Kicad и на плате разместить светодиоды в нужной вам форме, например сердечка.

  5. Изготовить вашу плату для прибора самостоятельно (это совсем несложно, в нашей инструкции все подробно описано).

  6. Приобрести все необходимые комплектующие вы можете самостоятельно, или у нас в виде набора из 20 светодиодов, если вам мало 20 светодиодов — то можете заказать больше.

  7. Запаять все компоненты на плату, смотри наше видео. При пайке светодиодов старайтесь сильно их не греть!

  8. Плата готова!

Для программирования, можно сразу подключить питание к ST-Link и SWIM вывод.

Переходим к программированию

Данный прибор достаточно простой в программировании. В этой статье подробно разобран пример программы. Для реального индикатора вам необходимо будет поменять в образце количество светодиодов и схемы их включения. Внимание! Не зажигайте одновременно больше одного светодиода на одном управляющем выводе — это может привести к выходу из строя светодиода.

Мы рекомендуем написать небольшую демо программу для проверки работы индикатора, прежде чем устанавливать его в прибор.

Приобретённые навыки

Пайка: пайка паяльником светодиодов! пайка корпуса TTSOP.

Схемотехника: управление светодиодами.

Программирование: 1-wire протокол в master и slave режимах, динамическая индикация с помощью PWM таймера, спящий режим.

Самостоятельная работа

На github мы выкладываем образец индикатора. На его основе вы можете самостоятельно разработать свой индикатор и использовать его в ваших приборах.

 

Read 7634 times