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

Обсуждаем контроллеры компании Atmel.
Ответить
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

"Проиксорить все биты в байте" с человеческого на бюрократический переводится как "посчитать единицы, определить, является их количество чётным или нечётным".
Или не переводится (ср. "вычесть все цифры в числе").

Компактно - сдвигами в цикле.
Быстро - по таблице.
Для любой хотелки должна быть специальная кнопка в AVR studio 4, надо найти её в ней - хм...
Реклама
Открыл глаза
Аватара пользователя
Сообщения: 63
Зарегистрирован: Вс май 30, 2010 20:27:33
Откуда: Санкт-Петербург

Сообщение Kill17 »

Спасибо, сделал так !

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

======== r16 - регистр с байтом
   CLR   R18
   CLR   R19
   LDI   R20,1
 write_bit:
      SBRC  R16,0
      EOR   R19,R20                       
      ROR   R16
      INC   R18
      CPI   R18,8
      BRNE  write_bit
;=========== в регистре R19 - результат 
Контактная информация:
Реклама
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

Циклом:

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

.def MyByte = R16
.def OnesCounter = R17
.def BitCounter = R18      ; программа должна быть читаемой, а не шифрованной! кульксакеп-стайл

ldi BitCounter, 8        ; такие счётчики практичнее вычитать, чем прибавлять - цикл так и эдак заканчивается по условию brne, но вычитание само по себе ставит флаг Z, без дополнительных сравнений

nextbit:
rol MyByte                 ; или ror, нам без разницы, с какой стороны начинать считать единицы (или нули, по сути то же самое) - интересует только их общее количество... можно даже lsl или lsr
brcc pc + 2                ; или brcs, по сути получится то же самое, но наоборот
inc OnesCounter
dec BitCounter
brne nextbit

; OnesCounter = количество единиц в MyByte (или нулей, по сути то же самое)
; в нечётном числе младший бит =1, в чётном =0

; отдельный вопрос - нужен ли нам дальше исходный MyByte... в реальной ситуации скорее нет, чем да
По таблице:

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

ldi ZH, high(Table * 2)
ldi ZL, low(Table * 2)

add ZL, MyByte
brcc pc + 2
inc ZH

lpm OnesCounter, Z

Table:

.db 0   ; количество единиц в числе 0b00000000
.db 1   ; количество единиц в числе 0b00000001
.db 1   ; количество единиц в числе 0b00000010
.db 2   ; количество единиц в числе 0b00000011
.db 1   ; количество единиц в числе 0b00000100
...
А смысл?
А если в AVR studio 6.2? А если вообще не в AVR studio?
Открыл глаза
Аватара пользователя
Сообщения: 63
Зарегистрирован: Вс май 30, 2010 20:27:33
Откуда: Санкт-Петербург

Сообщение Kill17 »

Возник вопрос по прерываниям. Камень - Atmega168. Вроде все сделал как надо, а прерывания не работает, что в железе, что в симуляторе. Прога запускается, доходит до команды SEI и все, сразу возврат в таблицу прерываний и тд. Может я что-то проглядел?
Спойлер

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

          .nolist
           .include "m168def.inc"
           .list

           .equ XTAL = 20000     
           .equ BAUD = 9600   
           .equ NB = ((10000*XTAL)/(16*BAUD)-5)/10

