image

В этой статье я хочу продолжить свой цикл о программировании Arduino для начинающих электронщиков. Мы познакомимся с подключением светодиодного семисегментного индикатора к микроконтроллеру через сдвиговый регистр, разберемся с особенностями его программной обработки. Также я продемонстрирую, как с помощью редактора электронных таблиц Excel можно генерировать семисегментные коды. И, как всегда, много внимание будет уделено деталям, которые часто воспринимаются понятными «по умолчанию», но на самом деле для новичка таковыми не являются. В конце, следуя «Arduino way», напишем простой класс для управления семисегментной индикацией.

Различные приборы и оборудование часто отображают информацию в цифровом виде. От типа индикации зависит скорость и точность ее восприятия наблюдателем.

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

image

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

Наибольшее распространение получили светодиодные сегментные индикаторы. Это связано с конструктивной простотой таких индикаторов, их высокой яркостью, хорошей контрастностью и практически полным отсутствием инертности. Еще одним неоспоримым преимуществом таких индикаторов является широкий диапазон рабочих температур, начиная от экстремально низких.

image

И действительно, имея под рукой 3D-принтер, вы можете получить светодиодный сегментный индикатор практически любой конфигурации. Например, я использую онлайн кастомайзер на thingiverse. Он позволяет достаточно гибко и без лишних заморочек настраивать модель, которую потом останется всего лишь распечатать и немного доработать напильником.

image

Подключение и управление


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

Сегменты принято обозначать буквами от A до G, как показано на рисунке. Индикаторы могут оснащаться восьмым сегментом – десятичная точка (decimal point), обозначается как DP или H.

image

Как правило, светодиоды в таких индикаторах объединяют катодами или анодами. Получаются индикаторы с общим катодом (ОК) или общим анодом (ОА).

image

Рассмотрим индикатор с общим анодом. Для управления таким индикатором на его общем аноде необходимо обеспечить положительный потенциал. Чтобы получить требуемый символ, на определенную комбинацию катодов необходимо подать отрицательный потенциал. Остальные выводы можно оставить неподключенными.

image

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

Пускай индикатор будет подключен через сдвиговый регистр 74HC595. Как управлять сдвиговым регистром можно почитать в одной из моих прошлых статей. Так как индикатор состоит из светодиодов, необходимо ограничивать их рабочий ток. Самый простым способом является использование токоограничивающих резисторов. В этом кроется основное преимущество светодиодного индикатора перед другими, мы получаем очень просто драйвер, фактически это любая TTL-совместимая микросхема и горстка резисторов. Но тут же кроется и недостаток — большой потребляемый ток. Зато внешняя подсветка для индикатора тоже не нужна.

image

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

Для включения требуемого сегмента при условии, что общий анод подключен к плюсу питания, на вывод сдвигового регистра необходимо записать логический ноль. Это установит низкий электрический уровень. Между анодом и катодом светодиода в сегменте возникнет положительная разница потенциалов, светодиод начнет светиться.

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

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

image

Давайте попробуем составить семисегментный код для отображения цифры 0 на индикаторе. Для этого необходимо включить светодиоды сегментов A, B, C, D, E, F. Сегменты G и H должны быть выключены. Соответственно, на выводах сдвигового регистра Q0 – Q5 необходимо установить уровни логического нуля, а для выводов Q6 и Q7 – необходимо установить единицы.

image

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

image

Использовать семисегментные коды в двоичном формате не очень удобно. С помощью стандартного калькулятора Windows можно преобразовать полученную двоичную комбинацию в другие представления чисел. Для более точной интерпретации сегментного кода рекомендую представлять его в шестнадцатеричном формате.

image

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

image

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

image

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

image

Excel для формирования семисегментных кодов


Наверняка на просторах интернета можно найти готовые программы для кодирования картинок в программный код на Си. Но я предлагаю проделать это самостоятельно с использованием редактора электронных таблиц Excel. Этот способ позволит получать коды не только для семисегментных индикаторов, но и для любых других.

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

image

Для этого можно объединять соседние ячейки, менять их размеры, установить видимые границы и залить ячейки серым цветом. Все это можно сделать через команду меню: Главная / Формат / Формат ячеек.

image

image

Далее немного оживим изображение индикатора. Сделаю так, чтобы сегменты меняли цвет на красный при заполнении. Для этого с зажатой кнопкой "Ctrl" выделю все ячейки, которые представляют собой сегменты индикатора. На вкладке "Главная" необходимо выбрать меню: Условное форматирование / Правила выделения ячеек / Равно

image

В диалоговом окне "Равно" в поле для ввода введу единицу. В принципе, это может быть любой другой удобный для вас символ.

image

Работать это должно примерно так, как показано на картинке. Если в ячейку ввести единичку, она окрасится в красный. Не заполненные ячейки останутся серыми. Согласитесь, что вероятность перепутать включаемые сегменты так будет значительно ниже.

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

image

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

image

Преобразование числа из двоичной системы счисления в десятичную буду производить следующим образом: каждый разряд числа умножу на вес соответствующего разряда. Чтобы определить вес разряда, нужно двойку возвести в степень его позиции в байте.

image

Далее, умножу вес бита на его двоичное значение, чтобы получить десятичное значение бита.

image

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

image

Преобразуем десятичный код в шестнадцатеричный.

image

В соседней ячейке получу значение в формате шестнадцатеричного числа для программы на Си.

image

Копипастим полученную табличку необходимое количество раз. Далее можно приступать к формированию семисегментных кодов.

image

Мой итоговый вариант выглядит вот так. Я перенес вычисления кодов на отдельную страницу. И в результате получаю готовую строку — инициализатор для программы на Си.

image

Управление сдвиговым регистром 74HC595


Если вам известен принцип работы сдвигового регистра 74HC595, вы можете смело пропустить этот раздел и перейти к следующему, в котором будет рассмотрено непосредственно программирование.

image

Микросхема 74HC595 представляет собой последовательный синхронный сдвиговый регистр, который преобразует последовательный код, поступающий на вход SER, в параллельный код на выходах Q0 – Q7.

