Ассемблер (ASM) для AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Ой спасибо действительно ошибка. Изначально все пины МК это входы, переделал код, проверил и все ровно компаратор не входит в прерывания. Что еще не так?
Спойлер

Код: Выделить всё


// Команда для переименования регистров.
.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; команда запрещает глобальные прерывания.
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)|(1<<DDB4)|(0<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
out DDRB, R16;
//Разрешаем глобальные прерывания
sei;
//Переходим к основному циклу проверки
rjmp START1;

START1:
nop;
rjmp START1;


Протеус:
Спойлер[img]
http://radiokot.ru/forum/download/file.php?id=295092
[/img]
Желательно отключать цифровые входы от лап АС
Попробовал как советовали выше:
Спойлер

Код: Выделить всё


// Команда для переименования регистров.
.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; команда запрещает глобальные прерывания.
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;
//Подключаем компаратор для сравнения сигналов
LDI R22,1<<ACIS1|1<<ACIS0|1<<ACIE;
OUT ACSR,R22;

LDI R22,1<<AIN1D|1<<AIN0D;//Если какой-либо из входов ADC3-0 используется как аналоговый,
OUT DIDR0,R22;//то в соответствующий бит ADC3D-ADC0D нужно устанавливать логическую единицу.


//Устанавливаем работу портов на вход и выход. 
//Устанавливаем выходы DDB1 и DDB0 работу на вход для компаратора
//Если порт DDB установлен в 1 то данный порт является выходам, 
//а если в 0 то входам.
ldi R16,(0<<DDB5)|(1<<DDB4)|(0<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
out DDRB, R16;
//Разрешаем глобальные прерывания
sei;
//Переходим к основному циклу проверки
rjmp START1;

START1:
nop;
rjmp START1;


Жаль но прерывания все равно нет.
Вложения
Коту3.png
(28.06 КБ) 392 скачивания
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

[uquote="strengerst",url="/forum/viewtopic.php?p=3216601#p3216601"]Жаль но прерывания все равно нет.[/uquote]У вас в схеме протеуса ошибка, состояние вывода PB0 не определено, поставьте на вывод PB0 резистор 10к на землю.
Реклама
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

и в программе недопустимые ошибки....
На старте не обязательно запрещать прерывания - они и так запрещены. В обработчике прерывания разрешать/запрещать прерывания НЕ НУЖНО, они запрещаются и разрешаться сами при входе в прерывание и выполнении команды RETI соответственно.

А вот что делать в прерывании КРАЙНЕ НЕ РЕКОМЕНДУЕТСЯ так это менять регистр статуса.
Ваша команда INC в обработчике прерывания таймера его меняет. Поскольку прерывание возникает в самый неожиданный момент выполнения программы, внезапное изменение регистра статуса может оказаться большим нежданчиком для программы и получишь постоянные глюки "из ниоткуда и везде".
Если в обработчике выполняется хоть одна команда изменяющая регистр статуса, его надо при входе в обработчик сохранить а перед выходом - освободить. Обычно для этого отводят отдельный регистр который больше нигде не используется - только в прерывании и только для хранения регистра статуса. Или если все регистры в ходу то сначала делаем PUSH любого регистра в стек и может использовать его в тех же целях, не забыв потом и этот регистр восстановить перед выходом из прерывания.
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18794
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Alexeyslav писал(а):а перед выходом - освободить
восстановить
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

И все равно нет прерывания по компаратору, спасибо всем за советы учту.
Переделанный код согласно замечанием: Может кто свой небольшой пример на асемблере скинет, что бы компаратор уходил в прерывания.
Спойлер

Код: Выделить всё

/ Команда для переименования регистров.
.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 START; TIM0_COMPA CompareA Handler
rjmp START; Timer0 CompareB Handler
rjmp START; Watchdog Interrupt Handler
rjmp START; ADC Conversion Handler

//Оброботка прерывания от компаратора
Comparator:
sbi PORTB,4; - Подкючаем подтягивающий резистор для включения лампы
reti; - Выход с под программы прерывания
//оброботка прерывания порта INT0, по высокому сигналу. 




//Определяем начальные параметры микроконтролера.

START:

 //инициализация стэка.(установка максимально размера ОЗУ);
 ldi R17, RAMEND;
 out SPL, R17;
 ldi ZERO, 0x00; //Присваеваем значение 0 переменной zero;
 
 //Отключаем аналогово-цифровой преобразователь
 CBI ADCSRA, ADEN;
//Подключаем компаратор для сравнения сигналов
LDI R22,1<<ACIS1|1<<ACIS0|1<<ACIE;
OUT ACSR,R22;

LDI R24,1<<AIN1D|1<<AIN0D;//Если какой-либо из входов ADC3-0 используется как аналоговый,
OUT DIDR0,R24;//то в соответствующий бит ADC3D-ADC0D нужно устанавливать логическую единицу.

//Устанавливаем работу портов на вход и выход. 
//Устанавливаем выходы DDB1 и DDB0 работу на вход для компаратора
//Если порт DDB установлен в 1 то данный порт является выходам, 
//а если в 0 то входам.
ldi R16,(0<<DDB5)|(1<<DDB4)|(0<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
out DDRB, R16;

//Разрешаем глобальные прерывания
sei;
//Переходим к основному циклу проверки
rjmp START1;

START1:
nop;
rjmp START1;
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

strengerst писал(а):И все равно нет прерывания по компаратору, спасибо всем за советы учту.
Переделанный код согласно замечанием: Может кто свой небольшой пример на асемблере скинет, что бы компаратор уходил в прерывания.
Вот рабочий пример в протеусе.
Реклама
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

strengerst писал(а):Жаль но прерывания все равно нет.
Адаптировал программу и проверил в железе на tiny2313, благо распиновка и поддержка такая же как tiny13. Работает!
Спойлер

Код: Выделить всё

	.INCLUDE "tn2313def.inc"

// Команда для переименования регистров.
.def ZERO=R22;
.def XXX=R23;
.list; // Отоброжения листинга исполнения команды.
.cseg; работаем с програмной памятью а не озу или eeprom
.org 0; устанавливаем начальную позицию строки
rjmp START; Reset Handler
	.org $0A
rjmp Comparator; Analog Comparator Handler
	.org $0D
ObrobotkaTIM0_COMPA:
inc XXX;
reti;
//Оброботка прерывания от компаратора
Comparator:
sbi PINB,4; - Подкючаем подтягивающий резистор для включения лампы
reti; - Выход с под программы прерывания

//Определяем начальные параметры микроконтролера.

START:
 //инициализация стэка.(установка максимально размера ОЗУ);
;Initial Value10011111, т.е. для tiny13 две следующие команды не нужны
 ldi R17, RAMEND;
 out SPL, R17;
 ldi ZERO, 0x00; //Присваеваем значение 0 переменной zero;
 
//инициализация портов ввода вывод

//Устанавливаем работу портов на вход и выход.
//Устанавливаем выходы DDB1 и DDB0 работу на вход для компаратора
//Если порт DDB установлен в 1 то данный порт является выходам,
//а если в 0 то входам.
	SBI	DDRB,4
;	ldi R16,1<<DDB4
;	out DDRB, R16;
//Подключаем компаратор для сравнения сигналов
	LDI	R22,1<<ACIE;1<<	ACIS1|1<<ACIS0|1<<ACIE
	OUT	ACSR,R22
	LDI	R22,1<<	AIN1D|1<<AIN0D
	OUT	DIDR,R22; отключение цифровых входов от аналоговой части
;	OUT	DIDR0,R22; отключение цифровых входов от аналоговой части


	SBI	ACSR,ACI; очистка флага AC
;Alternatively, ACI is cleared by writing a logic one to the flag

;	RCALL	TIMER
//Разрешаем глобальные прерывания
sei;
START1:
;nop;
rjmp START1;
.EXIT
Для tiny13 будет так
Спойлер

Код: Выделить всё

	.INCLUDE "tn13def.inc"

// Команда для переименования регистров.
.def ZERO=R22;
.def XXX=R23;
.list; // Отоброжения листинга исполнения команды.
.cseg; работаем с програмной памятью а не озу или eeprom
.org 0; устанавливаем начальную позицию строки
rjmp START; Reset Handler
	.org 5
rjmp Comparator; Analog Comparator Handler
	.org 6
ObrobotkaTIM0_COMPA:
inc XXX;
reti;
//Оброботка прерывания от компаратора
Comparator:
;sbi PORTB,4; - Подкючаем подтягивающий резистор для включения лампы
sbi PINB,4; - Подкючаем подтягивающий резистор для включения лампы
reti; - Выход с под программы прерывания

//Определяем начальные параметры микроконтролера.

START:
 //инициализация стэка.(установка максимально размера ОЗУ);
;Initial Value10011111, т.е. для tiny13 две следующие команды не нужны
; ldi R17, RAMEND;
; out SPL, R17;
 ldi ZERO, 0x00; //Присваеваем значение 0 переменной zero;
 
//инициализация портов ввода вывод

//Устанавливаем работу портов на вход и выход.
//Устанавливаем выходы DDB1 и DDB0 работу на вход для компаратора
//Если порт DDB установлен в 1 то данный порт является выходам,
//а если в 0 то входам.
	SBI	DDRB,4
;	ldi R16,1<<DDB4
;	out DDRB, R16;
//Подключаем компаратор для сравнения сигналов
	LDI	R22,1<<	ACIS1|1<<ACIS0|1<<ACIE
	OUT	ACSR,R22
	LDI	R22,1<<	AIN1D|1<<AIN0D
	OUT	DIDR0,R22; отключение цифровых входов от аналоговой части

	SBI	ACSR,ACI; очистка флага AC
;Alternatively, ACI is cleared by writing a logic one to the flag

;	RCALL	TIMER
//Разрешаем глобальные прерывания
sei;
START1:
;nop;
rjmp START1;
.EXIT
Вымогатель припоя
Аватара пользователя
Сообщения: 516
Зарегистрирован: Пт янв 18, 2013 15:11:02

Сообщение strengerst »

Всем спасибо буду пробовать.
Первый раз сказал Мяу!
Сообщения: 24
Зарегистрирован: Вс июн 19, 2016 06:31:18

Сообщение sibiryak69 »

Всем добрый день подскажите пожалуйста
в описании модуля USART tiny2313 есть такой пример приема кадра длинной 9 бит

USART_Receive:.
; Ожидаем пока данные будут получены
sbis UCSRA, RXC
rjmp USART_Receive
; Получаем статус и 9-й бит данных, а затем остальные данные
in г18. UCSRA
in r17, UCSRB
in r16, UDR
; Если ошибка, возвращаем -1
andi r18, (1«FE) | (1«D0R)| (1«UPE)
breq USART_ReceiveNoError
ldi r17, HIGH(-1)
ldi г16, L0W(-1)
USART_ReceiveNoError:
Выделяем 9-й бит и возвращаем полученные данные
Isг г17
andi г17, 0x01
ret

в данном примере не понятны две строки

ldi r17, HIGH(-1)
ldi г16, L0W(-1)

а точнее возвращаемые значения -1

HIGH(-1)
L0W(-1)

то есть как компилятор переведет -1 в двоичный код?

и для чего -1 записывается в регистры r17, r16?
Друг Кота
Аватара пользователя
Сообщения: 6349
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

Компилятор вообще переводит весь исходник в двоичный код :)) Зачем такая мудреная запись - не знаю, то же самое было бы

Код: Выделить всё

ldi   r16,0xFF
ldi   r17,0xFF
Это просто забивание r17, r16 единичками. Видимо, признак ПРИНЯТО С ОШИБКОЙ.
Изображение
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Забивается на выход невалидное значение, чтобы приложение потом у себя поняло что произошла ошибка, а не какие-то данные были приняты. Иначе в старшем байте старший бит(а в идеале все с 1-го по 7-й) точно должен быть равен нулю.
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 24
Зарегистрирован: Вс июн 19, 2016 06:31:18

Сообщение sibiryak69 »

а как понять запись
HIGH(-1)
L0W(-1)
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Куда то определить, занести -1=0xFFFF.
Тоже самое, но для 4 байт -1=FFFF FFFF
BYTE4(-1)
BYTE3(-1)
BYTE2(-1)
BYTE1(-1)
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

LOW Младшая часть слова.
HIGH Старшая часть слова.
16 бит.

BYTE1
BYTE2
BYTE3
BYTE4
Соответственно байты по старшинству 32-битное число.
Контактная информация:
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

[uquote="Demiurg",url="/forum/viewtopic.php?p=3223910#p3223910"]LOW Младшая часть слова.
BYTE1
BYTE2
BYTE3
BYTE4
Соответственно байты по старшинству 32-битное число.[/uquote]
BYTE4 -старший
BYTE3
BYTE2(HIGH)
BYTE1(LOW) -младший

.EQU BT4_1=-123456789 ;F8A4 32EB
.ORG 0
LDI R20,BYTE4(BT4_1)
LDI R21,BYTE3(BT4_1)
LDI R22,BYTE2(BT4_1)
LDI R23,BYTE1(BT4_1)
Изображение
Вложения
byte4_1.png
(6.45 КБ) 884 скачивания
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

И? Вам трудно было сразу написать, как положено, чтобы потом не было вопросов?
Или вы по асму что-то новое хотели мне сказать?
Контактная информация:
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Вы залезли с фигнёй типа "байты по старшинству", потому и написал...
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

[uquote="akl",url="/forum/viewtopic.php?p=3224085#p3224085"]Вы залезли фигнёй типа "байты по старшинству", потому и написал...[/uquote]
??? BYTE1 - младший, BYTE2 - следующий. Что непонятно?
Контактная информация:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 20
Зарегистрирован: Чт дек 07, 2017 04:44:22

Сообщение леМурр »

два вопроса, простой и сложный, начну с обоих :write:

LPM Rd, Z
какой диапазон для Rd? 0...31 или 16...31?

LPM Rd, Z+
будет ли инкрементить Z(high) c переполнением Z(low)?
..всего две 6Ф1П, включенные последовательно,
высушат обое ваших сапог даже в автомобиле..
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

леМурр писал(а): LPM Rd, Z
какой диапазон для Rd? 0...31 или 16...31?
0-31. То есть, можно даже в регистры ZL, ZH. Естественно, как указатель после этого использовать нельзя, нужно заново записать адрес.
леМурр писал(а): LPM Rd, Z+
будет ли инкрементить Z(high) c переполнением Z(low)?
Эта команда для регистровой пары. То есть, если младший ZL перешел через 0xFF, ZH автоматом инкрементируется.

На заметку: описание команд AVR.
Контактная информация:
Ответить

Вернуться в «AVR»