; ========= Interrupts ================= 

         .cseg
         .org $0000        	
          JMP RESET        ; (RESET) 
     ;    .ORG $002
     ;    RETI             	; (INT0) External Interrupt Request 0
     ;    .ORG $004
     ;    RETI             	; (INT1) External Interrupt Request 1
     ;    .ORG $006
     ;    RETI		      	; (PCINT0) Pin Change Interrupt Request 0
     ;    .ORG $008
     ;    RETI             	; (PCINT1) Pin Change Interrupt Request 1
     ;    .ORG $00A
     ;    RETI		      	; (PCINT2) Pin Change Interrupt Request 2
     ;    .ORG $00C 
     ;    RETI			  	; (WDT) Watchdog Time-out Interrupt
     ;    .ORG $00E
     ;    RETI				; (TIMER2 COMPA) Timer/Counter2 Compare Match A
     ;    .ORG $010
     ;    RETI			  	; (TIMER2 COMPB) Timer/Counter2 Compare Match B
     ;    .ORG $012
     ;    RETI			 	; (TIMER2 OVF) Timer/Counter2 Overflow
     ;    .ORG $014
     ;    RETI             	; (TIMER1 CAPT) Timer/Counter1 Capture Event
     ;    .ORG $016
     ;    RETI	     	  	; (TIMER1 COMPA) Timer/Counter1 Compare Match A
     ;    .ORG $018
     ;    RETI	            ; (TIMER1 COMPB) Timer/Coutner1 Compare Match B
     ;    .ORG $01A
     ;    RETI            	; (TIMER1 OVF) Timer/Counter1 Overflow
     ;    .ORG $01C
     ;    RETI		      	; (TIMER0 COMPA) Timer/Counter0 Compare Match A
     ;    .ORG $01E
     ;    RETI             	; (TIMER0 COMPB) Timer/Counter0 Compare Match B
     ;    .ORG $020
     ;    RETI             	; (TIMER0 OVF) Timer/Counter0 Overflow
     ;    .ORG $022
     ;    RETI             	; (SPI, STC SPI) Serial Transfer Complete
         .ORG $024
          JMP RX_RS232             	; (USART, RX USART) Rx Complete
     ;    .ORG $026
     ;    RETI             	; (USART, UDRE USART), Data Register Empty
     ;    .ORG $028
     ;    RETI             	; (USART, TX USART), Tx Complete
	 ;    .ORG $02A
     ;    RETI             	; (ADC) ADC Conversion Complete
     ;    .ORG $02C
     ;    RETI             	; (EE READY) EEPROM Ready
     ;    .ORG $02E
     ;    RETI             	; (ANALOG COMP) Analog Comparator
     ;    .ORG $030
     ;    RETI             	; (TWI) 2-wire Serial Interface
     ;    .ORG $032
     ;    RETI               ; (SPM READY) Store Program Memory Ready
	  	 .ORG   INT_VECTORS_SIZE      	; Êîíåö òàáëèöû ïðåðûâàíèé

; ========= END Interrupts =================    
 
RESET:
	

      LDI   R16,low(RAMEND) 
      STS   SPL,R16
      LDI   R16,high(RAMEND)
      STS   SPH,R16
      CLR   R16        
      STS   UBRR0H,R16
      LDI   R16,NB   
      STS   UBRR0L,R16
     
	
      LDI   R16,(1<<RXEN0)|(0<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)  
      STS   UCSR0B,R16
      LDI   R16,(1<<UCSZ00)|(1<<UCSZ01)
      STS   UCSR0C,R16


;===========
      LDI	R16,(1<<PB3)         
      OUT	DDRB, R16
      SBI   PORTB,3
;=========
SEI
JMP MAIN
RETI

RX_RS232:
      LDS  R16,UDR0
      cbi portb,3
RETI

Main:
NOP
NOP
JMP Main
RETI


Что-то вообще процесс дошел до смешного! Все равно картина такая же!
Спойлер

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

           .include "m168def.inc"
; ========= Interrupts =================
         .cseg
         .org $0000           
          RJMP RESET        ; (RESET)
         .ORG $002
         RETI                ; (INT0) External Interrupt Request 0
     ;    .ORG $004
     ;    RETI                ; (INT1) External Interrupt Request 1
     ;    .ORG $006
     ;    RETI               ; (PCINT0) Pin Change Interrupt Request 0
     ;    .ORG $008
     ;    RETI                ; (PCINT1) Pin Change Interrupt Request 1
     ;    .ORG $00A
     ;    RETI               ; (PCINT2) Pin Change Interrupt Request 2
     ;    .ORG $00C
     ;    RETI              ; (WDT) Watchdog Time-out Interrupt
     ;    .ORG $00E
     ;    RETI            ; (TIMER2 COMPA) Timer/Counter2 Compare Match A
     ;    .ORG $010
     ;    RETI              ; (TIMER2 COMPB) Timer/Counter2 Compare Match B
     ;    .ORG $012
     ;    RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
     ;    .ORG $014
     ;    RETI                ; (TIMER1 CAPT) Timer/Counter1 Capture Event
     ;    .ORG $016
     ;    RETI                ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
     ;    .ORG $018
     ;    RETI               ; (TIMER1 COMPB) Timer/Coutner1 Compare Match B
     ;    .ORG $01A
     ;    RETI               ; (TIMER1 OVF) Timer/Counter1 Overflow
     ;    .ORG $01C
     ;    RETI               ; (TIMER0 COMPA) Timer/Counter0 Compare Match A
     ;    .ORG $01E
     ;    RETI                ; (TIMER0 COMPB) Timer/Counter0 Compare Match B
     ;    .ORG $020
     ;    RETI                ; (TIMER0 OVF) Timer/Counter0 Overflow
     ;    .ORG $022
     ;    RETI                ; (SPI, STC SPI) Serial Transfer Complete
         .ORG $024
          JMP RX_RS232                ; (USART, RX USART) Rx Complete
     ;    .ORG $026
     ;    RETI                ; (USART, UDRE USART), Data Register Empty
     ;    .ORG $028
     ;    RETI                ; (USART, TX USART), Tx Complete
    ;    .ORG $02A
     ;    RETI                ; (ADC) ADC Conversion Complete
     ;    .ORG $02C
     ;    RETI                ; (EE READY) EEPROM Ready
     ;    .ORG $02E
     ;    RETI                ; (ANALOG COMP) Analog Comparator
     ;    .ORG $030
     ;    RETI                ; (TWI) 2-wire Serial Interface
     ;    .ORG $032
     ;    RETI               ; (SPM READY) Store Program Memory Ready
      
