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

Обсуждаем контроллеры компании Atmel.
Ответить
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

ну, за работу наоборот уж предъявляй претензии самому себе...
этот код тут совершенно ни при чем...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

А все. Разобрался. ))) Путаница у меня в голове возникла при сохранении и чтении старшего и младшего байта. А потом, как и указал, в ветвлениях. Там же наоборот получается, чем медленнее скорость, тем длиннее период! Значит число больше. Короче, точно сам накосячил. :)))

Если кому нужно, то выложу код и схему в какой-нибудь своей теме. Завтра на машине проверим и поставим ее. ))) Обязательно где-то надо отписаться будет.

Вопрос только небольшой. Что с чем сравнивается? Первое со вторым или наоборот?
Станислав
Реклама
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

а тебе brlo ни о чем не говорит?
и ты не знаешь, в какой из двух регистров заносится результат? даже, если результат операции виртуальный...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

:))) Из первого вычитаем второе... :dont_know: Простите, туплю.
brlo Если результат вычитания отрицательный, т.е. первое меньше, чем второе, то переходим.

Другой вопрос. Как создать в АВРСтудио ЕЕПРОМ файл? А то я старые значения затер...
Станислав
Реклама
Эиком - электронные компоненты и радиодетали
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

СКАЗОЧНИК писал(а):Другой вопрос. Как создать в АВРСтудио ЕЕПРОМ файл? А то я старые значения затер...

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

.eseg

.org 0x01

EE_PARAM:
.db 0x55, 0xAA
.dw 0x55AA
Нулевой (первый) байт никогда не используйте. После каждого чтения-записи из\в EEPROM сбрасывайте указатель EEPROM в 0, чтобы он указывал на нулевой байт и при скачках питания не затер данные.
Спойлер

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

;*************************************************************************
;========== EEPROM ===================
;*************************************************************************

;Так как возможна случайная запись в EEPROM в случае сбоя питания, то:
;1 - В микроконтроллере включить контроль снижения напряжения питания. 
;2 - Первый (0x00) байт никогда не используется. 
;3 - После ресета обнулить указатель адреса EEPROM. 
;Решения для увеличения ресурса EEPROM:
;4 - Перед записью считывается байт, предназначенный для записи,
;проверяется на равенство с записываемым, если байты равны, то переход
;к записи следующего байта. 
;5 - В конце работы с EEPROM обнулить указатель адреса. 

#if (EEPROM==YES)

.macro Read_EEPROM
	ldix	@0 ; Указатель адреса EEPROM.
	ldiy	@1 ; Указатель адреса SRAM.
	ldi		CNT,@2 ; Количество байтов.
	rcall	_Read_EEPROM
.endmacro

_Read_EEPROM:
	sbic	EECR,EEWE
	rjmp	_Read_EEPROM
.ifdef EEARH
	out		EEARH,XH
.endif
	out		EEARL,XL
	sbi		EECR,EERE
	sbi		EECR,EERE
	in		EEDREG,EEDR
	st		Y+,EEDREG
	adiw	XL,1
	dec		Cnt
	brne	_Read_EEPROM
.ifdef EEARH
	out		EEARH,RClr
.endif
	out		EEARL,RClr
	ret

EERead:
	sbic	EECR,EEWE
	rjmp	EERead
	sbi		EECR,EERE
	sbi		EECR,EERE
	in		EEDREG,EEDR
	ret

EEWrite:
	sbic	EECR,EEWE
	rjmp	EEWrite
	out		EEDR,EEDREG
	sbi		EECR,EEMWE
	sbi		EECR,EEWE
	ret

Write_EEPROM:
	sbic	EECR,EEWE
	rjmp	Write_EEPROM
.ifdef EEARH
	out		EEARH,YH
.endif
	out		EEARL,YL
	ld		EEDREG,X
	out		EEDR,EEDREG
	sbi		EECR,EEMWE
	sbi		EECR,EEWE
	adiw	XL,1
	adiw	YL,1
	dec		Cnt
	brne	Write_EEPROM
.ifdef EEARH
	out		EEARH,RClr
.endif
	out		EEARL,RClr
	ret

Write_Param_EEPROM:
;	LDIX	Param_SRAM
;	LDIY	Param_EEPROM
;	ldi		Cnt,Param_Size
W_P_E_0:
	sbic	EECR,EEWE
	rjmp	W_P_E_0
.ifdef EEARH
	out		EEARH,YH
.endif
	out		EEARL,YL
	ld		r17,X
	rcall	EERead
	cp		r17,EEDREG
	breq	W_P_E_2
	mov		EEDREG,r17
W_P_E_1:
	sbic	EECR,EEWE
	rjmp	W_P_E_1
.ifdef EEARH
	out		EEARH,YH
.endif
	out		EEARL,YL
	rcall	EEWrite
W_P_E_2:
	adiw	XL,1
	adiw	YL,1
	dec		Cnt
	brne	W_P_E_0
.ifdef EEARH
	out		EEARH,RClr
.endif
	out		EEARL,RClr
	ret

; Считывание параметров.
Read_Write_Param:
;	LDIX	Param_SRAM
;	LDIY	Param_EEPROM
;	ldi		Cnt,Param_Size
;	rcall	Read_EEPROM
	ret

#endif
Последний раз редактировалось Demiurg Ср мар 30, 2016 21:17:01, всего редактировалось 3 раза.
Контактная информация:
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

А, точно, есть же у меня в шапке программы такое место. )))) Спасибо.
Другой вопрос. А как по мне нужным адресам раскидать значения?

И у меня МК обучается, т.е. записывает эти значения сам в память. А здесь они будут жестко заданы?

З.Ы. Все. Увидел org.!!!!!!! Там начало адресов ЕЕПРОМ.

З.З.Ы. Блин, компилируется, но не записывает их. Чего-то еще надо? :roll: :oops:

З.З.З.Ы. ВСЕ. Всем спасибо. Разобрался. :music: :beer: :)))
Станислав
Реклама
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

есть желание поделиться с уважаемой публикой результатами своих наработок.
это "комплект" подпрограмм деления и умножения.
в самих подпрограммах никакой "хитрости" нет. это вполне стандартные методы деления и умножения.
"хитрость" заключается в том, что подпрограммы СОГЛАСОВАНЫ.
то есть, результат одной подпрограммы служит входным числом для другой подпрограммы, и никакой передачи между регистрами не требуется.
Спойлер

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

;--- деление 16 бит в R21:R20 на 8 бит в R16 ---
;------ целая часть в R20, остаток в R21 -------
div_16_8_8_8:			; 16 битов (2 байта) делим на 8 битов (1 байт), получаем целую часть 8 битов (1 байт) и остаток 8 битов (1 байт)
ldi R18, 8				; делаем 8 циклов сдвига делимого/результата
div_16_8a:
lsl R20
rol R21
brcs div_16_8b			; если в результате сдвига влево появился перенос, то сразу же идем на вычитание, мимо сравнения
cp R21, R16
brcs div_16_8c			; если меньше, то пропускаем вычитание
div_16_8b:
sub R21,R16
sbr R20, 1
div_16_8c:
dec R18
brne div_16_8a
ret

;--- деление 32 бита в R23:R22:R21:R20 на 16 бит в R17:R16 ---
;--------- целая часть в R21:R20, остаток в R23:R22 ----------
div_32_16_16_16:		; 32 бита (4 байта) делим на 16 битов (2 байта), и получаем целую часть 16 битов (2 байта) и остаток 16 битов (2 байта)
ldi R18, 16				; делаем 16 циклов сдвига делимого/результата
div_32_16a:
lsl R20
rol R21
rol R22
rol R23
brcs div_32_16b			; если в результате сдвига влево появился перенос, то сразу же идем на вычитание, мимо сравнения
cp R22, R16
cpc R23, R17
brcs div_32_16c	
div_32_16b:			; если меньше, то пропускаем вычитание
sub R22,R16
sbc R23,R17
sbr R20, 1
div_32_16c:
dec R18
brne div_32_16a
ret

;--- умножение 16 бит в R21:R20 на 16 бит в R17:R16 ---
;----------- результат в R23:R22:R21:R20 --------------
mul_16x16_32:			; 16 битов (2 байта) умножаем на 16 битов (2 байта) и получаем в результате 32 бита (4 байта)
mov R18, R20
mov R19, R21
mul R21, R17			; старший * старший	'
movw R23:R22, R1:R0	; старшая пара результата
mul R18, R16			; младший * младший
movw R21:R20, R1:R0	; младшая пара результата
mul R19, R16			; старший * младший
add R21, R0
adc R22, R1
mul R18, R17			; младший * старший
add R21, R0
adc R22, R1
adc R23, R31
ret
для наглядности таких "цепочечных" вычислений приведу пару примеров из моего проекта в теме Imax B1, или тестер максимальной емкости батареек 18650

пример №1. подпрограмма калибровки результата измерения напряжения или тока.
Спойлер

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

;--- калибровка тока или напряжения ---
calibr_zamer:
mov R16, R4			; передадим замер в сомножитель
mov R17, R5			; в первом сомножителе (R21:R20) уже находится калибровчный коэффициент
rcall mul_16x16_32
ldi R16,  low(1024)
ldi R17, high(1024)		; делим на 1024, так как результат АЦП - 10-битный
rcall div_32_16_16_16
;--- округление числа после деления ---
okruglenie:
lsl R22				; сдвигаем остаток от деления влево - умножение на 2
rol R23
cp R22, R16			; сравниваем удвоенный остаток с делителем
cpc R23, R17
brlo end_okrug			; если меньше, то ничего не делаем
inc R20				; а если больше или равно, то прибавляем 1 к целой части результата деления
brne end_okrug
inc R21
end_okrug:
mov R4, R20
mov R5, R21			; вернем в регистры прокалиброванные ток или напряжение
ret
хорошо видно, что результат умножения сразу же является делимым для деления.
заодно можете видеть, как правильно нужно делать в программе округление результата по величина остатка.
округление организовано по стандартному правилу: если получилось 0,5 или более, то к целой части прибавляем 1.

пример №2. вывод секундомера на индикатор.
Спойлер

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

clr R23				; в R22:R21:R20 уже находится набранное время, очистим старший байт
ldi R16,  low(3600)
ldi R17, high(3600)		; после деления на 3600 в целой части результата получаеи количество часов, а в остатке получаем количество секунд
rcall div_32_16_16_16	; остаток меньше 3600
ldi R16, 10				; сразу же делим целую часть первого деления на 10,
rcall div_16_8_8_8		; и получаем в целой части результата десятки часов, а в остатке получаем единицы часов
ldi R18, '0'
add R18, R20			; десятки часов
rcall write_lcd
ldi R18, '0'
add R18, R21			; единицы часов
rcall write_lcd
ldi R18, ':'				; выведем двоеточие
rcall write_lcd
mov R21, R23			; переместим остаток в делимое
mov R20, R22
clr R23				; очистим старшие байты
clr R22
ldi R16,  low(600)		; после деления количества секунд на 600 получаем десятки минут,
ldi R17, high(600)
rcall div_32_16_16_16	; остаток меньше 600
ldi R18, '0'
add R18, R20			; десятки минут
rcall write_lcd
mov R21, R23
mov R20, R22			; переместим остаток первого деления в делимое
ldi R16, 60				; после деления на 60 получаем единицы минут
rcall div_16_8_8_8		; остаток меньше 60
ldi R18, '0'
add R18, R20			; единицы минут
rcall write_lcd
ldi R18, ':'				; выведем двоеточие
rcall write_lcd
mov R20, R21			; переместим остаток от последнего деления в делимое
clr R21				; очистим старший байт
ldi R16, 10				; после деления на 10
rcall div_16_8_8_8		; получаем в целой части результата десятки секунд, а в остатке получаем единицы секунд
ldi R18, '0'
add R18, R20			; десятки секунд
rcall write_lcd
ldi R18, '0'
add R18, R21			; единицы секунд
rcall write_lcd
end_vyvod_sekynd:
я постарался сделать очень подробные комментарии своих действий.
здесь тоже хорошо видно, что целая часть результата 32-битного деления сразу же служит делимым для 16-битного деления.

обратите внимание, что в случае 16-битного (2 байта) делимого для 32-битного деления нужно обнулить 2 старших байта в R23:R22.
а в случае 3-байтного делимого - обнулить только самый старший байт в R23.

еще замечу, что полного исходника, откуда взяты эти фрагменты, в указанной теме нет.

у меня пока все. спасибо за внимание...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Очень полезная и хорошая информация, только я бы оформил в отдельную статейку. Можно к обучалке по АВР. Т.к. здесь со временем уйдет все это и найти будет очень сложно... :(
Станислав
Потрогал лапой паяльник
Сообщения: 315
Зарегистрирован: Пт янв 29, 2010 19:42:27

Сообщение 12val12 »

Подскажите решение небольшой задачки кто разбирается а ASM и циклических буферах
со входа 8 бит порта каждый третий такт записывается его состояние A
на другой 8 бит порт выход выводится на 20 тактов задержаннный A[i-20]
подразумевается использование регистиров у которых время доступа 1 такт (32 штв ниличии должно хватить)
так сказать цифровая ЛЗТ .Напомню записывается каждый третий такт
ух ты.... показывает
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

12val12 писал(а):со входа 8 бит порта каждый третий такт записывается его состояние A
на другой 8 бит порт выход выводится на 20 тактов задержаннный A[i-20]
надеюсь, считываются они тоже "каждый третий такт"? вы об этом умолчали...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Потрогал лапой паяльник
Сообщения: 315
Зарегистрирован: Пт янв 29, 2010 19:42:27

Сообщение 12val12 »

записывается и выводится каждый третий такт
ух ты.... показывает
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

так в чем проблема у вас? самое простое: заводите буфер на 256 ячеек, в регистровую пару, допустим, X записываете адрес начала этого буфера, а в регистровую пару, допустим, Y - записываете адрес на 20 больше. ну а потом пишите в буфер командой st Y+, R16, а считываете командой ld R17, X+ , после чего регистры XH и YH снова заполняете старшим байтом адреса буфера. вот и все.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Потрогал лапой паяльник
Сообщения: 315
Зарегистрирован: Пт янв 29, 2010 19:42:27

Сообщение 12val12 »

Думаю что таким образом темп записи будет гораздо меньше чем каждый третий такт
запись из порта в регистр 1 такт из регистра в озу 2 такта уже три ..
обратно из озу в регистр и из регистра в порт еще три..
таким образом темп записи будет каждый шестой такт это без учета закольцовывния

в общем ОЗУ исключается. только регистры и порты
ух ты.... показывает
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

12val12 писал(а):Думаю что таким образом темп записи будет гораздо меньше чем каждый третий такт
это очевидно
12val12 писал(а):в общем ОЗУ исключается. только регистры и порты
да? :))) ну давайте, продемонстрируйте, как это можно сделать.

чтение из порта в регистр - 1 такт
запись из регистра в порт - 1 такт
чтобы все это зациклить - минимум 2 такта, но чаще 3.
итак, на подготовку (перемещение, задержку) данных уже не остается ничего...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Сообщение dgrett »

А что, никак-никак не обойти привязку к тактам?
Я всё-всё узнAю и стану профессором.
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

12val12 писал(а):Напомню записывается каждый третий такт
1 такт - чтение из порта.
еще 1 такт - вывод в порт.
остается тебе придумать, как за 1 такт сделать задержку на 20 тактов.
а это возможно только телепортацией, причем в канал телепортации встроить задержку на 20 тактов.

