Введение
Написал новый драйвер семисегментного индикатора. Он имеет следующие особенности:
- предназначен для микроконтроллеров AVR,
- легко интегрируется в готовый проект,
- может использоваться с компиляторами IAR, GCC, CodeVision,
- поддерживает подключение индикаторов через сдвиговые регистры,
- поддерживает подключение индикаторов через различные буферы,
- поддерживает индикаторы с общим катодом и с общим анодом,
- предоставляет возможность посегментной или поразрядной развертки,
- позволяет выводить на один индикатор несколько переменных,
- при стандартном подключении позволяет работать с 8-ю разрядами,
- при подключении через сдвиговые регистры - с 16 разрядами.
Состав драйвера
indicator.h - настройки параметров, прототипы функций
indicator.c - реализация функционала
compiler.h - файл обеспечивающий совместимость с несколькими компиляторами
spi.h, spi.c - драйвер spi, требуется только в случае использования соответствующего подключения.
Подключение к проекту
1. Копируем все файлы драйвера в папку проекта.
2. Подключаем файлы indicator.c, spi.c к проекту внутри среды разработки.
3. Инклюдим заголовочный файл indicator.h к сишному файлу, в котором будут использоваться функции для работы с индикатором.
4. Настраиваем заголовочный файл indicator.h
5. Прописываем в код вызов пользовательских функций
Настройка конфигурации
Настройка конфигурации включает в себя следующие шаги:
Установка количества разрядов семисегментного индикатора
#define IND_AMOUNT_NUM 8
Для стандартной схемы включения и схемы с двумя сдвиговыми регистрами может принимать значение от 1 до 8. Для схемы с тремя сдвиговыми регистрами от 1 до 16.
Установка типа подключения семисегментного индикатора
#define IND_SPI_CONNECTION
Если используется подключение через сдвиговые регистры с управлением по SPI, то этот макрос трогать не нужно. Если используется стандартное подключение (без SPI), макрос нужно закомментировать.
Установка типа развертки
#define IND_SCAN_SEGMENT
Традиционно для вывода информации на семисегментный индикатор используется динамический метод, при котором каждый разряд или сегмент индикатора засвечивается на определенный промежуток времени с частотой незаметной для человеческого глаза.
Можно реализовать динамическую индикацию двумя способами - поочередно засвечивая разряды индикатора или поочередно засвечивая один из сегментов всех разрядов сразу. Первый метод реализуется более простым кодом, однако при большом количестве разрядов, требует высокой частоты смены разрядов и, соответственно, высокого тока засветки. Второй метод всегда будет иметь одну и ту же частоту обновления, поскольку количество сегментов индикатора остается одинаковым вне зависимости от количества его разрядов. Второй метод предпочтительней использовать при количестве разрядов в индикаторе больше 8.
Если закомментировать данный макрос, будет реализована поразрядная индикация, если оставить, то посегментная.
Выбор активного уровня сегментов
#define IND_ACTIVE_LEVEL_SEG 0
Это логический уровень, который нужно выставить на выводе микроконтроллера (или сдвигового регистра), чтобы один сегмент индикатора засветился. В зависимости от типа семисегментного индикатора (общий катод, общий анод) и схемы его включения (прямая, через инвертирующий буфер), уровень напряжения, требуемый для засветки одного сегмента, может быть или нулем или единицей.
Выбор активного уровня разрядов
#define IND_ACTIVE_LEVEL_DIG 0
Это логический уровень, который нужно выставить на выводе микроконтроллера (или сдвигового регистра), чтобы один разряд индикатора засветился. В зависимости от типа семисегментного индикатора (общий катод, общий анод) и схемы его включения (прямая, через инвертирующий буфер), уровень напряжения, требуемый для засветки одного разряда, может быть или нулем, или единицей.
Например, для зажигания сегментов индикатора с общим катодом, нужно на выводы сегментов подать единицу, а на вывод разряда логический ноль. Сегменты обычно подключают напрямую к микроконтроллеру, поэтому активный уровень сегментов будет 1. Разряды индикатора обычно подключают через транзистор, открывающийся при подаче логической единицы на базу. Таким образом, активный уровень разрядов будет тоже 1. (Если разряд индикатора подключить к микроконтроллеру напрямую, то активный уровень разряда будет 0.)
Установка порта, к которому подключены сегменты индикатора
#define IND_PORT_SEG PORTC
#define IND_DDR_SEG DDRC
Если используется подключение через сдвиговые регистры, эти настройки игнорируются.
Установка порта, к которому подключены разряды индикатора
#define IND_PORT_DIG PORTD
#define IND_DDR_DIG DDRD
Если используется подключение через сдвиговые регистры, эти настройки игнорируются.
Установка регистров к которым подключены сегменты и разряды индикатора
#define IND_SHIFT_REG_SEG 2
#define IND_SHIFT_REG_DIG1 1
#define IND_SHIFT_REG_DIG2 0
Сдвиговый регистр, подключенный непосредственно к микроконтроллеру имеет следующие значение: при использовании двух регистров - 1, при использовании трех - 2. Сдвиговый регистр, подключенный последним каскадом всегда имеет значение - 0.
Установка выводов, к которым подключены разряды семисегментного индикатора
#define IND_NUM1 0
#define IND_NUM2 1
#define IND_NUM3 2
#define IND_NUM4 3
#define IND_NUM5 0
#define IND_NUM6 0
#define IND_NUM7 0
#define IND_NUM8 0
#define IND_NUM9 0
#define IND_NUM10 1
#define IND_NUM11 2
#define IND_NUM12 3
#define IND_NUM13 0
#define IND_NUM14 0
#define IND_NUM15 0
#define IND_NUM16 0
Если используется традиционное подключение, номера соответствуют разрядам порта микроконтроллера и могут принимать значения от 0 до 7, при этом макросы IND_NUM9 - IND_NUM16 игнорируются. Если используется подключение через сдвиговые регистры, номера соответствуют выходам сдвигового регистра и могут принимать значения от 0 до 7.
Установка выводов, к которым подключены сегменты индикатора
#define IND_A 0
#define IND_B 1
#define IND_C 2
#define IND_D 3
#define IND_E 4
#define IND_F 5
#define IND_G 6
#define IND_COM 7
Если используется традиционное подключение, номера соответствуют разрядам порта микроконтроллера. Если используется подключение через сдвиговые регистры, номера соответствуют выходам сдвигового регистра. В обоих случаях диапазон возможных значений от 0 до 7.
Использование драйвера
Драйвер включает в себя четыре пользовательские функции.
void IND_Init(void) - функция инициализации. Настраивает порты ввода вывода, инициализирует внутренние переменные и SPI модуль микроконтроллера AVR, если он используется. Эта функция должна вызываться первой, например, в начале main`a.
void IND_Output(uint16_t value, uint8_t comma) - эта функция разделяет 16-и разрядное число на разряды, преобразует по таблице перекодировке и записывает в буфер. В дальнейшем его содержимое используется при обновлении данных на индикаторе. Число отображается на индикаторе, начиная с первого разряда.
Также эта функция принимает номер разряда, в котором будет гореть десятичная точка.
void IND_OutputFormat(uint16_t value, uint8_t comma, uint8_t position, uint8_t amount) - эта функция аналогична предыдущей, но может выводить числа в произвольные разряды семисегментного индикатора. Для этого функции передаются два параметра: position - начальный разряд и amount - количество отображаемых цифр. Минимальное значение обоих переменных - 1. Данная функция позволяет использовать один большой индикатор для отображения нескольких переменных.
void IND_Update(void) - функция обновляющая информацию на индикаторе. Эта функция должна периодически вызываться с частотой > 25* N. Где N - количество разрядов или сегментов индикатора, в зависимости от типа развертки. Вызов этой функции можно поместить в прерывание какого-нибудь таймера.
Тестовый проект
Тестовые проекты написаны в IAR`е и AtmelStudio6. Для проверки кода использовалась макетная плата и проект в Proteus`e. В Proteus`e индикаторы подключены напрямую к микроконтроллеру и сдвиговым регистрам с целью упрощения схемы. Использовать такую схему в реальности нельзя. В зависимости от выбранной конфигурации драйвера в Proteus`e будет работать один из индикаторов.
IND_driver_IAR.rar
IND_driver_AS6.rar
IND_driver_CV.rar
IND_driver_Proteus.rar
IND_driver.rar
Comments
Но данный код драйвера на самом деле не 2 кБ, а ~800 байт. Покрутите оптимизацию в проектах (она сейчас там минимальная) и увидите. IAR даже на самом низком уровне оптимизации дает 800 байт, AS6 при низкой оптимизации генерит порядка 2 кБ.
И по хексу нельзя судить о размере кода, в нем помимо прошивки содержаться служебные символы, адреса и контрольные суммы.
Поразрядная, - на 24 разряда, даже супер яркие индикаторы, и током до 30мА сегмента, светят плохо!
Посегментную я искал, искал…, нужно было на 24 разряда. Нашел только в одном месте рабочий пример, на основании которого написал по свое. Опробовал. Индикаторы, даже при токе 3,6мА на сегмент (резистор 820 Ом) светят достаточно прилично!
Здесь: SPI_ShiftReg.c/ #define F_CPU 80000000UL/ похож нолик лишний.
1) При подключении индикатора к МК непосредственно и при поразрядной индикации число выводится задом на перёд по разрядам.
А вот точка правильно.
2) При определённых комбинациях в заголовочном файле и передаваемых параметрах функции, точка не горит а помаргивает.
Может я что напутал или просто недочет?!
2)Не знаю. Надо проверять. У меня таких эффектов не наблюдалось. Что за комбинации и параметры?
А по поводу точки то обратил внимание что в PROTEUSE этот порт в отличии от других сегментов горит не красным и синим а красным и серым. Видимо что то в инициализации порта но я использовал IND_Init.
Code:
void IND_Init(void)
{
uint8_t i;
#ifndef IND_SPI_CONNECTION
IND_PORT_SEG = (1<<IND_A)|(1<<IND_B)|(1<<IND_C)|(1<<IND_D)|(1<<IND_E)|(1<<IND_F)|(1<<IND_G);
IND_DDR_SEG = (1<<IND_A)|(1<<IND_B)|(1<<IND_C)|(1<<IND_D)|(1<<IND_E)|(1<<IND_F)|(1<<IND_G);
Тоже самое писал, но коммент обрезался :(
У вас в библиотеке ошибка, исправьте.
В строках 120 и 121 нужно добавить "|(1
Такой вопрос у меня: Возможно ли отключить вывод первых нулей, чтоб не выводилось 001. Ну и регистры все-таки слева направо наверное нужно выводить.
Спутал вас с автором.
ТОчно
#include "mega16.h"
#include "indicator.h"
void main( void )
{
IND_Init();
while(1){
IND_OutputFormat(357, 0, 0, 0);
IND_Update();
delay_ms(400);
}
}
Однако На всех трех сегментах выводятся разные символы.
ЗЫ. Прошу строго не судить, изучение мк и си начал недавно.
Должно быть
IND_OutputForma t(357, 0, 1, 3);
вывести в 3 разряда, начальное положение 1-й разряд индикатора, без точки.
И на практике очень редко получается повесить сегменты на один порт из-за необходимости каких-то аппаратных узлов привязанных к определённой ноге так что предлагаю усложнить инициализацию так чтобы для каждого сегмента можно было определять и порт и бит.
Спасибо, разобрался. Плюс у меня не правильно были настроены активные уровни сегментов.
И еще. Сейчас, насколько я понял, частота обновления зависит от задержки. К примеру такой код
Code:
unsigned int data = 0;
void main( void ){
IND_Init();
while(1){
data++;
if (data == 1000) {
data = 0;
}
IND_Output(data, 0);
IND_Update();
delay_ms(1000);
}
}
В данном случае каждый сегмент индикатора обновляется 1 раз в секунду, причем поочередно.
Может стоит вывести частоту обновления в функцию IND_Update()? Чтобы было например IND_Update(1000 );
1) Настраиваешь таймер на прерывания 500 раз в секунду.
2) А потом в его обработчике прерывания пишешь Code:
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
IND_Update();
}
Теперь сегменты и разные порты.
Работа с PORTА. Работают все порты кроме РА7.
Работа с PORTС. РС0, РС1, РС6 работают, остальные нет.
Работа с PORTD. Работают все порты кроме PD7.
Исходя из этого у меня как минимум не будет работать один сегмент.
Если кто то может проверить отпишитесь пожалуйста после проверки
У меня возникла проблека: при отключенном SPI и посегментной развертке компилятор IAR ругается, мол "Error[Pe020]: identifier "PORTC" is undefined", и то же самое для DDRC, PORTD, DDRD. Пытаюсь привинтить все это для МК ATMega 32A. В чем может быть загвоздка? =\
Из соурсов подключал только Indicator.c.
chipenable.ru/index.php/forum/materialy-sajta-chipenable/3245-vetka-dlya-vremennogo-khraneniya-proektov.html
У меня была ошибка в том, что я закоментировал #include "compilers.h" в файле indicator.c =_=
+1
Первую выводящую на все разряды "минус" и вторую тушащую все разряды с помощью EMPTY_DIG. Всё в пару строк.
Code:
void IND_OutputFormat(uint16_t value, uint8_t comma, uint8_t position, uint8_t amount)
{
uint8_t tmp;
uint8_t i;
uint8_t m=0;
if ((position <= IND_AMOUNT_NUM)&&(position != 0)){
if(value&(1<<15))//проверяем является число отрицательным
{
value=~(value-1);
//value=0-value;//тоже самое
m=1;
}
for(i = 0; i < amount; i++){
tmp = value % 10;
if ((i == 0)||(value > 0)||(position <= comma)){
ind_buf[position-1] = read_byte_flash(number[tmp]);
}
else{
if(m==1){
ind_buf[position-1] = read_byte_flash(number[11]);
m=0;
}
else{
ind_buf[position-1] = read_byte_flash(number[IND_EMPTY_NUM]);
}
}
value = value/10;
position++;
if (position > IND_AMOUNT_NUM){
break;
}
}
}
if ((comma <= IND_AMOUNT_NUM) && (comma != 0)) {
ind_buf[comma-1] |= 1<<IND_COM;
}
}
О-о-очень полезная весчь!Пробовал самостоятельно поиграться Вашей библиотекой-рез ультат,ессно,ни какой.Как прикрутить блинк?(натолкни те на мысль).
Ну,тогда ИМЕЕТ смысл создать на форуме отдельный топик по индикации,а пожелания будут-и очень много...
Павел, драйвер еще не дорабатывал?
Возник вопрос.
Code:
T++;
if (T == 100)
{
T= 0;
}
IND_Output(T, 0);
delay_ms(100);
IND_Init(); стоит по переполнению таймера.
Вот и вопрос: чем выше частота таймера, тем медленнее изменяются значения Т. Как это победить?
Т.е. при максимальной частоте таймера значение Т сменяется раз в 5 секунд, вместо 0.1. Но чем ниже частота таймера, тем быстрее изменяется Т.
Мда... Никогда не владел языком :(
На дисплей выводится число, которое увеличивается на единицу каждую десятую долю секунды (по коду). Но на деле выходит то, что интервал смены числа зависит от частоты таймера на который повешена функция IND_Init(). Чем частота таймера выше, тем больше интервал увеличения числа. И наоборот, ставим частоту таймера ниже - интервал инкремента числа уменьшается. Как-то так.
Пробую прикрепить в CodeVision AVR
к своему проекту. выдает ошибку
Error: F:\temp\device\ AHcounter\AhC_v 3.0_RC_IntRef\i ndicator.c(83): undefined symbol 'IND_NUM1'
Как победить?
прикрепил как написано выше, файлы на си включивл в проект в компиляторе, а библиотеку indicator.h инклудил в коде
http://chipenable.ru/index.php/forum/materialy-sajta-chipenable/3245-vetka-dlya-vremennogo-khraneniya-proektov.html
Разобрался на следующий день.
Закоментировал просто больше чем надо.
А нету библиотеки для опроса 4 или 5 кнопок для code vision.
(Хотелось бы с длинными и короткими нажатиями).
Нашел на вашем сайте библиотеку для семисегментного индикатора с мигающими разрядами и с отображением символов.
Пока разбираюсь.
Есть задача подключить индикатор на 7 разрядов через 2 сдвиговых регистра (HC595). Я не пойму где в библиотеке настроить: к каким ногам регистра какие ноги МК подключать? Спасибо.
нужно выводить на семисегментный дисплей числа от 0 до FF
Code:
/*к каким выводам подключены разряды*/
#define IND_NUM1 0
#define IND_NUM2 1
#define IND_NUM3 2
#define IND_NUM4 3
#define IND_NUM5 6
#define IND_NUM6 7
#define IND_NUM7 4
#define IND_NUM8 5
/*к каким выводам подключены сегменты*/
#define IND_A 7
#define IND_B 0
#define IND_C 2
#define IND_D 6
#define IND_E 5
#define IND_F 3
#define IND_G 1
#define IND_COM 4
Буфер индикатора заполняю вызовом
Code:
IND_OutputFormat(tempbutton,2,1,4);
IND_OutputFormat(tempbutton1,6,5,4);
Но символы в каждый разряд выводятся не в том порядке, который я указываю.
RSS feed for comments to this post