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

Обсуждаем контроллеры компании Atmel.
Ответить
Мудрый кот
Аватара пользователя
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Время в худшем случае надо минимизировать.

Ладно. Пока хватит этого. Может со временем ещё что-то в голову придёт.
Всем кто участвовал :) , отдельно Engineer_Keen - спасибо.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15655
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

есть хорошее решение... но... у аврки нетуть команд простого вращения данных (только через С)... :cry:
Реклама
Родился
Сообщения: 1
Зарегистрирован: Ср июн 05, 2013 20:12:15

Сообщение jiffypop »

не получается реализовать часы-секундомер на AT89C51
в протеусе на индикаторах считает только до 09:09
помогите
Спойлер

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

    
 ;--------------------- 
 bank0    EQU    00000000B  ;определение банков данных
 bank1    EQU    00001000B  
                            
 ktdi     EQU    60550      ;коэффициент пересчета счетчика
                            
 ;-------------------- 
            ;
          bseg
          org 0
 bufT:    Dbit   1 
 flag  :    Dbit   1                           
          DSEG              ;
          ORG    25H        
 timsec:  DS     1   ;
               ;
                            
          ORG    30H        
 timdop:  DS     1          ; 1/200 секунды
 tim:     DS     4          ; значение времени
 tim1:    ds     4          ; 
 nomR:    DS     1          ;номер активного индикатора
 freq:    ds     1          ; 
 ksec:    ds     1          ;кол-во секунд в минуте
 kmin:    ds     1          ;макс значение 3 разряда
 k4:      ds     1          ;макс значение 2 разряда
 k2:      ds     1          ;макс значение 1 разряда
 
                            
          ORG    60H        ; 
 stack:   DS     20H        ; стека
                            
 ;##########################################################
 ;##              переопр-ие векторов irq                 ##
 ;##########################################################
          CSEG              
          ORG    0000H      ; 
          jmp    init       ; 
                            
          ORG    0003H      ; 
          reti              ; 
                            
          ORG    000BH      ; 
          jmp    dnind      ; 
                            
          ORG    0013H      ; 
          reti              ; 
                            
          ORG    001BH      ; 
          reti              ; 
                            
          ORG    0023H      ; 
          reti              ; 
                            
 ; ----------------- 
          ORG    0030H          
 init:    mov    sp,#(stack-1)  ; начальные значения  времени
                                
          mov    tim,#0         ; и коэффициентов пересчета  
          mov    tim+1,#0       ; 
          mov    tim+2,#0       
          mov    tim+3,#0       
          mov    nomR, #0   
          mov    freq, #200d
          mov    ksec, #60d
          mov    kmin, #6d
          mov    k4, #4d   
          mov    k2,#2d  
          clr    flag           ;разрешение увеличения счетчика времени
                                
 ; ---------------- Значение счетчика, маски прерываний, режим работы счетчика
          mov    TMOD,#00000001B    ; 
          mov    TH0,#(high ktdi)   ; 
          mov    TL0,#(low ktdi)    ;
          mov    IE,#10000010B      ; 
          mov    IP,#00000010B      ; 
          mov    TCON,#00010000B    ; 
                                
                                
 main:                          ;  проверка нажатия клавши установки минут
 aa:      setb    p3.4          ;
          mov     c, p3.4       ; 
          jnc  smin             ;

          setb    p3.5          ;  проверка нажатия клавши установки часов
          mov     c, p3.5       ;
          jnc  shour            ;

          setb    p3.7          ;  проверка нажатия клавши перехода в режим секундомера
          mov     c,p3.7
          jnc     tmode           

          jmp aa
 smin:    mov     timsec, #59
          mov     timdop, #199  ;+ минута 
          call     dnind       
          mov     timsec, #0
          mov     timdop, #0    
          

 a1:      setb    p3.4
          mov     c, p3.4       ; ждем, когда пользователь уберет руки с кнопки
          jnc  a1
          jmp aa 

 shour:   
          push   tim+3
          push   tim+2
         
          mov    tim+3, #9
          mov    tim+2, #5
          mov    timsec, #59    ; + час
          mov    timdop, #199
          call   dnind
          pop    tim+2          ;восстановление значения времени
          pop    tim+3    

 a2:      setb    p3.5
          mov     c, p3.5       ; ждем, когда пользователь уберет руки с кнопки
          jnc  a2
          jmp aa 
 
 