Синхронизация записи последовательного кода осуществляется подачей стробирующих импульсов на вход SCK. А вход RCK управляет обновлением выходов Q0-Q7. Это позволяет изменять состояние выходных сигналов Q0 – Q7 одновременно.

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

image

Для экспериментов традиционно буду использовать Proteus. Схема эксперимента представлена на рисунке.

image

Первым делом с помощью директивы макроопределения в программе обозначу выводы микроконтроллера, к которым подключен сдвиговый регистр.

//--------------------------------------------------
//Выходы для управления регистром
#define DATA    11
#define CLK     13
#define UPDATE  10

В функции "loop()" настрою эти выводы для работы на выход.

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  pinMode(DATA,OUTPUT);
  pinMode(CLK,OUTPUT);
  pinMode(UPDATE,OUTPUT);
}

Для управления сдвиговым регистром перед функцией "loop()" объявим функцию "shift()". Во входных параметрах функции будем передавать данные, для записи в регистр.

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){

}

Для последовательной передачи данных в теле функции организуем цикл "for". Счетчик "bitNum" в цикле будет определять номер бита переменной "data", отправляемый на вход регистра. Передачу данных начнем со старшего бита, чтобы он оказался на выходе Q7.

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){
  //последовательный сдвиг 8 бит 
  for(uint8_t bitNum = 7; bitNum < 8; --bitNum){
    
  }
}

Счетчик "bitNum" объявлен как целое без знака. Счет ведется в обратную сторону. При очередном вычитании из счетчика единицы, когда его значение было равным нулю, произойдет его переполнение. Новое значение счетчика станет равным 255. Это больше 8. Условие цикла не выполнятся, и цикл будет завершен.

Для записи бита на вход регистра в тело цикла поместим оператор проверки условия "if". Он будет проверять состояние бита по номеру в переменной "bitNum", и устанавливать соответствующее значение на входе регистра.

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){
  //последовательный сдвиг 8 бит 
  for(uint8_t bitNum = 7; bitNum < 8; --bitNum){
    //проверка бита
    if(data & (1<<bitNum))digitalWrite(DATA,HIGH);
    else                  digitalWrite(DATA,LOW);
  }
}

Немного сократим эту запись. Дело в том, что функция "digitalWrite()" уже содержит внутри проверку истинности своего второго входного параметра. Это позволяет обойтись без внешней проверки, а условие из нее сразу передать как входной параметр. Получается, на выводе микроконтроллера будет установлен низкий логический уровень, если в результате выполнения команды "data & (1<<bitNum)" получается ноль. При любом ненулевом результате, функция "digitalWrite()" запишет в порт логическую единицу.

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){
  //последовательный сдвиг 8 бит 
  for(uint8_t bitNum = 7; bitNum < 8; --bitNum){
    //проверка бита
    digitalWrite(DATA,data & (1<<bitNum));
  }
}

После установки значения на входе данных регистра, в теле цикла необходимо сформировать один стробирующий импульс записи. А после 8-ми бит данных подадим одиночный импульс для переключения выходной защелки.

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){
  //последовательный сдвиг 8 бит 
  for(uint8_t bitNum = 7; bitNum < 8; --bitNum){
    //проверка бита
    digitalWrite(DATA,data & (1<<bitNum));
    //строб записи
    digitalWrite(CLK,HIGH);
    digitalWrite(CLK,LOW);
  }
  //обновление выходов регистра
  digitalWrite(UPDATE,HIGH);
  digitalWrite(UPDATE,LOW);
}

На этом наша функция завершена. Остается проверить ее работоспособность. Вызовем функцию "shift()" из функции "loop()". В качестве входного параметра передадим семисегментный код семерки… на удачу.

//--------------------------------------------------
//супер цикл
void loop() {
  shift(0xF8);
}

Под спойлером вы можете найти полный скетч.
//--------------------------------------------------
//Выходы для управления регистром
#define DATA    11
#define CLK     13
#define UPDATE  10

//--------------------------------------------------
//Запись данных в регистр
void shift(uint8_t data){
  //последовательный сдвиг 8 бит 
  for(uint8_t bitNum = 7; bitNum < 8; --bitNum){
    //проверка бита
    digitalWrite(DATA,data & (1<<bitNum));
    //строб записи
    digitalWrite(CLK,HIGH);
    digitalWrite(CLK,LOW);
  }
  //обновление выходов регистра
  digitalWrite(UPDATE,HIGH);
  digitalWrite(UPDATE,LOW);
}

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  pinMode(DATA,OUTPUT);
  pinMode(CLK,OUTPUT);
  pinMode(UPDATE,OUTPUT);
}

//--------------------------------------------------
//супер цикл
void loop() {
  shift(0xF8);
}

Вывод семисегментного кода


Для проверки результатов кодирования семисегментных кодов решим несложную задачку. Разработаем программу таймера на 10 секунд, который будет осуществлять прямой счет, как показано на рисунке.

image

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

Для работы с SPI интерфейсом в программе необходимо подключить встроенную библиотеку <SPI.h>.

//--------------------------------------------------
//для работы с SPI интерфейсом
#include <SPI.h>

Семисегментный код, который был сгенерирован в Excel, разместим в массиве так, чтобы его нулевой элемент содержал код нуля, а старший элемент — код девятки.

//--------------------------------------------------
//массив семисегментных кодов
uint8_t segmCode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};

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

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  SPI.begin();
  digitalWrite(SS,LOW);
}

Фоновая программа будет содержать один цикл "for", который с интервалом в одну секунду поочередно запишет в регистр очередной семисегментный код.

//--------------------------------------------------
//супер цикл
void loop() {
  //считаем от нуля до десяти
  for(uint8_t i = 0; i < 10; ++i){  
    //запись в регистр кода по номеру i
    SPI.transfer(segmCode[i]);
    //обновляем выходы сдвигового регистра
    digitalWrite(SS,HIGH);
    digitalWrite(SS,LOW);
    //пауза для отображения цифры
    delay(1000);
  }
}

