РадиоКот >Обучалка >Микроконтроллеры и ПЛИС >Микроконтроллеры AVR - пишем, компилируем, прошиваем... >

Теги статьи: Динамическая индикация

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

Автор: Владимир
Опубликовано 25.05.2006

Итак, девочки и мальчики, сегодня дядя Сережа расскажет о том, как соорудить динамическую индикацию в домашних условиях, че это ваще такое, и зачем оно нам.

Не вдаваясь в нудные предисловия скажем так:

Динамическая индикация – это метод отображения целостной картины через быстрое последовательное отображение отдельных элементов этой картины. Причем, «целостность» восприятия получается благодаря инерционности человеческого зрения.

На этом принципе, как вы догадываетесь, построено кино и телевидение. Не слишком занудно?

Поконкретнее.

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

Кстати, индикаторы выглядят примерно вот так:

7-сегментные индикаторы

Уделим пару слов увиденному.

Перед нами – самый обычный светодиодный 7-сегментный индикатор. Вопрос: почему 7-сегментный, когда сегментов на самом деле – восемь? Ответ: потому что 8-й сегмент – это точка, которая не входит в изображение цифры и вообще, является необязательной. Бывают индикаторы и без точек.

Для нумерации сегментов используются латинские буквы от a до h . У всех всех всех 7-сегментных индикаторов в нашем бренном мире, сегменты нумеруются в том порядке, как это показано на рисунке, и никак иначе.

Теперь смотрим на схемы. Во-первых, почему их две? Да потому что индикаторы бывают разные. Бывают – с общим катодом (ОК), бывают – с общим анодом (ОА). Среди буржуйских более распространены, как ни странно, индикаторы с ОА. Но встречаются и с ОК. Так что – нужно быть осторожным, чтоб не спутать. Хотя, нам-то все равно. Нашими индикаторами будет управлять контроллер. А его можно запрограммировать как на работу с ОК так и с ОА. Тут сложностей нет.

У каждого индикатора – 9 ножек. С 1 по 8 – выводы сегментов, 9-я – общий. Допустим, мы хотим отображать 4-разрядное число. Надо 4 индикатора.

Арифметика маленького Пети: 8*4 = 32. То есть, нам потребуется 32 провода (не считая общие) Неслабо? Ничуть. Тем более, учитывая, что у большинства контроллеров количество каналов ввода/вывода как раз равно 32. Как-то меня не очень греет перспектива угрохать все выводы контроллера на индикацию. А вас? Ведь надо ж еще куда-то подключить кнопочки, ручечки, датчички и пр. пр. пр. а мало ли чего? Кстати, у любимого нами AT 90 s 2313 всего 15 каналов ввода/вывода. Как здесь прикажете быть? Вот тут нам и поможет динамическая индикация. Делаем очень просто: подключаем все индикаторы параллельно. Точнее, сажаем выводы сегментов на общую шину. А общие провода оставляем раздельно.

Смотрим небольшой поясняющий мультик:

Мультик :)

Че мы делаем?

Мы последовательно подаем напряжение на адресные входы индикаторов, и одновременно выдаем в шину данных 7-сегментный код, соответствующий индикатору, активному в данный момент.

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

Итак, я хочу, чтобы значения цифр, выводимых на индикацию, лежали в ячейках памяти. Поскольку у индикатора 4 разряда – значит цифр тоже будет 4, и соответственно, столько же ячеек памяти. Дабы не заморачиваться, мы объединяем все четыре ячейки в переменную Digit . Итак, пишем:


.include "d:avravrasmappnotes2313def.inc"


	.def	Temp1=R16
	.def	Temp2=R17
	.def	Temp3=R18
	.def	Temp4=R19
	.def	Temp=R20

.dseg

Digit:     .byte 4

Написали.
Теперь самое время определиться с портами.

Поскольку у нас на порт B уже повешены светодиоды – наверно не будет большим криминалом повесить туда еще и сегменты индикаторов.

Порт D пока что пустует – ну дык значит посадим туда общие провода. Рисуем схему:

Схема подключения индикаторов

Схему прошивки, как и договаривались, не показываем, но подразумеваем ее наличие.

В данной схеме используется два сдвоенных индикатора C562. Эти индикаторы – с общим катодом (об этом говорит буква C в названии). Будем иметь это ввиду при написании программы.

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

Резисторы в шине данных взяты меньшего номинала, чем были. Зачем? Чтоб ярче светили светодиоды. Поскольку индикация динамическая, то каждый индикатор работает только 1/4 общего времени работы схемы. Глаз это воспринимает как пропорциональное уменьшение яркости свечения (т.е. – тоже в 4 раза.). Чтобы как-то компенсировать этот недостаток, на светодиоды подается завышенный ток (больше максимально допустимого). В статическом режиме этот ток может причинить светодиодам вред. Однако в динамическом режиме, кратковременные воздействия тока не столь фатальны.

