Top.Mail.Ru

STM32 и семисегментный индикатор. Динамическая индикация.

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

Семисегментный индикатор. Принцип работы.

Что в целом из себя представляет семисегментный индикатор? Идея тут проста – просто упорядоченный набор светодиодов. Причем упорядоченность касается их физического расположения друг относительно друга:

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

Каждый из светодиодов представляет из себя отдельный сегмент, соответственно, имеем как раз 7 сегментов. При этом каждому сегменту ставится в соответствие условное буквенное обозначение – a, b, c и т. д. Поместим все это в пластиковый корпус и, наклеив наклейку, получаем законченный компонент:

7-сегментный индикатор.

Включая определенный набор диодов, можем получить наглядное отображение информации, к примеру, в виде цифры 7:

Принцип работы семисегментного индикатора.

Аналогичным образом и для любой другой цифры:

Отображение цифр.

Или для любого символа, варианты ограничены только количеством сегментов, конкретной целью и фантазией:

Произвольный символ.

Помимо этих семи сегментов почти всегда присутствует еще один, отвечающий за отображение точки:

Семисегментный индикатор.

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

Четырехразрядный индикатор.

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

Подключение семисегментного индикатора.

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

Семисегментный индикатор с общим анодом.

И с общим катодом:

7-сегментный индикатор с общим катодом.

Управление тогда будет выглядеть следующим образом, для общего анода:

  • подаем на общий вывод (аноды) положительное напряжение
  • катоды же нужных сегментов заземляем

Для общего катода то же самое, за исключением полярности:

  • подаем на общий вывод (катоды) 0 В
  • а на аноды сегментов положительное значение напряжения

Естественно, нужно учесть параметры конкретных диодов в конкретном же используемом индикаторе. Допустим, из документации узнаем, что прямой ток диодов – 20 мА при напряжении на диоде 2 В. При осуществлении управления напрямую с вывода микроконтроллера, например STM32, напряжение будет составлять 3.3 В, что очевидно не равно требуемым 2 В. Поэтому в цепь добавляется резистор:

Подключение к микроконтроллеру.

И номинал его рассчитывается следующим образом. Напряжение на диоде должно быть равно 2 В, с порта контроллера имеем 3.3 В, значит избыточные 1.3 В должны упасть именно на резисторе.

При этом ток через диод, а вместе с ним и ток через резистор, составит 20 мА. Поэтому по закону Ома спокойно рассчитываем необходимое значение сопротивления:

R = \frac{U_R}{I_R} = \frac{1.3 \medspace В}{20 \medspace мА} = 65 \medspace Ом

На этом расчетная деятельность закончена.

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

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

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

  • катод диодов – 1 штука
  • сегменты для отображения цифры/символа – 7 штук
  • сегмент десятичной точки – 1 штука

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

Решение же данной проблемы заключается в использовании динамической индикации. Принцип заключается в том, что в каждый момент времени светится только одна цифра. Допустим, нам нужно вывести на индикатор число "1971", действуем так:

  • Зажигаем "1" на месте первого разряда.
  • Ожидаем некоторое время, пусть 1 миллисекунду. В этом временном интервале у нас горит "1", остальные же три разряда выключены полностью.
  • Гасим "1" в первом разряде и зажигаем "9" на второй позиции.
  • Снова ожидаем в таком состоянии миллисекунду.
  • Повторяем аналогичные действия для оставшихся цифр "7" и "1".

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

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

И теперь нам требуется не 36, а только 12 выводов для управления 4-х разрядным индикатором. Рассмотрим более подробно на конкретном примере такого индикатора:

Вариант семисегментного индикатора.

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

Распиновка семисегментного индикатора.

