на 15 ноге висит клавиатура у меня - нужно переделать схему подключения! за одно обрати внимание, что у меня при нажатии генерится "1" Ты говорил что должен генерится "0" может это тоже стоит переделать ???
_________________ не зная броду не лезь к вольтмоду
ну и ждем'c исправленный код чтения клавиатуры... (заодно посмотрим как ты усвоил прежний урок)
по поводу 0 или 1 - это пофигу..
для твоего решения даже наверное 1 лучше
вообще я не люблю матричные клавиатуры - не получается на них нормально несколько нажатых кнопок отрабатывать
кстати по выходным линиям я бы вместо резюков на 100 ом поставил диоды !! так как в матричной клаве могут быть неприятные сюрпризы при нажатии нескольких кнопок одновременно
а вот если одиночные кнопки (1 кнопка на 1 пин порта) то лучше включать внутренний подтягивающий резистор и все ! никаких внешних больше не нужно, кнопка (ну или выключатель) одной ногой на порт, другой на землю..
а вот если одиночные кнопки (1 кнопка на 1 пин порта) то лучше включать внутренний подтягивающий резистор и все ! никаких внешних больше не нужно, кнопка (ну или выключатель) одной ногой на порт, другой на землю..
у меня ног не хватит ! (надо атмегу 64 тогда юзать)
_________________ не зная броду не лезь к вольтмоду
keyboardread: ldi temp,5 ; количество столбцов клавы = пять
ldi R17,0b00000001 ; первый столбец
; загружаем адрес метки (key_buffer) находящейся в ОЗУ в регистровую пару X ldi XL,low (key_buffer) ; младший байт адреса ldi XH,high(key_buffer) ; старший байт адреса
keyboardread_loop: ; цикл опроса
out PortD,R17 ; выводим в порт "Д" значение "R17" для выбора столбца клавиатуры in R18,PinB ; прочитали состояние столбца
st X+,R18 ; сохраним в ОЗУ состояние столбца клавы, ; адрес в регстровой паре "X" автоматом увеличится на 1
lsl R17 ; сдвинули единичку выбора столбца клавиатуры на 1 ; позицию влево
dec temp ; уменьшим счетчик brne keyboardread_loop ; если не все просканировали, то циклимся
ret ; возврат из подпрограммы
_________________ не зная броду не лезь к вольтмоду
ldi Temp,0b11110000 out DDRB,Temp ;настроили порт "В" ;х0000000 - вывод на передатчик ;00Х00000 - ДЛЯ ГЕНЕРАЦИИ (НЕ ЗНАЮ ЧТО ДЕЛАТЬ - ВЫХОД ИЛИ ВХОД) ;0000хххх - для чтения клавиатуры
ldi Temp,0b01111111 out DDRD,Temp ;настраиваем порт "D" на вывод(запись)(0-ввод, 1-вывод) ;но не весь, а только шесть млажших бит (PD0-PD5) ;к которым прицеплены четыре столбца клавиатуры ;и остальные настроил на вывод, для того что бы ;при их чтении получит не чёрте-че, а четкий ноль ;*только самый старши бит настроен на ВВОД (потому что в порте "D" отсутсвует эта нога)
;******************************************************************************* ; Чтение клавы и запись данных в ОЗУ ;*******************************************************************************
keyboardreed: ;метка - опрос клавиатуры
ldi Temp,5 ; количество столбцов клавы = пять
ldi Temp1,0b00000001 ; первый столбец
; загружаем адрес метки (key_buff) находящейся в ОЗУ в регистровую пару X ldi XL,low(key_buff) ; младший байт адреса ldi XH,high(key_buff) ; старший байт адреса
keyboardread_loop: ; цикл опроса
out PortD,Temp1 ; выводим в порт "Д" значение "Temp1" для выбора столбца клавиатуры in Temp2,PinB ; прочитали состояние столбца
st X+,Temp2 ; сохраним в ОЗУ состояние столбца клавы, ; адрес в регстровой паре "X" автоматом увеличится на 1
lsl Temp1 ; сдвинули единичку выбора столбца клавиатуры на 1 ; позицию влево
dec temp ; уменьшим счетчик brne keyboardread_loop ; если не все просканировали, то циклимся
rjamp keyboardreed ; зациклились бесконечно опрашивать клаву и перезаписывать данные
оо, кстати по написанию кода: на всех форумах программистов что я видел не приветствуется код вида
Код:
ldi Temp,0b01000000 ;разрешить прерывание компаратора out TIMSK,Temp
потому что без даташита нифига не понятно что за бит ты установил в TIMSK и могут даже не помочь (потому как лазать по даташиту с нуля как то геморойно)
нужно: посмотреть в даташите как называется пин разрешения прерывания (в нашем случае это OCIE1A), в .inc файле что ты вначале инклудишь он будет описан как:
то есть константе OCIE1A ему уже присвоен номер бита который нужно установить в порту
чтобы получить "1" в нужном разряде применяется левый сдвиг выполняемый компилятором
1 (единица =0b00000001) << (сдвинуть влево) OCIE1A (6 раз) то есть (1<<OCIE1A)
написать нужно вот так :
Код:
ldi Temp, (1<<OCIE1A) ;разрешить прерывание компаратора out TIMSK,Temp
если нужно несколько бит установить то применяется "|" то есть так: (1<<OCIE1A)|(1<<OCIE1B)
естественно это касается только установки в "1", в "0" ничего не устанавливаем
зачем это нужно ?
причину 1 я уже указал: банально код лучше читается - сразу понятно какое прерывание разрешили (без залезания в даташит)
причина 2 в меге32 например бит OCIE1A = 4 следовательно захотим мы перенести наш код на другой контроллер - работы будет в разы меньше (фактически в даташите мы только проверим чтобы бит OCIE1A был в том же регистре TIMSK, а все остальное будет компилироваться правильно)
подпричина 2 причины 2: у меня есть отладочная плата (pinboard) и я на меге16 чаще всего пишу код, и потом изменив только определение контроллера компилирую рабочий протестированный на меге16 код в туже тиньку2313 или мегу 8 (была у меня парочка маленьких проектов)
по тому что ты ночью написал: я просил проинициализировать таймер Т1 это регистры TCCR1A TCCR1B TCNT1 OCR1A TIMSK их все нужно инитить!
еще одно замечание: сначала мы инитим все регистры, а потом разрешаем прерывания
и вопрос: после какого действия инициализации счетчик Т1 начинает считать?
.cseg .org 0 rjmp RESET ; ну или START - как тебе приятнее :-)
.org INT0addr ; 0x0001 ; External Interrupt Request 0 reti .org INT1addr ; 0x0002 ; External Interrupt Request 1 reti .org ICP1addr ; 0x0003 ; Timer/Counter1 Capture Event reti .org OC1Aaddr ; 0x0004 ; Timer/Counter1 Compare Match A reti .org OC1addr ; 0x0004 ; For compatibility reti .org OVF1addr ; 0x0005 ; Timer/Counter1 Overflow reti .org OVF0addr ; 0x0006 ; Timer/Counter0 Overflow reti .org URXCaddr ; 0x0007 ; USART, Rx Complete reti .org URXC0addr ; 0x0007 ; For compatibility reti .org UDREaddr ; 0x0008 ; USART Data Register Empty reti .org UDRE0addr ; 0x0008 ; For compatibility reti .org UTXCaddr ; 0x0009 ; USART, Tx Complete reti .org UTXC0addr ; 0x0009 ; For compatibility reti .org ACIaddr ; 0x000a ; Analog Comparator reti .org PCIBaddr ; 0x000b ; Pin Change Interrupt Request B reti .org PCIaddr ; 0x000b ; For compatibility reti .org OC1Baddr ; 0x000c ; reti .org OC0Aaddr ; 0x000d ; reti .org OC0Baddr ; 0x000e ; reti .org USI_STARTaddr ; 0x000f ; USI Start Condition reti .org USI_OVFaddr ; 0x0010 ; USI Overflow reti .org ERDYaddr ; 0x0011 ; reti .org WDTaddr ; 0x0012 ; Watchdog Timer Overflow reti .org PCIAaddr ; 0x0013 ; Pin Change Interrupt Request A reti .org PCIDaddr ; 0x0014 ; Pin Change Interrupt Request D reti
команда компилятора .org помещает следующий за ней код по адресу метки адресов (типа PCIDaddr, OC1Aaddr ну в общем всех) указаны в inс файле по адресу если прерывание не используется сразу ставим RETI (возврат из прерывания) если прерывание используется то ставим RJMP и нужную нам метку процедуры обработчика прерываний
далее, задавать все регистры как temp1, temp2, temp3... тоже смысла не имеет, тогда уж оставь R16 R17 R18 .. - меньше кнопочек на клавиатуре нажимать придется если же хочешь сделать читабельно и красиво то называть нужно по функциям каждый регистр:
Код:
.def Temp=R16 ; это временный регистр для операций .def loopCount=R17 ; счетчик циклов .def bitPointer=R18 ; битовый указатель
опять таки кнопочек на клавиатуре придется нажимать много.. с другой стороны код более понятен будет...
кстати в какой программе собираешься писать ? inc файла attiny2313.inc например в avr studio нет, есть tn2313Adef.inc
первым делом после сброса мы запрещаем прерывания контроллера, почему то в примерах по avr так не пишут, хотя в давние времена когда правили бал i8080 и z80 программа всегда начиналась с запрещения прерываний (ну причина конечно есть, сейчас после сброса в avr сбрасываются все включенные прерывания, но вот на случай если выполнен не аппаратный сброс а переход на адрес 0 - прерывания лучше все таки выключить вручную)
Код:
RESET: cli ; запретили прерывания
далее, мы инитим стек !! не стоит это откладывать на долго, потому как до инициализации стека ты не можешь использовать RCALL и прерывания
Код:
LDI temp, low(ramend) out spl, temp
причем помним что SP обычно двубайтовый регистр, и только в контроллерах с памятью 256 или меньше байт однобайтовый ! (это если вдруг захочешь перейти на что нить типа мег - у них памяти от 512 байт, следовательно нужно будет инитить и SPL и SPH)
потом инитим ВСЕ линии портов
Код:
ldi Temp,0b10000000 out DDRB,Temp ;настроили порт "В" ;х0000000 - выход на передатчик ;0000хххх - вход чтения клавиатуры
ldi Temp,0b00011111 out DDRD,Temp ;настраиваем порт "D" на вывод(запись)(0-ввод, 1-вывод), 5 младших линий на выход (линии клавиатуры)
и только потом настраиваем встроенные устройства контроллера: счетчики, компараторы, АЦП и так далее
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 21
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения