Страница 1 из 1
помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 08:54:22
nickfreem
всем привет!написал прошивку для управления шаговым двигателем...не работает,не могу найти ошибку.особо опыта в програмировании нету.может кто подскажет что не так?
контроллер атмега16а с ножек PB0-PB3 сигнал идет на драйвер L293e.PB6 PB7 подключены светодиоды для индикации режима работы (шаг\полушаг) PD5 переключатель режимов.сейчас у меня оба светодиода горят в раз независимо от положения переключателя
.include"m16def.inc"
rjmp start
.def tmp=R16
.def counter=R17
.def nulreg=R19
.org OC1Aaddr
rjmp Obrabot
.org $30
start:
ldi tmp,High(Ramend)
out SPH,tmp
ldi tmp,Low(Ramend)
out SPL,tmp
ldi tmp,0b11001111
out DDRB,tmp
ldi tmp,~(1<<PD5)
out DDRD,tmp
ldi tmp,(1<<5)
out PORTD,tmp
ldi tmp,(1<<WGM12)|(1<<CS11)|(1<<CS10)
out TCCR1B,tmp
ldi tmp,High(625)
out OCR1AH,tmp
ldi tmp,Low(625)
out OCR1AL,tmp
ldi tmp,(1<<OCIE1A)
out TIMSK,tmp
sei
ldi counter,0
end:
rjmp end
Obrabot:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
Rcall Half_step
sbis PIND,5
Rcall Full_step
reti
Half_step:
ldi ZH,High(Table2)
ldi ZL,Low(Table2)
add ZL,counter
adc ZH,nulreg
lsl ZL
rol ZH
lpm tmp,Z
out PORTB,tmp
inc counter
reti
Full_step:
ldi ZH,High(Table1)
ldi ZL,Low(Table1)
add ZL,counter
adc ZH,nulreg
lsl ZL
rol ZH
lpm tmp,Z
out PORTB,tmp
inc counter
reti
.org $300
Table1:
.dw 0b10001000
.dw 0b10000100
.dw 0b10000010
.dw 0b10000001
.dw 0b10001000
.dw 0b10000100
.dw 0b10000010
.dw 0b10000001
Table2:
.dw 0b01001000
.dw 0b01001100
.dw 0b01000100
.dw 0b01000110
.dw 0b01000010
.dw 0b01000011
.dw 0b01000001
.dw 0b01001001
Re: помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 17:28:36
ANALOG
Используйте тег
Код: Выделить всё
, если выкладываете исходники. :wink:
По поводу самого кода - первое что бросается в глаза - нечетное число байт в строках массива. Попробуйте добавить нолики в каждую строку.
UPD: А нет, дело не в этом, я не заметил что стоит .dw
В метке Rezhim
переход по адресам Full_Step и Half_Step должен осуществляться с помощью rjmp, а не rcall. Так как rcall сохраняет в стек текущий адрес, и потом у вас из прерывания получится выход по неправильному адресу когда прога дойдет до reti
В общем, попробуйте поменять rcall на rjmp
Re: помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 19:23:36
Alkul
nickfreem писал(а):не работает,не могу найти ошибку.особо опыта в програмировании нету.может кто подскажет что не так?
Я вообще не увидел таблицы векторов. Где команда .org 0x00 ?
Посмотрите вот
эту тему, там сказано, как правильно оформлять заголовок программы
Увидел самую главную ошибку: в модели памяти ATmega16 в таблице векторов нужно использовать команды jmp, а не rjmp, потому что там под каждый вектор отводится два слова, а не одно.
Ну и согласен с предыдущим оратором насчет того, что вместо rcall нужно использовать rjmp. Причем лучше использовать jmp, а не rjmp. В связи с тем, что у команды rjmp ограничена "дальность" перехода. Не нужно надеяться, что компилятор выдаст ошибку.
Еще момент. Вот этот участок кода:
Код: Выделить всё
Obrabot:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
Вам не кажется, что переход на метку Rezhim будет сделан в любом случае? К чему тогда команда brne?