; ========= END Interrupts =================   
 
RESET:
   
      LDI   R16,low(RAMEND)
      STS   SPL,R16
      LDI   R16,high(RAMEND)
      STS   SPH,R16
      CLR   R16       
SEI

Main:
NOP
NOP
JMP Main
RETI



RX_RS232:
RETI
Нашел проблему!
LDI R16,low(RAMEND)
OUT SPL,R16
LDI R16,high(RAMEND)
OUT SPH,R16
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1314
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Именно поэтому лучше юзать библиотеку макроопределений.
Тогда бы стартовая инициализация уложилась бы в три безошибочных строки:

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

STACKINIT // Инициализация стека
 RAMFLUSH  // Очистка ОЗУ
 GPRFLUSH  // Очистка РОН (Регистров Общего Назначения)
Реклама
Мудрый кот
Аватара пользователя
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Задал вопрос, сам нашёл ответ! Kill17, круто!
НАПАЛМ писал(а):Именно поэтому лучше юзать библиотеку макроопределений.
Лучше, хуже...философия... :) Сам то понял в чём была проблема с инициализацией стека у Kill17?
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Открыл глаза
Аватара пользователя
Сообщения: 63
Зарегистрирован: Вс май 30, 2010 20:27:33
Откуда: Санкт-Петербург

Сообщение Kill17 »

Kavka писал(а): Сам то понял в чём была проблема с инициализацией стека у Kill17?
Я так понял, что он не прописывался из-за команды STS, я правельно понял&?
Контактная информация:
Мудрый кот
Аватара пользователя
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Kill17, ну, да, можно сказать, что и из-за неё. Хотя, скорее из-за того, что вы упустили тот момент, что команды in/out работают в адресном подпространстве сдвинутом относительно основного пространства данных.
И чтобы LDS/STS при тех определениях, что есть работали правильно надо вот так записать

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

      LDI   R16, low(RAMEND)
      STS   SPL + 0x20, R16
      LDI   R16, 0x20 + high(RAMEND)
      STS   SPH + 0x20, R16
А можно воспользоваться макросом, тогда команда будет подставляться соответствующая адресу регистра в/в.
Спойлер

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

.MACRO STORE 		;параметры: адрес, регистр
	.if	@0>0x3F
		sts	@0, @1
	.else
		out	@0, @1
	.endif
.ENDMACRO

.MACRO LOAD 		;параметры: адрес, регистр
	.if	@1>0x3F
		lds	@0, @1
	.else
		in	@0, @1
	.endif
.ENDMACRO
http://www.atmel.com/Images/doc2550.pdf
http://www.atmel.com/images/AVR001.zip
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Друг Кота
Аватара пользователя
Сообщения: 20093
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

НАПАЛМ писал(а):

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

 RAMFLUSH  // Очистка ОЗУ
 GPRFLUSH  // Очистка РОН (Регистров Общего Назначения)
Нафига вот это делать?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

Явной инициализацией ВСЕХ ячеек гарантируется начало работы с определённого и единственного состояния. Всегда.
Сам по себе переход на адрес "ресет" их не инициализировал бы.

Но и здравым смыслом тоже можно пользоваться - как в дополнение к "потому что так НАДО", так и вместо.



