
производство
   
Профиль
Группа: Модератор
Сообщений: 2724
Регистрация: 4.4.2002
Где: москва
Репутация: 20 Всего: 54
|
Так значит у тебя АВР  )) Хм... Так уж случилось, что лабник делал по АВР, так что могу скинуть примеры с коментариями  Вот для начала простой пример который можно отлаживать в AVR-Studio с описанием: | Код | ;***************************************************************************** ;* З А Д А Н И Е N1-2 * ;* (к лабораторной работе N3) * ;* * ;***************************************************************************** ;****************************** Константы ************************************ .EQU Stack=$0FFF; .Equ KB_Port=PortD; Регистр порта клавиатуры .Equ KB_DDR=DDRD; Регистр направления порта клавиатуры .Equ KB_PIN=PIND; Регистр выводов порта клавиатуры .Equ Ind_Port=PortC;Регистр вывода на сегм. индикат.(только на выход) ;****************************** Регистры ************************************* ;Переименование регистров (для удобства) .Def Zero=R3; .Def Acc=R16; .Def Bcc=R17; .Def Ccc=R18; .Def Dcc=R19; .Def Ecc=R20; ;*********************** Переменные ****************************************** .EQU Dig_0=$100; Разряд выводимого на индикатор числа .EQU KeyFlags=Dig_0+1; Сдвиговый регистр клавиатуры ;************************ Таблица прерываний ********************************* .ORG $0 rjmp Start; Вектор прерывания события RESET .ORG $30; Адрес исполняемой части ;************************* Основной цикл программы *************************** ;---------------------------- Инициализация ---------------------------------- Start: ldi R16, high(Stack); инициализация стека out SPH, R16 ldi R16, low(Stack) out SPL, R16 clr Zero; ldi Acc, $0; out KB_Port,Acc; PD0-3 выходы, PD4-6 входы: PORTD out KB_DDR, Acc; DDRD ;----------------------------------------------------------------------------- MainCycle: rcall AskKey; Опрос KB brtc MainCycle; Если флаг T очищен rcall ToDigits; Перевод в сегментный вид индикатора rjmp MainCycle; ;----------------------------------------------------------------------------- AskKey: clr Bcc; clt; очищаем флаг Т sbi KB_DDR,0; ищем нажатую клавишу в 0-ом ряду rcall Check; проверка на нажатие в 0-ом ряду cbi KB_DDR,0; восстанавливаем PORTE brcc CheckOut; если было нажатие переходим на CheckOut sbi KB_DDR,1; rcall Check; cbi KB_DDR,1; brcc CheckOut; sbi KB_DDR,2; rcall Check; cbi KB_DDR,2; brcc CheckOut; sbi KB_DDR,3; rcall Check; cbi KB_DDR,3; CheckOut: rjmp Dreb; проверка на дребезг
Check: in Acc, KB_Pin; Снимаем значения с входов порта клавиатуры swap Acc; переворачиваем тетрады ldi Ccc, 4; устанавливаем счетчик цикла Check01: dec Ccc; уменьшаем счетчик цикла breq Check02; если прошли 3 колонки, то на выход (нажатия нет) inc Bcc; Номер кнопки lsr Acc; поиск нажатой клавиши brcs Check01; если флаг С=0 было нажатие и мы set; устанавливаем флаг Т Check02: ret; Dreb: lds Ccc,KeyFlags; считываем знач. из сдвигового регистра клавиатуры lsl Ccc; сдвигаем его влево bld Ccc,0; Записываем в 0-ой бит Ссс значение флага T sts KeyFlags,Ccc; запоминаем сдвиговый регистр клавиатуры cpi Ccc,$FF; если точно было нажатие то на выход breq Check02; clt; если не было нажатия то очищаем флаг Т и на выход ret; ;----------------------------------------------------------------------------- ToDigits: ldi R30, low(DigitTab*2);загружаем в Z адрес таблицы преобразования ldi R31, high(DigitTab*2) add R30, Bcc; Поиск нужного отображаемого образа числа adc R31, Zero; lpm mov Acc,R0; младший разряд в сегментном виде sts Dig_0,Acc; сохраняем разряды в памяти ;здесь сохранение в ОЗУ сделано для иллюстрации работы с ОЗУ lds Ecc,Dig_0; загружаем старший разряд десятичного числа out Ind_Port,Ecc; выдаем код на шину данных индикаторов ret; ;************************* Таблицы ******************************************* DigitTAB: ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C .db $C0,$F9,$A4,$B0,$99,$92,$82,$F8,$80,$90,$88,$83,$C6
(Кратенько) В данном примере реализован опрос клавиатуры с защитой от дребезга и вывод номера нажатой клавиши на семисегментный индикатор в шестнадцатиричном виде. Программа начинается с объявления используемых констант. Таких как вершина стека (стек растёт вниз) и адреса используемых портов, которые удобно переобозначить. Далее идет раздел переименования регистров. А затем, раздел объявления используемых переменных, где указаны их имена и адреса. Ниже идет исполняемый код программы.
(Полненько) Рассмотрим подробнее работу программы. Практически любая программа начинается с инициализации, а если точнее, с команды безусловного перехода в процедуру инициализации, которая должна быть расположена по нулевому адресу в памяти программ (т.е. по нулевому вектору прерывания - RESET). В этой процедуре выполняется ряд подготовительных действий необходимых для нормальной работы программы. Например, инициализация стека, т.е. явное указание адреса вершины стека. В области памяти ввода вывода для этого существуют регистры SPH и SPL. Устанавливаются режимы работы выводов портов и их исходные состояния. Для удобства работы с адресами, а они в AVR шестнадцатиразрядные, используется переименованный в Zero регистр R3. Зачем это сделано, будет показано ниже. В основном цикле программы осуществляется только вызов процедур. Это делает программу более понятной и обеспечивает ее структурность. В данном случае вызываются две процедуры. Процедура опроса клавиатуры и процедура вывода кода нажатой клавиши на семисегментный индикатор. Последняя, вызывается только тогда, когда имело место нажатие клавиши. Признаком нажатия служит флаг T – флаг общего назначения в регистре SREG. Процедура AscKey использует так называемый «метод скользящего нуля» для поиска нажатой клавиши. Работает он следующим образом. Имеется Клавиатура размерностью 3*4, где 3 – число колонок, 4 – число рядов. Каждая колонка «подтянута» резистором к шине питания достаточно большим сопротивлением. Таким образом, на линиях колонок присутствует уровень логической единицы. Линии колонок подсоединены к микроконтроллеру. Режим работы этих выводов – вход. Линии рядов также подсоединены к порту микроконтроллера и выводы порта сконфигурированы как входные. Нажатие какой-либо из клавиш замыкает определенную линию колонок и линию рядов. Таким образом логические уровни замкнутых линий будут равны. При условии, что все выводы клавиатурного порта микроконтроллера работают на вход (режим – вход), замкнутые линии будут иметь уровень логической единицы (так как колонки подтянуты резистором к шине питания, а после нажатия клавиши к линии колонки подключается линия соответствующего ряда). Теперь если на линию ряда подать уровень логического нуля, то через резистор пойдет небольшой ток, а напряжение на замкнутых линиях будет соответствовать уровню логического нуля. Если логический ноль теперь поочередно подавать на каждую из линий рядов (т.е. как бы двигать ноль в порту), то нажатие легко отслеживается по наличию низкого уровня на линии колонок. Неприятным атрибутом любых контактов, в том числе и кнопок клавиатуры, является наличие дребезга, т.е. быстрое и непредсказуемое изменение состояния: замкнуто – незамкнуто. Это происходит при нажатии, отпускании, соединении, разъединении и т.д. Существует множество методов борьбы с дребезгом, один из которых мы разберем подробно. Будем опрашивать клавиатуру и каждый раз в случае если клавиша удерживается будем вдвигать единичку в статус байт клавиатуры. Этот байт мы создаем сами. Обозначим его KeyFlags. А в противном случае вдвигаем ноль. Как только значение этого байта станет равным $FF – нажатие было. Если нажатие все-таки имело место, то будет установлен флаг T и из основного цикла будет вызвана процедура вывода номера нажатой клавиши на семисегментный индикатор. В этой процедуре используется таблица образов цифр, т.е. какие сегменты индикатора должны гореть а какие нет для отображения той или иной цифры. Эта таблица расположена по адресу метки DigitTab в памяти программ. Этот адрес (умноженный на 2, т.к. в каждой ячейке памяти программ находится не байт, а 2 байта, т.е. слово) загружается в старшую и младшую части регистра Z, а затем к нему прибавляется номер нажатой клавиши. В случае переполнения младшей части нужно прибавить к старшей части единицу. Т.е. осуществить шестнадцатиричное сложение адреса и числа (номера нажатой клавиши). Для того, чтобы не использовать лишние команды используется регистр Zero. А т.к. с памятью программ, да и вообще с памятью приходиться работать довольно часто, то резервирование регистра Zero помогает экономить ресурсы контроллера и упрощает всевозможные сравнения с нулем, обнуления и т.д. Считанный из таблицы образ выводится на семисегментный индикатор.
|
--------------------
тут могла быть Ваша реклама...
|