Бегущая строка на Intel 8051: How-To. Часть 2
Вторая часть статьи Бегущая строка на Intel 8051: How-To. В статье рассказывается, как спроектировать и написать на ассемблере программу бегущей строки для системы на Intel 8051. В этой части будет рассмотрена архитектура программы и собственно сам код. Для всех дZенствующих асм-программеров и сочувствующих им =].
ВЫБОР АРХИТЕКТУРЫ ПРОГРАММЫ
Нормальная программа, естесственно, имеет какую-то структуру. Разобъем для начала всю программу на части, а потом объединим все в одно целое. Благодаря тому, что в ассемблере Intel 8051 есть возможность использовать метки перехода, программу можно разбить на более-менее независимые части, а связь между ними сделать за счет меток. Заметим, что переход на обработчики прерываний также выполняется с помощью меток.
Для того, чтобы все рассчитанные нами алгоритмы работали, нужно задать режим работы микроконтроллера, настроить все порты, etc.
Далее можно запускать бесконечный цикл, в котором происходит ожидание прерываний.
Бесконечный цикл в данном случае обязателен, ведь у нас не задано конечное время работы программы.
Далее - сами обработчики прерываний от таймеров. Все рассмотренные нами алгоритмы будут работать именно здесь. Вывод символов на индикаторы производится в обработчике прерывания от таймера TC_1 (который "считает" до 2.5 мс). Вместо прерываний по таймеру теоретически можно использовать "ручной" подсчет частоты: рассчитать количество тактов, необходимых для выполнения всех команд в обработчике функции, передающей символы на индикаторы, разделить на частоту работы микроконтроллера. Но это "некрасивый" и неправильный с точки зрения конструкции программы способ.
Далее можно разместить массив символов для передачи на индикаторы. Вообще, не важно, где размещать его, лишь бы все символы шли подряд.
Слово "STROKA" - это тоже всего лишь метка.
Смотрим общую структуру кода программы:
Теперь словесные алгоритмы преобразуем в ассемблерные.
Модуль 1. Основной модуль программы
Почему мы выбрали именно эти адреса? Потому что прерываниям TC_0 и TC_1 как раз соответствуют адреса 0Bh и 1Bh (см. документацию по микроконтроллеру; каждому из возможных прерываний микроконтроллера назначен определенный адрес), а адреса 00h и 30h должны ограничивать блок описания разделов программы. Идем далее.
Задаем начальные значения переменных и портов:
Итак, регистр R0 будет считать 7 прерываний таймера TC_0, чтобы получилось 77мс*7=500мс. Регистр R1 считает от 0 до 3, это 4 LED индикатора, данные по очереди посылаются на каждый из них. R2 считает номер символов, которые передаются на индикаторы.
Задаем режимы работы таймеров, их начальные значения:
Если что-то здесь непонятно - смотрите в документацию. Все сделано по мануалу от дяди Интела (смайл). Read the fu... the manual, наконец.
Модуль 2. Цикл ожидания прерывания от таймеров
С начальными описаниями разобрались. Далее идет бесконечный цикл. Ну, тут разбирать нечего :).
Модуль 3. Обработка прерываний
Далее в нашей программе обработчики прерываний от таймеров.
Прерывание от таймера ТС_0
Алгоритм работы этого прерывания простой и понятный: таймер 7 раз считает по 77 секунд, потом делает сдвиг бегущей строки. Также следим за состоянием регистра R2. Он считает от 0 до 12 (0Ch в шестнадцатеричном представлении), это 11 символов бегущей строки, которые также хранятся в памяти программ. Как номер символа преобразуется в конкретный символ - описано в обработчике TC_1.
Прерывание от таймера ТС_1
Как только наступило прерывание - остановили таймер, заново установили его на 2.5 мс, снова включили. Если R1 не равно 4, переходим по метке METKA1 в процедуру передачи текущего символа на текущий индикатор. Напомню, R1 отвечает за выбор индикатора, на который в данный момент отправляется символ для отображения. Если R1 равно 4, сбрасываем его в 0 и переходим в бесконечный цикл.
Как происходит выбор текущего символа бегущей строки? Мы не можем работать с массивами, когда процессор сам выделяет переменным адреса и память. Поэтому нам нужно брать символы напрямую из памяти ))). Метка STROKA указывает на адрес первого из символов бегущей строки. Текущий символ вычисляется как сумма номера текущего индикатора и регистра R2, который считает смещение символов. Эта сумма записывается в аккумулятор A, прибавляется к адресу первого символа (на который указывает метка STROKA), и получаем адрес нужного символа. Это происходит в процедуре передачи символа на индикатор:
Кроме передачи нужного символа в порт P1 (MOV P1,A), здесь описан процесс управления дешифратором (он управляется через порт P3; процесс описан в разделе «Алгоритм динамической индикации»).
Модуль 4. Вывод строки на индикаторы
Все, дальше у нас массив символов бегущей строки. Больше ничего в программе описывать не нужно, поэтому пишем ключевое слово END, код программы закончен.
Готово. Можно объединить все модули в программу.
КОД ПРОГРАММЫ
Написали. Теперь остается прогнать все это во Franklin'е. Если компилятор ошибок не выдает - значит синтаксических ошибок мы не сделали (большой радостный все ломающий смайл). Чтобы полностью проверить, правильно ли работает программа, нужно само устройство, распаянное на текстолитовой (или не текстолитовой) плате.. Паяйте :). Но вообще прога уже проверена в боевых условиях. Можно сильно не бояться (смайл).
ВЫБОР АРХИТЕКТУРЫ ПРОГРАММЫ
Нормальная программа, естесственно, имеет какую-то структуру. Разобъем для начала всю программу на части, а потом объединим все в одно целое. Благодаря тому, что в ассемблере Intel 8051 есть возможность использовать метки перехода, программу можно разбить на более-менее независимые части, а связь между ними сделать за счет меток. Заметим, что переход на обработчики прерываний также выполняется с помощью меток.
Для того, чтобы все рассчитанные нами алгоритмы работали, нужно задать режим работы микроконтроллера, настроить все порты, etc.
;______________МОДУЛЬ 1. Основной модуль программы________________
Для начала описываем адресов расположения модулей программы в памяти, хранящей код: основного модуля (в наших программах начинается с метки START) и обработчков прерываний.
Задаем начальные значения переменных, портов, режим работы таймеров.
Для начала описываем адресов расположения модулей программы в памяти, хранящей код: основного модуля (в наших программах начинается с метки START) и обработчков прерываний.
Задаем начальные значения переменных, портов, режим работы таймеров.
Далее можно запускать бесконечный цикл, в котором происходит ожидание прерываний.
Бесконечный цикл в данном случае обязателен, ведь у нас не задано конечное время работы программы.
;______________МОДУЛЬ 2. Цикл ожидания прерываний от таймеров_______
Просто бесконечный цикл.
Просто бесконечный цикл.
Далее - сами обработчики прерываний от таймеров. Все рассмотренные нами алгоритмы будут работать именно здесь. Вывод символов на индикаторы производится в обработчике прерывания от таймера TC_1 (который "считает" до 2.5 мс). Вместо прерываний по таймеру теоретически можно использовать "ручной" подсчет частоты: рассчитать количество тактов, необходимых для выполнения всех команд в обработчике функции, передающей символы на индикаторы, разделить на частоту работы микроконтроллера. Но это "некрасивый" и неправильный с точки зрения конструкции программы способ.
;______________МОДУЛЬ 3. Обработка прерываний_________________
Обработчики прерываний от таймеров. Тут именно 2 обработчика и метки, ведущие к этим обработчикам.
Обработчики прерываний от таймеров. Тут именно 2 обработчика и метки, ведущие к этим обработчикам.
Далее можно разместить массив символов для передачи на индикаторы. Вообще, не важно, где размещать его, лишь бы все символы шли подряд.
Слово "STROKA" - это тоже всего лишь метка.
;______________МОДУЛЬ 4. Вывод строки на индикаторы___________
Строка для вывода на индикаторы
Строка для вывода на индикаторы
Смотрим общую структуру кода программы:
;______________МОДУЛЬ 1. Основной модуль программы____________
Для начала описываем адресов расположения модулей программы в памяти, хранящей код: основного модуля (в наших программах начинается с метки START) и обработчков прерываний.
Задаем начальные значения переменных, портов, режим работы таймеров.
;___________________МОДУЛЬ 2. Цикл ожидания прерывания от таймеров___
Просто бесконечный цикл.
;___________________МОДУЛЬ 3. Обработка прерываний__________________
Обработчики прерываний от таймеров. Тут именно 2 обработчика и метки, ведущие к этим обработчикам.
;___________________МОДУЛЬ 4. Вывод строки на индикаторы______________
Строка для вывода на индикаторы.
Для начала описываем адресов расположения модулей программы в памяти, хранящей код: основного модуля (в наших программах начинается с метки START) и обработчков прерываний.
Задаем начальные значения переменных, портов, режим работы таймеров.
;___________________МОДУЛЬ 2. Цикл ожидания прерывания от таймеров___
Просто бесконечный цикл.
;___________________МОДУЛЬ 3. Обработка прерываний__________________
Обработчики прерываний от таймеров. Тут именно 2 обработчика и метки, ведущие к этим обработчикам.
;___________________МОДУЛЬ 4. Вывод строки на индикаторы______________
Строка для вывода на индикаторы.
Теперь словесные алгоритмы преобразуем в ассемблерные.
Модуль 1. Основной модуль программы
;-------Описание адресов расположения модулей программы
ORG 00h
JMP START;переход на инициализацию
ORG 0Bh
JMP TC_0;переход по прерыванию на обработчик таймера T/C 0
ORG 1Bh
JMP TC_1;переход по прерыванию на обработчик таймера T/C 1
ORG 30h
;-------Описание адресов расположения модулей программы
ORG 00h
JMP START;переход на инициализацию
ORG 0Bh
JMP TC_0;переход по прерыванию на обработчик таймера T/C 0
ORG 1Bh
JMP TC_1;переход по прерыванию на обработчик таймера T/C 1
ORG 30h
;-------Описание адресов расположения модулей программы
Почему мы выбрали именно эти адреса? Потому что прерываниям TC_0 и TC_1 как раз соответствуют адреса 0Bh и 1Bh (см. документацию по микроконтроллеру; каждому из возможных прерываний микроконтроллера назначен определенный адрес), а адреса 00h и 30h должны ограничивать блок описания разделов программы. Идем далее.
Задаем начальные значения переменных и портов:
START:; Инициализация программы
;-------Начальные описания
CLR P3.2; Выбор 1-го индикатора
CLR P3.3; Обнуление строба записи в регистре
CLR P3.4; Сброс разрешения переключения дешифратора
CLR P3.5
SETB P3.4; Разрешаем работу дешифратора
MOV R0,#0h; Инициализация итерационной переменной R0
; 7 прерываний = 0,5с.
MOV R1,#0h; Инициализация итерационной переменной R1,
; где R1=0..3 - так осуществляется выбор индикатора
MOV R2,#0h; Инициализация итерационной переменной R2
; (отсчитывает цикл смещения в строке STROKA)
;-------Начальные описания
;-------Начальные описания
CLR P3.2; Выбор 1-го индикатора
CLR P3.3; Обнуление строба записи в регистре
CLR P3.4; Сброс разрешения переключения дешифратора
CLR P3.5
SETB P3.4; Разрешаем работу дешифратора
MOV R0,#0h; Инициализация итерационной переменной R0
; 7 прерываний = 0,5с.
MOV R1,#0h; Инициализация итерационной переменной R1,
; где R1=0..3 - так осуществляется выбор индикатора
MOV R2,#0h; Инициализация итерационной переменной R2
; (отсчитывает цикл смещения в строке STROKA)
;-------Начальные описания
Итак, регистр R0 будет считать 7 прерываний таймера TC_0, чтобы получилось 77мс*7=500мс. Регистр R1 считает от 0 до 3, это 4 LED индикатора, данные по очереди посылаются на каждый из них. R2 считает номер символов, которые передаются на индикаторы.
Задаем режимы работы таймеров, их начальные значения:
;-------Описание работы таймеров
MOV TH0,#0h; Установка времени срабатывания таймера 0 на
MOV TL0,#0h; максимально возможное значение (71 мс)
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2,5 мс (400 Гц)
MOV TMOD,#00010001b; Определяем таймеры/счетчики в качестве таймеров
MOV IP,#00000010b; Устанавливаем приоритет TC_0=1, TC_1 = 0
MOV IE,#10001010b; Разрешаем прерывания
MOV TCON,#01010000b; Включение таймеров
;-------Описание работы таймеров
MOV TH0,#0h; Установка времени срабатывания таймера 0 на
MOV TL0,#0h; максимально возможное значение (71 мс)
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2,5 мс (400 Гц)
MOV TMOD,#00010001b; Определяем таймеры/счетчики в качестве таймеров
MOV IP,#00000010b; Устанавливаем приоритет TC_0=1, TC_1 = 0
MOV IE,#10001010b; Разрешаем прерывания
MOV TCON,#01010000b; Включение таймеров
;-------Описание работы таймеров
Если что-то здесь непонятно - смотрите в документацию. Все сделано по мануалу от дяди Интела (смайл). Read the fu... the manual, наконец.
Модуль 2. Цикл ожидания прерывания от таймеров
С начальными описаниями разобрались. Далее идет бесконечный цикл. Ну, тут разбирать нечего :).
TSIKL:;-------Цикл без операторов, в нем происходит ожидание прерывания от таймеров
NOP; Если бы тут были какие-то операторы, то выполнялись бы именно они
JMP TSIKL
NOP; Если бы тут были какие-то операторы, то выполнялись бы именно они
JMP TSIKL
Модуль 3. Обработка прерываний
Далее в нашей программе обработчики прерываний от таймеров.
Прерывание от таймера ТС_0
TC_0:;-------Подпрограмма обработки прерывания таймера 0
; Таймер 0 выполняет задержку на 0.5 с
INC R0 ; Увеличение на 1 итерационной переменной R0
CJNE R0,#7h,TC_0_END; Если R0==7, то R0 сбрасываем
MOV R0,#0h; если нет, то выходим из прерывания
INC R2 ; Увеличение на 1 итерационной переменной R2
CJNE R2,#0Ch,TC_0_END; Если R2==11, то
MOV R2,#0h; R2 сбрасываем, если нет, то выходим из прерывания
TC_0_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 0
; Таймер 0 выполняет задержку на 0.5 с
INC R0 ; Увеличение на 1 итерационной переменной R0
CJNE R0,#7h,TC_0_END; Если R0==7, то R0 сбрасываем
MOV R0,#0h; если нет, то выходим из прерывания
INC R2 ; Увеличение на 1 итерационной переменной R2
CJNE R2,#0Ch,TC_0_END; Если R2==11, то
MOV R2,#0h; R2 сбрасываем, если нет, то выходим из прерывания
TC_0_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 0
Алгоритм работы этого прерывания простой и понятный: таймер 7 раз считает по 77 секунд, потом делает сдвиг бегущей строки. Также следим за состоянием регистра R2. Он считает от 0 до 12 (0Ch в шестнадцатеричном представлении), это 11 символов бегущей строки, которые также хранятся в памяти программ. Как номер символа преобразуется в конкретный символ - описано в обработчике TC_1.
Прерывание от таймера ТС_1
TC_1:;--------Подпрограмма обработки прерывания таймера 1
; Таймер 1 выполняет "мигание" индикаторов с частотой 400 Гц
MOV TCON,#00010000b; Останавливаем таймер 1 на время установки
; времени срабатывания
MOV TH1,#0F6h ; Установка времени срабатывания
MOV TL1,#0FFh ; таймера 1 на 2.5 мс (400 Гц)
MOV TCON,#01010000b; Включение таймера 1
CJNE R1,#4h, METKA1; Если R1==4, то R1 сбрасываем,
MOV R1,#0h ; если нет, то переходим на метку TSIKL
; Таймер 1 выполняет "мигание" индикаторов с частотой 400 Гц
MOV TCON,#00010000b; Останавливаем таймер 1 на время установки
; времени срабатывания
MOV TH1,#0F6h ; Установка времени срабатывания
MOV TL1,#0FFh ; таймера 1 на 2.5 мс (400 Гц)
MOV TCON,#01010000b; Включение таймера 1
CJNE R1,#4h, METKA1; Если R1==4, то R1 сбрасываем,
MOV R1,#0h ; если нет, то переходим на метку TSIKL
Как только наступило прерывание - остановили таймер, заново установили его на 2.5 мс, снова включили. Если R1 не равно 4, переходим по метке METKA1 в процедуру передачи текущего символа на текущий индикатор. Напомню, R1 отвечает за выбор индикатора, на который в данный момент отправляется символ для отображения. Если R1 равно 4, сбрасываем его в 0 и переходим в бесконечный цикл.
Как происходит выбор текущего символа бегущей строки? Мы не можем работать с массивами, когда процессор сам выделяет переменным адреса и память. Поэтому нам нужно брать символы напрямую из памяти ))). Метка STROKA указывает на адрес первого из символов бегущей строки. Текущий символ вычисляется как сумма номера текущего индикатора и регистра R2, который считает смещение символов. Эта сумма записывается в аккумулятор A, прибавляется к адресу первого символа (на который указывает метка STROKA), и получаем адрес нужного символа. Это происходит в процедуре передачи символа на индикатор:
METKA1:
MOV A,R1 ; A=R1
ADD A,R2 ; A=R1+R2 (вычисляем смещение в строке, как сумму номера
; индикатора и циклического смещения R2)
MOV DPTR,#STROKA; Заносим в DPTR адрес начала строки STROKA
MOVC A,@A+DPTR; байт из строки
MOV P1,A ; Вывод этого байта в порт для индикации
SETB P3.3 ; Устанавливаем бит 3 порта P3 (вывод строба записи в регистр)
MOV B,R1
MOV C,B.0
MOV P3.2,C ; Подаем на вход дешифратора через P3.2 и P3.5
MOV C,B.1 ; номер индикатора
MOV P3.5,C ; записанный в R1
INC R1 ; Переключаемся на следующий индикатор
CLR P3.3 ; Конец строба записи в регистр
TC_1_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 1
MOV A,R1 ; A=R1
ADD A,R2 ; A=R1+R2 (вычисляем смещение в строке, как сумму номера
; индикатора и циклического смещения R2)
MOV DPTR,#STROKA; Заносим в DPTR адрес начала строки STROKA
MOVC A,@A+DPTR; байт из строки
MOV P1,A ; Вывод этого байта в порт для индикации
SETB P3.3 ; Устанавливаем бит 3 порта P3 (вывод строба записи в регистр)
MOV B,R1
MOV C,B.0
MOV P3.2,C ; Подаем на вход дешифратора через P3.2 и P3.5
MOV C,B.1 ; номер индикатора
MOV P3.5,C ; записанный в R1
INC R1 ; Переключаемся на следующий индикатор
CLR P3.3 ; Конец строба записи в регистр
TC_1_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 1
Кроме передачи нужного символа в порт P1 (MOV P1,A), здесь описан процесс управления дешифратором (он управляется через порт P3; процесс описан в разделе «Алгоритм динамической индикации»).
Модуль 4. Вывод строки на индикаторы
Все, дальше у нас массив символов бегущей строки. Больше ничего в программе описывать не нужно, поэтому пишем ключевое слово END, код программы закончен.
; Здесь описывается, как данные передаются на индикаторы.
STROKA:; Строка для вывода на индикаторы
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11001000b; П
db 11000110b; С
db 10111111b; -
db 10011001b; 4
db 11111000b; 7
db 10000010b; 6
db 10111111b; -
db 11000000b; 0
db 10010010b; 8
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
FINAL:
END.; Конец кода программы
STROKA:; Строка для вывода на индикаторы
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11001000b; П
db 11000110b; С
db 10111111b; -
db 10011001b; 4
db 11111000b; 7
db 10000010b; 6
db 10111111b; -
db 11000000b; 0
db 10010010b; 8
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
FINAL:
END.; Конец кода программы
Готово. Можно объединить все модули в программу.
КОД ПРОГРАММЫ
;_______________МОДУЛЬ 1. Основной модуль программы__________________________________
;-------Описание адресов расположения модулей программы
ORG 00h
JMP START; переход на инициализацию
ORG 0Bh
JMP TC_0 ; переход по прерыванию на обработчик таймера T/C 0
ORG 1Bh
JMP TC_1 ; переход по прерыванию на обработчик таймера T/C 1
ORG 30h
;-------Описание адресов расположения модулей программы
START:
;-------Начальные описания
CLR P3.2 ; Выбор 1-го индикатора
CLR P3.3 ; Обнуление строба записи в регистре
CLR P3.4 ; Сброс разрешения переключения дешифратора
CLR P3.5
SETB P3.4 ; Разрешаем работу дешифратора
MOV R0,#0h; Инициализация итерационной переменной R0
; 7 прерываний = 0,5с.
MOV R1,#0h; Инициализация итерационной переменной R1,
; где R1=0..3 - так осуществляется выбор индикатора
MOV R2,#0h; Инициализация итерационной переменной R2
; (отсчитывает цикл смещения в строке STROKA)
; 7 прерываний = 0,5с.
;-------Начальные описания
;-------Описание работы таймеров
MOV TH0,#0h; Установка времени срабатывания таймера 0 на
MOV TL0,#0h; максимально возможное значение (71 мс)
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2,5 мс (400 Гц)
MOV TMOD,#00010001b; Определяем таймеры/счетчики в качестве таймеров
MOV IP,#00000010b; Устанавливаем приоритет T/C_0=1, T/C_1 = 0
MOV IE,#10001010b; Разрешаем прерывания
MOV TCON,#01010000b; Включение таймеров
;-------Описание работы таймеров
;________________МОДУЛЬ 2. Цикл ожидания прерывания от таймеров_______________________
TSIKL:;-------Цикл без операторов, в нем происходит ожидание прерывания от таймеров
NOP; Если бы тут были какие-то операторы, то выполнялись бы именно они
JMP TSIKL
;________________МОДУЛЬ 3. Обработка прерываний_______________________________________
TC_0:;-------Подпрограмма обработки прерывания таймера 0
; Таймер 0 выполняет задержку на 0.5 с
INC R0 ; Увеличение на 1 итерационной переменной R0
CJNE R0,#7h,TC_0_END; Если R0==7, то R0 сбрасываем
MOV R0,#0h; если нет, то выходим из прерывания
INC R2 ; Увеличение на 1 итерационной переменной R2
CJNE R2,#0Ch,TC_0_END; Если R2==11, то
MOV R2,#0h; R2 сбрасываем, если нет, то выходим из прерывания
TC_0_END: RETI;; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 0
TC_1:;--------Подпрограмма обработки прерывания таймера 1
; Таймер 1 выполняет "мигание" индикаторов с частотой 400 Гц
MOV TCON,#00010000b; Останавливаем таймер 1 на время установки времени срабатывания
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2.5 мс (400 Гц)
MOV TCON,#01010000b; Включение таймера 1
CJNE R1,#4h, METKA1; Если R1==4, то R1 сбрасываем,
MOV R1,#0h; если нет, то переходим на метку TSIKL
METKA1:
MOV A,R1 ; A=R1
ADD A,R2 ; A=R1+R2 (вычисляем смещение в строке, как сумму номера индикатора
; и циклического смещения R2)
MOV DPTR,#STROKA; Заносим в DPTR адрес начала строки STROKA
MOVC A,@A+DPTR; байт из строки
MOV P1,A ; Вывод этого байта в порт для индикации
SETB P3.3 ; Устанавливаем бит 3 порта P3 (вывод строба записи в регистр)
MOV B,R1
MOV C,B.0
MOV P3.2,C; Подаем на вход дешифратора через P3.2 и P3.5
MOV C,B.1; номер индикатора
MOV P3.5,C; записанный в R1
INC R1 ; Переключаемся на следующий индикатор
CLR P3.3 ; Конец строба записи в регистр
TC_1_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 1
;________________МОДУЛЬ 4. Вывод строки на индикаторы_________________________________
; Здесь описывается, как данные передаются на индикаторы.
STROKA:; Строка для вывода на индикаторы
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11001000b; П
db 11000110b; С
db 10111111b; -
db 10011001b; 4
db 11111000b; 7
db 10000010b; 6
db 10111111b; -
db 11000000b; 0
db 10010010b; 8
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
FINAL:
END.; Конец кода программы
;-------Описание адресов расположения модулей программы
ORG 00h
JMP START; переход на инициализацию
ORG 0Bh
JMP TC_0 ; переход по прерыванию на обработчик таймера T/C 0
ORG 1Bh
JMP TC_1 ; переход по прерыванию на обработчик таймера T/C 1
ORG 30h
;-------Описание адресов расположения модулей программы
START:
;-------Начальные описания
CLR P3.2 ; Выбор 1-го индикатора
CLR P3.3 ; Обнуление строба записи в регистре
CLR P3.4 ; Сброс разрешения переключения дешифратора
CLR P3.5
SETB P3.4 ; Разрешаем работу дешифратора
MOV R0,#0h; Инициализация итерационной переменной R0
; 7 прерываний = 0,5с.
MOV R1,#0h; Инициализация итерационной переменной R1,
; где R1=0..3 - так осуществляется выбор индикатора
MOV R2,#0h; Инициализация итерационной переменной R2
; (отсчитывает цикл смещения в строке STROKA)
; 7 прерываний = 0,5с.
;-------Начальные описания
;-------Описание работы таймеров
MOV TH0,#0h; Установка времени срабатывания таймера 0 на
MOV TL0,#0h; максимально возможное значение (71 мс)
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2,5 мс (400 Гц)
MOV TMOD,#00010001b; Определяем таймеры/счетчики в качестве таймеров
MOV IP,#00000010b; Устанавливаем приоритет T/C_0=1, T/C_1 = 0
MOV IE,#10001010b; Разрешаем прерывания
MOV TCON,#01010000b; Включение таймеров
;-------Описание работы таймеров
;________________МОДУЛЬ 2. Цикл ожидания прерывания от таймеров_______________________
TSIKL:;-------Цикл без операторов, в нем происходит ожидание прерывания от таймеров
NOP; Если бы тут были какие-то операторы, то выполнялись бы именно они
JMP TSIKL
;________________МОДУЛЬ 3. Обработка прерываний_______________________________________
TC_0:;-------Подпрограмма обработки прерывания таймера 0
; Таймер 0 выполняет задержку на 0.5 с
INC R0 ; Увеличение на 1 итерационной переменной R0
CJNE R0,#7h,TC_0_END; Если R0==7, то R0 сбрасываем
MOV R0,#0h; если нет, то выходим из прерывания
INC R2 ; Увеличение на 1 итерационной переменной R2
CJNE R2,#0Ch,TC_0_END; Если R2==11, то
MOV R2,#0h; R2 сбрасываем, если нет, то выходим из прерывания
TC_0_END: RETI;; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 0
TC_1:;--------Подпрограмма обработки прерывания таймера 1
; Таймер 1 выполняет "мигание" индикаторов с частотой 400 Гц
MOV TCON,#00010000b; Останавливаем таймер 1 на время установки времени срабатывания
MOV TH1,#0F6h; Установка времени срабатывания
MOV TL1,#0FFh; таймера 1 на 2.5 мс (400 Гц)
MOV TCON,#01010000b; Включение таймера 1
CJNE R1,#4h, METKA1; Если R1==4, то R1 сбрасываем,
MOV R1,#0h; если нет, то переходим на метку TSIKL
METKA1:
MOV A,R1 ; A=R1
ADD A,R2 ; A=R1+R2 (вычисляем смещение в строке, как сумму номера индикатора
; и циклического смещения R2)
MOV DPTR,#STROKA; Заносим в DPTR адрес начала строки STROKA
MOVC A,@A+DPTR; байт из строки
MOV P1,A ; Вывод этого байта в порт для индикации
SETB P3.3 ; Устанавливаем бит 3 порта P3 (вывод строба записи в регистр)
MOV B,R1
MOV C,B.0
MOV P3.2,C; Подаем на вход дешифратора через P3.2 и P3.5
MOV C,B.1; номер индикатора
MOV P3.5,C; записанный в R1
INC R1 ; Переключаемся на следующий индикатор
CLR P3.3 ; Конец строба записи в регистр
TC_1_END: RETI ; Выход из прерывания
;--------Конец подпрограммы обработки прерывания таймера 1
;________________МОДУЛЬ 4. Вывод строки на индикаторы_________________________________
; Здесь описывается, как данные передаются на индикаторы.
STROKA:; Строка для вывода на индикаторы
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11001000b; П
db 11000110b; С
db 10111111b; -
db 10011001b; 4
db 11111000b; 7
db 10000010b; 6
db 10111111b; -
db 11000000b; 0
db 10010010b; 8
db 11111111b; <пробел>
db 11111111b; <пробел>
db 11111111b; <пробел>
FINAL:
END.; Конец кода программы
Написали. Теперь остается прогнать все это во Franklin'е. Если компилятор ошибок не выдает - значит синтаксических ошибок мы не сделали (большой радостный все ломающий смайл). Чтобы полностью проверить, правильно ли работает программа, нужно само устройство, распаянное на текстолитовой (или не текстолитовой) плате.. Паяйте :). Но вообще прога уже проверена в боевых условиях. Можно сильно не бояться (смайл).
- Просмотров: 1913
Версия для печати
#1
Vanger |
Vanger |
Дата публикации: 10 апреля 2009 01:08 | ICQ: --
цитировать
цитировать
#2
djnz |
djnz | огромное спасибо! )статья очень помогла)
вот только на индикаторе скорее всего будет выводиться ПС-476-05
вот только на индикаторе скорее всего будет выводиться ПС-476-05
Дата публикации: 6 ноября 2009 21:54 | ICQ: --
цитировать
цитировать


как было в статье на wasm.ru, чтобы хорошо писать на асме - нужно иметь особый склад ума
голова уже болит от вникания во все эти регистры-адресацию-чеготамеще. дофига всего приходится в голове держать. а программа то в сотню строк))