tmode:    mov    tim1, tim      ;режим секундомера
          mov    tim1+1, tim+1  ;сохранение текущего времени
          mov    tim1+2, tim+2  ;
          mov    tim1+3, tim+3
          mov    tim,#0         ; 
          mov    tim+1,#0       ; обнуление счетчиков
          mov    tim+2,#0       ;
          mov    tim+3,#0       ;

;----------------          
tmode1:   mov    ksec, #1           
          mov    timsec, #0     ;коэффициент пересчета времени для секундомера(он же считает сотые)
          mov    kmin, #10
          mov    freq, #2
          mov    k4, #9
          mov    k2, #9
          
st2:      setb   p3.5           ;остановка секундомера с обнулением

          mov    c, p3.5
          jc     st1
          setb   flag           ; запрет увеличения значений секундомера
          mov    tim,#0          
          mov    tim+1,#0        
          mov    tim+2,#0       
          mov    tim+3,#0  

          jmp    st2
           


st1:       setb p3.5         

           setb   p3.4        ; остановка без обнуления
           mov    c, p3.4
           jc   st5
st55:     
           setb    flag       ; запрет увеличения значений секундомера
           setb p3.5
           jmp    st1

st5:
            
;------------------
          clr    flag         ;  остаемся в режиме секундомера 
          setb   p3.7         ;  пока нажата кнопка
          mov    c, p3.7      ;
          jnc    tmode1       ;
         

          mov    freq, #200   ;возврат к режиму часов
          mov    ksec,#60
          mov    kmin, #6
          mov    k4, #4
          mov    k2, #2
          
                        
          mov    tim, tim1          ; и восстановление на дисплее текущего времени
          mov    tim+1,tim1+1       ; 
          mov    tim+2,tim1+2       
          mov    tim+3,tim1+3
          jmp    aa        
                             
 dnind:   push   ACC                ;сохранения acc и psw
          push   PSW              
          mov    PSW,#bank1         ; банк номер 1
          mov    TH0,#(high ktdi)   ; 
                 
          mov    TL0,#(low ktdi)    ;
                                  
 ; -----------------------          ;вывод на индикаторы
          mov    a,nomR             ; 
 ;         rrc    a                
 ;        mov    p1, #0            ; подаем на выводы p3.0, p3.1 значений
 ;         mov    p3.0,c            ; текущего индикатора
 ;         rrc    a                 ;
 ;         mov    p3.1,c            ; 
          mov p3, nomR
                                  
                                    ; Вывод точки
          mov    a,nomR           
          cjne   a,#1,dn1           ; Проверка номера разряда 
          mov    c,timsec.0         ; Мерцание точки
          jmp    dn2                
 dn1:     setb   c                  ; Точку выключаем
 dn2:     mov    bufT,c             ; Помещаем результат в буфер точки
                                  
                                    ; Вывод символа
          add    a,#tim             ; Вычисляем адрес в буфере
          mov    r0,a             
          mov    a,@r0              ; Чтение кода символа из буфера
          call   prind              ; вывод на индикатор
          inc    nomR               ; Увеличение номера текущего разряда
          mov    a,nomR           
          cjne   a,#4,dn3           ; Это последний разряд?
          mov    nomR,#0            ; Если да, то перейти на первый
 dn3:                         
                                  
 ;--------------------------------- Делитель на 200
         
         jb     flag,  dnif
         inc    timdop  
         
          mov    a,timdop         
          cjne   a,freq,dniF      
          mov    timdop,#0        
                                  
 ;---------------------------------Счет секунд
          inc    timsec           
          mov    a,timsec         
          cjne   a,ksec,dniF       
          mov    timsec,#0        
                                  
 ;------------------------------------ Счет основного таймера
          inc    tim+3              ; Единицы минут
	                                                                           
         
          mov    a,tim+3          
          cjne   a,#10d,dniF       
          mov    tim+3,#0         
                                  
          inc    tim+2              ; Десятки минут        
          mov    a,tim+2          
          cjne   a,kmin,dniF        
          mov    tim+2,#0         
                                  
          inc    tim+1              ; Единицы часов
          mov    a,tim+1          
          cjne   a,k4,dn4         
          mov    a,tim            
          cjne   a,k2,dniF        
          mov    tim,#0           
          mov    tim+1,#0         
          jmp    dniF             
 dn4:     cjne   a,#10,dniF       
          mov    tim+1,#0         
          inc    tim                ;  Десятки часов
                                  
 ;------------------------  Завершающие команды
 dniF:    pop    PSW              
          pop    ACC              
          reti                    
                                  
 
                            
                         
