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

warning: Creating default object from empty value in /var/www/fendercustomsh/data/www/avrlab.com/modules/taxonomy/taxonomy.pages.inc on line 34.

Семисегментный индикатор и динамическая индикация на AVR микроконтроллере ATmega8

В разных конструкциях бывает оправдано использовать семисегментные светодиодные индикаторы, дешево и сердито по сравнению с символьными ЖКИ. Светодиодный индикатор представляет собой восемь светодиодов (7 для представления цифры и 1 для точки) расположенные в виде слегка наклоненной цифры:
В разных конструкциях бывает оправдано использовать семисегментные светодиодные индикаторы, дешево и сердито по сравнению с символьными ЖКИ. Светодиодный индикатор представляет собой восемь светодиодов (7 для представления цифры и 1 для точки) расположенные в виде слегка наклоненной цифры:
семисегментный светодиодный индикатор
Светодиоды внутри имеют общий анод (ОА) или общий катод (ОК). То есть, для управления одной цифрой нужно 8 выводов микроконтроллера. А что же делать, когда нужно управлять, например, четырьмя цифрами? Использовать микроконтроллер с 4*8=32 выводами? Не экономично.

Для такого случая придумали динамическую индикацию. Для этого соединяем выводы, которые отвечают за включение сегментов в общую шину, а общими анодами (катодами) будем управлять через транзисторы. В отдельный момент времени горит только одна цифра. Таким образом быстро перебирая цифры на дисплее (как кадры в фильме) мы получим эффект постоянно горящего изображения. В замедленном варианте, как это происходит, можно посмотреть на картинке:
анимация динамической индикации
А вот ускоренная в 25 раз картинка, уже начинают вырисовываться контуры «12.34»:
анимация динамической индикации
Используя принцип динамической индикации мы сможем управлять четырьмя цифрами при помощи 8+4=12 выводов. Использование же 2-х сдвиговых регистров HC595 может сократить это число до 4. Рассмотрим схему подключения к микроконтроллеру:

Управлять же индикатором будем с помощью микроконтроллера ATmega8. Резисторы R5-R13 – ограничительные на 470 Ом. R1-R4 – по 1кОм. Транзисторы Q1-Q4 – любые PNP типа, я использовал BC807 в планарном исполнении. Конденсаторы С5,С7 – электролиты по 100 и 200мкф соответственно, С4,С6 – керамика по 0,1мкф. Так как индикатор с общим анодом, то соответственно включение разряда/сегмента производиться низким уровнем.

Для индикаторов с общим катодом схема аналогична, только транзисторы следует взять NPN структуры, и управляться индикатор будет высоким уровнем.
Продемонстрируем сказанное, напишем программу, которая будет перебирать числа от 0 до 9999 и выводить их на семисегментный индикатор.

  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3. // 0 1 2 3 4 5 6 7 8 9
  4. const unsigned char codes[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  5.  
  6. unsigned char data[4]={0x00,0x00,0x00,0x00};
  7. unsigned char counter=0;
  8.  
  9. void pause (unsigned int a)
  10. { unsigned int i; for (i=a;i>0;i--); }
  11.  
  12. void init_timer (void)
  13. { TIMSK=(1<<TOIE0); //Enable timer overflow interrupt
  14. TCCR0=(0<<CS00)|(1<<CS01)|(0<<CS02); //Prescaller = /1
  15. }
  16.  
  17. void convert_data (unsigned int x)
  18. {unsigned int temp,res;
  19. temp=x;
  20. res=temp/1000; //Calculate 1000-s
  21. data[3]=codes[res];
  22. temp=temp-res*1000;
  23.  
  24. res=temp/100; //Calculate 100-s
  25. data[2]=codes[res];
  26. temp=temp-res*100;
  27.  
  28. res=temp/10; //Calculaate 10-s
  29. data[1]=codes[res];
  30. temp=temp-res*10;
  31.  
  32. data[0]=codes[temp]; //Calculate 1-s
  33. }
  34.  
  35. ISR (TIMER0_OVF_vect)
  36. {PORTD=0xff;
  37. PORTB=~_BV(counter); //Enable digit
  38. PORTD=~data[counter]; //Write code
  39. counter=(counter+1)%4; //Increment digit counter
  40.  
  41. TCNT0=0x00; //Clear timer
  42. }
  43.  
  44. int main(void)
  45. { unsigned int x=0;
  46. DDRD=0xff;
  47. PORTD=0x00;
  48. DDRB=0x0f;
  49. PORTB=0x0f;
  50.  
  51. pause(1000); //Settle pause
  52. init_timer(); //Init timer
  53. sei(); //Interrupt enable
  54. while(1)
  55. {convert_data(x); //Conver data to codes
  56. if (x<9999) x=x+1; //Increment data
  57. else x=0;
  58. pause(30000);
  59. }
  60. return 1;
  61. }

Код очень простой. В массиве codes находятся коды, которые следует выводить на порт, чтобы получить желаемую цифру. Смена активной цифры производиться по прерыванию от переполнения таймера 0. А функция convert_data(int x) раскладывает число х по разрядам, и записывает соответствующие коды в массив data, данные из которого выводятся непосредственно на индикатор, при срабатывание прерывания.
Что из этого вышло, можно глянуть на рисунках:
фото динамической индикации
фото динамической индикации

Исходный код можно скачать в виде проекта под AVR Studio 4
Также, может кому пригодиться, платка для моего табло в формате .lay для программы Sprint Layout 5

RSS-материал