Полный скетч под спойлером.
//--------------------------------------------------
//для работы с SPI интерфейсом
#include <SPI.h>

//--------------------------------------------------
//массив семисегментных кодов
uint8_t segmCode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};																																															

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  SPI.begin();
  digitalWrite(SS,LOW);
}

//--------------------------------------------------
//супер цикл
void loop() {
  //считаем от нуля до десяти
  for(uint8_t i = 0; i < 10; ++i){  
    //запись в регистр кода по номеру i
    SPI.transfer(segmCode[i]);
    //обновляем выходы сдвигового регистра
    digitalWrite(SS,HIGH);
    digitalWrite(SS,LOW);
    //пауза для отображения цифры
    delay(1000);
  }
}


Этот программный код не имеет прикладного смысла. Единственная его задача заключалась в том, чтобы проверить правильность кодирования семисегментного кода. Не знаю, как у вас, но у меня все работает. Пишите о своих результатах в комментариях.

Вывод десятичного числа


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

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

image

Пускай верхний индикатор будет отображать десятки секунд, а нижний — единицы секунд.

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

Сперва, изменим диапазон счета для цикла "for", теперь он будет считать до 60 секунд.

  //считаем от нуля до 60 секунд
  for(uint8_t i = 0; i < 60; ++i){ 

Так как сдвиговые регистры включены последовательно, т.е. выход первого регистра подключен ко входу второго, первым делом нужно записывать единицы секунд, а за ними значение десятков.

//запись в регистр единицы секунд
    SPI.transfer(segmCode[i % 10]);
    //запись в регистр десятка секунд
    SPI.transfer(segmCode[i /10 % 10]);

Операция "i % 10" возвращает остаток от деления счетчика i на основание десятичной системы счисления, таким образом производится выделение младшего десятичного разряда. Для выделения десятков мы сперва выполняем сдвиг счетчика влево путем деления на основание системы счисления "i /10", и затем выделяем десятки секунд из младшего разряда получением остатка от деления.

Для примера возьмём i=34. Тогда для "i%10" получится, что 10 помещается в 34 целиком 3 раза, в остатке остается 4. Затем выполним операцию "34/10". При целочисленном делении получаем результат, аналогичный сдвигу вправо на один десятичный разряд. То есть тройка «переезжает» в разряд единиц, дробная часть откидывается. Операцию "34/10%10" целиком можно не выполнять, если вы гарантируете, что значение переменной никогда не будет иметь значимый разряд сотен.

Обратите внимание на то, как происходит преобразование десятичного числа в эквивалентный семисегментный код. Команда типа "segmCode[i % 10]" фактически производит табличную подстановку. Массив "segmCode" заполнен таким образом, что в его нулевом элементе размещен семисегментный код нуля, в первом — единицы, во втором — двойки, и так далее. Получается, что на сам индикатор мы выводим не десятичное число, а элемент массива перекодировки по индексу, который определяется этим десятичным числом.
Полный скетч под спойлером.
//--------------------------------------------------
//для работы с SPI интерфейсом
#include <SPI.h>

//--------------------------------------------------
//массив семисегментных кодов
uint8_t segmCode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};																																															

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  SPI.begin();
  digitalWrite(SS,LOW);
}

//--------------------------------------------------
//супер цикл
void loop() {
  //считаем от нуля до 60 секунд
  for(uint8_t i = 0; i < 60; ++i){  
    //запись в регистр единицы секунд
    SPI.transfer(segmCode[i % 10]);
    //запись в регистр десятка секунд
    SPI.transfer(segmCode[i /10 % 10]);
    //обновляем выходы сдвигового регистра
    digitalWrite(SS,HIGH);
    digitalWrite(SS,LOW);
    //пауза для отображения цифры
    delay(1000);
  }

  while(1);
}

Немного унификации


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

image

Увидев такое количество микросхем, вы можете спросить, почему бы не перейти на динамическую индикацию. Конечно, динамический способ имеет ряд неоспоримых плюсов. Но от динамической развертки может рябить в глазах. Если устройство индикации подвижно, в том числе испытывает вибрации, динамическая развертка может «рассыпаться». Тот же эффект возможен и в случае, если подвижно не устройство индикации, а сам наблюдатель. Поэтому в важных приложениях я стараюсь динамическую развертку избегать. А если вы переживаете за площадь печатной платы, используйте корпуса типа TSSOP или QFN. Они прекрасно помещаются под семисегментным индикатором и не занимают дополнительную площадь.

image

Условимся, что сдвиговый регистр «в хвосте» будет отображать единицы, т.е. младший десятичный разряд. Индикаторов в нашей схеме стало больше, и их количество фактически будет определять только здравый смысл.

Для вывода десятичного числа на индикаторы напишем функцию "decimalTo7segm()".

//--------------------------------------------------
//вывод десятичного числа произвольной разрядности
void decimalTo7segm(uint32_t dec, uint8_t numberOfDigits){
  for(; numberOfDigits; --numberOfDigits){
    //запись очередного семисегментного кода
    SPI.transfer(segmCode[dec%10]);
    //десятичный сдвиг вправо
    dec /= 10;
  }
  //обновляем выходы сдвигового регистра
  digitalWrite(SS,HIGH);
  digitalWrite(SS,LOW);
}

Через входные параметры функция "decimalTo7segm()" получает непосредственно само десятичное число "uint32_t dec". Входная переменная не обязательно должна быть 32-х разрядной, это будет зависеть от ваших потребностей. Если вам не нужно выводить слишком большие числа, ограничьте ее 16-ю или 8-ю разрядами, применив соответствующие типы данных. Количество доступных для отображения цифр индикаторов в функцию будет передавать входная переменная "numberOfDigits". Ну а логика работы функции должна быть понятна из комментариев к коду.

Остается вызвать функцию "decimalTo7segm()" из "loop()". Для удобства проверки работоспособности, передам значение 1234 и укажу количество индикаторов как 4.

//--------------------------------------------------
//супер цикл
void loop() {
  //вывод десятичного числа
  decimalTo7segm(1234, 4);
  while(1);
}