;###########################################
;##   процедура вывода числа на дисплей   ##
;###########################################
prind:   push   psw        ; Сохранение регистра PSW в стеке
         push   DPH        ; Сохранение регистра DPTR в стеке (старш.)
         push   DPL        ; (младш. Половина)
         mov    DPTR,#zg   ; Загрузка начала таблицы знакогенератора
         movc   a,@a+DPTR  ; Считывание кода цифры в аккумулятор
         mov    c,bufT     ; Считывание буфера точки
         mov    acc.7,c    ; Запись значения тоски в старший разряд
         mov    p1,a       ; Вывод полученного кода в порт P1
         pop    DPL        ; Восстановление регистра DPTR (младш.)
         pop    DPH        ; (старш. Половина)
         pop    psw        ; Восстановление регистра psw
         ret               ; Выход из подпрограммы
                            
                            
;--------------------------------------------------------------------
; таблица соответствия чисел коду, который надо подавать на индикатор
;--------------------------------------------------------------------
                            
         ORG    0700H      ; поближе к концу
;------------------------------------------ 
zg:      DB     11000000B  ; число  0
         DB     11111001B  ; число  1
         DB     10100100B  ; число  2
         DB     10110000B  ; число  3
         DB     10011001B  ; число  4
         DB     10010010B  ; число  5
         DB     10000010B  ; число  6
         DB     11111000B  ; число  7
         DB     10000000B  ; число  8
         DB     10010000B  ; число  9
         
  end   
Последний раз редактировалось Gudd-Head Чт июн 06, 2013 10:25:06, всего редактировалось 1 раз.
Причина: Нарушение п.2.5 Правил Форума
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

А что говорит отладчик? Попробуй запустить алгоритм счета отдельно под отладчиком в бесконечном цикле.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 162
Зарегистрирован: Вс дек 09, 2012 12:14:44

Сообщение 1essor1 »

Разбираю АЦП в тине13 по даташиту. Не совсем ясно назначение этих двух регистров:
СпойлерИзображение
ADCSRB - если мы запускаем множественные преобразования, то выбираем то, от чего они будут запускаться, так?
Допустим, если записать 010 в ADTS[2:0] то преобразования будут начинаться по каждому внешнему прерыванию INT0, да?

А DIDR0 для чего? И каково его практическое значение?
Я так понял, что там речь идет об отключении цифрового буффера на пине, используемом для АЦП, и что данное отключение позволит снизить потребление энергии?
Реклама
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

С DIDR0 все понятно - если по какому-то выводу используется АЦП, то соответствующий бит DIDR0 ставим 1, запрещая цифровой буфер. Зачем? А не будет лишний раз дергаться при изменении входного (аналогового) напряжения, что может повысить точность АЦП и, возможно, слегка уменьшит потребление.
Реклама
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Именно. Там не просто потребление, а тот факт что цифровой вход будет работать параллельно аналоговому, и когда напряжение будет колебаться около порога срабатывания цифрового входа - он будет очень часто переключатся что помимо шума в измерениях даст еще и повышенное потребление.
Контактная информация:
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

С ADCSRB - похоже да, выбирается, от чего они будут запускаться. Если вообще разрешен автоматический запуск АЦП битом ADATE регистра ADCSRA.
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 162
Зарегистрирован: Вс дек 09, 2012 12:14:44

Сообщение 1essor1 »

Спасибо за помощь! :beer: Теперь всё ясно.

Возник еще вопрос по поводу использования режима ADC noise reduction. Я понял это делается так: настраиваемся на этот режим, настраиваем и включаем АЦП, разрешаем прерывания, но преобразование не запускаем. Далее уходим в сон командой SLEEP - запускается преоразование, по окончанию которого поступившее прерывание разбудит мк? Всё так?
Опять же насколько высока реальная практическая ценность сего режима? Имеет смысл его использовать?
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Огромная ценность. Контроллер в момент измерения спит, а значит на АЦП не действуют шумы от работы внутренних узлов. Именно с этой целью введен такой режим работы.
Контактная информация:
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 162
Зарегистрирован: Вс дек 09, 2012 12:14:44

Сообщение 1essor1 »

Есть пользовательский флаг Т, который чертовски удобен, но его одного мало. Можно ли взять какой-нибудь регистр, и сделать из него регистр с флагами, чтобы каждый бит был отдельным флагом, в идеале обозванный своим именем. И я так понимаю придется писать макросы ветвления, в зависимости установлен флаг или нет(на подобии BRTC и BRTS)?