короче, твои желания не реализуемы.
читать порт и выводить в порт можно только с одинаковой скоростью.
1. чтение из порта.
2. задержка на 18 тактов.
3. вывод в порт.
таким образом, читать ты сможешь только через каждые 20 тактов.
делал я подобную "линию задержки" в стародавние времена, еще на "Спектруме" - и получился у меня ревербератор.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

   .dseg
buf:
   .byte 256
   .cseg
   ldi XL, lo(buf)
   ldi r17, hi(buf)
   ldi YL, lo(buf)+20
loop: 
   mov XH, r17 ; 1 такт
   mov YH, r17 ; 1 такт, итого 2
   in r16, PINB ; 1 такт, итого 3
   st Y+, r16 ; 2 такта, итого 5
   ld r16, Х+ ; 2 такта, итого 7
   out PORTD, r16 ; 1 такт, итого 8
   rjmp loop ; 2 такта, итого 10
   
быстрее, наверное, невозможно...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

а сколько тактов по твоему коду уйдет, пока адрес передвинется на 20 байт?
а уйдет (10 твоих тактов) умножить на 20 = 200 тактов. а ему нужно задержать всего на 20 тактов.
а для 20 тактов смещение адреса должно быть +2, а не +20.
к тому же, твой цикл - бесконечный.
а программе нужно заниматься еще и своим делом, и только с некоторой периодичностью обращаться к вводу и выводу.
но тут автор вопроса не дал разъяснений. может, у его программы и не будет других дел, как только бегать по такому циклу бесконечно...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Потрогал лапой паяльник
Сообщения: 315
Зарегистрирован: Пт янв 29, 2010 19:42:27

Сообщение 12val12 »

вот набросал похожее схематически .(не силен я в программировании)
тут задержка >22 тактов . с равномерным темпом ввода -вывода 1/4
возможно ли исключить 1 nop?возможно заджампить в начало за 1 такт ?
контроллер кроме как задержкой заниматься не будет
цель - другой контроллер смотрит сигнал . ловит событие одним портом
а после срабатывания сможет видеть за пару мкс до события задержанной линией

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

1  in r0,PORTA
      out portB,r5
	  nop  nop
   in r1,PORTA
     out portB,r6
	  nop  nop
   in r2,PORTA	 
     out portB,r7
	  nop  nop
   in r3,PORTA
     out portB,r8
	  nop  nop
   in r4,PORTA	 
     out portB,r9
	  nop  nop
   in r5,PORTA
      out portB,r10
	  nop  nop
   in r6,PORTA
     out portB,r0
	  nop  nop
   in r7,PORTA	 
     out portB,r1
	  nop  nop
   in r8,PORTA
     out portB,r2
	  nop  nop
   in r9,PORTA	 
     out portB,r3
	  nop  nop 
   in r10,PORTA
     out portB,r4
jmp 1 
ух ты.... показывает
Модератор
Аватара пользователя
Сообщения: 19100
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

12val12 писал(а):возможно заджампить в начало за 1 такт ?
это сначала нужно разработать новый процессор, в котором джамп выполняется за 1 такт.
12val12 писал(а):тут задержка >22 тактов
я насчитал 26 тактов (4 * 6 + 2 = 26 - от чтения в r0 до вывода из r0).

а если убрать один nop, то тогда задержка составит 3 * 6 + 2 = 20 тактов.
в твоем тексте чтение происходит каждый четвертый такт. а без одного nop будет происходить каждый третий такт (что тебе и нужно). и задержка составит ровно 20 тактов (что тебе и нужно).
правда, джамп будет периодически делать сбой на 1 такт...

можно оставить оба nop. но тогда делать вывод из r0 после чтения в r5, тогда задержка будет 22 такта, и джамп мешать не будет.
но и придется мириться с чтением каждый четвертый такт...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ответить

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