Библиотека для семисегментного индикатора с произвольным подключением выводов

17/12/2013 - 06:15 Pavel Bobkov

Введение

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

Особенности библиотеки:

- предназначена для микроконтроллеров AVR,
- легко интегрируется в готовый проект,
- может использоваться с компиляторами IAR, GCC, CodeVision,

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

Полная версия библиотеки дополнительно обеспечивает:

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

Состав библиотеки

indicator_2f.h - настройка параметров и подключения
indicator_2f.c - реализация функций
compiler_4.h - файл обеспечивающий поддержку трех компиляторов
port_macros.h - макросы виртуальных портов

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

1. Копируем все файлы в папку проекта. 
2. Подключаем indicator_2f.c к проекту
3. Инклюдим заголовочный файл indicator_2f.h к сишному файлу, в котором будут использоваться функции библиотеки. 
4. Настраиваем параметры и подключение индикатора в файле indicator_2f.h
5. Прописываем в код вызов функций библиотеки индикатора

Настройка библиотеки индикатора

Настройка конфигурации состоит из следующих шагов.

1. Задаем количество цифр индикатора. Их может быть от 1 до 8.


#define IND_AMOUNT_NUM 4


2. Задаем тип развертки


#define IND_SCAN_SEGMENT 1


1 - посегментная развертка. За один цикл засвечиваются один сегмент всех разрядов.
0 - поразрядная развертка. За один цикл засвечиваются все сегменты одного разряда. 

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

3. Подключаем/отключаем функцию моргания


#define IND_USE_BLINK 1


0 – функция моргания не используется, 1 – функция моргания используется. В первом случае получается более компактный код.

4. Задаем период моргания


#define IND_DUR_BLINK 2000


Эта настройка определяет количество циклов, в течении которых моргающие разряды индикатора гаснут/горят. Один цикл – это время между вызовами функции обновления индикатора IND_Update().

5. Задаем куда подключены сегменты индикатора 

Настройки, которые можно менять, обозначены на рисунке красной рамкой. 


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


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

Типов порта два - _VIRT и _REAL. Порт считается виртуальным в двух случаях: если он состоит из выводов нескольких портов, если он состоит из выводов одного порта, но они располагаются не по порядку.

Если используется реальный порт, то указывается тип _REAL. Это создает более компактный код.

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

C- буква порта, 0 - используемый вывод порта, _HI - высокий активный уровень.

Здесь стоит остановиться только на активном уровне вывода. Есть три значения этого параметра: _HI, _LOW, _NONE.

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

6. Задаем куда подключены разряды индикатора

Настройки, которые можно менять, обозначены на рисунке красной рамкой.

 


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


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

Использование библиотеки