Как вообще лучше поступить в данной ситуации?

P.S. допустим так

.def FLAG_REG = r16

.equ flag7 = 7
.equ flag6 = 6
.equ flag5 = 5
.equ flag4 = 4
.equ flag3 = 3
.equ flag2 = 2
.equ flag1 = 1
.equ flag0 = 0

установка флага
ldi FLAG_REG, (1<<flag5)

сброс флага
ldi FLAG_REG, (0<<flag5)

А как организовать ветвление по установленному/сброшеному пока не придумал :dont_know:
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

Сбросить и установить флаг с помощью LDI не получится. Надо использовать SBR, CBR (кстати, которые аналогичны ANDI и ORI по кодам инструкций)

А ветвления - SBRS/SBRC

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

Сообщение Alexeyslav »

нет так не выйдет... LDI ты установишь флаг но напрочь затрешь все остальные.

я использую макросы:

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

 .macro set_bit
  SET
  BLD   @0,@1
.endmacro

.macro clear_bit
  CLT
  BLD   @0,@1
.endmacro

.macro go_if_set
 BST    @0,@1
 BRTS   @2
.endmacro

.macro go_if_clear
 BST    @0,@1
 BRTC   @2
.endmacro
0-вой параметр можно заменить на константу, в твоем случае FLAG_REG

или для каждого регистра сделать именные макросы, чтобы каждый раз не указывать имя регистра к которому он привязан. А если часто используешь макрос к конкретному биту, то можно сделать индивидуальные макросы.
Контактная информация:
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 162
Зарегистрирован: Вс дек 09, 2012 12:14:44

Сообщение 1essor1 »

ploop, а у меня как раз этих команд в справочнике почему то не было :dont_know: Я уж тут велосипед стал изобретать, с масками и сравнениями :)))

Alexeyslav, спасибо за наработки! Только одно но. Вы же используете флаг Т в макросах, не стоит ли по заходу в макрос топить содержимое регистра SREG в стеке, а потом доставать. Вдруг этот флаг используется, а здесь он произвольным образом изменится?
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Слишком накладно выходит. Как правило, если доходишь до того уровня что есть необходимость использовать эти макросы, то флаг T у тебя не используется. А это происходит когда есть необходимость использовать два флага и больше. поэтому, используй макросы и забудь про индивидуальное использование этого флага. А ежели все-таки используешь, то добавь сохранение в стеке регистра флагов, это сразу добавит на одну операцию лишних 10 тактов(+4 ячейки памяти программ на каждую операцию с флагом) и опять же потребует один свободный регистр(а если нет - то +4 такта на его сохранение). не слишком уж много сложностей для реализации простых флагов? Проще забыть про использование флага T и пользоваться макросами.
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

ploop, а у меня как раз этих команд в справочнике почему то не было :dont_know: Я уж тут велосипед стал изобретать, с масками и сравнениями :)))
А, возможно их добавили для новых версий AVR - 48-88-168. Я говорю же, то их код совпадает, что и операций ANDI и ORI, то есть ваш велосипед с масками вовсе не велосипед.
Проще забыть про использование флага T и пользоваться макросами.
Вы про собственный регистр с флагами?
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

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

Сообщение ploop »

Нет конечно. Я его использую чаще с командами BLD-BST (как в макросе у вас выше)
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

ploop писал(а):А, возможно их добавили для новых версий AVR - 48-88-168. Я говорю же, то их код совпадает, что и операций ANDI и ORI
Да нет, для ATmega8 они прекрасно есть. Интересно, что SBR совпадает с ANDI, а CBR имеет такой же код, но константа инвертируется компилятором, ведь обнуляются биты, соответствующие единицам константы.

Каких-то команд может не быть в какой-то таблице, т.к. полно книг по AVR (большинство), где рассматриваются древние МК, и/или таблица команд дана урезаной.
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

SBR это вроде синоним ORI.

Но у меня прикол был с CBR - по алгоритму идет очистка одной половинки байта, затем SWAP и вторая половинка, точно такой же командой. в AVRStudio первая команда CBR не делает ничего! а вторая срабатывает... точно так же себя ведет протеус(вот что странно), после замены на ANDI с нужной константой - все работает на ура, хотя код команды в прошивке ТОЧНО ТАКОЙ ЖЕ. Пипец, 3 дня потерял чтобы найти эту заковырку. Никогда не думал что проблема может воспроизвестись в двух совершенно разных программах.
Контактная информация:
Ответить

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