Наверное, после команды
должна быть какая-то еще? Возможно, reti ? Трудно гадать, не зная, какую логику работы вы держали в голове, когда писали программу.
Еще один момент.
Вы инициализируете Counter значением 8 и сравниваете его с нулем. А в теле программы после меток
Вы делаете инкремент Counter'а. Это правильно? Его нужно увеличивать на 1? Или, быть может, все же уменьшать? Тогда нужна команда dec counter, а не inc counter.
Re: помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 20:44:58
ANALOG
Alkul писал(а):Где команда .org 0x00 ?
Да это можно не писать, и так ведь с нуля команды идут
Alkul писал(а):Еще момент. Вот этот участок кода:
Код: Выделить всё
Obrabot:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
...
Вы инициализируете Counter значением 8 и сравниваете его с нулем.
Не, тут тоже все правильно. Obrabot - это обработчик прерывания от таймера.
При входе в него первым делом значение counter сравнивается с 8
и если не равно - то сразу переходим к Rezhim, а если равно - то скидываем в 0 и идем дальше в Rezhim (где потом и делается инкремент этого регистра).
Таким образом, counter все время крутится от 0 до 7.
Re: помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 20:51:36
Alkul
ANALOG писал(а):Alkul писал(а):Где команда .org 0x00 ?
Да это можно не писать, и так ведь с нуля команды идут
А компилятор об этом знает?