Ну вот, вроде все. Теперь пишем программулину дальше.


.cseg
.org 0

              rjmp RESET    ; Reset Handler
              rjmp EXT_INT0 ; IRQ0 Handler
              rjmp EXT_INT1 ; IRQ1 Handler
              rjmp TIM_CAPT1 ; Timer1 Capture Handler
              rjmp TIM_COMP1 ; Timer1 Compare Handler
              rjmp TIM_OVF1 ; Timer1 Overflow Handler
              rjmp TIM_OVF0 ; Timer0 Overflow Handler
              rjmp UART_RXC ; UART RX Complete Handler
              rjmp UART_DRE ; UDR Empty Handler
              rjmp UART_TXC ; UART TX Complete Handler
              rjmp ANA_COMP ; Analog Comparator Handler



EXT_INT0  :	ret
EXT_INT1  :	ret
TIM_CAPT1 :	ret
TIM_OVF0  :	ret
TIM_OVF1  :   ret
UART_RXC  :   ret
UART_DRE  :   ret
UART_TXC  :   ret
ANA_COMP  :   ret
TIM_COMP1 :   ret



reset:        ldi Temp1,RamEnd	;инициализация стека
              out SPL,Temp1

              cli

              ldi Temp,0b11111111 ;настройка портов
              out ddrb,Temp

              ldi Temp,0b00001111
              out ddrd,Temp

              ldi Temp,4
              sts Digit  ,Temp      ;загрузка начальных сначений
              ldi Temp,3
              sts Digit+1,Temp
              ldi Temp,2
              sts Digit+2,Temp
              ldi Temp,1
              sts Digit+3,Temp


;*********************************************************
;MAIN
;*********************************************************

IndicCycle:   rcall Display        ;цикл индикации
              rjmp IndicCycle

;*********************************************************
Display:
;последовательный вывод на индикацию содержимого
;переменной Digit

              lds Temp1,Digit      ;загружаем 0-ю ячейку
              ldi Temp,0b00001110  ;активируем 0-й разряд
                                   ;индикации
              out PortD,Temp
              rcall Decoder        ;вызываем 7-сегм. декодер
              out PortB,Temp1      ;выводим значение в порт
              rcall Delay1         ;ждем

              lds Temp1,Digit+1    ;и .т.д
              ldi Temp,0b00001101
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              rcall Delay1

              lds Temp1,Digit+2
              ldi Temp,0b00001011
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              rcall Delay1

              lds Temp1,Digit+3
              ldi Temp,0b00000111
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              rcall Delay1

              ret


;*********************************************************
Decoder:
;преобразование двоичного числа
;в код 7-сегментного индикатора

              ldi ZL,Low(DcMatrix*2)   ;инициализация массива
              ldi ZH,High(DcMatrix*2)

              ldi Temp2,0             ;прибавление переменной
              add ZL,Temp1            ;к 0-му адресу массива
              adc ZH,Temp2

              lpm                     ;загрузка значения
              mov Temp1,r0
              ret

DcMatrix:
;массив - таблица истинности декодера
              ;     hgfedcba   hgfedcba
              .db 0b00111111,0b00000110	;0,1
              .db 0b01011011,0b01001111	;2,3
              .db 0b01100110,0b01101101	;4,5
              .db 0b01111101,0b00000111	;6,7
              .db 0b01111111,0b01101111	;8,9

;*********************************************************
Delay1:
;цикл задержки

              push Temp1
              push Temp2


              ldi Temp1,0
              ldi Temp2,50

d11:          dec Temp1
              brne d11
              dec Temp2
              brne d11

              pop Temp2
              pop Temp1

              ret

Очень внимательно читаем программу.

Сначала мы настраиваем прерывания, порты и стек. Это стандартно.
Затем, мы записываем в переменную Digit число 1234.
Потом мы выходим в главный цикл программы. из этого цикла вызывается функция Display , которая, собственно, и занимается динамическим выведением на индикацию числа из переменной Digit . Функция состоит из 4-х похожих кусков. Эти куски различаются лишь номером вызываемой ячейки Digit и разрядом текущего индикатора.
Из каждого кусочка вызывается функция Decoder – 7-сегментный декодер. Этот декодер преобразует значение из ячейки Digit в код 7-сегментного индикатора, и передает этот код обратно функции Display , которая выводит его на индикацию.

Вот так, в общих чертах, все просто и понятно.

Далее мы сделаем из этого дела секундомер.

<<--Вспомним пройденное----Поехали дальше-->>




Эти статьи вам тоже могут пригодиться:

О среднем токе замолвите слово (к вопросу о динамической индикации).

Динамическая индикация 9 разрядного индикатора по последовательной шине.