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

Для вывода часто применяют светодиодные индикаторы. Выводить информацию на них можно как статически, так и динамически. Дальше я попробую в картинках показать какие виды динамической индикации бывают и как она вообще работает.
main
1. Статическая индикация.
Самый простой вид индикации — статический. При ее использовании каждый сегмент индикатора постоянно находится в одном из двух состояний — включен или выключен. Ее основное достоинство в том, что после вывода информации, например в сдвигающий регистр, состояние индикатора не изменится пока не будут изменены данные в этих регистрах. Так же т.к. напряжение на сегментах присутствует постоянно яркость индикатора будет максимальной. Кроме этих двух плюсов есть также два больших минуса. Во первых требуется большое число регистров (один разряд — одна микросхема), нужна куча резисторов — по одному на каждый сегмент. Можно конечно поставить специальные драйверы (что-то вроде mbi5026), которым резисторы не нужны и выходов и них больше (аж 16 штук), но они стоят денег. И во вторых все сборки, в которых от 3 и больше разрядов, идут с соединенными сегментами и статически их использовать просто не получится. Да и разводить все это дело на плате дело нудное и не интересное.
Поэтому перейдем к динамической индикации.

2. Динамическая индикация.
При динамической индикации сегменты зажигается по очереди. А за счет инерции глаза кажется, что индикатор горит постоянно. Из ее основных плюсов — требуется гораздо меньше внешних элементов. Основной минус — для нее постоянно требуется внимание процессора:) Частота смены сегментов выбирается обычно не ниже 50Гц. Лучше использовать частоты не кратные 50, иначе при искусственном освещении может появиться мерцание. Частота прерываний считается как «Кол-во разрядов» х «Частота обновления». Так для 8 разрядов с частотой 60Гц нужно вызывать прерывание с F=8х60=480Гц.
Есть два вида такой индикации — поразрядная и посегментная. Первая наиболее известна и популярна, вторая лучше подходит когда нужно большое количество разрядов (больше 10).

2.1 Поразрядная динамическая индикация.
Самый известный и популярный вид индикации. Ее смысл в том, что в каждый момент времени горит только один разряд. На схеме ниже к порту С подключены сегменты, а к порту D катоды разрядов.
Поразрядная индикация
Для вывода используется следующая подпрограмма прерывания таймера:

#define   SegPort   PORTC
#define   PosPort   PORTD
volatile unsigned char buffer[6];
// Прямое изображение символа. 1 - сегмент горит!
unsigned char __flash digit[] = {127-64,127-64-32-16-8-1,127-32-4,127-32-16,127-16-8-1,127-16-2,127-2,127-64-32-16-8,127,127-16};

__interrupt void TIMER1_interrupt (void)
{
  // Начало вывода с позиции 0
  // Позиция выводимого разряда 0xFE=0b11111110
  static u8 pos=0,mask=0xFE;
  // Выключение сегментов
  SegPort=0;
  // Выводим следующий разряд
  PosPort=mask;
  // Выводим символ из буфера
  SegPort=buffer[pos];
  // Следующая позиции вывода
  pos++;
  mask=mask<<1;mask=mask | 1;
  // Если дошли до конца, то повторяем сначала
  if(mask==0xBF)
  {
    mask=0xFE;
    pos=0;
  }
}

Алгоритм работы описан в комментариях. Гашение сегментов вначале необходимо для устранения мерцания при смене разряда. Если этого не сделать, то при смене разряда на нем будет выведен символ с предыдущей позиции. Хоть это происходит и короткое время, но красоты не прибавляет.
На следующей осциллограмме видно как бежит «0» выбора разряда. Так же на нижней линии видно сколько времени индикатор выключен (почти 13мс), а сколько включен (чуть больше 2.5мс).

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

2.2 Посегментная динамическая индикация.
Ее главное отличие от поразрядной индикации является в том, что в ней перебираются не разряды, а сегменты индикатора. В результате частота загорания каждого сегмента не зависит от количества разрядов. На схеме ниже вывод идет на 24-х разрядный индикатор. В ней к порту С также подключены сегменты, а катоды включены через сдвигающий регистр 74HC595.
24 разряда
Для вывода используется следующая подпрограмма прерывания таймера:

volatile unsigned char buffer[24];
// Обратное изображение символа. 1 - сегмент не горит!
unsigned char __flash digit[] = {1+2+4+8+16+32,2+4,1+2+8+16+64,1+2+4+8+64,2+4+32+64,1+4+8+32+64,1+4+8+16+32+64,1+2+4,1+2+4+8+16+32+64,1+2+4+8+32+64};