Re: помогите разобраться с прошивкой
Добавлено: Ср янв 15, 2014 20:59:04
ANALOG
Ну да, если после .cseg сразу код писать, он с нуля и пойдет в прошивку.
А вот, куда сам .cseg делся - вот это действительно интересно
И все-таки мне кажется, что ошибка в массивах с пустыми байтами.
ТС, попробуйте вот такой код:
Спойлер
Код: Выделить всё
.include"m16def.inc"
.cseg
rjmp start
.def tmp=R16
.def counter=R17
.def nulreg=R19
.org OC1Aaddr
rjmp Obrabot
.org $30
start:
ldi tmp,High(Ramend)
out SPH,tmp
ldi tmp,Low(Ramend)
out SPL,tmp
ldi tmp,0b11001111
out DDRB,tmp
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
out DDRD,tmp
ldi tmp,(1<<5)
out PORTD,tmp
ldi tmp,(1<<WGM12)|(1<<CS11)|(1<<CS10)
out TCCR1B,tmp
ldi tmp,High(625)
out OCR1AH,tmp
ldi tmp,Low(625)
out OCR1AL,tmp
ldi tmp,(1<<OCIE1A)
out TIMSK,tmp
sei
ldi counter,0
end:
rjmp end
Obrabot:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
rjmp Half_step
sbis PIND,5
rjmp Full_step
reti
Half_step:
ldi ZH,High(Table2*2) ;вместо lsl ZL rol ZH можно сразу вбить удвоенные адреса
ldi ZL,Low(Table2*2)
add ZL, counter ;добавляем counter 2 раза чтобы пропустить нули из массива
adc ZL, counter
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
Full_step:
ldi ZH,High(Table1*2)
ldi ZL,Low(Table1*2)
add ZL, counter
adс ZL, counter ;здесь то же самое
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
;.org $300
;зачем тут .org $300 - непонятно. Компилятор и так массив разместит после того кода, что написан выше
;а вот если вы, вдруг, допишете еще кода и он уже не будет влезать в $300 - то это только лишних проблем добавит
Table1:
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
Table2:
.db 0b01001000, 0
.db 0b01001100, 0
.db 0b01000100, 0
.db 0b01000110, 0
.db 0b01000010, 0
.db 0b01000011, 0
.db 0b01000001, 0
.db 0b01001001, 0
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 07:28:27
Alkul
ANALOG писал(а):
ТС, попробуйте вот такой код:
Код: Выделить всё
.cseg
rjmp start
.def tmp=R16
.def counter=R17
.def nulreg=R19
.org OC1Aaddr
rjmp Obrabot
Для AVR с памятью 16кБ нужно писать не rjmp, а jmp. В таблице векторов прерываний под каждый вектор отводится 2 слова памяти, а не одно. Пусть тредстартер сразу привыкает писать правильно.
И тему, на которую я дал ссылку ранее, тоже стоит изучить. Так, как оформил таблицу векторов прерываний тредстартер, а равно и так, как написали Вы, нельзя. И в той теме я писал, почему, и чем чревато иное оформление таблицы. Приводил пример того, как это нужно делать правильно.
И еще
Код: Выделить всё
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
С точностью до наоборот.
конструкция вида
установит бит 5. а не сбросит. То есть, код
даст в регистре tmp результат 0b00100000, а не 0b11011111. Попробуйте в симуляторе.
А тредстартеру я, пожалуй, тоже посоветую пользоваться симулятором (например, AVR Studio) для отладки "логики" программы. Там сразу будет видно, как массивы заполняются, как прерывание вызывается и так далее. На все вопросы тредстартер получит ответ самостоятельно. Это и для наработки опыта полезно.
И еще рекомендация тредстартеру - пишите комментарии. Сам в начале сталкивался с этим. Напишешь программу, вроде все в ней понятно. А потом вернешься к ней через полгодика - уже ничего не помнишь. Приходится заново вникать.
Позволю себе привести пример того, как пишу программы я. Привожу кусок обработчика прерывания по приему байта по UART, взятый из одной разработки:
Спойлер
Код: Выделить всё
;Подпрограмма обработки прерывания по получению байта по USART --------------------------------------------------------------------------
adrURXC: ;USART RX Complete Handler
push R16 ;Сохранить на стеке рег.R16
in R16,SREG ;Сохранить на стеке
push R16 ;регистр состояния SREG
push YL ;Сохранить на стеке
push YH ;рег.пару Y
push R17 ;Сохранить на стеке рег.R17
push R18 ;Сохранить на стеке рег.R18
lds R16,UDR0 ;Занести принятый по USART байт в рег.R16
lds R17,RECVBYT ;Занести в рег.R17 кол-во принятых байт пакета
tst R17 ;Кол-во принятых байт равно нулю? (это первый байт пакета?)
brne USRXC2 ;Если нет, то переход на метку USRXC2
;Принят первый байт пакета (байт адреса)
;Инициализировать таймер 2 на отсчет 5мс, за которые весь пакет должен быть принят
USRXC1: ;
;Инициализировать таймер-счетчик 2 на отсчет интервала 5 мс. По окончанию интервала - сбрасывать USART и обнулять счетчик принятых байт
lds YL,FLAGS ;Занести в рег.YL содержимое ячейки FLAGS
andi YL,NONSELDELAY ;Обнулить бит SELDELAY для того, чтобы переполнение таймера-счетчика 2 обрабатывалось как отсчет
;времени приема пакета запроса
sts FLAGS,YL ;Сохранить в памяти новое значение ячейки FLAGS
ldi YL,0x9F ;Инициализировать таймер-счетчик
sts TCNT2,YL ;на отсчет 5мс при тактовой частоте 20МГц и коэффициенте деления 1024
ldi YL,0x07 ;Запустить таймер-счетчик 2
sts TCCR2B,YL ;с коэффициентом деления тактовой частоты 1024
ldi YL,(1<<TOIE2) ;Разрешение прерываний
sts TIMSK2,YL ;по переполнению таймер-счетчика 2
rjmp USRXC3 ;Перейти на метку USRXC3 для записи принятого байта в буфер принимаемого пакета
;Принят не первый байт пакета
USRXC2:
cpi R17,0x02 ;Принят третий байт пакета?
brne USRXC3 ;Если нет, то переход на метку USRXC3
;Принят третий байт пакета, откорректировать длину принимаемого пакета
ldi YL,0x05 ;В рег. YL занести кол-во служебных байт пакета (без учета длины поля данных)
add YL,R16 ;Теперь в рег.YL общая длина принимаемого пакета
sts LONGRECV,YL ;Сохранить новое значение длины пакета в ячейке LONGRECV
;Запись полученного по USART байта в буфер принимаемого пакета
USRXC3:
ldi YL,low(BUFRECV) ;Занести в рег.пару Y
ldi YH,high(BUFRECV) ;адрес начала буфера принимаемого пакета
add YL,R17 ;Прибавить к адресу начала буфера смещение,
brcc USRXC4 ;соответствующее адресу текущего
inc YH ;принимаемого байта
USRXC4:
st Y,R16 ;Сохранить текущий принятый байт в буфер принимаемого пакета
lds R16,LONGRECV ;Занести в рег.R16 длину принимаемого пакета
inc R17 ;Инкремент кол-ва принятых байт
cp R17,R16 ;Принят весь пакет данных?
brlo USRXC4_0 ;Если кол-во принятых байт меньше длины пакета, то пакет принят не полностью,
;переход на метку USRXC100
rjmp USRXC4_1 ;Иначе пакет принят полностью, перейти на метку USRXC4_1
USRXC4_0:
rjmp USRXC100 ;Пакет принят не полностью, перейти на метку USRXC100
USRXC4_1:
;Иначе принят весь пакет, рассчитать CRC принятого пакета
subi R17,0x02 ;Вычислить длину пакета за вычетом двух байт CRC
sts LENPAK,R17 ;Занести уменьшенную на 2 длину пакета в ячейку LENPAK
ldi YL,low(BUFRECV) ;Занести в рег.пару Y
ldi YH,high(BUFRECV) ;адрес начала буфера принимаемого пакета
call CRC ;Вызвать подпрограмму расчета CRC, результат в ячейках CRC_L и CRC_H
ldi YL,low(BUFRECV) ;Занести в рег.пару Y
ldi YH,high(BUFRECV) ;адрес начала буфера принимаемого пакета
add YL,R17 ;Прибавить к адресу начала буфера смещение,
brcc USRXC5 ;соответствующее адресу текущего
inc YH ;принимаемого байта
;Сейчас в рег.паре Y адрес младшего байта CRC принятого пакета
USRXC5:
ld R17,Y+ ;Занести в рег.R17 ст.байт принятой CRC
lds R16,CRC_H ;Занести в рег.R16 ст.байт рассчитанной CRC
cp R16,R17 ;Сравнить рассчитанный и принятый младшие байты CRC
brne USRXC_BAD ;Если они не равны, перейти на метку USRXC_BAD для отмены принятия пакета
ld R17,Y ;Занести в рег.R17 мл.байт принятой CRC
lds R16,CRC_L ;Занести в рег.R16 мл.байт рассчитанной CRC
cp R16,R17 ;Сравнить рассчитанный и принятый старшие байты CRC
brne USRXC_BAD ;Если они не равны, перейти на метку USRXC_BAD для отмены принятия пакета
;CRC принятого пакета верна
ldi YL,low(BUFRECV) ;Занести в рег.пару Y
ldi YH,high(BUFRECV) ;адрес первого байта, хранящего адрес целевого детектора
ld R16,Y+ ;Занести в рег.R16 байт KOPLEN
;Проверка предназначения пакета
lds R17,ADDRESS ;Занести в рег.R17 собственный адрес детектора
cp R16,R17 ;Сравнить собственный адрес с адресом целевого детектора
breq USRXC6 ;Если адреса равны, переход на проверку кода команды
rjmp USRXC_BAD ;Иначе пакет предназначен для другого детектора
С первого взгляда кажется, что такой стиль требует гораздо бОльшего времени для написания кода, но это не так. А уж при отладке и сопровождении программы экономит кучу времени.
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 14:28:45
ANALOG
Alkul писал(а):ANALOG писал(а):
Код: Выделить всё
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
конструкция вида
установит бит 5. а не сбросит.
То есть, код
даст в регистре tmp результат 0b00100000
Совершенно верно, но обратите внимание на символ
~ в оригинальной версии от ТС
После инверсии то, что вы написали превратится в 0b11011111 - и в итоге, PD5 настроен на вход, а все остальные порты - на выход. А зачем настраивать лишние порты на выход, если они не используются? Чтобы спалить их, случайно дотронувшись отверткой?
Насчет прерываний - это да, лучше конечно использовать jmp вместо rjmp, но при использовании одного единственного прерывания это погоды не сделает, ну а ели по-хорошему делать, то таблица прерываний для ATmega16 будет представлять собой что-то вроде этого:
Спойлер
Код: Выделить всё
.cseg
jmp RESET ; Reset Handler
jmp EXT_INT0 ; IRQ0 Handler
jmp EXT_INT1 ; IRQ1 Handler
jmp TIM2_COMP ; Timer2 Compare Handler
jmp TIM2_OVF ; Timer2 Overflow Handler
jmp TIM1_CAPT ; Timer1 Capture Handler
jmp TIM1_COMPA ; Timer1 CompareA Handler
jmp TIM1_COMPB ; Timer1 CompareB Handler
jmp TIM1_OVF ; Timer1 Overflow Handler
jmp TIM0_OVF ; Timer0 Overflow Handler
jmp SPI_STC ; SPI Transfer Complete Handler
jmp USART_RXC ; USART RX Complete Handler
jmp USART_UDRE ; UDR Empty Handler
jmp USART_TXC ; USART TX Complete Handler
jmp ADC ; ADC Conversion Complete Handler
jmp EE_RDY ; EEPROM Ready Handler
jmp ANA_COMP ; Analog Comparator Handler
jmp TWSI ; Two-wire Serial Interface Handler
jmp EXT_INT2 ; IRQ2 Handler
jmp TIM0_COMP ; Timer0 Compare Handler
jmp SPM_RDY
EXT_INT0:
EXT_INT1:
TIM2_COMP:
TIM2_OVF:
TIM1_CAPT:
;TIM1_COMPA:
TIM1_COMPB:
TIM1_OVF:
TIM0_OVF:
SPI_STC:
USART_RXC:
USART_UDRE:
USART_TXC:
ADC:
EE_RDY:
ANA_COMP:
TWSI:
EXT_INT2:
IM0_COMP:
SPM_RDY:
reti
TIM1_COMPA:
Obrabot:
...
...
RESET:
...
...
При использовании какого-либо прерывания - закомментить его в блоке "заглушек" и вынести отдельно. Кстати, ТС на заметку - обработчикам прерываний лучше не давать имена типа "Obrabot", а оставлять названия как в даташите, чтобы было понятно где какое прерывание обрабатывается. Ну это так, из области придирок к оформлению
Примечание: код приведен в качестве примера как делать, и возможно, нужно будет поменять имена некоторым прерываниям, если окажется, что такие имена уже заняты (например, ADC так точно уже занято - это команда сложения с флагом переноса)
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 17:28:43
Alkul
ANALOG писал(а):ну а ели по-хорошему делать, то таблица прерываний для ATmega16 будет представлять собой что-то вроде этого
Выше я давал
ссылку на тему, где сам все это подробно и расписывал
ANALOG писал(а):После инверсии то, что вы написали превратится в 0b11011111 - и в итоге, PD5 настроен на вход, а все остальные порты - на выход.
А инверсию-то зачем делать? Я согласен, что на выход нужно настраивать только те порты, которые задействуются как выходы.
Вы приводите исходник со строками:
Код: Выделить всё
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
out DDRD,tmp
Я так понял, что бит PD5 у автора задействуется, как переключатель режимов. То есть, должен быть выходом. А Вы в DDRD нуль записываете.
Нужен выход на PD5 - значит, писать
И никаких проблем. Остальные выводы порта D останутся входами.
Но что-то странное - Вы не находите? Мы тут с Вами дискутируем, а тредстартер куда-то пропал. Оно ему вообще надо? Может, мы тут зря время тратим?

Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 20:12:49
ANALOG
Alkul писал(а):Я так понял, что бит PD5 у автора задействуется, как переключатель режимов. То есть, должен быть выходом. А Вы в DDRD нуль записываете.
Тут мы с вами видимо, по-разному понимаем задумку автора, но мне кажется, что PD5 все-таки должен быть входом, т.к. далее в коде идет чтение из PinD:
Код: Выделить всё
Rezhim:
sbic PIND,5
rjmp Half_step
sbis PIND,5
rjmp Full_step
reti
То есть, к PD5 подключен переключатель, которым извне управляется работа МК в одном из 2-х режимов.
Alkul писал(а):А инверсию-то зачем делать?
Совершенно незачем, но у автора-то она делается (символ
~):
О чем я и говорю, автор настраивает PD5 на вход с помощью значения ~(1<<PD5), что эквивалентно записи 0b11011111. В общем-то, цель достигнута - в DDRD 5-й бит = нолик, соответственно PD5 = вход. Но при таком подходе все остальные биты становятся единичками, поэтому я и предлагаю в DDRD закинуть просто 0 = все порты на вход.
Но что-то странное - Вы не находите? Мы тут с Вами дискутируем, а тредстартер куда-то пропал. Оно ему вообще надо? Может, мы тут зря время тратим?