Здесь у нас вариант с общим анодом. Суммарно этот семисегментный индикатор содержит в себе 4 разряда, по 8 сегментов каждый (7 + 1 для точки) и 12 выводов для управления всем хозяйством. Восемь сегментов каждого из разрядов соединены анодами и каждый из них, в свою очередь, выведен на выходной разъем. В данном случае это пины с номерами 12, 9, 8 и 6. Сегменты же разных разрядов соединены катодами между собой. Так точка 1-го разряда, соединена с точками 2-го, 3-го и 4-го разрядов, и этот сигнал выходит на 3-й контакт разъема:

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

  • Подаем на 12-й вывод положительное напряжение, 9-й, 8-й, 6-й заземляем. Таким образом, мы "активируем" только первый разряд.
  • Для того, чтобы зажечь единицу нужно подать на катоды диодов b и c 0 В (выводы 7 и 4). На остальные же катоды подаем то же напряжение, что и на анод. В итоге гореть будут только светодиоды b и c первого разряда.
  • Ожидаем некоторое непродолжительное время.
  • Далее наша задача вывести "9" на второй позиции, потушив все остальные разряды. Для этого по той же схеме – подаем на 9-й вывод положительное напряжение, 12-й, 8-й, 6-й заземляем.
  • Теперь у нас "активирован" второй разряд и только он.
  • Для отображения "9" подаем на катоды диодов a, b, c, d, f, g - 0 В, на катод диода e – то же напряжение, что и на его анод, дабы он оставался в покое.
  • Все, в дальнейшем те же действия для 3-го и 4-го разрядов и все это повторяем циклично. Результатом будет отображение нужного числа.

В итоге, управление осуществляется 12-ю выводами микроконтроллера, что тоже немало, но, как минимум, меньше 36-ти. Есть, конечно же, в продаже и 7-сегментные индикаторы, в которых на разъем выведены все 36 сигналов, соответственно, они не закорочены между собой внутри. Вот, например:

36-выводный индикатор.

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

Семисегментный индикатор и STM32, библиотека и пример.

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

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

Библиотека для STM32.

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

Здесь самое время для важного дополнения: при активации нескольких сегментов ток через пины Dig1...Dig4 может превысить допустимые для микроконтроллера значения, а из этого следует логичный вывод, что нужно предусмотреть наличие ключей на транзисторах. Привожу вариант с p-n-p транзисторами и дисплеем с общим анодом:

Схема подключения семисегментного индикатора

Какие именно брать порты роли никакой не играет, настраиваем просто в качестве обычных выходов:

STM32CubeMx.

С этим все понятно, генерируем код и добавляем в проект файлы библиотеки:

  • segment_lcd.c
  • segment_lcd.h

Вся связь с HAL сосредоточена только в одном месте, а именно в функции:

static void SetOutput(McuPin output, uint8_t state)
{
  HAL_GPIO_WritePin(output.port, output.pin, (GPIO_PinState)state);
}

Таким образом, максимально просто можно перейти и к варианту без HAL. Функции, которые я реализовал для использования вне драйвера:

  • SEG_LCD_Process();
  • SEG_LCD_Result SEG_LCD_WriteNumber(float number);
  • SEG_LCD_Result SEG_LCD_WriteString(char* str);

В целом, их назначение ясно из их же названия, тем не менее на примере посмотрим более подробно. Вторая и третья из перечисленных возвращают результат выполнения операции, и здесь два варианта:

  • SEG_LCD_OK
  • SEG_LCD_ERROR

О том, как я построил работу с экраном, я досконально рассказывать не буду. В случае возникновения вопросов, буду рад пояснить любые нюансы в комментариях или на форуме 👍

Итак, необходимая конфигурация. И, конечно же, основным моментом является задание используемых портов ввода-вывода, что осуществляется в файле segment_lcd.c:

static McuPin digitPins[DIGITS_NUM] = { {GPIOB, GPIO_PIN_3}, {GPIOB, GPIO_PIN_4},
                                        {GPIOB, GPIO_PIN_5}, {GPIOB, GPIO_PIN_6} };

static McuPin segmentPins[SEGMENTS_NUM] = { {GPIOA, GPIO_PIN_11}, {GPIOA, GPIO_PIN_10},
                                            {GPIOA, GPIO_PIN_9}, {GPIOA, GPIO_PIN_8},
                                            {GPIOB, GPIO_PIN_15}, {GPIOB, GPIO_PIN_14},
                                            {GPIOB, GPIO_PIN_13} };

static McuPin dotPin = {GPIOB, GPIO_PIN_12};

Как видите, я задал все как на схеме выше. DIGITS_NUM определяет количество разрядов, у меня:

#define DIGITS_NUM                                                          4

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

static uint8_t charactersTable[DIGIT_CHARACTERS_NUM + EXTRA_CHARACTERS_NUM] =
               {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x40, 0x00};

Каждый символ - один байт, 7 младших битов которого определяют, должен ли гореть конкретный сегмент. Первые 10 элементов массива - это цифры от 0 до 9, именно в такой последовательности, за ними же следуют дополнительные символы, список которых можно пополнить своими. Рассматриваем на примере, возьмем, третий элемент массива, то есть цифру 2, значение равно 0x5B, либо в двоичном виде 0b01011011.

Старший бит всегда нулевой, потому что сегментов 7, а битов 8, ничего неожиданного. Последующие же биты (от 6-го до 0-го) задают состояние сегментов (от g до a). Итак, цифра 2:

Пример кодирования сегментов.

Должны гореть сегменты a, b, d, e, g, что и кодируется этими битами. С этим разобрались, теперь дополнительные символы. Я добавил пробел и минус, то есть два символа, это количество задано в segment_lcd.h:

#define EXTRA_CHARACTERS_NUM                                                2

Далее их ASCII коды:

#define ASCII_MINUS_CODE                                                    0x2D
#define ASCII_SPACE_CODE                                                    0x20

В хэдере на этом все пока, идем обратно в segment_lcd.c и находим массив дополнительных символов:

static SEG_LCD_ExtraCharacter extraCharacters[EXTRA_CHARACTERS_NUM] = { {ASCII_MINUS_CODE, DIGIT_CHARACTERS_NUM},
                                                                        {ASCII_SPACE_CODE, DIGIT_CHARACTERS_NUM + 1} };

Первое поле структуры задает ASCII код, второе - позицию символа в массиве кодов charactersTable[]. DIGIT_CHARACTERS_NUM - число цифр, то есть 10. Таким образом, в данном случае имеем символ минуса (ASCII_MINUS_CODE) и его позицию: DIGIT_CHARACTERS_NUM (10). Смотрим на 10-й элемент массива, а там у нас значение 0x40:

static uint8_t charactersTable[DIGIT_CHARACTERS_NUM + EXTRA_CHARACTERS_NUM] =
               {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x40, 0x00};

И снова иллюстрация:

Добавление произвольного символа.

Все четко, получаем символ минуса!

Упустил из виду "полярность" управления сегментами. Итак, у нас либо общий анод, либо общий катод, задается тут (плюс учитываем подключенные транзисторы), для варианта со схемы выше:

#define SEGMENT_PIN_ACTIVE                                                  0
#define DIGIT_PIN_ACTIVE                                                    0

DIGIT_PIN_ACTIVE равен 0, а не 1, по той простой причине, что для того, чтобы открыть транзисторы, на базу надо подать низкий уровень, тогда на пинах Dig1...Dig4 дисплея будут 3.3 В.

Ну и, пожалуй, конфигурация завершена на этом, суммарно вышло три этапа:

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

Для функционирования библиотеки достаточно добавить периодический вызов SEG_LCD_Process(). В этой функции в том числе осуществляется переключение разрядов для динамической индикации, поэтому между вызовами следует сделать небольшую задержку:

while (1)
{
	/* USER CODE END WHILE */

	/* USER CODE BEGIN 3 */
	SEG_LCD_Process();
	HAL_Delay(1);
}
/* USER CODE END 3 */

Если паузу сделать слишком большой, то соответственно, будет видно, что цифры загораются по очереди, а не горят постоянно. И финишируем небольшим демо-проектом, в котором будем менять значение переменной от -10 до 10 с шагом 0.01, производя инкрементирование каждые 10 мс. Результат прокинем на индикатор. Все манипуляции теперь только в main.c, подключаем библиотеку, чтобы использовать семисегментный индикатор:

/* USER CODE BEGIN Includes */
#include "segment_lcd.h"

/* USER CODE END Includes */

Объявляем переменные:

/* USER CODE BEGIN PV */
float outputValue = -10;
float outputStep = 0.01;
float outputLimit = 10;
uint32_t outputPeriod = 10;

/* USER CODE END PV */

Ну и решение поставленной задачи:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
  uint32_t previousTime = HAL_GetTick();
  uint32_t currentTime = HAL_GetTick();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    SEG_LCD_Process();
    HAL_Delay(1);

    currentTime = HAL_GetTick();
    if ((currentTime - previousTime) >= outputPeriod)
    {
      outputValue += outputStep;

      if (outputValue >= outputLimit)
      {
        outputValue = (-1) * outputLimit;
      }

      SEG_LCD_WriteNumber(outputValue);
      previousTime = currentTime;
    }
  }
  /* USER CODE END 3 */
}

Вся суть в двух функциях:

  • SEG_LCD_Process()
  • SEG_LCD_WriteNumber(outputValue)

Результат работы программы таков:

И на этом заканчиваем на сегодня, библиотека писалась быстро и на коленке, параллельно с процессом написания текста статьи, так что если что пишите )

Исходный код файлов библиотеки:

/**
  ******************************************************************************
  * @file           : segment_lcd.c
  * @brief          : 7-segment LCD driver.
  * @author         : MicroTechnics (microtechnics.ru)
  ******************************************************************************
  */



/* Includes ------------------------------------------------------------------*/

#include "segment_lcd.h"
#include <stdio.h>



/* Declarations and definitions ----------------------------------------------*/

static McuPin digitPins[DIGITS_NUM] = { {GPIOB, GPIO_PIN_3}, {GPIOB, GPIO_PIN_4},
                                        {GPIOB, GPIO_PIN_5}, {GPIOB, GPIO_PIN_6} };

static McuPin segmentPins[SEGMENTS_NUM] = { {GPIOA, GPIO_PIN_11}, {GPIOA, GPIO_PIN_10},
                                            {GPIOA, GPIO_PIN_9}, {GPIOA, GPIO_PIN_8},
                                            {GPIOB, GPIO_PIN_15}, {GPIOB, GPIO_PIN_14},
                                            {GPIOB, GPIO_PIN_13} };

static McuPin dotPin = {GPIOB, GPIO_PIN_12};

static uint8_t charactersTable[DIGIT_CHARACTERS_NUM + EXTRA_CHARACTERS_NUM] =
               {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x40, 0x00};

static SEG_LCD_ExtraCharacter extraCharacters[EXTRA_CHARACTERS_NUM] = { {ASCII_MINUS_CODE, DIGIT_CHARACTERS_NUM},
                                                                        {ASCII_SPACE_CODE, DIGIT_CHARACTERS_NUM + 1} };

static uint8_t currentCharacters[DIGITS_NUM] = {0x00, 0x00, 0x00, 0x00};
static uint8_t currentDots[DIGITS_NUM] = {0, 0, 0, 0};
static uint8_t currentDigitIndex = 0;