__interrupt void TIMER1_interrupt (void)
{
  // Начало вывода с сегмента 1
  static u8 seg=1;
  u8 i;
  // Гашение сегментов
  SegPort=0;
  // Перебор всех элементов в буфере
  // Т.к. первый элемент буфера соответствует младшему разряду регистра (L1),
  // то перебор начинаем с конца буфера.
  for(i=23;i!=0xFF;i--)
  {
    // Если сегмента нет в символе, то выводим "1"
    if(buffer[i] & seg) SaveBit1();
    else SaveBit0();
  }
  // Запись регистров
  SaveOut();
  // Вывод сегмента
  SegPort=seg;
  // Переход к следующему сегменту
  seg=seg<<1;
  if(!seg) seg=1;
}

В ней SaveBit1 и SaveBit0 — запись бита в регистр, а SaveOut — запись состояния регистров на выход защелок. Алгоритм работы подпрограммы в следующем — идет перебор всех байтов в буфере и если в данной позиции текущий сегмент не должен гореть, то в регистр записывается 1. Единица пишется, т.к. активный уровень у общего вывода индикатора — «0». После перебора всего буфера в выходы защелок фиксируется новое состояние и зажигается новый сегмент.
На следующей картинке видно как бежит «1» выбора сегмента. На ней так же видно, что увеличение кол-ва разрядов в четыре раза не приводит к уменьшению времени свечения одной позиции.


Все схемы нарисованы условно и не годятся для реального применения без надлежащего согласования, как-то резисторы, транзисторы и т.п.

Тут лежат файлы обоих проектов для IAR и схемы для Proteus. Так же в архиве лежат анимированные gif файлы, в которых покадрово показан порядок зажигания каждого разряда. На самом сайте почему-то анимация не работает:(
Добавил gifки на свой сайт

  • +4
  • 14 мая 2011, 21:55
  • PRC

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

RSS свернуть / развернуть
blindage.org/?p=2824
вот еще хорошее дополнение. тут описан алгоритм вывода цифр (типа знакогенерация). догнать до знаковых и дробных чисел думаю не проблема.
0
  • avatar
  • 21h
  • 14 мая 2011, 23:13
Какой дружественный сайт, ничего не показывает:) — вот
0
ну сделай что он просит. надо же как-то хостинг дружественных сайтов оплачивать. тем более то там всего 2 малюсеньких баннера от гугла.
-1
А мою баннерорезку он не спалил почему-то.
0
AdBlock?
0
Он самый.
0
тю. у меня тоже адблок и увидел его.
0
Ты не просишь, ты требуешь. К посетителям можно было и повежливее обратиться, особенно учитывая, что это люди одних с тобой интересов, возможно коллеги, на чьих сайтах ты сам бываешь и видишь более приветливый приём.
+4
раскрыть комментарий
-5
В знак уважения, я ухожу с сайта по рекламе, если информация на сайте мне понравилась. Резалка банеров стоит только потому, что мегабайт трафика стоит 1,64€ — тратить эти деньги на просмотр баннеров как-то не улыбается, а ещё ждать, пока подгрузится баннер воткнутый до контента, на мобильном соединении не самый лучший вариант.
Но если ты рассматриваешь «трафик» как людей приносящих тебе доход, тем более странно с ними так разговаривать — они тебе доход, а ты им хамство.
0
1.64 евры за мегабайт это около 60 рублей. мягко сказать это враньё или ты на северном полюсе живешь, где инет только через спутниковую приемопередающую тарелку. да и то сомневаюсь, что там инет будет так стоить.
-1
не не. у вас интернет на северный полюс доставляется оленями-девственниками на платиновых табличках.
-3
Сомнительный способ раскрутить сайт. Сотни других похожих сайтов как то без принудительной рекламы обходятся.
0
он в раскрутке не нуждается и в 2 раза старше самого easyelectronics. мой сайт — что хочу, то и делаю.
-4
что то твой «раскрученный» «в два раза старший» сайт впервые вижу. в запросах в гугле по МК и програмированию что то он не встречался.
0
И как успехи? Много дает с рекламы?
0
доход вырос в 2 раза примерно через месяц после введения таких правил. теперь хватает на оплату хостинга. до оплаты домена еще далеко.
-1
да, вместо 100 рублей — получаешь двести? уж на хостинг и домен всегда можно найти деньги, даже для заведомо убыточных проектов. копейки же.
если с сайта нельзя получить больше тысячи-двух в месяц, то не стоит даже ставить рекламу, а тем более так агрессивно. самый прикол в том, что AdBlock режет рекламу, не отвлекаясь на всякие банеры с надписями о запрете))))
0
А кто отвлекается?)
0
ну, вот у PRC например
0
Что это за баннерорезка, что кто-то может запретить ей резать?)
0
Хм. У меня через два месяца после запуска сайт стал окупать домен и хостинг. А спустя пол года с него уже можно было худо бедно жить.
0
пенсионер. раз старше — надо слушаться. *пошел ставить на свои сайты*
0
идиотизм.
+1
ещё раньше динамика использовалась потому, что в статике сегменты выгорали быстро )
0
Это вроде только у ЖК есть — деградация сегментов при управление высоким напряжением. Поэтому и используют противофазное. Или со светодиодными тоже такая фигня была?
0
сейчас это наверное не актуально, но в благославенные девяностые это было аргументом для отечественных индикаторов.
0
Тогда уже и разряды на 595 завести и будет счастье — динамическая индикация по 3-м проводам.Правда с уменьшением общего количества знакомест аж на 8.
0
  • avatar
  • Zov
  • 16 мая 2011, 11:16
