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

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 7
Зарегистрирован: Вс май 27, 2012 17:43:37

Сообщение мелкая »

Alkul писал(а):
мелкая писал(а):Может кто нибудь объяснит как изменить код что бы получить интервал 1)0-6 2)0-9
под "интервалом" тут понимается количество итераций?
Диапазон!
Реклама
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Ты не оттуда берешь случайное число, видимо. Там у тебя в непосредственной близости к выходу есть "ANDI R31,0xE0" что как бы уменьшает шансы на нормальное выделение диапазона, удивительно что оно тебе дает хоть что-то на выходе.
Бери там где у тебя на выходе имеется нормальное случайное число 0..255 хотябы.
Контактная информация:
Реклама
Родился
Сообщения: 7
Зарегистрирован: Вс май 27, 2012 17:43:37

Сообщение мелкая »

Я очень сильно извиняюсь за свою бестолковость и надоедливость, но где найти это нормальное число на выходе???
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Алгоритм сама разрабатывала? По какому принципу он работает?
Классика - это длинный сдвиговый регистр с обратными связями.

В ЭТОТ алгоритм я еще не вкурил, шибко он ээээ... непонятный и без коментариев.
Особенно важны комментарии к используемым переменным-регистрам.

Более того регистры R30 и R31 рабочие. Скопируй в конце с регистра R30 в R28 например и обрезай его тем алгоритмом что я дал. Нельзя менять значение регистров R30 и R31 это сбивает работу ГСЧ.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

самый простой способ что бы получить интервал ...... нужно из исходного значения вычитать число на 1 большее максимального значения интервала, до тех пор, пока остаток больше вычитаемого......
Реклама
Родился
Сообщения: 7
Зарегистрирован: Вс май 27, 2012 17:43:37

Сообщение мелкая »

Alexeyslav писал(а):Алгоритм сама разрабатывала? По какому принципу он работает?
Классика - это длинный сдвиговый регистр с обратными связями.

В ЭТОТ алгоритм я еще не вкурил, шибко он ээээ... непонятный и без коментариев.
Особенно важны комментарии к используемым переменным-регистрам.

Более того регистры R30 и R31 рабочие. Скопируй в конце с регистра R30 в R28 например и обрезай его тем алгоритмом что я дал. Нельзя менять значение регистров R30 и R31 это сбивает работу ГСЧ.
попробовала как вы сказали и получился диапазон от 0-7, ANDI R28, 0xE0 если ставить значение 0x0F ничего не выводит!

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

MOV   R28,R30                  
		
			ANDI R28, 0xE0
loop:		CPI R28, 0x0A   
			BRLO next
	;		SUBI R28, 0x0A 
	;		rjmp loop

next:		SWAP  R28
			LSR   R28
		;	INC   R28            
			MOV   random,R28
Реклама
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Хорошо, а отладка что дает? какое значение находится в R30 R31 на момент начала выполнения этого кусочка алгоритма?

Чтобы что-то существенное появилось в R30 и R31 алгоритм надо прокрутить несколько раз.

И до меня только что дошло что это очень фиговый и предсказуемый ГСЧ, поэтому у тебя в первом варианте и пошла "интерференция" в виде повторяющихся чисел.

Копируй все-таки в R28 содержимое регистра R31.

и правильно будет ANDI R28, 0x0F и никак не иначе. Эта строчка должна ограничивать количество бит, чтобы зря не крутится в цикле вычитая 10. Но вообще, её можно убрать вообще. Только тогда алгоритм будет прокручивать вычитание от 0 до 25 раз чтобы результат попал в нужные рамки. Вобщем-то это самый простейший но ресурсоемкий вариант реализации функции деления чисел.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

Оригинал линейного конгруентного генератора ПСЧ:

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

;
;X(i+1)= ( A*X(i) + B) mod 65536
;
;A= 77 (A mod 4= 1)
;B= 1 нечетное
;
;