/* Functions -----------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
SEG_LCD_Result SEG_LCD_WriteString(char* str)
{
  uint8_t currentDigitIndex = 0;

  for (uint8_t i = 0; i < DIGITS_NUM; i++)
  {
    currentCharacters[i] = 0x00;
    currentDots[i] = 0;
  }

  while(*str != '\0')
  {
    if (*str == ASCII_DOT_CODE)
    {
      if (currentDigitIndex > 0)
      {
        currentDots[currentDigitIndex - 1] = 1;
      }
    }
    else
    {
      if ((*str >= ASCII_NUMBER_FIRST_CODE) && (*str <= ASCII_NUMBER_LAST_CODE))
      {
        uint8_t currentCharacterIndex = (*str - ASCII_NUMBER_FIRST_CODE);
        currentCharacters[currentDigitIndex] = charactersTable[currentCharacterIndex];
        currentDigitIndex++;
      }
      else
      {
        uint8_t found = 0;

        for (uint8_t i = 0; i < EXTRA_CHARACTERS_NUM; i++)
        {
          if (*str == extraCharacters[i].asciiCode)
          {
            uint8_t currentCharacterIndex = extraCharacters[i].symbolsTableOffset;
            currentCharacters[currentDigitIndex] = charactersTable[currentCharacterIndex];
            found = 1;
            currentDigitIndex++;
            break;
          }
        }

        if (found == 0)
        {
          return SEG_LCD_ERROR;
        }
      }
    }

    if (currentDigitIndex == DIGITS_NUM)
    {
      break;
    }

    str++;
  }

  if (currentDigitIndex < DIGITS_NUM)
  {
    for (int8_t i = currentDigitIndex - 1; i >= 0; i--)
    {
      currentCharacters[i + (DIGITS_NUM - currentDigitIndex)] = currentCharacters[i];
      currentDots[i + (DIGITS_NUM - currentDigitIndex)] = currentDots[i];
    }

    for (uint8_t i = 0; i < (DIGITS_NUM - currentDigitIndex); i++)
    {
      currentCharacters[i] = 0x00;
      currentDots[i] = 0;
    }
  }

  return SEG_LCD_OK;
}



/*----------------------------------------------------------------------------*/
SEG_LCD_Result SEG_LCD_WriteNumber(float number)
{
  char temp[DIGITS_NUM + 2];
  snprintf(temp, DIGITS_NUM + 2, "%.2f", number);
  SEG_LCD_WriteString(temp);
  
  return SEG_LCD_OK;
}



/*----------------------------------------------------------------------------*/
static void SetOutput(McuPin output, uint8_t state)
{
  HAL_GPIO_WritePin(output.port, output.pin, (GPIO_PinState)state);
}



/*----------------------------------------------------------------------------*/
static void SetSegmentPins(uint8_t characterCode)
{
  for (uint8_t i = 0; i < SEGMENTS_NUM; i++)
  {
    uint8_t bit = (characterCode >> i) & 0x01;

    if (bit == 1)
    {
      SetOutput(segmentPins[i], SEGMENT_PIN_ACTIVE);
    }
    else
    {
      SetOutput(segmentPins[i], !SEGMENT_PIN_ACTIVE);
    }
  }
}



/*----------------------------------------------------------------------------*/
void SEG_LCD_Process()
{
  for (uint8_t i = 0; i < DIGITS_NUM; i++)
  {
    SetOutput(digitPins[i], !DIGIT_PIN_ACTIVE);
  }

  SetSegmentPins(currentCharacters[currentDigitIndex]);

  if (currentDots[currentDigitIndex] == 1)
  {
    SetOutput(dotPin, SEGMENT_PIN_ACTIVE);
  }
  else
  {
    SetOutput(dotPin, !SEGMENT_PIN_ACTIVE);
  }

  SetOutput(digitPins[currentDigitIndex], DIGIT_PIN_ACTIVE);

  currentDigitIndex++;
  if (currentDigitIndex == DIGITS_NUM)
  {
    currentDigitIndex = 0;
  }
}



/*----------------------------------------------------------------------------*/
/**
  ******************************************************************************
  * @file           : segment_lcd.h
  * @brief          : 7-segment LCD driver.
  * @author         : MicroTechnics (microtechnics.ru)
  ******************************************************************************
  */

#ifndef SEG_LCD_H
#define SEG_LCD_H



/* Includes ------------------------------------------------------------------*/

#include "stm32f1xx_hal.h"



/* Declarations and definitions ----------------------------------------------*/

#define DIGITS_NUM                                                          4
#define SEGMENTS_NUM                                                        7

#define SEGMENT_PIN_ACTIVE                                                  0
#define DIGIT_PIN_ACTIVE                                                    !SEGMENT_PIN_ACTIVE

#define DIGIT_CHARACTERS_NUM                                                10
#define EXTRA_CHARACTERS_NUM                                                2

#define ASCII_NUMBER_FIRST_CODE                                             0x30
#define ASCII_NUMBER_LAST_CODE                                              0x39

