Ссылки на цикл статей я вам давал. Читайте, там все разжевано и даже картинки есть. Вам осталось написать программу по этим картинкам.
Ассемблер (ASM) для AVR в вопросах и ответах
- Сообщения: 1495
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Ассемблер ничем не отличается от других языков в плане абстракций. Проектирование сверху вниз. Забудьте о регистрах, байтах и тактах. Устройство, блоки устройства, блоки блоков. Алгоритмы. Берете бумажку и составляете ТЗ. Рисуйте алгоритмы. Когда это у вас будет, тогда будут и программы. По сути, программы будут писаться по нарисованным алгоритмам. Пишите программы на ассемблере так, как будто вы пишете на языке высокого уровня.
Ссылки на цикл статей я вам давал. Читайте, там все разжевано и даже картинки есть. Вам осталось написать программу по этим картинкам.
Ссылки на цикл статей я вам давал. Читайте, там все разжевано и даже картинки есть. Вам осталось написать программу по этим картинкам.
- Реклама
[uquote="radio-fan",url="/forum/viewtopic.php?p=3189945#p3189945"]
Код: Выделить всё
;#############################################################################################
;ПРЕРЫВАНИЕ ПО КНОПКЕ
;#############################################################################################
EXT_INT0: in Temp, SREG ;сохраняем флаги в стек
push Temp ;
clr Temp ;
out GICR, Temp ;запрещаем прерывание по кнопке
out TCCR1B, Temp ;останавливаем компаратор
out TCCR0, Temp ;останавливаем таймер 0
out TCNT0, Temp ;очищаем регистр 0 таймера
cbr Flag, 0b01000000 ;длинного нажатия нет
sbrs Flag, 5 ;если 0 то было нажатие, если 1 то отпускание
rjmp PushCycl ;
clr Count ;
ldi Temp, 0b00000011 ;настройка предделителя
out TCCR1B, Temp ;вывод в TCCR1B
mov Temp, Flag ;сравниваем счётчик нажатий
andi Temp, 0b00001111 ;
cpi Temp, 11 ;
brne GO1 ;
andi Flag, 0b11110000 ;
rjmp GO2 ;
GO1: inc Flag ;
GO2: cbr Flag, 0b00100000 ;
ldi TimCount, 195 ;пауза 0,05 с
ldi Temp, 0b00000001 ;запускаем таймер 0
out TCCR0, Temp ;частота 1/8
clr count ;
pop Temp ;извлекаем флаги из стека
out SREG, Temp ;
reti
PushCycl: sbr Flag, 0b00100000 ;
ldi TimCount, 146 ;пауза 0,25 с
ldi Temp, 0b00000011 ;частота 1/32
out TCCR0, Temp ;
pop Temp ;извлекаем флаги из стека
out SREG, Temp ;
sei ;
rjmp Do ;конец прерывания[/uquote]Здесь будет срыв стека, т.к. выход из прерывания по RJMPясен пень, куда ж ему деваться-то?radio-fan писал(а): если из прерывания выходить не через reti, то в стеке будет оставаться адрес?
не смотря на то, что ассемблер позволяет делать, что угодно, все-таки хорошей практикой следует признать выход из прерывания туда, откуда был вход. собственно, как и из любой другой подпрограммы.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
RETI всего лишь сбрасывает блокировку прерываний
(восстанавливает флаг "глобального разрешения" I в регистре статуса SREG после того, как он будет АВТМАТИЧЕСКИ СБРОШЕН при входе в прерывание)
По обработке стека и RET и RETI
ОДНО И ТО ЖЕ.

(восстанавливает флаг "глобального разрешения" I в регистре статуса SREG после того, как он будет АВТМАТИЧЕСКИ СБРОШЕН при входе в прерывание)
По обработке стека и RET и RETI
ОДНО И ТО ЖЕ.
- Реклама
только речь проBOB51 писал(а):По обработке стека и RET и RETI
ОДНО И ТО ЖЕ
akl писал(а):rjmp Do ;конец прерывания
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
[uquote="radio-fan",url="/forum/viewtopic.php?p=3191470#p3191470"]...если из прерывания выходить не через reti, то в стеке будет оставаться адрес?[/uquote]Да, но указатель стека SP будет смещен и следующие прерывания с таким же условием будут его смещать и смещать. В итоге зависон обеспечен.
смотря как выходить
можно и "комбинированным" способом через "подстановку вектора возврата"... изменение значения самого указателя стека...
там важнее вопрос - допускается или нет на том участке "вложенное" внешнее прерывание.

