Как подключить люминесцентный индикатор к микросхеме к176ие4. Цифровой индикатор на К176ИЕ4. Назначение выводов К176ИЕ4

Программирование работы многоразрядного семисегментного индикатора



Алгоритм работы программы

Во второй части статьи о мы рассмотрели вопросы . Сегодня мы узнаем как подключить к микроконтроллеру многоразрядный семисегментный индикатор , организовать динамическую индикацию и напишем программу для вывода информации на многоразрядный индикатор

Подключение многоразрядного семисегментного индикатора

Давайте еще раз посмотрим схему подключения многоразрядного семисегментного индикатора к микроконтроллеру:

На этой схеме выводы порта РВ (РВ0 — РВ7) микроконтроллера через токоограничительные резисторы подключены к соответствующим сегментам (a-g) многоразрядного семисегментного индикатора. Соответствующие сегменты всех разрядов индикатора соединены параллельно. Катоды (аноды) каждого разряда индикатора подключены через транзисторы к выводам порта PD.

Организация динамической индикации

Работа многоразрядного индикатора осуществляется следующим образом:

1. На управляющий транзистор первого разряда индикатора (7Seg1), с вывода порта микроконтроллера PD0 подается логическая единица, которая открывает транзистор, в результате чего подается напряжение питания на данный разряд индикатора. На базах остальных транзисторов — логический ноль, транзисторы закрыты.
2. На выводах порта РВ0-РВ7 выставляется двоичный код соответствующей десятичной цифры — высвечивается нужная цифра в первом разряде.
3. На управляющий транзистор второго разряда (7Seg2) с вывода порта PD1 подается логическая единица (на остальные транзисторы — логический ноль) — подается питание на второй разряд индикатора.
4. На выводах порта РВ0-РВ7 выставляется двоичный код следующей (второй) десятичной цифры — высвечивается нужная цифра во втором разряде.
5. На управляющий транзистор третьего разряда (7Seg3) с вывода порта PD2 подается логическая единица (на остальные транзисторы — логический ноль) — подается питание на третий разряд индикатора.
6. На выводах порта РВ0-РВ7 выставляется двоичный код следующей (третьей) десятичной цифры — высвечивается нужная цифра во втором разряде.
7. И так, по кругу

Такая работа многоразрядного семисегментного индикатора называется —динамическая индикация .
Частота переключения разрядов должна быть в пределах 100 герц, тогда не будет заметно мерцание разрядов.

Для переключения разрядов можно задействовать (на примере микроконтроллера ATtiny2313) таймер «TIMER 0 «.
Настройка таймера производится следующим образом (при тактовой частоте 1 мГц — заводская установка):
— предделитель таймера устанавливаем в СК/8
— вызов прерывания по переполнению счетчика таймера

Вот так настройка таймера выглядит в программе:
Где:
— SP — настройка стека
— Timer 0 — настройка параметров таймера
— TIMSK — настройка прерывания

Алгоритм работы программы

Рассмотрим алгоритм программы для осуществления динамической индикации и вывода данных в многоразрядный семисегментный индикатор:

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

Ну а теперь — самое легкое. Напишем программу вывода данных на многоразрядный семисегментный индикатор с динамической индикацией.

Программа индикации на многоразрядном семисегментном индикаторе

Как я уже писал в другой статье — , и чем продуманнее он будет написан, тем легче будет писать программу.

Назначение переменных:

Давайте посмотрим какие переменные для работы подпрограммы вывода данных на индикатор назначил я:

Data0, Data1 и Data2 — переменные, в которые основная программа записывает вычисленное значение (трехзначное)
Data — переменная, в которой записан адрес первой переменной данных — Data0
@Data — эта запись означает, что в переменной Data будет храниться адрес первой переменной данных — Data0
DataIndex — эта переменная хранит текущий номер переменной данных, которая выводилась на индикацию последней (0, 1 или 2, соответственно для Data0, Data1 или Data2)
PortDigits — эта переменная хранит данные о том, какой разряд индикатора зажигался последним

Настройка стека:

Стек настраивается в самом начале основной программы, мы его рассматривать не будем, так как к нашей подпрограмме он не относится

Настройка восьмиразрядного таймера Taimer0:

Taimer0 в подпрограмме используется как средство обеспечивающее динамическую индикацию разрядов индикатора

Настроенный таймер через определенные промежутки времени вызывает прерывание, в результате чего происходит остановка основной программы и осуществляется переход в подпрограмму обработки прерывания. В нашем случае — вызывается подпрограмма вывода данных на индикатор.
Как настраивается таймер: Частота переключения разрядов должна быть в пределах 100 Гц для предотвращения мерцания индикаторов при их поочередном зажигании (дело это в принципе индивидуальное, и зависит от особенностей вашего зрения).
Тактовая частота микроконтроллера — 1 мГц, или 1 000 000 Гц
Устанавливаем внутренний делитель частоты таймера в СК/8 — рабочая частота таймера будет в 8 раз меньше тактовой частоты микроконтроллера
Получаем: 1000 000/8 = 125 000 Гц, или 125 кГц — тактовая частота таймера
Настраиваем вызов прерывания по переполнению счетчика таймера (счетчик таймера восьмиразрядный и считает до 255, после этого сбрасывается в ноль и вызывается прерывание)
Получаем: 125 000/255 = 490 Гц (что соответствует времени приблизительно в 2 миллисекунды)
Мы поочередно зажигаем три разряда:
Получаем: 490/3 = 163 Гц — разряды индикатора будут переключаться с частотой 163 Гц.
Настройка таймера производится соответствующей настройкой соответствующих регистров таймера.
Давайте посмотрим как это происходит в Algorithm Builder:

Инициализация индикатора

Инициализация индикатора — эта фраза подразумевает настройку разрядов портов, к которым подключены выводы индикатора на вывод, а также обнуление переменных данных Data0…2 и запись первоначальных данных в остальные переменные. Процесс инициализации индикатора прописывается в начале основной программы.
Назовем подпрограмму инициализации Ini_Indikator2/
Давайте посмотрим этот процесс на примере:


В первой строке разряды порта РВ с 0 по 6 (к которым подключены семь сегментов индикатора) настраиваются на вывод информации (десятичную точку индикатора не используем).
Во второй строке разряды порта PD с 0 по 2 (к которым подключены управляющие транзисторы) также настраиваются на вывод.
Третьей строкой на выходах порта РВ устанавливается логический ноль — сегменты индикатора погашены для индикаторов с общим катодом).
Четвертая строка — обнуляем переменную DataIndex
Пятая строка — в переменную PortDigits записываем единицу
Следующие три строки — обнуляем переменные данных