А для современных 7-сегментных индикаторов нужно ставить по резистору у каждого катода/анода или у них внутреннее сопротивление свое нормальное?
0
Нужно. Или использовать правильные драйверы светодиодов.
0
Широко потребляемые 7-сегментники идут без встроенных ограничительных резисторов. Поэтому рекомендуется поставить.
0
А со встроенным сопротивлением они существуют?
0
Именно 7-семисегментники не знаю (возможно) но отдельные светодиоды(модули) есть.Светодиоды со встроенным резистором
0
Я не встречал. Да и вряд ли их делать будут. Контролеры ведь на разных напряжениях работают, им и резисторы разные нужны.
0
Это как раз не проблема. Есть драйверы, есть current-limiting diodes. Но бывают ли индикаторы с чем-то из этого встроенным — хз.
0
С драйверами резисторов не нужно:)
0
Спасибо автору за идею!
Модифицировал пример под любые порты сегментов, на случай того когда ножки сегментов подключены к разным портам микроконтроллера, как у меня.
Выкладываю фотки, и модифицированный исходник, вдруг кому то пригодится.
Токоограничивающие резисторы в цепи сегментов 100 ом, яркость индикатора лучше чем на фотке.
Методику расчета резисторов не знаю, поэтому взято на угад, думаю номинал резисторов можно уменьшить(например до 10 ом) и ничего не сгорит.




#define   F_CPU 1000000UL
#define   ENABLE_BIT_DEFINITIONS
#include <avr/io.h>  //подключаем библиотеку ввода вывода
#include <avr/interrupt.h>  //подключаем библеотеку прерываний


#define   u8   unsigned char

#define   A_PORT  PORTD
#define   B_PORT  PORTC
#define   C_PORT  PORTC
#define   D_PORT  PORTD
#define   E_PORT  PORTD
#define   F_PORT  PORTC
#define   G_PORT  PORTC
#define   DP_PORT  PORTC

#define A_SEG  5
#define B_SEG  3
#define C_SEG  1
#define D_SEG  7
#define E_SEG  6
#define F_SEG  4
#define G_SEG  2
#define DP_SEG  0


#define	  OutPort   PORTD //порт к которому подключена 74HC595
#define	  ST_CP	    3
#define	  SH_CP	    4
#define	  DS	    2
volatile u8 buffer[8];
//   dec         63           6        91           78          102     109            125         
//   bin     00111111     00000110
//   seg     DPGFEDCBA    DPGFEDCBA 
//отображ. цифра  "0"      "1" 
//u8  digit[] = {1+2+4+8+16+32,2+4,1+2+8+16+64,1+2+4+8+64,2+4+32+64,1+4+8+32+64,1+4+8+16+32+64,1+2+4,1+2+4+8+16+32+64,1+2+4+8+32+64};
	
