Из этого замечания на 30 стр. DS, следует, что выход из POWER-DOWN будет только при низком уровне на INT0.mig-11101 писал(а):...
Попробуйте так
Из этого замечания на 30 стр. DS, следует, что выход из POWER-DOWN будет только при низком уровне на INT0.mig-11101 писал(а):...
akl писал(а):Из этого замечания на 30 стр. DS, следует, что выход из POWER-DOWN будет только при низком уровне на INT0.mig-11101 писал(а):...
Попробуйте так
Код: Выделить всё
.DSEG
Variables: .byte 3
Variavles2: .byte 1
.CSEG
; Переменная лежит в памяти, сначала надо ее достать.
LDS R16, Variables ; Считать первый байт Variables в R16
LDS R17, Variables+1 ; Считать второй байт Variables в R17
LDS R18, Variables+2 ; Ну и третий байт в R18
; Теперь прибавим к ней 1, т.к. AVR не умеет складывать с константой, только
; вычитать, приходиться извращаться. Впрочем, особых проблем не доставляет.
SUBI R16,(-1) ; вообще то SUBI это вычитание, но -(- дает +
SBCI R17,(-1) ; А тут перенос учитывается. Но об этом потом.
SBCI R18,(-1) ; Математика в ассемблере это отдельная история
STS Variables,R16 ; Сохраняем все как было.
STS Variables+1,R17
STS Variables+2,R18Код: Выделить всё
SUBI R16,(-1) ; вообще то SUBI это вычитание, но -(- дает +
SBCI R17,(-1) ; А тут перенос учитывается. Но об этом потом.
SBCI R18,(-1) ; Математика в ассемблере это отдельная историяКод: Выделить всё
SUBI (Rd,K8) вычитание константы Rd=Rd-K8
SBCI (Rd,K8) вычитание константы с переносом Rd=Rd-K8-C
Спасибо за помощь. Все заработало как надо буду доделывать прогу.DX168B писал(а):Видать отправляешь в этот порт целый байт.
Отправив целый байт целиком в порт, ты влияешь на все выводы этого порта.
Если одна часть выводов, например порта D, настроена на выход, а другая на вход, то
лучше управлять выходами порта по отдельности и отслеживать
входы тоже по отдельности(как я писАл выше).
Ещё 2 полезные команды:
sbi - подать на отдельную ногу лог. 1 (подать ток)
cbi - подать на отдельную ногу лог. 0 (убрать ток)
А вот синтаксис:Код: Выделить всё
sbi PortD, 0 ;Запустить ногу PD0 cbi PortD, 0 ;Отрубить ногу PD0 sbi PortD, 1 ;Запустить ногу PD1 cbi PortD, 1 ;Отрубить ногу PD1 sbi PortD, 2 ;Запустить ногу PD2 cbi PortD, 2 ;Отрубить ногу PD2 sbi PortD, 3 ;Запустить ногу PD3 cbi PortD, 3 ;Отрубить ногу PD3 ; И т.д.
Где про этот флаг можно прочесть более подробно? Т.к. хочется понимать четко почему пишется код именно так, а не иначе.SII писал(а):C -- флаг переноса/заёма. Устанавливается в операциях сложения, вычитания, сравнения и сдвигов. С его помощью осуществляется, например, сложение или вычитание многобайтовых величин (собственно, тут пример именно такой).
ldi work,0
ldi work1,0
ldi work2,0
del3_0:
inc work
cpi work,30
brne del3_1
ret
del3_1:
inc work1
cpi work1,255
brne del3_1
jmp del3_2
del3_2:
inc work2
cpi work2,5
brne del3_2
jmp del3_0
Да, действительно, я никогда не задумывался об этом. Всегда использовал языки высокого уровня - задал себе тип и имя переменной и делай что хочешь в пределах диапазона допустимых значений. В ассемблере-же всё изнутриSII писал(а):Это Вам надо хорошо разобраться с двоичной арифметикой вообще -- как складываются и вычитаются двоичные числа "на бумаге" (тогда увидите, как возникают переносы и заёмы), а после этого -- как производится сложение-вычитание чисел, имеющих большую разрядность, чем используемый процессор (в Вашем случае процессор 8-разрядный, а числа -- 16-разрядные, но сама идея не зависит от конкретной разрядности). У всех компьютерных архитектур этот флаг присутствует, поэтому не играет роли, AVR это, PIC, IA-32... В общем, это основа основ
Код: Выделить всё
0001000110001100Код: Выделить всё
0001001010001010и сразу за ней вызывается вторая(такая же. только она перемещает из другой таблички число в младший рег. 16-битного таймера)next_time_H:;
; *
ldi work,0x00; *
out TIMSK,work;запретить прерывания таймерoв
ldi ZH,High(speed_value_delays_H1*2); *
ldi ZL,Low(speed_value_delays_H1*2); *
; *
; *
;
; *
add ZL,BLDC_cnt;указать адрес ячейки таблицы
adc ZH,work
;*
lpm; извлечь из флеш-памяти *
mov t_count1_H,r0;вывести значение
; *
out TCNT1H,t_count1_H;отправить в таймер *
ldi work,0b00000100;разрешить прерывание по переполнению *
out TIMSK,work ; *
; *
ret ;*
;*************************************
Таблички:next_time_L:;
; *
ldi work,0x00; *
out TIMSK,work;запретить прерывания таймерoв
ldi ZH,High(speed_value_delays_L*2); *
ldi ZL,Low(speed_value_delays_L*2); *
; *
; *
;
; *
add ZL,BLDC_cnt;
adc ZH,work
;
; *
lpm; *
mov t_count1_L,r0; *
out TCNT1L,t_count1_L; *
ldi work,0b00000100; *
out TIMSK,work ; *
; *
ret ;*
И другая типа такой же.speed_value_delays_L:
.db 0b11111111, 0b00000100, 0b00000100, 0b11111100, 0b00000100, 0b10010010, 0b00000100, 0b11111010, 0b00000000, 0b01001000
.db 0b11111010, 0b01010010, 0b01000110, 0b11111110, 0b10000100, 0b11001110, 0b00000100, 0b00001000, 0b00000010, 0b11011110
.db 0b10100110, 0b01011010, 0b00000100, 0b10011010, 0b00100110, 0b10101000, 0b00100000, 0b10011000, 0b11111100, 0b01100000
.db 0b11000100, 0b00010100, 0b01100100, 0b10110100, 0b00000100, 0b01000000, 0b10000110, 0b11000010, 0b11111110, 0b00111010
.db 0b01101100, 0b10011110, 0b11010000, 0b00000010, 0b00101010, 0b01010010, 0b10000100, 0b10100010, 0b11001010, 0b11110010
.db 0b00010000, 0b00111000, 0b01010110, 0b01110100, 0b10010010, 0b10110000, 0b11001110, 0b11100010, 0b00000000, 0b00010100
.db 0b00110010, 0b01000110, 0b01100100, 0b01111000, 0b10001100, 0b10100000, 0b10110100, 0b11001000, 0b11011100, 0b11110000
.db 0b00000100, 0b00011000
Первые 3 бита регистра TCCR1B отвечают(по крайней мере в меге16) за предделитель тактовой частоты. Зачем его сбрасывать а потом устанавливать в прерывании, если можно запретить прерывание по переполнению(а по выходу из прерывания разрешить) и обнулить счётчики(собсно это у вас есть). Не подумайте, что придираюсь: просто интересно.T1_OVER1:
OUT TCCR1B,ZERO ;остановить таймер
OUT TCNT1H,ZERO
OUT TCNT1L,ZERO
RCALL NEXT
OUT TIFR,_FF ; сброс флагов Т1
OUT TCCR1B,A ; запусить таймер
Интересует зачем здесь применена строчка АDIW ZL,1.NEXT:
ldi ZH,High(T_speed1*2); *
ldi ZL,Low(T_speed1*2); *
add ZL,BLDC_cnt ;указать адрес ячейки таблицы
adc ZH,ZERO
LPM; извлечь из флеш-памяти *
OUT TCNT1H,R0;отправить в таймер *
ADIW ZL,1
LPM
OUT TCNT1L,R0;отправить в таймер *
INC BLDC_cnt ; только для теста!!!!!!!
INC BLDC_cnt ; только для теста!!!!!!!
ret ;*
Проще, если требуется последовательно извлекать из таблички. А если изменение счётчика должно происходить, допустим, по нажатию кнопки, то не очень.Если это мега16, то проще использовать команду LPM Rxx,Z+
Liv абсолютно прав и для данного случая, ведь из таблички извлекается больше одного байта. Если уж на асме писать, то зачем делать хуже, чем сделает С-компилятор?Roman Venom писал(а):Проще, если требуется последовательно извлекать из таблички. А если изменение счётчика должно происходить, допустим, по нажатию кнопки, то не очень.
Код: Выделить всё
...
adc ZH,ZERO
LPM R0, Z+
OUT TCNT1H,R0
; и эта команда оказалась не нужна ; ADIW ZL,1
LPM
OUT TCNT1L,R0
...Код: Выделить всё
...
adc ZH, ZERO
LPM R0, Z+ ; младший
LPM ZL, Z ; старший
OUT TCNT1H, ZL ; старший
OUT TCNT1L, R0 ; младший
...