void IND_Init(void) - функция инициализации. Настраивает порты ввода вывода, инициализирует внутренние переменные. Эта функция должна вызываться первой, например, в начале main`a.

void IND_OutSym(char *str, uint8_t pos) – записывает в буфер индикатора строку символов. Принимает указатель на строку (*str) и позицию первого символа (pos). Символы, которые может отобразить индикатор, определены в файле indicator_2f.c в массиве sym[]. Можно добавлять в этот массив свои символы.

Пример:


IND_OutSym(“cod”, 1);


void IND_OutUint(uint16_t value, uint8_t comma) – преобразует беззнаковое 16-и разрядное число (value) и записывает его в буфер индикатора. Число отображается на индикаторе, начиная с первого разряда. Также эта функция принимает номер разряда (comma), в котором будет гореть десятичная точка.

void IND_OutInt(int16_t value, uint8_t comma) – преобразует 16-и разрядное число со знаком (value) и записывает его в буфер индикатора. В первом разряде индикатора отображается знак числа. Также эта функция принимает номер разряда (comma), в котором будет гореть десятичная точка.

void IND_OutUintFormat(uint16_t value, uint8_t comma, uint8_t firstPos, uint8_t lastPos) - преобразует беззнаковое 16-и разрядное число (value) и записывает его в буфер индикатора в заданые позиции (firstPos, lastPos). Также эта функция принимает номер разряда (comma), в котором будет гореть десятичная точка.

void IND_OutIntFormat(int16_t value, uint8_t comma, uint8_t firstPos, uint8_t lastPos) - преобразует беззнаковое 16-и разрядное число со знаком (value) и записывает его в буфер индикатора в заданые позиции (firstPos, lastPos). Знак числа отображается в первой заданной позиции (firstPos). Также эта функция принимает номер разряда (comma), в котором будет гореть десятичная точка.

void IND_BlinkMask(uint8_t value) – задает маску (value), которая определяет моргающие разряды индикатора. Каждый бит маски соответствует одному разряду индикатора: нулевой бит – это первый разряд, первый бит – второй и так далее. Единица в маске – разряд моргает, ноль – не моргает.

Пример:


//задаем моргание 1, 2, 3, 4 разрядов индикатора
IND_BlinkMask (0x0f); 

//ни один из разрядов не моргает
IND_BlinkMask (0x00); 


void IND_Update(void) - функция обновляющая информацию на индикаторе. Эта функция должна периодически вызываться с частотой > 25* N. Где N - количество разрядов или сегментов индикатора, в зависимости от типа развертки. Вызов этой функции можно поместить в прерывание какого-нибудь таймера. В идеале ее нужно сделать встраиваемой, то есть описать прерывание таймера в файле indicator_2l.c и поместить в него код этой функции. Также можно вызывать эту функцию из основного цикла по сигналу таймера.

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

Файлы

Облегченная версия библиотеки

IND-driver-2l-IAR.rar
IND-driver-2l-winavr.rar

Полная версия библиотеки

IND-driver-2f-IAR.rar
IND-driver-2f-winavr.rar

П.С: Об ошибках пишите в комментариях или 
вконтакте. Я ее, конечно, проверил, но косяки могут быть. А вообще получилось неплохо. 

Comments   

# axill 2013-12-17 17:00
Павел, спасибо за библиотеку. Оригинальная идея по конфигурации с запятой, пока не смотрел как оно работает, но давно искал способ настраивать библиотеки без указывания отдельно PORT, DDR, PIN.
В качестве идеи для расширения возможностей - добавить регулировку яркости. Сам такое сделал на часах и яркость меняется в зависимости от внешнего освещения, 16 градаций яркости как для самих цифр так и для двоеточия между ними. Работает отлично, логика тоже простая - временной слот выделенный для отображения сегмента (или цифры смотря какой тип сканирования) делится на 16 и зажигается на время от 0 до 16/16. Могу поделиться кодом часов, у меня он не выделен в библиотеку
# Pashgan 2013-12-17 17:11
Идея объявления выводов таким образом, берет начало с макросов Аскольда Волкова. По крайней мере у него я впервые увидел такой подход. А вообще избавиться от длинных объявлений портов можно с помощью указателей. Но это не оптимально с точки зрения размера кода и скорости его выполнения. http://chipenable.ru/index.php/programming-avr/item/173-rabota-s-portom-cherez-ukazateli.html
# axill 2013-12-17 18:01
про использование указателей читал, не стал применять как раз по названным вами причинам
в последней библиотеке решил попробовать очень простой подход - объявляешь например LCD_PORTB если используется порт B или LCD_PORTD если порт D и т.д. все равно кол-во портов конечно, а уже внутри библиотеки исходя из этого определяешь и PORT и PIN и DDR
# foxit 2013-12-17 17:52
Quoting axill:
Могу поделиться кодом часов, у меня он не выделен в библиотеку

Неплохо бы было увидеть реализацию
# axill 2013-12-17 17:57
Quoting foxit:

Неплохо бы было увидеть реализацию

тут все описано, есть видео и код управления яркостью тоже там приложен
# axill 2013-12-17 17:58
забыл ссылку http://radiokot.ru/circuit/digital/home/176/
# foxit 2013-12-17 17:51
Спасибо за библиотеку.
# Pashgan 2013-12-20 01:49
Пожалуйста.
# Plotnik 2013-12-18 05:29
Паша,насколько МНОГО репостов необходимо? Мне,желательно, полную версию.
# Pashgan 2013-12-20 01:48
Репостов много не бывает. Скоро выложу.
# Neiver 2013-12-25 20:00
Могу предложить еще пару полезных фишек для этой библиотеки. Индикацию чисел с разрядностью болшей, чем кол-во разрядов на индикаторе в экспоненциально м формате. Например, 12000 можно вывести на 4 разрядный индикатор как 1.2E4. Ну и выравнивание влево-вправо тоже бывает полезным.
# Pashgan 2013-12-27 05:15
Запишу на будущее.
# Sergofan5 2014-01-07 13:45
Как бы заполучить полную версию библиотеки, щас как раз пилю один проектик - очень подсобила бы????
# Kh_Shad 2014-01-08 12:00
Интересно, а если нет контакта, то как можно получить полную библиотеку? Или когда она появиться в доступе на сайте?
# Pashgan 2014-01-08 13:58
Обновил статью. Качайте, проверяйте. Остальные проекты в процессе. Праздники и все такое.. сами понимаете.
# Sergofan5 2014-01-09 12:16
Вопрос по полной версии библиотеки - почему при использовании функции IND_OutSym("LEd ",1);IND_OutSym ("UoLt",1); после первого вывода слова volt, начинает выводить ledt - остается буква t в конце и так пока не сделаешь ресет, потом снова все повторяется????
# Pashgan 2014-01-09 13:45
Потому что в буфере индикатора остается символ 't'. Добавь пробел - "LEd " и эта буква будет затираться.
# Kh_Shad 2014-01-09 14:26
Огромное Спасибо! Мне понравился Ваш подход к организации драйвера. Легко внедрил в проек (пользуюсь самописной осью для МК). Кстати Вы системным программировани е не занимались, а то оформление дравера наталкивает на это.
# Pashgan 2014-01-09 14:55
Это радует.
Нет, системным программировани ем не занимался.
# Tit0xFF 2014-02-14 00:34
За библиотеку спасибо, но есть вопросик. Почему нельзя было придать сегментам нормальные, осмысленные, общепринятые имена (abcdef dp)? Вот сиди и думай кто из них кто...
# Pashgan 2014-02-14 08:08
Потому что библиотека использует макросы виртуальных портов. А эти макросы требуют определенного синтаксиса объявления портов.
# Tit0xFF 2014-02-15 11:31
То есть, если вместо дефайна
IND_SEG_0
сделать
IND_SEG_A ,
то библиотека не смогла бы работать?
# Pashgan 2014-02-25 16:39
Да.
# mmavka 2014-03-02 21:04
Доброго времени суток!
Попробовал сегодня эту библиотеку. Все круто!
Но есть одно, но. При посегментной индикации очень сильно неравномерна засветка индикатора (все сегменты засвечены по разному). А при поразрядной - все ОК.
# JoJo 2014-03-03 07:55
Резисторы на каждый сегмент поставь, тогда все будет равномерно светиться.
# mmavka 2014-03-05 18:19
Стоят на всех сегментах. Сегменты управляются транзисторами, разряды 2003A. Только резисторы по 30 ом, может в этом дело.
# САБ 2014-03-06 12:25
При посегментной резисторы ставятся в цепи разрядов, при поразрядной - в цепи сегментов. У вас резисторы стоят в цепи сегментов и через резистор течет ток одновременно включенных сегментов всех знакомест. Поэтому и яркость меняется в зависимости от того, на скольких индикаторах зажжен конкретный сегмент.
# mmavka 2014-03-14 11:31
Предлагаю дополнить!
Code:
void IND_Clear(void)
{
uint8_t i;

/*очищаем внутренний буфер*/
for(i = 0; i < IND_AMOUNT_NUM; i++) {
ind_buf = 0;
}
}
# Pashgan 2014-03-18 20:08
Ок. Когда подойдет время следующего апгрейда - дополню.
# dim 2014-03-23 17:21
Все супер, только хотелось бы добавить поддержку SPI как программно, так и аппаратно (в предыдущей библиотеке только аппаратно - это не удобно, если хочется поставить это дело на tiny13, например)
# Oleg82 2014-11-11 14:55
А не подскажите где почитать про макросы , а то не совсем понятна такая запись Code: #define _PM_DirPort_VIRT(port, id, value) do{ PM_SetDir(port##_##0, value, 0); .
# Oleg82 2014-11-14 16:49
И еще заметил одну ошибку в функции IND_Update
Там где реализация поразрядной развертки
Code: dig = (1<<count); при count=0 dig =1
и при PM_SetLevBitsPort(IND_DIG_PORT, dig); он зажет PORTD.0 ( это в моем случае ) но у меня в настройках стоит #define IND_DIG_0 D, 2, _LOW . Т.е изначально dig должен = 2
# Oleg1 2015-10-03 13:52
Не выходит настроить библиотеку. Может кто подскажет в чем проблема. На дисплей в протеусе выводятся непонятные символы вместо того что прописано в коде.
http://forum.cxem.net/index.php?app=core&module=attach§ion=attach&attach_id=372222
http://forum.cxem.net/index.php?app=core&module=attach§ion=attach&attach_id=372224
# skullhead 2015-11-17 07:18
Добрый день! Почему то после использования функции IND_Update перестают работать остальные порты, хотя они никак не задействованы в настройках библиотеки. в чем может быть дело?
# skullhead 2015-11-18 09:47
Прошу прощения за глупый вопрос. проблема была в схемотехнике.
# Алексей_К 2015-12-17 16:26
Все прекрасно, встроил в проект библиотеку, но одно НО. Не работает моргание (IND_BlinkMask) . Че-то разбираться не тенкт особо... Может подскажете, в чем может быть дело?
# Алексей_К 2015-12-17 16:34
Извиняюсь, я не указал... Я использую полную версию для WinAVR - IND-driver-2f-w inavr.rar
# Dmitry 2016-01-12 09:50
Поразрядная индикация работает только когда порт на котором висят сегменты реальный , если его определить как виртуальный выводится по одному сегменту в каждом разряде . Это так и задумано ?
# Алексей_К 2016-01-16 09:22
Так и не разобрался с миганием... А оно нужно, так как хорошо помечать разряды для коррекции. Так все работает идеально, но мигание работает ТОЛЬКО при большой задержке, да и то не правильно... Эх...
# s1292oia 2016-02-10 16:34
Очень понравилась библиотека. Адаптирую для своего проекта. Немного разобрался с миганием. Запускается в следующем порядке:
1. вызывается функция мигания (единожды, иначе приводит к неверному отображению);
2. затем функция обновления индикатора
3. затем функция записи символов в буфер.
Теперь любые выводимые символы будут мигать, пока снова не будет вызвана функция мигания с нулевым значением
# sem 2017-01-27 16:47
Как при виводе дробных чисел узнать где виводить точку использую
IND_OutUintFormat

У вас недостаточно прав для комментирования.