//Индикатор с общим катодом, для общего анода ввести в программе инверсию.	
//               0    1    2    3    4    5    6    7    8    9 
u8  digit[] = {0xd7,0x50,0x67,0x75,0xf0,0xb5,0xb7,0x51,0xf7,0xf5};	
	
	
//***************************************************************************
void SaveBit0 (void)
{
  // Запись в регистр 0
  OutPort |=1<<DS;     //устанавливаем в единицу DS бит переменной OUTport
  OutPort |=1<<SH_CP;
  asm("nop");
  asm("nop");
  OutPort &=~(1<<SH_CP); //обнуляем бит SH_CP
}
void SaveBit1 (void)
{
  // Запись в регистр 1
  OutPort &=~(1<<DS);
  OutPort |=1<<SH_CP;     
  asm("nop");asm("nop");
  OutPort &=~(1<<SH_CP);
}
void SaveOut (void)
{
  // Запись регистров в защелку
  OutPort |=1<<ST_CP;
  asm("nop");
  asm("nop");
  OutPort &=~(1<<ST_CP);
}
//***************************************************************************
// Timer 1, F=65*8=520Hz
ISR(TIMER1_COMPA_vect)
{
  // Начало вывода с сегмента 1
  static u8 seg=64;//0b10000000;
  u8 i;
  // Гашение сегментов
  //SegPort=0;
  
  
  A_PORT &= ~(1<<A_SEG);// записываем нуль в нужный бит
B_PORT &= ~(1<<B_SEG);// записываем нуль в нужный бит
C_PORT &= ~(1<<C_SEG);// записываем нуль в нужный бит
D_PORT &= ~(1<<D_SEG);// записываем нуль в нужный бит
E_PORT &= ~(1<<E_SEG);// записываем нуль в нужный бит
F_PORT &= ~(1<<F_SEG);// записываем нуль в нужный бит
G_PORT &= ~(1<<G_SEG);// записываем нуль в нужный бит
DP_PORT &= ~(1<<DP_SEG);// записываем нуль в нужный бит
  
  // Перебор всех элементов в буфере
  // Т.к. первый элемент буфера соответствует младщему разряду регистра (L1),
  // то перебор начинаем с конца буфера.
  for(i=7;i!=0xFF;i--)
  {
    // Если сегмент есть в символе, то выводим
    //if(buffer[i]simvol[j] & seg) SaveBit1();
	   if(buffer[i] & seg) SaveBit1();
   
	else SaveBit0();
  }
  // Запись регистров
  SaveOut();
  //Проверяем установлен ли бит в переменной, обнуляем все биты кроме проверочного, а потом сравниваем полученное значение с нулем

  
  if ((seg & (1<<0)) != 0) {A_PORT |= (1<<A_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<1)) != 0) {E_PORT |= (1<<E_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<2)) != 0) {D_PORT |= (1<<D_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<3)) != 0) {DP_PORT |= (1<<DP_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<4)) != 0) {C_PORT |= (1<<C_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<5)) != 0) {G_PORT |= (1<<G_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<6)) != 0) {B_PORT |= (1<<B_SEG);} ;// записываем 1 в нужный бит;}
  if ((seg & (1<<7)) != 0) {F_PORT |= (1<<F_SEG);} ;// записываем 1 в нужный бит;}
  
 
  // Переход к следующему сегменту
  seg=seg<<1;
  if(!seg) seg=1;
}
//***************************************************************************
void main(void)
{
DDRD=0b11111100 ;//	
  DDRC=0xFF;
//DDRC=0b00011111 ;//	
	
  // Timer 1
 //16000/1024=15625/32=488,28гц;488/8=61гц на сегмент
 //32=0x20h ; задаем делитель
  OCR1AH=0x00; ;
  OCR1AL=0x20; ;
  TCCR1B=1<<WGM12 | 1<<CS12|1<<CS10;// CTC mode; f/1024; 
  TIMSK=1<<TOIE2 | 1<<OCIE1A; //разрешение прерывание по переполнению
  
  // Заполним буфер
  u8 i,j=0;
  for(i=0;i<8;i++)
  {
   buffer[i]=digit[j];
    j++;if(j==8) j=0;
  }
  sei(); //разрешаем прерывания
  // Цикл
  while(1);
}
0
Пример написан в AVR Studio 5
0
Это у тебя Белорусский виртуальный осциллограф?
0
  • avatar
  • gadz
  • 07 декабря 2012, 23:34
А по ссылке narod.ru/disk/12891821001/Dinamic.rar.html ничего нет! Выложите еще пожалуйста!
0
По ссылке «файл удален пользователем»
Просьба перезалить заново.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.