#define ASCII_MINUS_CODE                                                    0x2D
#define ASCII_SPACE_CODE                                                    0x20

#define ASCII_DOT_CODE                                                      0x2E



typedef enum {
  SEG_LCD_OK,
  SEG_LCD_ERROR
} SEG_LCD_Result;



typedef struct SEG_LCD_ExtraCharacter
{
  uint8_t asciiCode;
  uint8_t symbolsTableOffset;
} SEG_LCD_ExtraCharacter;



typedef struct McuPin
{
  GPIO_TypeDef *port;
  uint16_t pin;
} McuPin;



/* Functions -----------------------------------------------------------------*/

extern void SEG_LCD_Process();
extern SEG_LCD_Result SEG_LCD_WriteNumber(float number);
extern SEG_LCD_Result SEG_LCD_WriteString(char* str);




#endif // #ifndef SEG_LCD_H

Ссылка на проект: MT_SegmentLCD_Project.

Подписаться
Уведомить о
guest

21 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
KIR
KIR
1 год назад

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

KIR
KIR
Ответ на комментарий  Aveal
1 год назад

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

Антон
Антон
Ответ на комментарий  Aveal
1 год назад

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

KIR
KIR
Ответ на комментарий  Aveal
1 год назад

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

Эдуард
Ответ на комментарий  KIR
1 год назад

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

Эдуард
Ответ на комментарий  KIR
1 год назад

Идиотское решение.
Если зажигать 1 ток будет Х
Если зажигать 8 ток будет 4Х.
Яркость 8ки будет меньше яркости 1 в четыре раза.
А резистор один. Управлять придётся каждым сегментом отдельно. Это увеличивает частоту сканирования в 9 раз и возникают ударные токи на светодиодах. Разве только делать отсечку перед пробоем светодиода. Это усложняет програмный код многократно.
А уменьшить размер можно уменьшением размера деталей.
Резисторы 0402 и будет счастье.

KIR
KIR
Ответ на комментарий  Эдуард
1 год назад

Эдуард, во-первых, после ваших статей я о Вас лучше думал. По меньшей мере ожидал, что на личности (см выше) вы переходить не будете, а вы снизошли до прямых оскорблений. Ну и банально своим прозорливым умом попытаетесь вникнуть в глубину идеи )) Во-вторых, суть предложенного и РЕАЛИЗОВАННОГО как раз в том, что зажигается все посегментно на каждой цифре, те ток не падает независимо от отображения. Частота не сканирования, а таки обновления, действительно при прочих равных меняется. В случае если используется 4 цифры (а в паяльнике софт для которого я писал это именно так) при алгоритме выше надо зажигать 4 раза по 8 сегментов каждой цифры, в том что использовал я - 8 раз по одному сегменту всех4 цифр. Только и всего. Это работает и не имеет никакого отношения ни к "маяться дурью" ни к затратам на "покупку новогооборудования" ни к уменьшению размера деталей, кстати они там 0201...

KIR
KIR
Ответ на комментарий  KIR
1 год назад

Кстати код тоже не слишком сложный, читай практически такой же сложности

Эдуард
Ответ на комментарий  KIR
1 год назад

А нельзя как то связаться, что бы обсудить этот метод, я могу объяснить, что мне в нём не нравится.

Эдуард
Ответ на комментарий  KIR
1 год назад

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

Kir
Kir
Ответ на комментарий  Эдуард
1 год назад

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

Эдуард
Ответ на комментарий  Kir
1 год назад

Там писанины много.

Эдуард
Ответ на комментарий  Aveal
1 год назад

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

Роман
Роман
1 год назад

В вашей схеме через ножку, допустим Dig1 при выставленной цифре "8" будет идти ток порядка 20*7=140мА, при максимальном токе для порта stm32 - 25мА, если не ошибаюсь. Такая схема будет безопасно работать только если зажигать по очереди каждый сегмент отдельно (предположительно яркость при этом значительно снизится) либо использовать транзисторы для усиления выходов Dig1-4.

21
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x