random:
   MOV   R30,rnd_l   ;N=X
   MOV   R31,rnd_h

   LSL   rnd_l      ;*2
   ROL   rnd_h
   LSL   rnd_l      ;*4
   ROL   rnd_h

   ADD   R30,rnd_l   ;N=N+X*4
   ADC   R31,rnd_h

   LSL   rnd_l      ;*8
   ROL   rnd_h
   
   ADD   R30,rnd_l   ;N=N+X*8
   ADC   R31,rnd_h

   LSL   rnd_l      ;*16
   ROL   rnd_h
   LSL   rnd_l      ;*32
   ROL   rnd_h
   LSL   rnd_l      ;*64
   ROL   rnd_h

   ADD   R30,rnd_l   ;N=N+X*64  итого N= X*77
   ADC   R31,rnd_h

   ADIW   R30,1   ;N=N + 1

   MOV   rnd_l,R30   ;X=N
   MOV   rnd_h,R31

   ANDI   R31,0xE0   ;xxx0 0000
   CPI   R31,0xC0
   BRCC   random
                  ; 0...5,0 0000
   SWAP   R31
   LSR   R31
   INC   R31            ;0000 0,1...6
   MOV   rnd,R31

   RET
Docendo discimus
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2560
Зарегистрирован: Ср янв 16, 2008 08:34:04
Откуда: KMV

Сообщение serg_svd »

Прошу помощи с обработкой данных в АЦП ATtiny13A. Решил осваивать ассемблер, но не все с ходу получается. Итак, есть устройство на данном МК. Его задача, используя АЦП, сравнивать полученные значения с пороговыми и зажигать светодиоды.
С инициализацией МК, портов, АЦП справился. Особых трудностей не возникло. После инициализации АЦП, запускаем однократное преобразование с разрешением прерывания и переводом МК в режим ADC Noise Reduction. По окончании преобразования, уходим по вектору прерывания ADCCaddr (ADC Conversion Complete) на подпрограмму считывающую значения старшего и младшего регистров АЦП

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

adc_complete:	
		ldi zl, adcl			; Считываем младший байт
		ldi zh, adch			; Считываем старший байт
		reti				; возврат из пррывания
До этого момента в AVR симуляторе все проходит как и задумано.
Но дальше столкнулся с непониманием как мне сравнить эти считанные данные с пороговыми значениями, которые я посчитал заранее сам. То есть МК нужно только сравнивать с готовыми пороговыми значениями. Считать он ничего не будет сам. Нужен аналог команды If...Then...Else, но при этом надо как-то сравнивать двухбайтные числа.
Как пример, первое пороговое значение в десятичном виде равно 795 (АЦП 10 битный)
Вырвнивать результат по левому краю и переходить на 8 битный режим АЦП я не хочу. Снижается точность измерения напряжения с 0,014 В до 0,056 В. Меня это не устраивает

И вопрос №2, но он относится к вышеизложенному. Если я присвою метке значение

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

.EQU U1 = 795
то можно ли потом как-то работать с этой меткой напрямую и сравнивать с преобразованным значением? Это связано просто с удобством изменения пороговых значений. Или необходимо делить на старший и младший байт?
"Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли
Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

serg_svd писал(а):но при этом надо как-то сравнивать двухбайтные числа.
... так же как и однобайтные - анализируя флаги...... смотри встроенную справку по ассемблеру в AVR Studio
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

serg_svd
Сравнивать двухбайтные числа просто: команда CPC (как и CP, только флаг переноса учитывает).
Ну например так:

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

.EQU my_const = 795 ; Наша константа
...
LDI R16, HIGH(my_const)
LDI R17, LOW(my_const)

CP ZH, R16
CPC  ZL, R17
ляляля
Собутыльник Кота
Аватара пользователя
Сообщения: 2560
Зарегистрирован: Ср янв 16, 2008 08:34:04
Откуда: KMV

Сообщение serg_svd »

ChipKiller писал(а): ... так же как и однобайтные - анализируя флаги...... смотри встроенную справку по ассемблеру в AVR Studio
Я не совсем понял где это там искать?
Если можно поподробнее, я все же новичок в этом :facepalm:
"Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли
Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Сравнивать числа несложно, достаточно вычесть пороговое из анализируемого и в зависимости от флагов делать то что нужно. Если результат равен нулю, после вычитания выставляется признак Z в статусе, далее можно использовать команду перехода BREQ, или лучше BRNE для перехода к следующей проверке.
Но тебе надо скорей всего проверять на условие БОЛЬШЕ или МЕНЬШЕ, используй другие признаки.
Например признак переноса C возникнет когда анализируемое число МЕНЬШЕ порога, поскольку в результате вычитания возникает заём. далее используй команды перехода BRxx в зависимости от необходимой логики.
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2560
Зарегистрирован: Ср янв 16, 2008 08:34:04
Откуда: KMV