Теперь нам необходимо куда-то записать которые будут подаваться на разряды порта PB для высвечивания соответствующей цифры на индикаторе.
В статье по программированию работы одноразрядного семисегментного индикатора, мы эти коды записывали программным путем в ОЗУ микроконтроллера. Сейчас мы сделаем по-другому — запишем двоичные коды в теле самой программы.
Для этого создадим таблицу двоичных кодов и присвоим ей имя, к примеру D0_9:

В этой таблице размещены двоичные коды (хотя и записаны в шестнадцатиричной системе) цифр от 0 до 9.

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

Подпрограмма вывода данных на многоразрядный семисегментный индикатор

Присвоим подпрограмме имя, к примеру Indikator2 , посмотрим на нее и разберем построчно:


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

В переменной DataIndex храниться номер ячейки памяти (0, 1 или 2) с данными (Data0, Data1 или Data2) которые необходимо вывести на разряд индикатора в текущий момент. Первоначально мы записали в нее ноль.
Первой строкой мы записываем содержимое DataIndex в регистр R20 , теперь в нем соответственно то-же ноль.
Во второй строчке мы увеличиваем содержимое регистра R20 на единицу (r20++) , теперь в R20 записана единица, означающая, что данные мы будем брать из переменной Data1. При втором прерывании R20 увеличится еще на единицу, станет равным 2, и соответственно следующие данные мы будем брать из переменной Data2. При следующем прерывании R20 станет равным 3.
Следующей строчкой (r20<3) мы проверяем какая цифра записана в регистре R20 — если меньше трех (0,1 или 2), то переходим по стрелке, а если равно трем, то обнуляем регистр R20 и данные теперь берем из переменной Data0.
Далее записываем содержимое R20 в переменную DataIndex .
Следующей командой @Data -> Y записываем адрес переменной Data0 в двойной регистр Y (R28, R29).
Затем складываем содержимое двойного регистра Y с содержимым R20 (0,1 или 2).
Командой [Y] -> r21 записываем содержимое переменной данных (или Data0, или Data1, или Data2 — в зависимости от значения r20) в рабочий регистр R21. Теперь в регистре R21 записана цифра из соответствующей переменной данных (к примеру цифра 5).
Следующей командой @D0_9*2 -> Z мы загружаем начальный адрес таблицы с двоичными кодами в двойной регистр Z (R30, R31). По начальному адресу у нас находится двоичный код для цифры 0.
Теперь мы складываем содержимое Z с R21 (с пятеркой) и получаем в регистре Z адрес в таблице двоичного кода с цифрой 5.
Следующей командой LPM[Z] -> R21 мы записываем двоичный код цифры 5 в рабочий регистр R21.
Команду NOP — холостой ход , можно и не прописывать — она вставлена для разделения отдельных кусков программы для наглядности.
Следующей командой PortDidgit -> R20 мы загружаем в рабочий регистр R20 содержимое переменной PortDidgit, а в нее мы предварительно записали единицу. Теперь в R20 записана единица (#b 0000 0001).
Следующей командой <Следующей командой R20 -> PortD мы подаем напряжение на второй разряд индикатора. При следующем прерывании произойдет еще один сдвиг влево (#b 0000 0100) и будет подключен третий разряд индикатора.
С помощью команды R20.3=1 записанной в овале, мы проверяем — достигла ли логическая единица при сдвигах третьего разряда регистра, и если — да, то записываем в R20 единицу (начинается новый круг).
Командой R21 -> PortB мы выводим двоичный код соответствующей цифры на подключенный разряд индикатора.
Командой R20 -> PortDigits — мы сохраняем текущее значение в переменной (последний зажженный разряд индикатора).

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


Для отображения четырехразрядного числа необходимо завести одну общую переменную в которой будет лежать число которое хотим вывести (переменная W ), четыре переменные в которых будут храниться данные для каждого знака (N ) и еще четыре переменные для промежуточных преобразований (M ), чтобы не трогать главную переменную. Переменная должна соответствовать тому значению, которое будет в ней хранитс я. Так для переменной W достаточным будет тип integer , так как переменная такого типа способна хр анить значения от -32768 до +32767 (или word если не планируется использование отрицательных чисел). В переменных N будут лежать числа от 0 до 9 поэтому достаточным будет использование переменной типа byte
. А в переменных M будут находиться те же значения что и в переменной W , поэтому ставим тип integer .

Dim W As Integer
Dim N1 As Byte
Dim N2 As Byte
Dim N3 As Byte
Dim N4 As Byte
Dim M1 As Integer
Dim M2 As Integer
Dim M3 As Integer
Dim M4 As Integer


После объявления переменных настраиваем порты на выход которые будут использоваться для подключения индикатора:

DDRC = &B11111111
DDRD = &B11111111


DDRC =& B 00001111 и DDRD = & B 01111111 (четыре первых ноги порта С под аноды и шесть первых порта D под сегменты).

Затем присваиваем переменной W то значение, которое собираемся вывести на индикатор:

W = 1234

"Arial","sans-serif""> В основном цикле программы присваиваем переменным М значение переменной W , я делаю так:

M1 = W
M2 = M1
M3 = M1
M4 = M1


"Arial","sans-serif""> Это не паранойя)), это сделано с той целью, чтобы в во всех переменных М лежало одно и тоже число, так как во время операции присваивания легко может ворваться прерывание (если такое имеется и не отключено), в обработчике которого переменная W может измениться. И в случае если присваивание шло таким образом: М1= W , M 2= W , M 3= W , M 4= W в переменных М будут лежать разные значения что приведет к каше в показаниях.

После присвоения переменным значения начинаем работать с
каждой из них, преобразуя таким образом, чтобы в переменную N попало то значение, которое будет
отображаться на индикаторе: в переменной
N 1 должна оказаться «1», в N 2 – «2», в N 3 – «3», а в N 4 – «4».

M1 = M1 / 1000 " M1 = 1234/1000 = 1,234
N1 = Abs (m1) " N1 = Abs (1,234) = 1

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

Для присвоения двойки переменной N 2 операция будет немного сложнее:

M2= M2 Mod 1000 " M2 =1234 Mod 1000 = 234
M2 = M2 / 100 " M2 = 234 / 100 = 2,34
N2= Abs (m2) " N2 = Abs (2,34) = 2

"Arial","sans-serif""> Для начала функцией Mod мы возвращаем переменной первые три
цифры числа (остаток от деления на 1000), а дальше все как в первом случае.

С двумя последними разрядами практически тоже самое:

M3 = M3 Mod100
M3 = M3 / 10
N3 = Abs (m3)

M4 = M4 Mod 10
N4= Abs (m4)


Теперь в наших переменных лежат те значения, которые мы хотим отобразить, самое время микроконтроллеру подрыгать ногами и вывести эти значения на индикатор, для этого вызываем подпрограмму обработки индикации:

"Arial","sans-serif"">

Gosub Led

"Arial","sans-serif"">Процессор перепрыгнет на подпрограмму с меткой Led :

Led:

Portc = &B00001000

"Arial","sans-serif""> Здесь подаем высокий уровень на PORTC .3 , к этой ноге у нас подсоединен анод первого разряда. Затем выбираем, какие сегменты необходимо зажечь, чтобы отобразить значение первой переменной. Она у нас единица поэтому ноль будет на ногах Portd .1и Portd .2, что соответствует сегментам B и С индикатора.

Select Case N1









End Select
Waitms 5

"Arial","sans-serif""> После того как зажгли нужные сегменты ждем 5 мс и переходим к отображению следующих чисел:

Portc = &B00000100
Select Case N2
Case 0 : Portd = &B11000000
Case 1 : Portd = &B11111001
Case 2 : Portd = &B10100100
Case 3 : Portd = &B10110000
Case 4 : Portd = &B10011001
Case 5 : Portd = &B10010010
Case 6 : Portd = &B10000010
Case 7 : Portd = &B11111000
Case 8 : Portd = &B10000000
Case 9 : Portd = &B10010000
End Select

Waitms 5

Portc = &B00000010

Select Case N3
Case 0 : Portd = &B11000000
Case 1 : Portd = &B11111001
Case 2 : Portd = &B10100100
Case 3 : Portd = &B10110000
Case 4 : Portd = &B10011001
Case 5 : Portd = &B10010010
Case 6 : Portd = &B10000010
Case 7 : Portd = &B11111000
Case 8 : Portd = &B10000000
Case 9 : Portd = &B10010000
End Select

Waitms 5

Portc = &B00000001

Select Case N4
Case 0 : Portd = &B11000000
Case 1 : Portd = &B11111001
Case 2 : Portd = &B10100100
Case 3 : Portd = &B10110000
Case 4 : Portd = &B10011001
Case 5 : Portd = &B10010010
Case 6 : Portd = &B10000010
Case 7 : Portd = &B11111000
Case 8 : Portd = &B10000000
Case 9 : Portd = &B10010000
End Select

Waitms 5

"Arial","sans-serif""> После отображения информации на индикаторе необходимо возвратится в основной цикл программы, где нужно завершить цикл и обозначить конец программы.

"Arial","sans-serif"">Вот что получим в итоге:

"Arial","sans-serif"">

"Arial","sans-serif""> За счет маленькой задержки переключения не будут заметны человеческому глазу и мы увидим целое число 1234.

Скачать исходник и проект в протеусе можно ниже: "Arial","sans-serif"">

В одном из предыдущих уроков мы научились зажигать сегменты светодиодного индикатора. Хотя это можно сделать только с помощью Ардуино, мы использовали в нашем уроке дополнительный компонент — . Эта полезная микросхема сэкономила нам несколько ценных выводов микроконтроллера. Но один семисегментный индикатор почти бесполезен. Он ведь отображает всего одну цифру. А что если мы хотим вывести большое число, скажем, от 0 до 500? Нам потребуется целых три цифры, а значит и три индикатора. Как будем подключать их к контроллеру? Можем напрямую, но тогда мы займем 7*3 = 21 вывод! Это очень расточительно. К тому же, нужна будет уже другая плата, так как у Ардуино Уно просто не хватит цифровых выводов. Попробуем использовать сдвиговый регистр? Уже лучше. Теперь нам понадобится три регистра, объединенных в цепочку, а также три вывода Ардуино для управления ими. В общем то на этом можно бы было и остановить оптимизацию нашей схемы, но мы пойдем дальше. Обойдемся всего одним сдвиговым регистром!

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

Как известно, наше зрение обладает свойством инерции, или персистенции. Это способность глаза соединять быстро сменяющиеся изображения в одно. Таким образом, чтобы человек видел на индикаторе трехзначное число, вовсе необязательно зажигать все цифры разом. Достаточно в один момент времени включать только один отдельный индикатор. Переключение между соседними индикаторам должно происходить с большой частотой, чтобы получить эффект персистенции. Такой подход к выводу данных называется динамической индикацией. В действительности, многие символьные и матричные светодиодные и газоразрядные индикаторы работают именно по такому принципу. Попробуем и мы собрать схему динамической индикации для управления тремя семисегментными индикаторами.

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

В этом уроке мы используем три семисегментных индикатора с общим катодом. Нам также потребуется один сдвиговый регистр, подключенный одновременно ко всем индикаторам. Чтобы в каждый момент времени включать только один индикатор, используем три полевых транзистора, которые будут в нужный момент подключать катод к земле. Кстати, вместо трёх отдельных индикаторов лучше применять один трехцифровой индикатор. Суть схемы от этого не изменится, но проводов будет меньше! Принципиальная схема
Внешний вид макета
В качестве электронных ключей рекомендуем использовать транзисторы в корпусе TO92, например 2N7000. Для подключения каждого транзистора понадобится два резистора: на 100-150 Ом и на 2.2-10 кОм. Первый резистор призван защитить вывод контроллера от бросков тока, возникающих на затворе во время создания поля. Второй же резистор поможет быстро выключить ключ, когда мы подадим низкий уровень на соответствующий вывод контроллера (через него на землю сольется остаточный заряд затвора). На каждой линии от регистра к индикатору необходим токозадающий резистор 200-300 Ом, чтобы светодиоды в индикаторе не перегорели. Этот нюанс работы со светодиодами мы рассмотрели на . Тщательно собираем схему и переходим к программе. Программа для динамической индикации const byte digit_pins = {5,6,7}; const byte data_pin = 2; const byte sh_pin = 4; const byte st_pin = 3; unsigned long tm, next_flick; const unsigned int to_flick = 1; byte digit = 0; unsigned int counter = 125; const byte digits = { B11101110, B10000010, B11011100, B11010110, B10110010, B01110110, B01111110, B11000010, B11111110, B11110110 }; void fill(byte d){ for(char i=0; i<8; i++){ digitalWrite(sh_pin, LOW); digitalWrite(data_pin, digits[d] & (1< next_flick){ next_flick = tm + to_flick; digit++; if(digit == 3) digit = 0; setDigit(digit, counter); } } Часть этой программы, включая переменные data_pin , sh_pin , st_pin и функцию fill уже известны нам из . Массив digits хранит десять комбинаций сегментов для цифр от 0 до 9. Для экономии памяти мы храним каждую комбинацию в одном байте, а для лучшего понимания мы записали их в бинарном виде. Чтобы переключать индикаторы воспользуемся . Будем каждую миллисекунду заполнять регистр нужной комбинацией и включать соответствующий индикатор. Для этого мы используем функцию setDigit . Аргумент digit — это индекс включаемого в данный момент индикатора, а counter — трехзначное число, которые мы хотим высветить. Параметр to_flick отвечает за период переключения индикатора. Он равен 1, а значит смена цифр для отображения происходит каждую миллисекунду. Что если увеличить этот параметр? Скажем до 100мс, или даже до 500мс. Эффект инерции зрения пропадет и мы начнем замечать смену цифр. Программа счетчика с динамической индикацией В предыдущем примере переменная counter хранила число 125 по-умолчанию. Попробуем теперь добавить в программу счетчик секунд, чтобы counter увеличивался на единицу каждую секунду, вплоть до числа 999. const byte digit_pins = {5,6,7}; const byte data_pin = 2; const byte sh_pin = 4; const byte st_pin = 3; unsigned long tm, next_sec, next_flick; const unsigned int to_sec = 1000; const unsigned int to_flick = 1; unsigned int counter = 0; byte digit = 0; const byte digits = { B11101110, B10000010, B11011100, B11010110, B10110010, B01110110, B01111110, B11000010, B11111110, B11110110 }; void fill(byte d){ for(char i=0; i<8; i++){ digitalWrite(sh_pin, LOW); digitalWrite(data_pin, digits[d] & (1< next_sec){ next_sec = tm + to_sec; counter++; if(counter == 1000) counter = 0; } tm = millis(); if(tm > next_flick){ next_flick = tm + to_flick; digit++; if(digit == 3) digit = 0; setDigit(digit, counter); } } Загружаем программу на Ардуино и наблюдаем работу счетчика!

Задания

  1. Цифровой секундомер. Собрать схему с трехцифровым индикатором. Добавить в схему . При нажатии на кнопку, секундомер должен запускать отсчет. При повторном нажатии — останавливать. Дополнительно, к секундомеру можно добавить дробную часть, отображаемую на третьем индикаторе через точку.
  2. Цифровой вольтметр для напряжений от 0 до 10 Вольт. Собрать схему с трехцифровым индикатором. Добавить в схему делитель напряжения из двух резисторов на 10 кОм, подключенный к аналоговому входу Ардуино. Написать программу, которая будет каждые 100 мс считывать значение на аналоговом входе, переводить его в Вольты и выводить на индикатор. Для правильного отображения дробной части, необходимо подключить восьмой сегмент — точку.

Заключение

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

Иногда требуется подключить к микроконтроллеру несколько семисегментных индикаторов или светодиодную матрицу, при этом для отображения информации используется динамическая индикация. Суть динамической индикации заключается в поочередном выводе информации на индикаторы. Ниже на схеме представлен пример соединения нескольких семисегментных индикаторов (для примера с общим катодом) для реализации динамической индикации, вообще с учетом точки получается 8 сегментов, но по старинке их называют именно так. Все выводы (аноды) одноименных сегментов соединяют вместе, итого 8 линий которые через резисторы подключают к микроконтроллеру. Общий катод каждого индикатора подключают к микроконтроллеру через транзистор.


Алгоритм индикации следующий: сначала устанавливаем на линиях требуемые логические уровни в зависимости от того какие сегменты надо включить на первом индикаторе (индикация слево направо), при этом высокий логический уровень для включения, низкий для выключения сегмента. Далее подаем высокий логический уровень на базу транзистора VT1, тем самым общий катод первого индикатора подключается к общему проводу, в этот момент загораются те сегменты, на анодах которых присутствует логическая единица. Через определенное время (пауза) индикатор отключаем, подав низкий логический уровень на базу транзистора, затем снова меняем логические уровни на линиях в соответствии с выводимой информацией, предназначенной для второго индикатора, и подаем сигнал включения на транзистор VT2. Таким образом, по порядку в круговом цикле коммутируем все индикаторы, вот и вся динамическая индикация.

Для получения цельного изображения без мерцаний, переключение необходимо выполнять с большой скоростью, для исключения мерцания светодиодов частоту обновления необходимо устанавливать от 70 Гц и более, я обычно устанавливаю 100 Гц. Для вышерассмотренной конструкции пауза рассчитывается следующим образом: для частоты в 100 Гц период равен 10 мс, всего 4 индикатора, соответственно время свечения каждого индикатора устанавливаем на уровне 10/4=2,5 мс. Существуют многоразрядные семисегментные индикаторы в одном корпусе, в которых одноименные сегменты соединены внутри самого корпуса, естественно для их использования необходимо применять динамическую индикацию.

Для реализации динамической индикации необходимо воспользоваться прерываниями по переполнению одного из таймеров. Ниже представлен код с использованием таймера TMR0:

;Реализация динамической индикации для 4-х семисегментных индикаторов ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; swapf STATUS,W ; clrf STATUS ; movwf STATUS_TEMP ; ; bcf ind1 ;выключение 1-го индикатора bcf ind2 ;выключение 2-го индикатора bcf ind3 ;выключение 3-го индикатора bcf ind4 ;выключение 4-го индикатора; incf shet,F ;инкремент регистра shet movlw .5 ;проверка содержимого регистра shet xorwf shet,W ;на равенство числу 5 btfss STATUS,Z ; goto met1 ;число в регистре shet не равно 5 movlw .1 ;число в регистре shet равно 5: запись числа 1 movwf shet ;в регистр shet ; met1 movlw .1 ;проверка содержимого регистра shet xorwf shet,W ;на равенство числу 1 btfss STATUS,Z ; goto met2 ;число в регистре shet не равно 1: переход на met2 movf datind1,W ;число в регистре shet равно 1: копирование movwf PORTB ;содержимого регистра datind1 в регистр PORTB bsf ind1 ;включение 1-го индикатора met2 movlw .2 ;проверка содержимого регистра shet xorwf shet,W ;на равенство числу 2 btfss STATUS,Z ; goto met3 ;число в регистре shet не равно 2: переход на met3 movf datind2,W ;число в регистре shet равно 2: копирование movwf PORTB ;содержимого регистра datind2 в регистр PORTB bsf ind2 ;включение 2-го индикатора goto exxit ;переход на метку exxit met3 movlw .3 ;проверка содержимого регистра shet xorwf shet,W ;на равенство числу 3 btfss STATUS,Z ; goto met4 ;число в регистре shet не равно 3: переход на met4 movf datind3,W ;число в регистре shet равно 3: копирование movwf PORTB ;содержимого регистра datind3 в регистр PORTB bsf ind3 ;включение 3-го индикатора goto exxit ;переход на метку exxit met4 movf datind4,W ;копирование содержимого регистра datind3 movwf PORTB ;в регистр PORTB bsf ind4 ;включение 4-го индикатора; movlw .100 ;запись числа 156 в регистр таймера TMR0 movwf TMR0 ; ; movwf STATUS ; swapf W_TEMP,F ; swapf W_TEMP,W ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа ................. movlw b"11010011" ;OPTION_REG, тем самым устанавливаем внутренний ;устанавливаем коэффициент предделителя 1:16 ; clrf shet ;обнуление регистра shet, перед запуском;прерываний по переполнению TMR0, выполняется; clrf datind1 ;очистка регистров вывода информации на clrf datind2 ;индикаторы, равнозначно выключению clrf datind3 ;индикаторов, так как индикаторы с общим clrf datind4 ;катодом; bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0 bsf INTCON,T0IE ;разрешение прерываний по переполнению TMR0 bsf INTCON,GIE ;разрешение глобальных прерываний; movlw b"00000110" ;пример вывода числа 13,52 movwf datind1 ; movlw b"11001111" ; movwf datind2 ; movlw b"01101101" ; movwf datind3 ; movlw b"01011011" ; movwf datind4 ; ; ................. ; ................. ; ................. ; ; end ;конец всей программы;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Реализация динамической индикации для 4-х семисегментных индикаторов

;Частота тактового генератора для примера 4 МГц, машинный цикл 1 мкс

org 0000h ;начать выполнение программы с адреса 0000h

goto Start ;переход на метку Start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Подпрограмма обработки прерываний

org 0004h ;начать выполнение подпрограммы с адреса 0004h

movwf W_TEMP ;сохранение значений ключевых регистров

swapf STATUS,W ;

movwf STATUS_TEMP ;

bcf ind1 ;выключение 1-го индикатора

bcf ind2 ;выключение 2-го индикатора

bcf ind3 ;выключение 3-го индикатора

bcf ind4 ;выключение 4-го индикатора

incf shet,F ;инкремент регистра shet

movlw .5 ;проверка содержимого регистра shet

xorwf shet,W ;на равенство числу 5

btfss STATUS,Z ;

goto met1 ;число в регистре shet не равно 5

movlw .1 ;число в регистре shet равно 5: запись числа 1

movwf shet ;в регистр shet

met1 movlw .1 ;проверка содержимого регистра shet

xorwf shet,W ;на равенство числу 1

btfss STATUS,Z ;

goto met2 ;число в регистре shet не равно 1: переход на met2

movf datind1,W ;число в регистре shet равно 1: копирование

movwf PORTB ;содержимого регистра datind1 в регистр PORTB

bsf ind1 ;включение 1-го индикатора

goto exxit ;переход на метку exxit

met2 movlw .2 ;проверка содержимого регистра shet

xorwf shet,W ;на равенство числу 2

btfss STATUS,Z ;

goto met3 ;число в регистре shet не равно 2: переход на met3

movf datind2,W ;число в регистре shet равно 2: копирование

movwf PORTB ;содержимого регистра datind2 в регистр PORTB

bsf ind2 ;включение 2-го индикатора

goto exxit ;переход на метку exxit

met3 movlw .3 ;проверка содержимого регистра shet

xorwf shet,W ;на равенство числу 3

btfss STATUS,Z ;

goto met4 ;число в регистре shet не равно 3: переход на met4

movf datind3,W ;число в регистре shet равно 3: копирование

movwf PORTB ;содержимого регистра datind3 в регистр PORTB

bsf ind3 ;включение 3-го индикатора

goto exxit ;переход на метку exxit

met4 movf datind4,W ;копирование содержимого регистра datind3

movwf PORTB ;в регистр PORTB

bsf ind4 ;включение 4-го индикатора

exxit bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0

movlw .100 ;запись числа 156 в регистр таймера TMR0

swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров

swapf W_TEMP,F ;

swapf W_TEMP,W ;

retfie ;выход из подпрограммы прерывания

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Основная программа

Start ................. ;первоначальная настройка регистров

................. ;специального назначения

.................

bsf STATUS,RP0 ;запись двоичного числа 11010011 в регистр

movlw b"11010011" ;OPTION_REG, тем самым устанавливаем внутренний

movwf OPTION_REG ;источник тактового сигнала для TMR0

bcf STATUS,RP0 ;включаем предделитель перед TMR0

;устанавливаем коэффициент предделителя 1:16

clrf shet ;обнуление регистра shet, перед запуском

;прерываний по переполнению TMR0, выполняется

;однократно, после включения питания

clrf datind1 ;очистка регистров вывода информации на

clrf datind2 ;индикаторы, равнозначно выключению

clrf datind3 ;индикаторов, так как индикаторы с общим

clrf datind4 ;катодом

bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0

bsf INTCON,T0IE ;разрешение прерываний по переполнению TMR0

bsf INTCON,GIE ;разрешение глобальных прерываний

movlw b"00000110" ;пример вывода числа 13,52

movlw b"11001111" ;

movlw b"01101101" ;

movlw b"01011011" ;

................. ;

................. ;

................. ;

end ;конец всей программы

В основной программе сначала настраиваем таймер с помощью регистра OPTION_REG, ранее я рассказывал про использование таймеров для . Далее очищаем регистр shet, предназначенный для введения счета от 1 до 4, для каждого индикатора. Этот регистр инкрементируется в подпрограмме обработки прерываний и там же корректируется (он будет считать от 1 до 4), поэтому данная очистка выполняется однократно после включения питания. По этому регистру будем определять, какой индикатор включать и выдавать данные соответствующие ему. Следующим шагом будет очистка регистров хранения информации, четыре регистра dataind1,2,3,4 соответствующие четырем индикаторам. Очистка равнозначна выключению индикаторов, так как в подпрограмме обработки прерываний, содержимое этих регистров передается в регистр PORTB, к которому подключены аноды индикаторов. Это необходимо для того чтобы на индикаторах не высвечивался всякий мусор после разрешения прерываний, в принципе этого можно и не делать, если сразу записывать правильную информацию для вывода. Далее сбрасываем флаг прерывания по переполнению таймера, разрешаем прерывания по переполнению TMR0, и наконец, разрешаем глобальные прерывания.

В подпрограмме обработки прерываний, первым делом выключаем все индикаторы (подав низкие логические уровни на базы транзисторов), потому что неизвестно какой из них включен. Производим инкремент регистра shet, с проверкой на равенство числу 5, при наличии такого совпадения записываем в регистр число 1, так как необходимо вести счет от 1 до 4. Далее проверяем, какое именно число лежит в регистре shet, по которому загружаем в PORTB данные из регистров хранения информации (dataind) для соответствующего индикатора и включаем его. После чего сбрасываем флаг прерывания по переполнению TMR0, записываем число 100 в таймер (ниже приведен расчет этого значения), для временной задержки и выходим из обработчика прерываний. При первом прерывании включается первый индикатор, во втором прерывании второй и так по круговому циклу. В основной программе остается только загружать данные в регистры хранения информации для каждого индикатора. В подпрограмме прерываний не забываем сохранять и восстанавливать значения ключевых регистров, об этом я писал в статье про .

Для вывода чисел лучше использовать знакогенератор в виде таблицы данных. Например, чтобы вывести число 3456 на индикаторы, его необходимо разбить на разряды, при этом лучше использовать отдельные регистры для хранения чисел разрядов (от 0 до 9), далее прогнать эти регистры через знакогенератор, получив тем самым правильные байты (загружаемые в регистры dataind) для зажигания соответствующих сегментов.

Частоту тактового генератора примем за 4 МГц, машинный цикл 1 мкс. Частота обновления каждого индикатора пускай составит 100 Гц (период T=10 мс), соответственно необходимая временная задержка равна 10/4 = 2,5 мс. Коэффициент предделителя для TMR0 устанавливаем равным 1:16, при этом максимально возможная задержка равна 256х16 = 4096 мкс, а нам требуется пауза в 2,5 мс. Рассчитаем число для записи в TMR0: 256-((256х2,5)/4,096) = 256-156,25 = 99,75. После округления получим число 100.

Ниже можно скачать модель для программы Proteus, прошивку и исходник с реализацией динамической индикации на 4-х разрядный индикатор с общим катодом с применением микроконтроллера PIC16F628A. Для примера на индикатор выводятся числа 0000; 0001; 0002; 13,52; 9764.

Теперь рассмотрим подключение матрицы с разрешением 8х8 точек (светодиодов). Структуру матрицы обычно рассматривают в виде строк и столбцов. На картинке ниже в каждом столбце соединены катоды всех светодиодов, а в каждой строке аноды. Строки (8 линий, аноды светодиодов) через резисторы подключают к микроконтроллеру. Каждый столбец (катоды светодиодов) подключают к микроконтроллеру через 8 транзисторов. Алгоритм индикации такой же, сначала устанавливаем необходимые логические уровни на строках, в соответствии с тем, какие светодиоды должны гореть в столбце, далее подключаем первый столбец (индикация слева направо). Через определенную паузу выключаем столбец, и изменяем логические уровни на строках для отображения второго столбца, далее подключаем второй столбец. И так поочередно коммутируем все столбцы. Ниже представлена схема подключения матрицы к микроконтроллеру.


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

Самым распространенным последовательным регистром является микросхема 74НС595, которая содержит в себе сдвиговый регистр для загрузки данных, и регистр хранения через который данные передаются на выходные линии. Загружать данные в него просто, устанавливаем логический 0 на входе тактирования SH_CP, далее устанавливаем требуемый логический уровень на входе данных DS, после чего переключаем вход тактирования в 1, при этом происходит сохранение значения уровня (на входе DS) внутри сдвигового регистра. Одновременно с этим происходит сдвиг данных на один разряд. Снова сбрасываем вывод SH_CP в 0, устанавливаем требуемый уровень на входе DS и поднимаем SH_CP в 1. После полной загрузки сдвигового регистра (8 бит), устанавливаем в 1 вывод ST_CP, в этот момент данные передаются в регистр хранения и поступают на выходные линии Q0…Q7, после чего сбрасываем вывод ST_CP. Во время последовательной загрузки, данные сдвигаются от Q0 до Q7. Вывод Q7’ подключен к последнему разряду сдвигового регистра, этот вывод можно подключить на вход второй микросхемы, таким образом можно загружать данные сразу в две и более микросхемы. Вывод OE переключает выходные линии в третье (высокоомное) состояние, при подаче на него логической 1. Вывод MR предназначен для сброса сдвигового регистра, то есть установка низких логических уровней на выходах триггеров регистра, что эквивалентно загрузке восьми нулей. Ниже представлена диаграмма загрузки данных в микросхему 74НС595, установка значения 11010001 на выходных линиях Q0…Q7, при условии, что изначально там были нули:


Рассмотрим подключение матрицы 8×8 к микроконтроллеру PIC16F628A с помощью двух сдвиговых регистров 74HC595, схема представлена ниже:


Данные загружаются в микросхему DD2 (управление логическими уровнями на строках, аноды светодиодов) затем через вывод Q7’ передаются в DD3 (управление столбцами), соответственно сначала загружаем байт для включения столбца, затем байт с логическими уровнями на строках. К выходным линиям DD3 подключены транзисторы коммутирующие столбцы матрицы (катоды светодиодов). Ниже приведен код программы для вывода изображения на матрицу:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Реализация динамической индикации для матрицы с разрешением 8х8 ;Частота тактового генератора для примера 4 МГц, машинный цикл 1 мкс org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма обработки прерываний org 0004h ;начать выполнение подпрограммы с адреса 0004h movwf W_TEMP ;сохранение значений ключевых регистров swapf STATUS,W ; clrf STATUS ; movwf STATUS_TEMP ; ; movwf FSR_osn ;в регистр FSR_osn movf FSR_prer,W ;восстановление ранее сохраненного значения movwf FSR ;регистра FSR из регистра FSR_prer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;загрузка содержимого регистра stolb в микросхему movf stolb,W ;копирование содержимого регистра stolb movwf var ;в регистр var met2 btfsc var,0 ;устанавливаем вывод ds в соответствии с btfss var,0 ; bcf ds ; bcf sh_cp ; rrf var,F ;сдвиг регистра var вправо, для подготовки;следующего бита goto met2 ;scetbit не равен нулю: переход на метку met2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;загрузка содержимого регистра INDF в микросхему;74HC595 (последовательный сдвиговый регистр) movf INDF,W ;копирование содержимого регистра INDF movwf var ;в регистр var movlw .8 ;запись числа 8 в регистр scetbit, для отсчета movwf scetbit ;переданных битов met1 btfsc var,7 ;устанавливаем вывод ds в соответствии с bsf ds ;значением 7-го бита регистра var btfss var,7 ; bcf ds ; bsf sh_cp ;тактируем вывод sh_cp, для защелкивания данных bcf sh_cp ; rlf var,F ;сдвиг регистра var влево, для подготовки;следующего бита decfsz scetbit,F ;декремент с условием регистра scetbit goto met1 ;scetbit не равен нулю: переход на метку met1 ; bsf st_cp ;тактируем вывод st_cp, для передачи загруженных bcf st_cp ;байтов на выходные линии микросхем 74HC595 ; bcf STATUS,C ;сброс бита C регистра статус перед сдвигом rrf stolb,F ;сдвиг влево регистра stolb ; incf FSR,F ;инкремент регистра FSR, подготовка следующего;регистра для отправки данных на 74HC595 decfsz shet,F ;декремент с условием регистра shet goto exxit ;регистр shet не равен 0: переход на exxit movlw data1 ;регистр shet равен 0: запись адреса первого movwf FSR ;регистра хранения иннформации в регистр FSR movlw .8 ;запись числа 8 в регистр shet, для ведения movwf shet ;счета столбцов ; exxit bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0 movlw .124 ;запись числа 124 в регистр таймера TMR0 movwf TMR0 ; ; movf FSR,W ;сохранение текущего значения регистра FSR movwf FSR_prer ;в регистр FSR_prer movf FSR_osn ,W ;восстановление ранее сохраненного значения movwf FSR ;регистра FSR из регистра FSR_osn ; swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров movwf STATUS ; swapf W_TEMP,F ; swapf W_TEMP,W ; ; retfie ;выход из подпрограммы прерывания;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start ................. ;первоначальная настройка регистров................. ;специального назначения................. bsf STATUS,RP0 ;запись двоичного числа 11010011 в регистр movlw b"11010010" ;OPTION_REG, тем самым устанавливаем внутренний movwf OPTION_REG ;источник тактового сигнала для TMR0 bcf STATUS,RP0 ;включаем предделитель перед TMR0 ;устанавливаем коэффициент предделителя 1:8 ; movlw .8 ;запись числа 8 в регистр shet, перед запуском movwf shet ;прерываний по переполнению TMR0, выполняется;однократно, после включения питания movlw b"10000000" ;запись двоичного числа 10000000 в movwf stolb ;регистр stolb, для включения 1-го столбца;выполняется однократно, после включения питания; movlw data1 ;запись адреса первого регистра (регистры хранения movwf FSR_prer ;информации) в регистр FSR_prer, выполняется;однократно, после включения питания; movlw .8 ;очистка 8-ми регистров вывода информации на movwf tmp ;матрицу, равнозначно выключению movlw data1 ;матрицы movwf FSR ; met3 clrf INDF ; incf FSR,F ; decfsz tmp,F ; goto met3 ; ; bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0 bsf INTCON,T0IE ;разрешение прерываний по переполнению TMR0 bsf INTCON,GIE ;разрешение глобальных прерываний; m1 movlw data1 ;пример вывода буквы R movwf FSR ; movlw b"00000000" ; movwf INDF ; incf FSR,F ; movlw b"01111111" ; movwf INDF ; incf FSR,F ; movlw b"00001001" ; movwf INDF ; incf FSR,F ; movlw b"00011001" ; movwf INDF ; incf FSR,F ; movlw b"00101001" ; movwf INDF ; incf FSR,F ; movlw b"01000110" ; movwf INDF ; incf FSR,F ; movlw b"00000000" ; movwf INDF ; incf FSR,F ; movlw b"00000000" ; movwf INDF ; ; ................. ; ................. ; ................. ; ; end ;конец всей программы;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Реализация динамической индикации для матрицы с разрешением 8х8

;Частота тактового генератора для примера 4 МГц, машинный цикл 1 мкс

org 0000h ;начать выполнение программы с адреса 0000h

goto Start ;переход на метку Start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Подпрограмма обработки прерываний

org 0004h ;начать выполнение подпрограммы с адреса 0004h

movwf W_TEMP ;сохранение значений ключевых регистров

swapf STATUS,W ;

movwf STATUS_TEMP ;

movf FSR,W ;сохранение текущего значения регистра FSR

movwf FSR_osn ;в регистр FSR_osn

movf FSR_prer,W ;восстановление ранее сохраненного значения

movwf FSR ;регистра FSR из регистра FSR_prer

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;74HC595 (последовательный сдвиговый регистр)

movf stolb,W ;копирование содержимого регистра stolb

movwf var ;в регистр var

movlw .8 ;запись числа 8 в регистр scetbit, для отсчета

movwf scetbit ;переданных битов

met2 btfsc var,0 ;устанавливаем вывод ds в соответствии с

bsf ds ;значением 7-го бита регистра var

bsf sh_cp ;тактируем вывод sh_cp, для защелкивания данных

rrf var,F ;сдвиг регистра var вправо, для подготовки

;следующего бита

decfsz scetbit,F ;декремент с условием регистра scetbit

goto met2 ;scetbit не равен нулю: переход на метку met2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;74HC595 (последовательный сдвиговый регистр)

movf INDF,W ;копирование содержимого регистра INDF

movwf var ;в регистр var

movlw .8 ;запись числа 8 в регистр scetbit, для отсчета

movwf scetbit ;переданных битов

met1 btfsc var,7 ;устанавливаем вывод ds в соответствии с

bsf ds ;значением 7-го бита регистра var

bsf sh_cp ;тактируем вывод sh_cp, для защелкивания данных

rlf var,F ;сдвиг регистра var влево, для подготовки

;следующего бита

decfsz scetbit,F ;декремент с условием регистра scetbit

goto met1 ;scetbit не равен нулю: переход на метку met1

bsf st_cp ;тактируем вывод st_cp, для передачи загруженных

bcf st_cp ;байтов на выходные линии микросхем 74HC595

bcf STATUS,C ;сброс бита C регистра статус перед сдвигом

rrf stolb,F ;сдвиг влево регистра stolb

incf FSR,F ;инкремент регистра FSR, подготовка следующего

;регистра для отправки данных на 74HC595

decfsz shet,F ;декремент с условием регистра shet

goto exxit ;регистр shet не равен 0: переход на exxit

movlw data1 ;регистр shet равен 0: запись адреса первого

movwf FSR ;регистра хранения иннформации в регистр FSR

movlw .8 ;запись числа 8 в регистр shet, для ведения

movwf shet ;счета столбцов

movlw b"10000000" ;запись двоичного числа 10000000 в

movwf stolb ;регистр stolb, для включения 1-го столбца

exxit bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0

movlw .124 ;запись числа 124 в регистр таймера TMR0

movf FSR,W ;сохранение текущего значения регистра FSR

movwf FSR_prer ;в регистр FSR_prer

movf FSR_osn ,W ;восстановление ранее сохраненного значения

movwf FSR ;регистра FSR из регистра FSR_osn

swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров

swapf W_TEMP,F ;

swapf W_TEMP,W ;

retfie ;выход из подпрограммы прерывания

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Основная программа

Start ................. ;первоначальная настройка регистров

................. ;специального назначения

.................

bsf STATUS,RP0 ;запись двоичного числа 11010011 в регистр

movlw b"11010010" ;OPTION_REG, тем самым устанавливаем внутренний

movwf OPTION_REG ;источник тактового сигнала для TMR0

bcf STATUS,RP0 ;включаем предделитель перед TMR0

;устанавливаем коэффициент предделителя 1:8

movlw .8 ;запись числа 8 в регистр shet, перед запуском

movwf shet ;прерываний по переполнению TMR0, выполняется

;однократно, после включения питания

movlw b"10000000" ;запись двоичного числа 10000000 в

movwf stolb ;регистр stolb, для включения 1-го столбца

Информация с логическими уровнями для строк каждого столбца, хранится в 8-ми регистрах хранения информации, обращение к которым выполняется через . Адресу первого регистра присвоено название data1. Кроме первоначальной записи регистров shet и stolb, необходимо записать в регистр FSR_prer адрес первого регистра хранения информации (регистр – data1, запись в FSR_prer выполняется однократно, далее корректируется в обработчике), только после этого разрешать прерывания по переполнению TMR0.

Перед разрешением прерываний, желательно очистить регистры хранения информации, данная операция производится с помощью дополнительного регистра tmp (в качестве счетчика) и косвенной адресации, очистка равнозначна выключению матрицы.

В подпрограмме обработки прерываний загружаем в микросхему DD2 содержимое регистра stolb (при первом входе в обработчик после разрешения прерываний, в регистре лежит число 10000000, как было сказано выше). Загрузка начинается с младшего бита регистра stolb, который сдвигается в направлении от Q0 к Q7 (внутри микросхемы DD2) по мере загрузки, алгоритм загрузки был рассмотрен выше, так что думаю, разобраться в коде не составит труда. Далее загружаем в DD2 содержимое регистра INDF, это один из регистров хранения информации, адрес которого находится в FSR (при первом входе в обработчик после разрешения прерываний в FSR лежит адрес первого регистра хранения информации с названием data1). Загрузка начинается со старшего бита регистра INDF. После загрузки рассмотренных 2-х байтов, тактируем вывод st_cp, тем самым загруженные данные передаются на выходные линии микросхем DD2, DD3. Таким образом, при первом входе в обработчик коммутируется первый столбец матрицы, в котором загораются светодиоды, на анодах которых присутствует высокий логический уровень, в соответствии с содержимым регистра data1 (первый регистр хранения информации).

Далее сдвигаем регистр stolb вправо на один бит, для того чтобы подготовить к коммутации второй столбец матрицы при следующем входе в обработчик прерываний. Перед сдвигом необходимо очистить флаг C регистра STATUS, так как сдвиг происходит через этот флаг, и его состояние не известно на момент сдвига. После сдвига, инкрементируем регистр FSR, подготавливая следующий регистр хранения информации (после регистра data1) с логическими уровнями строк для второго столбца. Далее декрементируем с условием регистр shet, и если он не равен нулю, сбрасываем флаг прерывания по переполнению TMR0, производим запись числа в таймер, и выходим из обработчика прерываний.

При следующем входе в обработчик включится второй столбец матрицы и так далее. При обнулении регистра shet (после коммутации 8-го столбца), в него записывается число 8 для очередного цикла коммутации столбов, кроме этого корректируется значение регистра stolb, в регистр FSR записывается адрес первого регистра хранения информации (data1).

Выполним расчет временной задержки для таймера TMR0, частота тактового генератора 4 МГц, машинный цикл 1 мкс. Чтобы избежать мерцания светодиодов, примем частоту обновления каждого столбца в 100Гц (период T=10 мс), временная задержка равна 10/8 = 1,25 мс. Коэффициент предделителя TMR0 установим равным 1:8, при этом максимально возможная задержка равна 256х8 = 2048 мкс. Для паузы в 1,25 мс таймер должен отсчитать (256х1,25)/2,048 = 156,25 раз, округляя получим 156 отсчетов. Соответственно в таймер необходимо записать число 256-156 = 100. Но это не совсем правильное значение, так как на выполнение подпрограммы обработки прерываний затрачивается некоторое время, в данном случае на это уходит около 190 мкс, в перерасчете с учетом коэффициента предделителя получаем 190/8 = 23,75 или 24 отсчета. Правильное значение для записи в TMR0 равно: 100+24=124.

В основной программе записываем 8 регистров хранения информации, в соответствии с тем, что хотим вывести на матрицу. Ниже представлена схема поясняющая вывод информации на матрицу для вышерассмотренного кода.


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

Ниже по ссылке можно скачать прошивку и исходник для микроконтроллера PIC16F628A, с реализацией динамической индикации на матрице 8х8 с применением двух сдвиговых регистров 74HC595, схема подключения была рассмотрена выше. На матрицу поочередно выводятся буквы R, L, цифра 46, смайлик, и просто узор в виде креста, эта анимация продемонстрирована в видеоролике ниже.

с метками , . Читать .

  • Сергей Савенков

    какой то “куцый” обзор… как будто спешили куда то