(я так и не понял, для чего занадобился подсчёт количества единиц в байте... начинающему программисту)
Последний раз редактировалось nirq Пн июл 07, 2014 10:08:36, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 20093
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

nirq писал(а):Сам по себе переход на адрес "ресет" их не инициализировал бы.
Так а зачем их инициализировать? В программе всё равно идёт ПРИСВОЕНИЕ значения, без разницы что там было до этого.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

А это уже и есть здравый смысл: сначала обнулили 1024 ячейки "оптом", потом сразу переинициализировали 50 из них отличными от нуля значениями "в розницу".
Или не сразу, а ближе к середине. И разные ячейки в разных местах.
Или 49 ячеек инициализировали, а про ещё одну забыли. И привет отладка.

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

Чат.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1314
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Kavka писал(а):Задал вопрос, сам нашёл ответ! Kill17, круто!
НАПАЛМ писал(а):Именно поэтому лучше юзать библиотеку макроопределений.
Лучше, хуже...философия... :) Сам то понял в чём была проблема с инициализацией стека у Kill17?
Да, я прогонял у себя программу, хотел написать, гляжу, а тут уже и сам он ответил.

По поводу обнуления озу и рон: да, это не всегда нужно, согласен. Но это 100% верняк, минус еще одно место возможных косяков. Лучше задать начальную точку отсчета и плясать от неё. Мало ли как программу решишь написать и какие ходы придумать.
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

РОНы обнуляются вместе со всей периферией по любым сигналам сброса, и обнулять их стоит только в том случае если вы используете "программный сброс" путем перехода на вектор сброса. Но это вообще довольно специфическое применение и усы надо держать остро... там и проблемы с инициализацией периферии могут возникнуть.
Контактная информация:
akl
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

РОНы обнуляются вместе со всей периферией по любым сигналам сброса
:shock: Отсебятина. Удалите, пока никто не видел.
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

И опять здравый смысл: РОН явно инициализируется непосредственно перед любой (разумной) попыткой им воспользоваться.
Как временная, сугубо локальная переменная.

ldi Maksimum, 100
cp TekuscheeZnachenie, Maksimum
brsh ...


или

lds Temp1, TekuscheeZnachenie
lds Temp2, Maksimum

cp Temp1, Temp2
brsh ...


Поэтому проблема (не)инициализации РОН при ресете имеет скорее академический характер, чем практический.
А за аппаратные ("периферийные") регистры вопрос отпадёт сам собой, если приглядеться например к MCUCSR.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Сообщение dr.doc »

Возможно пишу не совсем по этой теме, за что прошу прощения.
В общем, суть проблемы(?) такова: задался целью написать на ассемблере программу для работы с датчиком DS18B20, и, в принципе, успешно ее решил. Но! В datasheet сказано, что датчик выдает при чтении 1. LSB температуры, 2. MSB температуры, 3 и 4-й байты регистры аварии верхнего и нижнего предела, 5. Регистр конфигурации, 3 резервных байта и байт CRC.
Так вот, в Proteus для корректного съема температуры приходится конвертировать 1-й и 3-й байты! Конечно, в документе есть сноска "если функция аварии DS18B20 не используется, то регистры TH and TL могут быть ячейками универсальной памяти" - Какой и как я не нашел. И как в реальности работает такой датчик?
PS Датчик один. Конфигурация: Presense, SKIP ROM, READ ROM, запись 9-ти байт по порядку в ОЗУ (.dseg .org 0x60 rec: .byte 9), Convert temperature. И, далее, с опросом состояния по циклу.
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
akl
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Много лишнего. Может так проще.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Сообщение dr.doc »

Так я ведь так и делаю. Единственное отличие - начал смотреть все 9 байт. Сначала выводил их по UART, а потом конвертировал в hex и на 44780. Просто может модель датчика такая? С 2-мя первыми байтами дело не прошло, поэтому пришлось читать все для понимания причин...
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 39
Зарегистрирован: Пн дек 31, 2012 13:16:59

Сообщение *скрыто* »

Так не должно быть, а уверенны что корректно считываются все 9 байт? Быть может что-то со скоростью и датчик молчит при опросе второго байта а начинае отдавать второй когда считываете третий

В регистрах TH TL можно хранить любые 2 байта если не пользоваться командой alarm search. Это и подразумевается под ячейками универсальной памяти
Ответить

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