STM Урок 12. HAL. Динамическая индикация



 

Урок 12

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

 

Продолжим работать с семисегментными индикаторами. Только работать мы будем уже сразу с несколькими индикаторами, чтобы нам получить на них числа не от 1 до 9, так как это не совсем интересно, а ещё и большие числа.

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

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

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

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

Давайте посмотрим схему самого индикатора 4-разрядного 7-сегментного. У меня индикатор вот такого вот типа (нажмите на картинку для увеличения изображения)

 

image00_0500

 

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

Вот так вот всё у нас подключено к контроллеру (нажмите на картинку для увеличения изображения)

 

image01_0500

 

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

Общие аноды подключены через ключевые транзисторы в инверсном режиме. также применены токоограничивающие резисторы.

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

 

image03_0500

 

Также как и раньше проект создаем из LED_STAT, называем его LED_DYN.

Запускаем куб, включаем на выход ещё 4 порта для индикации PE3-PE6.

 

image02

 

В настройках в Configuration вообще ничего не трогаем.

Генерируем проект.

Добавляем файл led.c

Собираем, прошиваем, смотрим.

 

image04

 

У нас всё работает, но рабоает одновременно, так как мы пока общими анодами никак не управляем.

В главной функции main() изменим инициализацию лапок, чтобы индикаторы не светились

 

  /* USER CODE BEGIN 2 */

  HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6

        |GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10

          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14,

        GPIO_PIN_SET);

 

Ещё раз собираем, прошиваем, смотрим.

Закрываем проект, заходим в куб добавляем 6й таймер

 

image05

 

Смотрим Clock Configuration – частота APB1 стоит 84. Оставляем её без изменений

 

image06

 

 

Заходим в Configuration->TIM6

Выставляем параметр Prescaler 41999, Counter Period 2000. Должно быть равно 1 секунде

 

image07

 

Включаем прерывания

 

image08

 

Применяем изменения в таймере, генерируем проект и открываем его в Keil.

В файле main.c включаем старт таймера

 

  HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6

        |GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10

          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14,

        GPIO_PIN_SET);

        HAL_TIM_Base_Start_IT(&htim6);

 

В файле stm32f4xx_it.c находим функцию для прерывания TIM6_DAC_IRQHandler и пишем туда для проверки таймера

 

HAL_TIM_IRQHandler(&htim6);

/* USER CODE BEGIN TIM6_DAC_IRQn 1 */

HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);

 

Всё это просто пока для эксперемента, чтобы проверить, работает ли вообще таймер.

Ещё раз собираем, прошиваем, смотрим.

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

Закрываем проект, заходим в куб, меняем Counter Period на 500

 

image09

 

Генерируем проект.

В файл stm32f4xx_it.c добавим переменную для счётчика разрядов, а заодно подключим туда файл led.h

 

#include «stm32f4xx_it.h»

 

/* USER CODE BEGIN 0 */

#include «led.h»

uint8_t n_count=0;

 

 

Убираем свой код из функции TIM6_DAC_IRQHandler и пишем туда следующий код:

 

  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */

        if(n_count==0)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);

                segchar(R1);

        }

        if(n_count==1)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);

        }

        if(n_count==2)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_6, GPIO_PIN_SET);

        }

        if(n_count==3)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_6,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_SET);

        }

        n_count++;

        if (n_count>3) n_count=0;

 

Ещё раз собираем, прошиваем, смотрим

 

image10

 

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

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

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

В файл led.c добавим переменные для разрядов

 

//———————————————

uint8_t R1=0, R2=0, R3=0, R4=0;

//———————————————

 

Туда же добавляем новую функцию

 

//———————————————

void ledprint(uint16_t number)

{

        R1 = number%10;

        R2 = number%100/10;

        R3 = number%1000/100;

        R4 = number/1000;

}

 

Создадим для неё прототип.

В файл stm32f4xx_it.c проекстерналим переменные

 

uint8_t n_count=0;

extern uint8_t R1, R2, R3, R4;

/* USER CODE END 0 */

 

Добавим строчки в функции TIM6_DAC_IRQHandler

 

  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */

        if(n_count==0)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);

                segchar(R1);

        }

        if(n_count==1)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);

                segchar(R2);

        }

        if(n_count==2)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_6, GPIO_PIN_SET);

                segchar(R3);

        }

        if(n_count==3)

        {

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_6,        GPIO_PIN_RESET);

                HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_SET);

                segchar(R4);

        }

        n_count++;

        if (n_count>3) n_count=0;

 

В файле main.c комментируем всё в бесконечном цикле.

Добавим туда вызов функции

 

        HAL_TIM_Base_Start_IT(&htim6);

        ledprint(1234);

 

Ещё раз собираем, прошиваем, смотрим

 

image11

 

Мы видим, что число «1234» у нас отображается, но в связи с малой скоростью смены разрядов цифры показываются по очереди.

Закрываем проект, заходим в куб, меняем Counter Period на 20, это будет 1/100 секунды.

Генерируем проект, открываем его в Keil.

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

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

 

image12

 

Опять заходим в куб, меняем Counter Period на 10.

Генерируем проект, собираем, прошиваем, смотрим и видим что мерцания пропали. Здесь нет смысла это показывать, тем более что на видео наоборот, в этом случае мерцает больше. чем при периоде 20, видимо, это, из-за несовпадения частоты таймера с частотой кадров камеры.

Теперь убираем строчку

 

        ledprint(1234);

 

Меняем тип переменной i

 

  /* USER CODE BEGIN 1 */

        uint16_t i=0;

  /* USER CODE END 1 */

 

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

 

                for(i=0;i<10000;i++)

                {

                        ledprint(i);

                        HAL_Delay(100);

                }

 

Ещё раз собираем, прошиваем, смотрим

 

image13

 

Наш четырёхразрядный счётчик отлично работает, благодаря применению динамической индикации.

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

Отладочную плату и индикаторы можно приобрести здесь:

STM32F4-DISCOVERY

Семисегментный чертырехразрядный индикатор красный с общим анодом 10 шт

 

 

Смотреть ВИДЕОУРОК

 

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

7 комментариев на “STM Урок 12. HAL. Динамическая индикация
  1. Прекрасно работающий код спасибо большое. Хотелось спросить как его можно модифицировать чтобы можно было выводить float на экран

    • Где-то мы выводили значения с плавающей запятой на светодиодный индикатор и именно через драйвер MAX7219, может когда какой-то датчик прикручивали к нему, только точно не помню.

  2. Тимур:

    1. А для чего нужны эти транзисторы на схеме? (понятно, что каком режиме они работаю, вопрос в том с какой целью?).
    2. Можно ли без них обойтись?

    • Виталий:

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

  3. Тимур:

    т.е. просто как ключи?

    • Юрий:

      Да, в этой схеме транзисторы используются как ключи. Я кстате не использовал в схеме их. Резисторы использовал 2k.Индикатор потреблял 0.75mA-сегмент. А если 8*0.75mA=6mA на ножке(общий Анод1), а ножка STM32 можно нагружать 25mA.

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

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

*