Сообщение serg_svd »

Правильно и я понял ваши советы для преобразованного значения выше или равного пороговому?

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

.EQU U1 = 795
..........
ldi R17, high(u1)
ldi R18, low(u1)
cp zh, R17
cpc zl, R18
brsh blue_ON
Если все верно, то это лишь вершина айсберга. Далее мне нужно проверить следующие пороговые значения:
1) >=u2 AND <u1
2) >= u3 AND <u2
3) <u3

При этом u1>u2>u3. Подскажите пожалуйста как правильнее это реализовать и следует ли сразу из всех пороговых значений (констант) извлеч старший и младши байт в РАЗНЫЕ регистры (потребуется 6 регистров) Или можно сделать последовательный перебор условий и использовать при этом одни и теже 2 регистра (R17, R18)?
"Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли
Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Последовательно проверить в цикле не получится, потому что нужны будут ведь разные действия а это означает что одна и та же команда перехода в цикле должна будет отправлять по разным адресам.

Возможно, легче будет сделать подпрограмму которая бы по списку значений вернула бы результат равный номеру значения которое больше требуемого, тогда проверку можно прокрутить в цикле - как только очередное значение станет больше или равно - цикл прерывается а номер итерации будет указывать на индекс значения которое стало больше. вычитаем единицу, и получаем то что нам нужно либо изначально начинаем считать с 1 а инкремент делать после проверки.

С индексом уже можно построить проверку условий типа CASE которая использует простую проверку на НЕРАВНО.
Контактная информация:
Родился
Сообщения: 5
Зарегистрирован: Вс июн 10, 2012 17:50:32

Сообщение gyparr »

привет всем, кто сидит в этой ветке)
у меня тупой вопрос, объясните плиз что делают эти строки

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

ldi r16,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)
ldi r17,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK)
Они взяты из проекта USI-SPI для аттини, так вот реально подогнать эти строки под работу SPI атмега48?
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

gyparr писал(а):...что делают эти строки

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

ldi r16,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)
ldi r17,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK)
... формируют сигнал CLK
Опытный кот
Аватара пользователя
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна

Сообщение avreal »

serg_svd писал(а):подпрограмму считывающую значения старшего и младшего регистров АЦП

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

adc_complete:	
		ldi zl, adcl			; Считываем младший байт
		ldi zh, adch			; Считываем старший байт
		reti				; возврат из пррывания
Это такой тест на внимательность форумчан? :tea:
Ну так не прошли :-)
Эта подпрограмма загружает константы, а не считывает порты.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Контактная информация:
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

avreal писал(а):Это такой тест на внимательность форумчан? Ну так не прошли :-)
... да уж - перескакивая с AVR на другие МК легко забыть про инструкции in и out :)
Собутыльник Кота
Аватара пользователя
Сообщения: 2560
Зарегистрирован: Ср янв 16, 2008 08:34:04
Откуда: KMV

Сообщение serg_svd »

avreal писал(а):Это такой тест на внимательность форумчан? :tea:
Ну так не прошли :-)
Эта подпрограмма загружает константы, а не считывает порты.
Теста никакого не было. Я пытаюсь учиться, но пока не знаю что выйдет из этого.
Команд много, в голове не все к сожалению удерживаются и тут я действительно упустил из виду команды in и out

Ну а насчет теста поясните пожалуйста мне вот такой пример

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

start:
sbic pinb, pinb0
cbi portb, pinb0
sbis pinb, pinb0
sbi portb, pinb0
rcall wait   	; Пауза
rjmp start
Это несложный код для переключения светодиода из одного сосстояния в другое. В AVR симуляторе работает без проблем. В железе не пробовал. Но вот в протеусе он не работает вообще (светодиод постоянно горит). Поясните пожалуйста почему?
А в AVR симуляторе заметил, что после выполнения команды cbi вначале пеерключается регистр порта PORTB.0, и только на следующем такте PINB.0. И только за счет этого этот кусок кода работает, позволяя "запутать" команду sbis, которая думает, что бит в порту еще установлен.
В книге по микроконтроллерам семейста ATtiny в разделе описания портов этому я пояснения не нашел.
"Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа." Ро́берт Ше́кли
Я правильных ответов знаю мало, поэтому не стесняюсь и много спрашиваю.
Ответить

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