Крайне странно, сам хотел об этом написать.
nickfreem, отпишитесь, нам интересно ведь, исправленный код проверяли/не проверяли? Работает/не работает?
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 20:30:30
nickfreem
прошу прощения что замолчал..много читал а вот результатов особо не было поэтому и не отписывался.издевался над кодом и вот до чего дошел
Код: Выделить всё
Half_step:
ldi tmp,01000000
out PORTB,tmp
inc counter
reti
Full_step:
ldi ZH,High(Table1)
ldi ZL,Low(Table1)
add ZL,counter
adc ZH,nulreg
lsl ZL
rol ZH
lpm tmp,Z
out PORTB,tmp
inc counter
reti
.org $300
Table1:
.dw 0b10001000
.dw 0b10000100
.dw 0b10000010
.dw 0b10000001
.dw 0b10001000
.dw 0b10000100
.dw 0b10000010
.dw 0b10000001
в одном положении переключателя горит только PB7(full step)в другом положении когда должен гореть только PB6,горят оба..
.cseg добавил в начало кода.reti d full\half менял на ret.
так же убрал процедуру и забил всё через jmp но результата никакого..как горели оба так и горят
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 20:40:29
ANALOG
Тут вы 0b пропустили, а 01000000 компилятор понимает как десятичное число, а оно очень большое и в регистр точно никак не влезет. Наверняка компилятор выдал warning по этому поводу
Попробуйте полностью тот код, который я выкладывал:
Спойлер
Код: Выделить всё
.include"m16def.inc"
.cseg
rjmp start
.def tmp=R16
.def counter=R17
.def nulreg=R19
.org OC1Aaddr
rjmp Obrabot
.org $30
start:
ldi tmp,High(Ramend)
out SPH,tmp
ldi tmp,Low(Ramend)
out SPL,tmp
ldi tmp,0b11001111
out DDRB,tmp
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
out DDRD,tmp
ldi tmp,(1<<5)
out PORTD,tmp
ldi tmp,(1<<WGM12)|(1<<CS11)|(1<<CS10)
out TCCR1B,tmp
ldi tmp,High(625)
out OCR1AH,tmp
ldi tmp,Low(625)
out OCR1AL,tmp
ldi tmp,(1<<OCIE1A)
out TIMSK,tmp
sei
ldi counter,0
end:
rjmp end
Obrabot:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
rjmp Half_step
sbis PIND,5
rjmp Full_step
reti
Half_step:
ldi ZH,High(Table2*2) ;вместо lsl ZL rol ZH можно сразу вбить удвоенные адреса
ldi ZL,Low(Table2*2)
add ZL, counter ;добавляем counter 2 раза чтобы пропустить нули из массива
adc ZL, counter
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
Full_step:
ldi ZH,High(Table1*2)
ldi ZL,Low(Table1*2)
add ZL, counter
adс ZL, counter ;здесь то же самое
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
;.org $300
;зачем тут .org $300 - непонятно. Компилятор и так массив разместит после того кода, что написан выше
;а вот если вы, вдруг, допишете еще кода и он уже не будет влезать в $300 - то это только лишних проблем добавит
Table1:
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
Table2:
.db 0b01001000, 0
.db 0b01001100, 0
.db 0b01000100, 0
.db 0b01000110, 0
.db 0b01000010, 0
.db 0b01000011, 0
.db 0b01000001, 0
.db 0b01001001, 0
У вас точно в таблицах с этими .dw что-то не так пошло
А вот еще версия с "правильной" таблицей прерываний:
Спойлер
Код: Выделить всё
.include"m16def.inc"
.cseg
jmp RESET ; Reset Handler
jmp EXT_INT0 ; IRQ0 Handler
jmp EXT_INT1 ; IRQ1 Handler
jmp TIM2_COMP ; Timer2 Compare Handler
jmp TIM2_OVF ; Timer2 Overflow Handler
jmp TIM1_CAPT ; Timer1 Capture Handler
jmp TIM1_COMPA ; Timer1 CompareA Handler
jmp TIM1_COMPB ; Timer1 CompareB Handler
jmp TIM1_OVF ; Timer1 Overflow Handler
jmp TIM0_OVF ; Timer0 Overflow Handler
jmp SPI_STC ; SPI Transfer Complete Handler
jmp USART_RXC ; USART RX Complete Handler
jmp USART_UDRE ; UDR Empty Handler
jmp USART_TXC ; USART TX Complete Handler
jmp ADC ; ADC Conversion Complete Handler
jmp EE_RDY ; EEPROM Ready Handler
jmp ANA_COMP ; Analog Comparator Handler
jmp TWSI ; Two-wire Serial Interface Handler
jmp EXT_INT2 ; IRQ2 Handler
jmp TIM0_COMP ; Timer0 Compare Handler
jmp SPM_RDY
EXT_INT0:
EXT_INT1:
TIM2_COMP:
TIM2_OVF:
TIM1_CAPT:
;TIM1_COMPA:
TIM1_COMPB:
TIM1_OVF:
TIM0_OVF:
SPI_STC:
USART_RXC:
USART_UDRE:
USART_TXC:
ADC:
EE_RDY:
ANA_COMP:
TWSI:
EXT_INT2:
IM0_COMP:
SPM_RDY:
reti
RESET:
ldi tmp,High(Ramend)
out SPH,tmp
ldi tmp,Low(Ramend)
out SPL,tmp
ldi tmp,0b11001111
out DDRB,tmp
ldi tmp, 0b00000000 ;здесь лучше записать просто 0, а не ~(1<<PD5), т.к. ~(1<<PD5) = 11011111, а лишние порты на вывод - это нехорошо
out DDRD,tmp
ldi tmp,(1<<5)
out PORTD,tmp
ldi tmp,(1<<WGM12)|(1<<CS11)|(1<<CS10)
out TCCR1B,tmp
ldi tmp,High(625)
out OCR1AH,tmp
ldi tmp,Low(625)
out OCR1AL,tmp
ldi tmp,(1<<OCIE1A)
out TIMSK,tmp
sei
ldi counter,0
end:
rjmp end
TIM1_COMPA:
cpi counter,8
brne Rezhim
ldi counter,0
Rezhim:
sbic PIND,5
rjmp Half_step
sbis PIND,5
rjmp Full_step
reti
Half_step:
ldi ZH,High(Table2*2) ;вместо lsl ZL rol ZH можно сразу вбить удвоенные адреса
ldi ZL,Low(Table2*2)
add ZL, counter ;добавляем counter 2 раза чтобы пропустить нули из массива
adc ZL, counter
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
Full_step:
ldi ZH,High(Table1*2)
ldi ZL,Low(Table1*2)
add ZL, counter
adс ZL, counter ;здесь то же самое
adc ZH, nulreg
lpm tmp,Z
out PORTB,tmp
inc counter
reti
;.org $300
;зачем тут .org $300 - непонятно. Компилятор и так массив разместит после того кода, что написан выше
;а вот если вы, вдруг, допишете еще кода и он уже не будет влезать в $300 - то это только лишних проблем добавит
Table1:
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
.db 0b10001000, 0
.db 0b10000100, 0
.db 0b10000010, 0
.db 0b10000001, 0
Table2:
.db 0b01001000, 0
.db 0b01001100, 0
.db 0b01000100, 0
.db 0b01000110, 0
.db 0b01000010, 0
.db 0b01000011, 0
.db 0b01000001, 0
.db 0b01001001, 0
Re: помогите разобраться с прошивкой
Добавлено: Чт янв 16, 2014 20:50:39
Alkul
nickfreem писал(а):reti d full\half менял на ret.
А это зря. Метки Half_step и Full_step у Вас ведь в обработчике прерывания находятся. Команда reti в отличие от ret кроме обычных действий по выходу из подпрограммы еще и разрешает глобальные прерывания (бит I регистра SREG). Поставив после обработчика прерывания команду ret, Вы оставляете прерывания запрещенными при выходе из обработчика.
nickfreem писал(а):так же убрал процедуру и забил всё через jmp но результата никакого..как горели оба так и горят
Хотелось бы увидеть Ваш код целиком.
Скажите, Вы пробовали по моему совету "прогнать" его в симуляторе? Там ведь все будет видно - разрешены ли прерывания, вызывается ли обработчик, устанавливаются ли биты в регистрах портов.