можно и "комбинированным" способом через "подстановку вектора возврата"... изменение значения самого указателя стека...
там важнее вопрос - допускается или нет на том участке "вложенное" внешнее прерывание.
- Сообщения: 24
- Зарегистрирован: Вс июн 19, 2016 06:31:18
Всем спасибо за подсказку с этим "ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)" разобрался, в СИ то же пользуются таким приемом
- Сообщения: 89
- Зарегистрирован: Вт мар 31, 2015 01:12:46
Добрый день! Программа на АSM для тини2313 работает не совсем красиво, как того хотелось бы. Сразу скажу, в качестве практического развития пытаюсь сделать освещения на, как бы, модель автомобиля. Есть 4 кнопки, 4 пары св-диодов. Нажимаем кн1-вкл поворот влево, кн2- передний свет и т.д. Далее будет идти речь только о левом повороте и переднем освещении (для простоты и понятности изложения).
Чего хочется: есть две кнопки( с фиксацией). Нажимаем одну - первая пара св-диодов должна моргать (частота 1Гц). Нажимаем вторую кнопку - другая пара св-диодов должна просто засветится.
Что не получается: программа работает правильно, НО! не красиво... допустим, я нажал на кн1 и через долю секунды на кн2. Первая пара св-диодов загорелась, вторая пара тоже уже должна загореться, НО! МК в это время выполняет задержку для свечения первой пары, затем выключит первую пару и вновь 0,5секунды будет выполнять задержку и лишь затем включит мне вторую пару... и эта небольшая задержка во вкл 2-рой пары создает в моей душе неприятный осадок
)))
У меня была идея
по коду программы по чаще растолкать команду опроса вкл 2-рой пары, но... интуиция новичка мне подсказывает, что это не профессионально
Код программы:
;Инициализация портов
clr R16
out DDRD,R16
ser R16
out PORTD,R16
out DDRB,R16
clr R16
out PORTB,R16
;Основной цикл
MAIN:
check_L:sbis PIND,PIND0 ;Запрос вкл левой пары
rjmp left
cbi PORTB,7
cbi PORTB,6
check_F:sbis PIND,PIND1 ;Запрос вкл передней пары
rjmp frwrd
cbi PORTB,5
cbi PORTB,4
rjmp MAIN
left: sbi PORTB,7 ;Вкл левой пары
sbi PORTB,6
rcall delay_LR
cbi PORTB,7
cbi PORTB,6
rcall delay_LR
rjmp check_F
frwrd: sbi PORTB,5 ;Вкл передней пары
sbi PORTB,4
rjmp check_L
delay_LR:
; ===========
; delay loop generator
; 500000 cycles:
(Задержку вырезал да бы не засорять эфир)
ret
Спасибо за ответ!
Чего хочется: есть две кнопки( с фиксацией). Нажимаем одну - первая пара св-диодов должна моргать (частота 1Гц). Нажимаем вторую кнопку - другая пара св-диодов должна просто засветится.
Что не получается: программа работает правильно, НО! не красиво... допустим, я нажал на кн1 и через долю секунды на кн2. Первая пара св-диодов загорелась, вторая пара тоже уже должна загореться, НО! МК в это время выполняет задержку для свечения первой пары, затем выключит первую пару и вновь 0,5секунды будет выполнять задержку и лишь затем включит мне вторую пару... и эта небольшая задержка во вкл 2-рой пары создает в моей душе неприятный осадок
У меня была идея
Код программы:
;Инициализация портов
clr R16
out DDRD,R16
ser R16
out PORTD,R16
out DDRB,R16
clr R16
out PORTB,R16
;Основной цикл
MAIN:
check_L:sbis PIND,PIND0 ;Запрос вкл левой пары
rjmp left
cbi PORTB,7
cbi PORTB,6
check_F:sbis PIND,PIND1 ;Запрос вкл передней пары
rjmp frwrd
cbi PORTB,5
cbi PORTB,4
rjmp MAIN
left: sbi PORTB,7 ;Вкл левой пары
sbi PORTB,6
rcall delay_LR
cbi PORTB,7
cbi PORTB,6
rcall delay_LR
rjmp check_F
frwrd: sbi PORTB,5 ;Вкл передней пары
sbi PORTB,4
rjmp check_L
delay_LR:
; ===========
; delay loop generator
; 500000 cycles:
(Задержку вырезал да бы не засорять эфир)
ret
Спасибо за ответ!
4 кнопки (да еще и с фиксацией!) и 4 светика (группы светиков) это задача для релейно-контактной логики (не то чтоб для МК). Ну отсилы еще пару NE555...
а тут "МК не справляется"...