Полный скетч под спойлером.
//--------------------------------------------------
//для работы с SPI интерфейсом
#include <SPI.h>

//--------------------------------------------------
//массив семисегментных кодов
uint8_t segmCode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};																																															

//--------------------------------------------------
//вывод десятичного числа произвольной разрядности
void decimalTo7segm(uint32_t dec, uint8_t numberOfDigits){
  for(; numberOfDigits; --numberOfDigits){
    //запись очередного семисегментного кода
    SPI.transfer(segmCode[dec%10]);
    //десятичный сдвиг вправо
    dec /= 10;
  }
  //обновляем выходы сдвигового регистра
  digitalWrite(SS,HIGH);
  digitalWrite(SS,LOW);
}

//--------------------------------------------------
//настройка периферии микроконтроллера
void setup() {
  SPI.begin();
  digitalWrite(SS,LOW);
}

//--------------------------------------------------
//супер цикл
void loop() {
  //вывод десятичного числа
  decimalTo7segm(1234, 4);
  while(1);
}

Улучшения в стиле «Arduino way»


Я лично не являюсь сторонником использования классов для программирования микроконтроллеров, и, наверное, когда-то посвящу этому отдельную статью. Но кого интересует оптимизация кода, если мы используем Arduino? Все-таки Arduino — это в первую очередь про удобство. Поэтому предлагаю оформить обработчик индикатора в виде отдельного класса.

Создадим класс "SevenSegmIndicator". Этот класс должен будет описывать свойства и алгоритм работы семисегментного индикатора.

//--------------------------------------------------
//класс для работы с индикаторами
class SevenSegmIndicator{
public:

private:
  //количество индикаторов (минимальное количество 1)
  uint8_t numberOfDigits = 1;
  //семисегментный код
  uint8_t segmCode[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; 
};

Наш класс будет иметь два свойства: "numberOfDigits" и массив "segmCode[]". Переменная "numberOfDigits" будет использоваться для хранения в программе количества индикаторов, размещенных на схеме. По умолчанию этому полю будет присваиваться минимальное количество индикаторов, которое может обрабатывать наша программа, т.е. один. Массив "segmCode[]" хранит семисегментные коды. Массив заполним сразу.

С помощью спецификатора доступа "private" эти переменные будут скрыты от остального кода, доступ к ним возможен только для методов класса.

После спецификатора доступа "public" разместим методы нашего класса, которые будут реализовывать основную логику его работы. Эти методы будут доступны в остальной программе.

  //основной метод для вывода данных в индикаторы
  void update(uint32_t dec){
    for(uint8_t num = numberOfDigits; num; --num){
      //запись очередного семисегментного кода
      SPI.transfer(segmCode[dec%10]);
      //обновляем выходы сдвигового регистра
      digitalWrite(SS,HIGH);
      digitalWrite(SS,LOW);
      //десятичный сдвиг вправо
      dec /= 10;
    }
  }

Метод "update()" фактически будет повторят написанную нами ранее функцию "decimalTo7segm()".

Для инициализации будущих объектов класса добавим в него конструктор. Он будет производить инициализацию SPI интерфейса микроконтроллера, а также записывать количество индикаторов в схеме.

  //конструктор
  SevenSegmIndicator(uint8_t n){
    //запуск аппаратного SPI
    SPI.begin();
    digitalWrite(SS,LOW);
    //запоминаем количество индикаторов
    numberOfDigits = n;
  }

Объявление объекта класса будет производиться аналогично обычным переменным. Количество индикаторов передается в качестве инициализатора с помощью конструктора, который мы объявили ранее.

//объект для работы с 4-мя индикаторами
SevenSegmIndicator myIndicator = 4;

Теперь в функции "setup()" больше не останется кода, так как он теперь будет выполняться конструктором класса.

Нам осталось воспользоваться методом класса "updae()" для вывода на индикатор десятичного числа. Разместим его вызов в функции "loop()".

  //вывод десятичного числа
  myIndicator.update(1234);

Полный скетч под спойлером.
//--------------------------------------------------
//для работы с SPI интерфейсом
#include <SPI.h>

//--------------------------------------------------
//класс для работы с индикаторами
class SevenSegmIndicator{
public:
  //конструктор
  SevenSegmIndicator(uint8_t n){
    //запуск аппаратного SPI
    SPI.begin();
    digitalWrite(SS,LOW);
    //запоминаем количество индикаторов
    numberOfDigits = n;
  }

  //основной метод для вывода данных в индикаторы
  void update(uint32_t dec){
    for(uint8_t num = numberOfDigits; num; --num){
      //запись очередного семисегментного кода
      SPI.transfer(segmCode[dec%10]);
      //обновляем выходы сдвигового регистра
      digitalWrite(SS,HIGH);
      digitalWrite(SS,LOW);
      //десятичный сдвиг вправо
      dec /= 10;
    }
  }
private:
  //количество индикаторов (минимальное количество 1)
  uint8_t numberOfDigits = 1;
  //семисегментный код
  uint8_t segmCode[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};  
};

//объект для работы с 4-мя индикаторами
SevenSegmIndicator myIndicator = 4;

//--------------------------------------------------
void setup() {
  
}

//--------------------------------------------------
//супер цикл
void loop() {
  //вывод десятичного числа
  myIndicator.update(1234);
  while(1);
}

Послесловие


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

На этом, пожалуй, можно заканчивать. Но а вы можете посмотреть другие мои статьи на тему программирования Arduino:
1. Тактовая кнопка, как подключить правильно к "+" или "-"
2. Экономим выводы для Arduino. Управление сдвиговым регистром 74HC595 по одному проводу
3. Блокирующая обработка тактовой кнопки для Arduino. Настолько полный гайд, что ты устанешь его читать
4. Неблокирующая обработка тактовой кнопки для Arduino. Как использовать прерывание таймера «в два клика» в стиле ардуино
5. С чем едят конечный автомат
6. На пол пути к конечному автомату для Arduino. Однопроходные функции и фиксация событий программы с помощью флагов

Комментарии (72)


