Здравствуйте, BVSV!
Вот и программа.
Я сделал следующие предположения:
1) Для работы с ЖКИ сигналы RS заведен на A1, а R/W на A0
В результате для адресации регистров и операции используются два младших бита адреса
Для отличия от обычной памяти я предположил использовать старший бит адреса.
2) Кроме цифр остаются еще две клавиши, которые я предлагаю использовать следующим образом:
левая нижняя - для очистки числа, 0 приведет к останову,
правая нижняя - для отработки введенного числа
Причем младшую цифру я игнорирую, т.к. она лишняя.
3) для выхода я использую бит p1.7
Период у нас получается 125 мкс
Скважность меняется от 1/25 до 80/100 = 20/25 или от 5 мкс до 100 мкс (получается, что макс 1000 надо делить на 10)
Реальные цифры Вы увидете только на осциллографе :)
Для включения/выключения напряжения на выходе используются два таймера.
Один включает, второй выключает...
[code h=200];регистры ЖКИ
;конкретные адреса задавайте сами.
;важны только два младших бита
;предполагается, что RS заведен на A1, а R/W на A0
IR_WRITE equ 8000h
IR_READ equ 8001h
DR_WRITE equ 8002h
DR_READ equ 8003h
CLEAR equ 01h ;команда очистки экрана
SET_POS_0 equ 80h ;установка позиции 0
SET_POS_4 equ 84h ;установка позиции 4
;строка с цифрами
obM_0 equ 30h ;младший
obM_1 equ 31h
obM_2 equ 32h
obM_3 equ 33h ;старший
DEB_COUNT equ 100 ;число проверок для устранения дребезга клавиатуры
org 0 ;начало
jmp Start ;переход на основную работу
org 0bh ;адрес вектора 0 таймера
setb p1.7 ;включаем на выходе 1
setb tr1 ;запускаем таймер 1
reti
org 1bh ;адрес вектора 1 таймера
clr p1.7 ;выключаем сигнал на выходе
clr tr1 ;останавливаем таймер 1
reti
Start:
mov tmod,#00100010b ;оба таймеpа - 8-битные перегружаемые
mov ie,#8ah ;Разpешить пpеpывания от таймеpов + вообще разрешить
mov th0,255-125 ;константы для периода 125мк, что соответствует частоте 8кГц
mov tl0,255-125
call display_init ;вывод на экран ob/m с 5 позиции
Stop: ;останов
clr p1.7 ;выход в 0, останов
clr tr0 ;останов таймера 0
clr tr1 ;останов таймера 1
Zero:
mov obM_0,'0' ;инициируем строку с цифрами в '0000'
mov obM_1,'0'
mov obM_2,'0'
mov obM_3,'0'
MainLoop:
call display ;вывод строки на монитор
ScanLoop: ;цикл сканирования клавиатуры
call scan ;сканируем клавиатуру
cjne a,#0ffh, GetDigit ;если код 0-11, то на анализ кода
jmp ScanLoop ;0ffh - нет кода - на цикл сканирования
GetDigit: ;нажата клавиша
cjne a,#0ch,CmpEnter ;продолжаем сравнение
jmp Zero ;нажата левая нижняя - сброс числа в 0
CmpEnter:
cjne a,#0dh,Digit ;нажата цифра?
call Calculate ;нажата правая нижняя - изменяем скважность
jz Stop ;если ноль, то останавливаем
jmp ScanLoop ;на сканирование клавиатуры
Digit: ;циклически вдвигаем цифру
mov obM_3,obM_2 ;старшая цифра теряется
mov obM_2,obM_1
mov obM_1,obM_0
mov obM_0,a
jmp ScanLoop ;на сканирование
Calculate: ;расчет скважности
;преобразуем строку в число (младший разряд игнорируем)
mov a,obM_3 ;проверим, чтобы число "входило" в один байт
; (допустимо вообще <= 100)
cjne a,#'2',cmp_hi_digit ;проверим старший разряд
cmp_hi_digit:
jc mul_hi ;если старший разряд < 2, то все в порядке
mov a,#'1' ;иначе меняем на 1
mul_hi: ;формируем число
anl a,#0fh ;преобразуем символ '0'-'9' в число 0-9
mov b,#100 ;
mul ab ;сотня
mov r2,a ;сохраним
mov a,obM_2
anl a,#0fh
mov b,#10
mul ab ;десятки
add a,r2
mov r2,a
mov a,obM_0
anl a,#0fh ;единицы
add a,r2 ;все число
jz calc_ret ;проверим на 0
cjne a,#101,cmp_max ;проверим на максимальное - 100
cmp_max:
jc set_timers ;<= 100 - все в порядке
mov a,#100 ;ограничиваемся 100 (1000 об/м)
set_timers: ;задаем таймер
cpl a
inc a ;константа для срабатывания таймера 1
mov th1,a
mov tl1,a
setb tr0 ;запускаем таймер 0
calc_ret:
ret
scan: ;сканируем клавиатуру
mov r2,#4 ;четыре линии
mov r3,#11111110b ;маска сканкода для выбора линии p1.0 - p1.3
mov r4,#0 ;база группы кнопок 0, 3, 6, 9
scan_loop: ;цикл сканирования линий
mov p1,r3 ;вывод сканкода
mov a,p1 ;читаем код клавиши из p1.4 - p1.6
swap a ;код в acc.0 - acc.2
anl a,#07h ;сбросим незначащие биты
cjne a,#07h,debounce ;если есть нажатие, идем на устранение дребезга
jmp next ;нет нажатия - на следующую линию сканирования
debounce: ;устранение дребезга
mov r5,a ;сохраним код
mov r6,#DEB_COUNT ;число циклов проверки дребезга
debounce_loop: ;цикл проверки дребезга
mov a,p1 ;читаем код
swap a
anl a,#07h
cjne a,5,next ;если не равен сохраненному (r5 нулевого банка),
; то на следующее сканирование
djnz r6,debounce_loop ;проверяем DEB_COUNT раз
;клавиша нажата!
wait_off: ;подождем отпускания клавиши
mov a, p1 ;читаем код
swap a
anl a,#07h
cjne a,#07h,wait_off ;ждем отпускания
;сформируем из кода вида 00001101b число r4 + 1
mov r2,#3 ;число бит
mov a,r5 ;сканкод кнопки
conv_loop:
rrc a ;циклически выдвигаем младший бит в C
jnc scan_ret ;0 - число посчитано
inc r4 ;инкремент
djnz r2,conv_loop ;3 раза
scan_ret:
mov a,r4 ;код клавиши 0-11
mov dptr,#table ;таблица перекодировки
movc a,@a+dptr ;код в соответствии с таблицей
ret
next: ;переходим на следующую линию сканирования
inc r4 ;база для следующей линии клавиш (по 3 кнопки в линии)
inc r4
inc r4
mov a,r3 ;маска
rl a ;циклически сдвигаем (перемещаем 0 бит влево)
mov r3,a
djnz r2,scan_loop ;по всем линиям
mov a,#0ffh ;ничего не нажато
ret
;таблица кодов, соответствующих скан-кодам
;размещение, как на телефонной клавиатуре
;1 2 3
;4 5 6
;7 8 9
;c 0 d
;c - сброс
;d - ввод
table: db '1','2','3','4','5','6','7','8','9',0ch,'0',0dh
;п/п для работы с ЖКИ
WAIT_LCD: ;ожидание готовности
mov DPTR,#IR_READ
WAIT_BUSY:
movx a,@DPTR
jb acc.7,WAIT_BUSY ;ждем бит IR.7
ret
WRITE_LCD_DR: ;запись байта на ЖКИ
mov DPTR,#DR_WRITE
movx @DPTR,a
acall WAIT_LCD
ret
WRITE_LCD_IR: ;запись байта в регистр IR
mov DPTR,#IR_WRITE
movx @DPTR,a
acall WAIT_LCD
ret
display: ;п/п вывода строки цифр
mov a,#SET_POS_0 ;позиция 0
acall WRITE_LCD_IR
mov r0,#obM_0 ;адресс массива
mov r1,#4 ;количество
out_num_loop:
mov a,@r0
acall WRITE_LCD_DR
djnz r1,out_num_loop
ret
display_init: ;инициализация ЖКИ
mov a,#CLEAR ;очищаем экран
acall WRITE_LCD_IR
mov a,#SET_POS_4 ;устанавливаем позицию 4
acall WRITE_LCD_IR
mov a,#'o' ;выводим сообщение
acall WRITE_LCD_DR
mov a,#'b'
acall WRITE_LCD_DR
mov a,#'/'
acall WRITE_LCD_DR
mov a,#'m'
acall WRITE_LCD_DR
ret
end
[/code]