а тут "МК не справляется"...
- Сообщения: 1849
- Зарегистрирован: Вс дек 25, 2016 08:34:54
Я бы использовал таймер (частота 1Гц), в прерывании таймера изменял бы состояние первой пары св-диодов.dumbass писал(а):Программа на АSM для тини2313...Чего хочется: есть две кнопки( с фиксацией). Нажимаем одну - первая пара св-диодов должна моргать (частота 1Гц). Нажимаем вторую кнопку - другая пара св-диодов должна просто засветится.
В основном цикле опрашивал бы кнопки без каких либо задержек, ну разве что на дребезг.
При опросе первой кнопки принимаем решение о запуске таймера или даем разрешение таймеру моргать первой парой св-диодов.
При опросе второй кнопки - зажигаем вторую пару св-диодов.
Где-то так.
- Сообщения: 89
- Зарегистрирован: Вт мар 31, 2015 01:12:46
Спасибо за ответы!!!
С помощью NE555 не хочется решать так проблему. Хочется решить программно, а не аппаратно ( для того ж и изучаю МК
)
Буду пытаться на таймерах... нужно только до них добраться их изучить как следует.
Спасибо за понятный алгоритм и видео, очень доходчиво и понятно.
Если получится, то обязательно поделюсь результатами
С помощью NE555 не хочется решать так проблему. Хочется решить программно, а не аппаратно ( для того ж и изучаю МК
Буду пытаться на таймерах... нужно только до них добраться их изучить как следует.
Спасибо за понятный алгоритм и видео, очень доходчиво и понятно.
Если получится, то обязательно поделюсь результатами
Если с пониманием таймеров сложности, можно и без них. Просто не использовать полусекундные задержки, а дробить их на более короткие.
[uquote="dumbass",url="/forum/viewtopic.php?p=3208923#p3208923"]... Хочется решить программно, а не аппаратно ( для того ж и изучаю МК
)...[/uquote]
Ну ежли только для учебы...
Есть буфер ввода (одновременно ВСЕ ВОЗМОЖНЫЕ комбинации кнопок) и есть буфер вывода (одновременно ВСЕ ВОЗМОЖНЫЕ комбинации включения светиков) есть таймер опроса и таймер инвертора... (независимо - программные или аппаратные).
Можно еще флажок добавить - разрешение работы инвертора.
Итогом - согласно статуса считанного состояния входных линий активируем соответствующие позиции выходных сигналов и флаг разрешения работы инвертора.
Порционно выпихиваем содержимое буфера вывода в порт вывода. А инвертор в ведомы ему моменты меняет статус нужных ему бит в буфере (пока ессно его работа разрешена флажком).

Ну ежли только для учебы...
Есть буфер ввода (одновременно ВСЕ ВОЗМОЖНЫЕ комбинации кнопок) и есть буфер вывода (одновременно ВСЕ ВОЗМОЖНЫЕ комбинации включения светиков) есть таймер опроса и таймер инвертора... (независимо - программные или аппаратные).
Можно еще флажок добавить - разрешение работы инвертора.
Итогом - согласно статуса считанного состояния входных линий активируем соответствующие позиции выходных сигналов и флаг разрешения работы инвертора.
Порционно выпихиваем содержимое буфера вывода в порт вывода. А инвертор в ведомы ему моменты меняет статус нужных ему бит в буфере (пока ессно его работа разрешена флажком).
Надо просто правильно разбить программу на задачи. Сделайте так называемый суперцикл, который будет выполняться с заранее заданной задержкой - например 10мс. В этом цикле, смотрим на кнопки и выставляем в переменной "флажки". Задача простая как 5 копеек, не правда ли?
Вторая задача - на каждый флажок своя ветка в суперцикле, с немигающими фарами понятно - ничего дополнительно анализировать не надо, просто смотрим на КОНКРЕТНЫЙ флажок и включаем нужную пару светодиодов, или выключаем.
Немного сложнее с поворотами - для каждого из них заводишь дополнительную переменную счетчик - когда флажок поворота неактивен - принудительно гасим соответствующий светодиод и ОБНУЛЯЕМ его счетчик, если флажок активен - и счетчик равен нулю - меняем состояние светодиода на противоположное. Инкрементируем счетчик, и когда он достигает значения 100(или 50?) - сбрасываем. Всё.
В итоге имеем не одну монолитную программу которую сложно отлаживать, а отдельные блоки логика которых просматривается прозрачно(зависит исключительно от строго указанных входных данных и имеет конкретный легко проверяемый результат работы) и которые отлаживать можно отдельно от остальных.
Вторая задача - на каждый флажок своя ветка в суперцикле, с немигающими фарами понятно - ничего дополнительно анализировать не надо, просто смотрим на КОНКРЕТНЫЙ флажок и включаем нужную пару светодиодов, или выключаем.
Немного сложнее с поворотами - для каждого из них заводишь дополнительную переменную счетчик - когда флажок поворота неактивен - принудительно гасим соответствующий светодиод и ОБНУЛЯЕМ его счетчик, если флажок активен - и счетчик равен нулю - меняем состояние светодиода на противоположное. Инкрементируем счетчик, и когда он достигает значения 100(или 50?) - сбрасываем. Всё.
В итоге имеем не одну монолитную программу которую сложно отлаживать, а отдельные блоки логика которых просматривается прозрачно(зависит исключительно от строго указанных входных данных и имеет конкретный легко проверяемый результат работы) и которые отлаживать можно отдельно от остальных.
- Сообщения: 516
- Зарегистрирован: Пт янв 18, 2013 15:11:02
Всем привет, не могу справиться с банальной задачей - подключение компаратора и сделать так что бы он вошел в прерывание, из-за разности напряжения в 2 вольта, и подключил PORTB4 . Вот код на ассемблере, и снимок в протеусе.
Снимок в протеусе

Спойлер
Код: Выделить всё
// Команда для переименования регистров.
.def ZERO=R22;
.def XXX=R23;
.list; // Отоброжения листинга исполнения команды.
.cseg; работаем с програмной памятью а не озу или eeprom
.org 0; устанавливаем начальную позицию строки
rjmp START; Reset Handler
rjmp START; IRQ0 Handler
rjmp START;; PCINT0Z Handler
rjmp START; Timer0 Overflow Handler
rjmp START; EEPROM Ready Handler
rjmp Comparator; Analog Comparator Handler
rjmp ObrobotkaTIM0_COMPA; TIM0_COMPA CompareA Handler
rjmp START; Timer0 CompareB Handler
rjmp START; Watchdog Interrupt Handler
rjmp START; ADC Conversion Handler
//Оброботка прерывания от компаратора
Comparator:
CLI; команда запрещает глобальные прерывания.
cbi DDRB,4; - Устанавливаем порт как на выход,
sbi PORTB,4; - Подкючаем подтягивающий резистор для включения лампы
sei; - команда разрешает глобальные прерывания
reti; - Выход с под программы прерывания
//оброботка прерывания порта INT0, по высокому сигналу.
//Прерывания при совапдении таймера
ObrobotkaTIM0_COMPA:
inc XXX;
reti;
/*Код установки таймера счетчика*/
TIMER:
/*
TIFR0 - регистр индикации флагов прерывания
TOV0 - флаг индикации по переполнению таймера
OCF0A,OCF0B - флаг индикации по совпадению.
OCR0A,OCR0B - регистр установки значения для совпадения.
TCCR0A - регистр управления A;
TCCR0B - регистр управления B;
*TIMSK0 - Регистр выбора режима срабатывания прерывания
TOIE0 - по переполнению, OCIE0A - по совпадению со значанием в регистре А,
OCIE0B - по совпадению со значанием в регистре B.
*/
ldi R16, (1<<OCIE0A);Установка режима по совпадению с А;
out TIMSK0, R16;
ldi R16, 0xFF; Устанавливаем значение при совпадении с А
out OCR0A, R16;
ldi R16, 0x00;// Сбрасываем все флаги таймера
out TIFR0, R16;
/*Скорость работы таймера выбираем СК/1024 - где СК - частота работы микроконтролера
в нашем случаи мы выставляем во fuces clkdiv8 что обеспечит нам частоту 9,6Мhz/8=1,2Mhz значит
скорость работы таймера будет 1,2Mhz/1024=1,17Khz что увеличивает счет значения. Чем меньше
частота тем большее время срабатывания до прерывания*/
ldi R16, (1<<CS02)|(0<<CS01)|(1<<CS00);
out TCCR0B, R16;
ret; //возврат из подпрограммы TIMER:
//Определяем начальные параметры микроконтролера.
START:
CLI; команда запрещает глобальные прерывания.
//инициализация стэка.(установка максимально размера ОЗУ);
ldi R17, RAMEND;
out SPL, R17;
ldi ZERO, 0x00; //Присваеваем значение 0 переменной zero;
//Отключаем аналогово-цифровой преобразователь
CBI ADCSRA, ADEN;
//Подключаем компаратор для сравнения сигналов
////Команда CBI устанавливает значение в 0 регистра ACSR ячейки ASD что включает компаратор - по умолчанию он и так включен;
CBI ACSR, ACD;
//Команда SBI устанавливает значение в 1 регистра ACSR ячейки ACIE которая включает разрешения прерывания от компаратора.
SBI ACSR, ACIE;
//Устанавливаем условие генерации прерывания выставляем изменения сосотояния от 0 до 1;
sbi ACSR, ACIS1;
sbi ACSR, ACIS0;
//инициализация портов ввода вывод
//Устанавливаем работу портов на вход и выход.
//Устанавливаем выходы DDB1 и DDB0 работу на вход для компаратора
//Если порт DDB установлен в 1 то данный порт является входам,
//а если в 0 то выходам.
ldi R16,(0<<DDB5)|(0<<DDB4)|(0<<DDB3)|(0<<DDB2)|(1<<DDB1)|(1<<DDB0);
out DDRB, R16;
//Разрешаем глобальные прерывания
sei;
//Переходим к основному циклу проверки
rjmp START1;
START1:
nop;
rjmp START1;
Спойлер
- Вложения
-
- Коту.png
- (27.85 КБ) 429 скачиваний
Код: Выделить всё
//Если порт DDB установлен в 1 то данный порт является входам,
//а если в 0 то выходам.
Желательно отключать цифровые входы от лап АС
Код: Выделить всё
//Отключаем аналогово-цифровой преобразователь
; CBI ADCSRA, ADEN;
//Подключаем компаратор для сравнения сигналов
////Команда CBI устанавливает значение в 0 регистра ACSR ячейки ASD что включает компаратор - по умолчанию он и так включен;
;CBI ACSR, ACD;
//Команда SBI устанавливает значение в 1 регистра ACSR ячейки ACIE которая включает разрешения прерывания от компаратора.
;SBI ACSR, ACIE;
//Устанавливаем условие генерации прерывания выставляем изменения сосотояния от 0 до 1;
LDI R22,1<<ACIS1|1<<ACIS0|1<<ACIE
OUT ACSR,R22
LDI R22,1<<AIN1D|1<<AIN0D
OUT DIDR0,R22
;sbi ACSR, ACIS1;
;sbi ACSR, ACIS0
Последний раз редактировалось akl Чт окт 26, 2017 11:02:00, всего редактировалось 1 раз.
[uquote="strengerst",url="/forum/viewtopic.php?p=3216583#p3216583"]А вот и нет. В книги написано:
[/uquote]
читайте оригинальные даташиты. в этой книжке ошибка.
читайте оригинальные даташиты. в этой книжке ошибка.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!