  1. dlinyj
    00.00.0000 00:00
    +5

    Спасибо за статью! С экселем крутое решение. Когда я ковырялся с "Волшебным чемоданом", то использовал программу "Segment Code Generator". Там достаточно в широких пределах можно настроить декодировщик, раз я даже для такого старья смог подобрать сегменты.


    image


    1. OldFashionedEngineer Автор
      00.00.0000 00:00
      +2

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


      1. dlinyj
        00.00.0000 00:00
        +1

        Да, я эксель тоже использую для программирования и формирования готового кода. Вполне себе рабочий вариант.


        1. OldFashionedEngineer Автор
          00.00.0000 00:00
          +2

          Я когда-то в шестом билдере себе писал всякие штуки. Но потом столкнулся с тем, что старые экзешники без бубна не запускаются. И забил на это. Стараюсь свои программы-помощники по минимуму делать.


  1. engine9
    00.00.0000 00:00
    +7

    Как и прежде отличная статья. А я немного вкину эстетики и визуала от автора Posy.


    1. OldFashionedEngineer Автор
      00.00.0000 00:00
      +2

      Спасибо, хорошее дополнение! Я сам люблю вечерком такие видосики позалипать.


      1. engine9
        00.00.0000 00:00

        У этого человека весь канал — услада глаз технофетишиста.


  1. asg128
    00.00.0000 00:00
    +2

    Свойство segmCode лучше бы сделать static. Сэкономит память если понадобится пара экземпляров класса.


    1. OldFashionedEngineer Автор
      00.00.0000 00:00
      +1

      Согласен. Я бы segmCode вообще не массивом сделал, а указателем. Но про оптимизацию кода надо отдельно писать. И я не уверен, что ардуино эти фичи поддерживает. Они как-то выборочно синтаксис реализовывают.


  1. vconst
    00.00.0000 00:00
    +5

    следуя «Arduino way», напишем простой класс для управления семисегментной индикацией

    Ардуино-вэй — это нагуглить и надергать всяких либ, написаных непойми кем, в код накопипастить куски из примеров и потом удивляться — почему ничего не работает ))


    1. OldFashionedEngineer Автор
      00.00.0000 00:00
      +4

      Мне понятен Ваш сарказм. К сожалению, часто происходит именно так, как Вы и написали. Своими статьями я хотел бы как-то переломить это. Сама по себе платформа ардуино весьма неплохая, но вот именно такой подход необдуманного копипаста и привел к тому, что ее многие недолюбливают.


      1. vconst
        00.00.0000 00:00
        +1

        Да, это универсально, от контроллера не зависит. Просто таких — большинство


        На счет "платформа ардуино весьма неплохая" — я бы поспорил...


        Прилепил к ардуинке датчик уровня CO2, не абы какой — шведский от Senseair, прилепил простенький олед-экранчик на одну строчку. Все работает — уровень углекислоты показывается. Потом прилепил бошевский датчик температуры и экранчик — снова все ок
        Попробовал загрузить гладкий шрифт покрасивее — памяти не хватило


        А потом подключил оба датчика с экраном — и тут понеслось…


        Питания хватает только от включенного компа, от банки или выключенного компа — не заводится. Датчик, которому должно хватать 3 вольта — завелся только тогда, когда я переключил его в 5 вольт. И показания датчиков — странные, всякая дичь, думаю, из-за косяков питания. Когда пробовал подать 5 вольт прямо на пины, а не от юсб — тоже ничего не заработало


        Спрашиваю знакомых спецов по электронике и микроконтроллерам, говорят: "Все так и есть"


        Воткнул все это дело в есп32 — ноль вопросов, ноль проблем.


        1. dlinyj
          00.00.0000 00:00

          Переписать на си, не?


          1. OldFashionedEngineer Автор
            00.00.0000 00:00

            Ну это уже не Arduino-way получается)))


            1. dlinyj
              00.00.0000 00:00

              Это нормальная практика


          1. vconst
            00.00.0000 00:00

            Как это решит проблему с питанием?


            У меня датчики не завелись, хорошие датчики — надо заметить, не нонеймовая "шняга на шилдах для ардуино-кит", просто потому что я их два сразу воткнул.


            1. dlinyj
              00.00.0000 00:00
              +1

              Если проблема с питанием, то Ардуино тут не при чем.


              1. vconst
                00.00.0000 00:00

                Есп32 этой проблемы не имеет, при точно таком же питании


                1. dlinyj
                  00.00.0000 00:00
                  +4

                  Претензии к проводам, и контактам которыми вы подключаете. Причина не в плате. Ну чудес не бывает, питание берётся напрямую. Если там 3,3 В, ну значит меняйте схемотехнику подключения. Грешить на ардуино, когда творите дичь, ну странное дело.


                  1. vconst
                    00.00.0000 00:00

                    Ой, ну да ладно, это не рокет сайнс, обычные гребёнки, обычные бредборды, обычные проводки с дюпоновскими разъёмами


                    Один датчик работает, второй работает — а вместе начинается треш угар и содомия. Все тоже самое на есп — "не было слышно ни крика, ни стона". Да и в нескольких разных чатах разработчики микроконтроллеров говорят в один голос — "это нормально, это ардуино"


                    1. OldFashionedEngineer Автор
                      00.00.0000 00:00
                      +1

                      В свое время я попал в один не совсем типовой для себя проект по промышленной автоматике. Установка была выполнена на основе контроллера ОВЕН ПЛК100. Ведущий программист специализировался на сименсе, и что есть сил материл ОВЕН. Типа у него зависает все, глючит в разных местах. Я стал разбираться. Оптимизировал количество переменных для передачи на рабочее место оператора. Переписал обмен по сети на низком уровне. Все заработало. К слову сказать, овен на codesys работает, а там библиотеки сделаны по аналогии в winapi. Оказалось, что проблема не в овене, а в том, что программист работал не в той парадигме.

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


                      1. dlinyj
                        00.00.0000 00:00

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

                        Процитирую классика:

                        Может, что-то в консерватории подправить?


                    1. dlinyj
                      00.00.0000 00:00

                      а и в нескольких разных чатах разработчики микроконтроллеров говорят в один голос — «это нормально, это ардуино»

                      То есть вы решили не выяснять причину, а посто списали на платформу? Если там линейный стаб, то его может просто не хватать.

                      Но судя по описанию, платформа тут не при чём. Просто пытаются не читая документации и не разбираясь в платформе творить дичь, и удивляются что не работает и ругают платформу. А всего-то надо было открыть документацию.


                      1. vconst
                        00.00.0000 00:00

                        //пожимает плечами


                        На одной платформе какой-то непонятные и сложнодиагностируемые проблемы, на второй все заводится — стоит только воткнуть


                        Надо было сразу слушать советов профи и не связываться с ардуино


                      1. iig
                        00.00.0000 00:00

                        пожимает плечами ;)

                        Внутре ардуины - самый обычный микроконтроллер Atmega. Отлично документированный и более понятный чем Esp8266 :) (ESP32 не видел, так что как ну него все просто - никак не прокомментирую).


                      1. vconst
                        00.00.0000 00:00

                        Да все они документированы. Но не все хотят ради мелкой поделки гуглить API и писать все с нуля, особенно на платформе, которая изначально выпускалась как обучающая.


                        Вопщем, претензий особо нет. Если пользовать ее как обучалку соединения готовых и проверенных шилдов — то проблем никаких. А хочется что-то за рамками "Набора 32 датчика для Ардеино", попытаться воткнуть что-то серьезное и начинаются проблемы.


                        Или ты начинаешь вьезжать в АПИ и сам писать себе интерфейс для подключаемых устройств, или… Или просто собираешь все на более предсказуемой платформе


                      1. dlinyj
                        00.00.0000 00:00

                        Вдруг в какой-то момент всё перестанет работать и на ESP32 и будет работать на ардуине, переедете обратно?


                        Тут надо понять проблему, что было не так, а не платформу винить. Я не против, что ESP более удачная и совершенная платформа, у меня к AVR есть куча претензий. Но судя по описанию, там вины платформы нет вообще.


                      1. vconst
                        00.00.0000 00:00

                        Я воткнул в бредборд епс вместо ардуино, назначил пины — и оно уже работает. Заборю лень и спаяю по нормальному, а не дюпонами на гребенках


                      1. iig
                        00.00.0000 00:00

                        Я воткнул в бредборд епс вместо ардуино, назначил пины — и оно уже работает.

                        И код переписали под ESP?


                      1. vconst
                        00.00.0000 00:00

                        А что там переписывать?
                        Один датчик по uart, второй на i2c и на той же шине — мелкий oled


                        Я почему и удивился, что не городил на одном ардуино управление автоматизацией конвейера по сборке айфонов. Всего лишь подключил датчики чуть получше, чем "стандартные" dht11


                        Я сам не профи схемотехник, осваиваю все это "методом тыка", пробуя разные нагугленные либы, примерно как описывал в каменте, где стебался на "ардуино вэй" ))


                        Но в одном случае это не прокатило от слова "вообще", а в другом — даже не пискнуло


                      1. iig
                        00.00.0000 00:00

                        А что там переписывать?

                        С ардуины на Espressif SDK? Чуть менее чем все ;)


                      1. vconst
                        00.00.0000 00:00

                        Начать можно с того, что в проекте "выведи на олед температуру, влажность и со2" — ничего писать не надо. Там скетч умещается "в один экран"


                      1. iig
                        00.00.0000 00:00

                        Смайлик_с_разведенными_руками ;)

                        В expressif все функции иначе называются, как минимум. НЯП по ихнему blink если судить.

                        https://github.com/espressif/esp-idf/blob/master/examples/get-started/blink/main/blink_example_main.c


        1. OldFashionedEngineer Автор
          00.00.0000 00:00

          Универсальность - это всегда зло! Конечно же решить проблемы совместимости на 100% очень сложно. К тому же Arduino проектировалась еще когда TTL3,3V была не на столько распространена. И разработчики это веяние не уловили. Еще 20 лет назад я часто испытывал такую боль, когда попадались микросхемы с безальтернативным 3,3В питанием. А сейчас уже наоборот получается.


          1. vconst
            00.00.0000 00:00

            Еще 20 лет назад я часто испытывал такую боль, когда попадались микросхемы с безальтернативным 3,3В питанием. А сейчас уже наоборот получается.

            Ну, как сказать.
            Например, арудинка жрет от 4 до 12 вольт и не подавится, даже если случайно 19 завести. А есп уже от обычного 18650 может поплохеть, ибо там 3,7, а не 3,3. И найти преобразователь на 5 воль — плевое дело, на любом условном озоне их дофига. А вот с 5 на 3 — уже поискать надо и заказать из Китая, скорее всего, а не "завтра с озона"


            1. OldFashionedEngineer Автор
              00.00.0000 00:00

              Я немного не о том. Сейчас можно целиком устройство сделать с единым питанием на 3,3В. Раньше это вызывало проблемы. Не все микросхемы можно было найти на 3,3. А некоторые были уже только на 3,3. Ещё и уровни надо было согласовывать.


              1. vconst
                00.00.0000 00:00

                Это верно, да


        1. iig
          00.00.0000 00:00

          Попробовал загрузить гладкий шрифт покрасивее — памяти не хватило

          Воткнул все это дело в есп32 — ноль вопросов, ноль проблем.

          В esp памяти значительно больше чем в atmega ;)

          А с питанием - вы даташиты смотрели? Что за LDO стоят в ардуинке, должны ли они вытягивать ваши датчики по 3.3В? Не нужны ли преобразователи уровня для подключения 5В датчика к контроллеру с 3.3В сигналами?


          1. vconst
            00.00.0000 00:00

            Два датчика, которые питаются от 3 до 6, условно. Потребление децльное


            Короче — снова ардуино отправляется в пыльный угол дальнего ящика )


            1. OldFashionedEngineer Автор
              00.00.0000 00:00

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

              Ардуино достаточно нишевая штука. Она изначально для обучения делалась. Причем по всей видимости не совсем электронщиками делалась. От нее всего можно ожидать. Но даташиты читать все таки стоит.


  1. maru
    00.00.0000 00:00
    +1

    Скажите, а как называется кодировка сегментов, когда положение единицы может быть как слева, так и справа? Какой для этого есть термин? Видел часто такое на светофорах, пример https://www.youtube.com/watch?v=v7IGNy8iL0I&t=52s


    1. OldFashionedEngineer Автор
      00.00.0000 00:00
      +1

      Это кто как придумает. Тут какого-то единого стандарта нет. Символы ограничены только расположением сегментов.

      На светофорах бывает единицу делают в сегментах E и F, чтоб с дистанции она не сливалась с цифрой с права от неё. Диаметр круга ограничен, расстояние между цифрами сильно не увеличить. Вот и делают так.


  1. PanDubls
    00.00.0000 00:00

    Моя память иногда работает как облако тэгов

    Сквозь него пробежало несколько солдат, когда он посмотрел поверх костлявого плеча Загрязнения.

    -- ЧТО ЭТО ЗА СВЕТЯЩИЕСЯ ШТУКИ?

    Таким тоном говорят, когда точно знают, что не смогут понять ответ, но хотят показать, что им интересно происходящее.

    -- Семисегментные индикаторы на светодиодах.

    Белая рука Загрязнения любовно легла на ближайший блок реле, который сразу оплавился.


  1. sterr
    00.00.0000 00:00

    А где про динамику? Особенно про диагональную. Там то экселем вряд ли обойдешься...


    1. OldFashionedEngineer Автор
      00.00.0000 00:00

      По статистике длинные статьи до конца не читают. Про динамику отдельно напишу.


  1. IgorKKK
    00.00.0000 00:00

    Почему 74HC595 а не MAX 7219?Объясните потаенный смысл всей этой заметки. Ведь новички прочитают её и поверят, что это передовой и единственный способ управления.


    1. OldFashionedEngineer Автор
      00.00.0000 00:00

      "Потаенный" смысл моей статьи написан до ката. Про динамическую индикацию у меня не было цели рассказыввывать. МАХ 7219 я не считаю хорошим вариантом.


      1. IgorKKK
        00.00.0000 00:00
        +1

        Таки объяснили бы нубам почему микросхема, специально созданная для управления этими индикаторами, хуже сдвигового регистра. А дальше уже их выбор куда идти.


        1. OldFashionedEngineer Автор
          00.00.0000 00:00

          Основной упор статьи все таки больше на кодирование индикаторов. К сожалению, все разом в одной статье ни кто не будет читать даже. Из моих наблюдений, если хабр ставит время в 30 минут, то уже не дочитывают материал.

          МАХ 7219 на чип и дипе 900р стоит. Наверное больше объяснять ни чего и не надо.


          1. IgorKKK
            00.00.0000 00:00

            Объяснять надо. И не путаться в показаниях. Если МАХ7219 дороже сдвигового регистра, это не значит что он хуже, как вы утверждали чуть ранее.

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

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

            Я бы даже не обратил внимания на этот текст, если бы он не был адресован нубам, которые, как известно, зело доверчивы.

            А цена ЧиД, как аргумент... Ну это ещё фол. Все мы знаем места, где этот аргумент точно не проходит.


            1. OldFashionedEngineer Автор
              00.00.0000 00:00

              Статья это не учебное пособие, а мнение автора по какому-то вопросу. Я делюсь своим опытом и в начале статьи вполне конкретно написано, про что она. Если у вас есть своя точка зрения, вы тоже можете ей поделиться и написать свою статью.

              Я не утверждал, что что-то хуже или лучше. Прочитайте внимательно мои комментарии.


            1. vconst
              00.00.0000 00:00
              +1

              Я не профи, но есть у меня подозрение, что статья про сдвиговый регистр не потому что "так надо", а потому что это более низкий уровень — непосредственно схемотехника


              То есть — это как упражнение на программирование базовой логики для тех, кому это интересно


              Если подходить максимально практически, то была бы не статья, а ссылка на готовый шилд от ада фрукт и его либу на гитхабе. Но зачем оно такое?


              1. OldFashionedEngineer Автор
                00.00.0000 00:00

                То есть — это как упражнение на программирование базовой логики для тех, кому это интересно

                Очень хорошее замечание, спасибо


  1. aumi13
    00.00.0000 00:00

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


    1. OldFashionedEngineer Автор
      00.00.0000 00:00

      Надо про управление яркостью написать? Я могу... традиционно коротенько, минут на 40 )))


      1. aumi13
        00.00.0000 00:00

        а почему бы и нет, чтобы любительские часы не превращались в фонари по ночам.


        1. OldFashionedEngineer Автор
          00.00.0000 00:00
          +1

          А как же тогда в ночи путь до холодильника искать?!


        1. OldFashionedEngineer Автор
          00.00.0000 00:00

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


          1. vconst
            00.00.0000 00:00

            Не обращайте внимания на каменты )


            Само написание систематизированных текстов — полезный скилл. Не за карму же вы их пишете ))


            1. OldFashionedEngineer Автор
              00.00.0000 00:00

              Я когда-то преподавателем работал. Много времени прошло. Иногда выговориться надо))) Вот "на автомате" пишу про базовые вещи. Особенно когда где-то по работе или в интернете встречаюсь с пробелами у людей.

              https://habr.com/ru/post/722184/ посмотрите вот этот пост, особенно код в конце для управления семисегментным индикатором. Вот как после такого я могу не писать свои статьи?!!


              1. vconst
                00.00.0000 00:00

                //обобщенно


                Ну ок, может я что-то и накосячил, но либы там простые. Температурный датчик просто по i2c. СО2 еще проще — через uart посылаются командные последовательности и считывается ответ. Там нет ничего такого, что может этакий затык создать, все просто как мычание


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


                Ну, каждый с чего-то начинает. Для таких вещей не обязательно изучать ТПУ и схемотехнику, там все можно на высоком уровне достаточно просто сделать. Тем более, к примеру — на кнопке у него гасится дребезг считыванием через 100 микросекунд, нормальное решение, причем — не через delay, как у "уроках по ардуино", а по timestamp. Про фазовую модуляцию в каментах написали по делу, но может у человека как раз лаба именно по ней была, и не по частотной. Что электроники — то я в ней почти не разбираюсь, нечего сказать


                Дальше какая-то лапша… Странная. Может копипаста, причем — из своего предыдущего проекта, а не SO


                1. OldFashionedEngineer Автор
                  00.00.0000 00:00

                  С ардуино есть конечно нюансы. Я тоже сталкивался, что простые на первый взгляд вещи оказываются совсем не простыми в реализации. Особенно когда нужно угадывать, как и какая периферия для библиотек используется. Когда в обращениях к периферии между библиотеками возникают коллизии.

                  Иногда обращаю внимание, что у прокаченных специалистов бомбит в комментариях. Лично я спокойно отношусь к тому, что не все в этом мире разбираются в электронике. И наоборот, это же хорошо, что люди пытаются что-то делать. Если ничего не делать, то ничему и не научишься. Только не нужно рубить с плеча и делать скоропостижные выводы о платформе на основе первого неудачного опыта.

                  Конкретно про регулятор, на который я дал ссылку. Я обратил внимание именно на способ управления семисегментным индикатором. Это сделано откровенно плохо. Но не потому, что автор хотел сделать плохо. Где-то же ему нужно учиться, как сделать лучше? Вот это и есть моя мотивация. Я пишу свои статься, чтоб помочь таким вот энтузиастам.


  1. green88
    00.00.0000 00:00

    Я фигею, дорогая редакция! Да зачем тут какой то Excel. Ещё и с генерацией каких то кодов. Ну ППЦ!
    Просто рисуй знакогенератор в тексте и всё. Причём как хочешь, в любых вариациях. Хочешь так:
    // шрифт
    static const uint8_t font[] PROGMEM = {
    MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F , //0 a
    MASK_B | MASK_C , //1 --
    MASK_A | MASK_B | MASK_D | MASK_E | MASK_G, //2 f| |b
    MASK_A | MASK_B | MASK_C | MASK_D | MASK_G, //3 --g
    MASK_B | MASK_C | MASK_F | MASK_G, //4 e| |c
    MASK_A | MASK_C | MASK_D | MASK_F | MASK_G, //5 -- .h
    MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G, //6 d
    MASK_A | MASK_B | MASK_C , //7
    MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G, //8
    MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G, //9
    MASK_A | MASK_B | MASK_C | MASK_E | MASK_F | MASK_G, //A
    MASK_B | MASK_C | MASK_E | MASK_F , //||
    MASK_A | MASK_B | MASK_F | MASK_G, //o x
    MASK_B | MASK_C | MASK_D | MASK_E | MASK_G, //d x
    MASK_G, //- x
    0, //F x
    };
    Хочешь так:
    static const uint8_t font[] PROGMEM = {
    //gfedcba
    B0111111, //0 a
    B0000110, //1 --
    B1011011, //2 f| |b
    B1001111, //3 g--
    B1100110, //4 e| |c
    B1101101, //5 -- .h
    B1111101, //6 d
    B0000111, //7
    B1111111, //8
    B1101111, //9
    B1110111, //A
    B1111100, //b
    B0111001, //C
    B1011110, //d
    B1111001, //E
    B1110011 //F
    };


    1. OldFashionedEngineer Автор
      00.00.0000 00:00

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


      1. green88
        00.00.0000 00:00

        Да я понимаю, наглядность и всё такое. Но тут то всё просто как божий день.) Зачем ещё какие то дополнительные телодвижения! Наглядность должна быть в самом тексте программы, а не с какими то непонятными кодами.


        1. OldFashionedEngineer Автор
          00.00.0000 00:00

          В том и дело, что Вы понимаете. Поэтому Вам это не нужно. Но реально есть люди, которые не понимают, но хотели бы понимать.


          1. green88
            00.00.0000 00:00
            -1

            Считаю что даунам не место в программировании. Извините.


            1. OldFashionedEngineer Автор
              00.00.0000 00:00

              То есть не бывает иной точки зрения, кроме вашей? Вы считаете, если мне реально быстрее и проще сделать это в экселе, то я рукожоп? Это табличка в экселе делается не дольше пяти минут.


              1. green88
                00.00.0000 00:00

                Почему не бывает? Конечно бывает. Но я считаю что наглядно нужно писать в самом тексте программы, а не прибегать к каким то дополнительным ухищрениям. При том что в этом (я) не вижу абсолютно никакой необходимости. Я об этом говорил выше.


                1. OldFashionedEngineer Автор
                  00.00.0000 00:00

                  Наглядность в коде? Это там, где от слова "MASK" в глазах рябит? Если бы люди так легко переваривали двоичные коды, язык С, наверное, и не изобрели.

                  Скажите, а если нужно картинку на растровый индикатор вывести, вы тоже её сразу в двоичном коде будете писать?

                  Самодокументированность кода - это конечно же хорошо. Но и сопроводительную документацию ни кто не отменял. Так же, как я ни где не видел запретов на использование дополнительных инструментов.


  1. green88
    00.00.0000 00:00

    На растровый то, как раз и более нагляднее будет выглядеть. Прям начертание явно, типа
    B00001100 // верхняя часть символа
    и т.д.
    Конечно. Запретов никаких нет. Но и раздувание не приветствуется. А главное, заради чего?
    К чему вы привлекаете дополнительные (нехилые!) приложения! Когда они здесь совсем лишние.


    1. OldFashionedEngineer Автор
      00.00.0000 00:00

      Какое раздувание? Какие нехилые приложения? Ну вы чего в самом деле? Как минимум владение разными инструментами развивает мышление.

      Вы серьёзно собираетесь вот так по битам рисовать всю ascii таблицу?!