Обсуждаем контроллеры компании Atmel.
Ответить

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

Пт авг 03, 2007 17:25:54

Доброго времени суток всем.
Вопрос конечно нужно было задать в обучалке, но боюсь меня там не услышат, по этому прошу простить меня и помоч :cry:
Вопрос в следующем, пришел тот злащасный день когда мне понадобилась работа с не целыми числами типа 1,5 в ассемблере, ести ли какие либо стандартные варианты работы с такими числами или нужно чегото мудрить, если мудрить то как???
Может у кого есть заготовки для работы с такими числами.
Заранее спасибо.

Пт авг 03, 2007 17:52:19

воспользуйся поиском - на эту тему были разговоры...

Пт авг 03, 2007 19:56:47

Вот здесь посмотрите...

Пт авг 03, 2007 23:35:18

На офф.сайте Атмел находил какие то экзамплы...

Сб авг 04, 2007 11:08:48

Я бы начал с выяснения, ассемблер КАКОГО таракана рассматривается. PIC, Atmel... да их же много. Вот в ассемблере IBM PC :) вполне можно работать с IEEE-шной плавучкой и командами сопроцессора :).

Второй вопрос - в каком диапазоне нужны числа и с какой точностью. По секрету: иногда помогаат ужасный прием: просто перейти в другой масштаб. Нужно "полтора"? Пиши 15 или 150... или 1500... Держи делитель в уме и не забудь скорректировать масштаб при выводе числа куда надо.

Сб авг 04, 2007 19:25:59

Всем большое спасибо за советы, вроде разобрался, использую вариант с масштабом, работает!

Ср дек 05, 2007 20:08:52

Здравствуйте!

Помогите пожалуйста в ассемблере. Нужно запустить 16 битный таймер, и в определенный момент его считать и сбросить. (ATTiny2313) Я смотрел datasheet и несколько переведенных статей. Мне нужны только CS12, CS11 и CS10 (001)-делитель частоты. А что делать с остальными битами настройки? В ноль их всех? И надо ли их вообще устанавливать если они мне не нужны?
Как устанавливать параметры таймера?
Так?
ldi r17,0b00000001
out TCCR1B,r17
Чтение и установка в даташите вроде понятно написано (с примером)
Как таймер запустить? Или он запускается автоматически? (вместе с МК)

Ср дек 05, 2007 20:21:49

Ассемблер для AVR руководство на русском.
Последний раз редактировалось tych Чт май 15, 2008 11:34:30, всего редактировалось 1 раз.

Ср дек 05, 2007 20:29:46

Да я нашел его. Нужная вещь. Но это три бита из байта TCCR1B а остальные биты как ставить? Какие настройки нужно ОБЯЗАТЕЛЬНО настроить у таймера? Как насчет остальных вопросов?

Ср дек 05, 2007 20:56:20

Там код не ассемблековский. Как установить параметры в ассемблере? Если кто может подсказать конкретней буду рад почитать ответ.

Ср дек 05, 2007 21:51:25

Инженер писал(а):Как таймер запустить? Или он запускается автоматически? (вместе с МК)
таймер запускается сразу после установки нужного коэффициента предделителя. останавливается при задании CS10=CS11=CS12=0

Вт янв 29, 2008 12:57:40

Артур писал(а):Здравствуйте! Помогите разобраться пожалуйста? Я хочу чтоб контроллер установил порт В в высокий уровень и через 2 сек в низкий уровень и на этом всё прекратилось! А получается что он постоянно мигает :( будто программа запускается снова и снова
Вот сам код:
Код:
;подключаем файл описания регистров
.include "c:/wavrasm/include/tiny2313.inc"

;задаем имена регистрам для удобства
.def temp=r17
.def temp1=r18
.def temp2=r19

;присваиваем значения temp и temp1
ldi temp,0xff
ldi temp1,0x00

;установливаем порт В на выход
out ddrb,temp

;зажигаем порт В
out portb,temp
 
;вызываем подпрограмму задержки 2 секунды
rcall loop
   
;гасим порт В
out portb,temp1

;подпрограммa задержки 2 сек
loop:   
   ldi  R21, 0x48
loop0:  ldi  R22, 0xBC
loop1:  ldi  R23, 0xC4
loop2:  dec  R23
        brne loop2
        dec  R22
        brne loop1
        dec  R21
        brne loop0
        ldi  R21, 0x02
loop3:  dec  R21
        brne loop3
        nop
        nop
ret

В чем тут фишка? Спасибо!


Что-то я не вижу вектора прерывания reset... :shock:

А вообще есть два способа:
1. Поставить перед loop: оператор sleep и контроллер будет спать.
2. Перед loop написать:
Код:
main:
    rjmp main

тогда МК зациклиться на этом месте.

Вт янв 29, 2008 14:35:30

Спасибо Mamonth за идею! Можно действительно так поступить
Код:
main:
    rjmp main

Но всётаки с чем простите связана эта аномалия выполнения программы циклически? Ведь в моём коде нет перехода на начало!
Конечно мы обманем и зациклим её в этом месте но хотелось бы всетаки с этим разобраться. Я уже и компиляторы разные попробовал - не в них дело!

Вт янв 29, 2008 16:02:40

никакой аномалии нет - RET в конце твоего кода и заставляет программу начаться заново

Ср янв 30, 2008 10:53:37

ARV писал(а):никакой аномалии нет - RET в конце твоего кода и заставляет программу начаться заново
Спасибо! А как зделать так чтоб она не начиналась заново? А я мог потом использовать задержку из любого другого места программы ну типа так
Код:
rjmp loop

Ср янв 30, 2008 11:36:33

структура программы должна быть такой:
Код:
; объявления констант, переменных и т.п.
     .org 0
     rjmp   Start  ; переход на начало основного участка программы
; тут размещаются векторы прерываний
     rjmp   Interrupt1 ; какой-то вектор прерываний
 
Start:
     ; тут начинается инициализация стека
     ; потом все подготовительные операции
     ; настройка портов, таймеров и т.п.
MainLoop:
    ; тут начинается участок основного цикла,
    ; т.е. тот код, который непрерывно циклически выполняется
    ; отсюда можно вызывать вспомогательные подпрограммы
    rcall    Delay

    rjmp   MainLoop ; переход к началу цикла
    ; если не надо зацикливаться, то надо как-то остановить выполнение кода в этой точке, например так:
    rjmp    PC   ; предыдущий rjmp не нужен, разумеется

; тут начинаются вспомогательные подпрограммы
Delay:
    ; подпрограмма задержки
    ret

OtherProc:
    ; еще какая-то подпрограмма
    ret

Interrupt1:
    ; обработчик какого-то прерывания
    reti

    ; и так далее

Пн мар 03, 2008 15:37:09

Спасибо! Всё понял! :)
И ещё вопросик почему не получается вызывать подпрограммы? Посмотрите пожалуйста код?
Код:
.include "C:\VMLAB\include\2313def.inc"
.def temp=r16
.def temp1=r17
.def temp2=r18
.def clear_display=r19
.def return_home=r20
.def display_on=r21
.def display_off=r22
.def function_set=r23
.def write_data=r24
.def write_command=r25
.cseg
.org 0
;векторы прерываний
rjmp RESET
       
RESET:
   rjmp START
reti
;начало проги
START:
;настройка портов
   ldi temp,0xff
   ldi temp1,0b01100000
   out ddrb,temp      ;port b выход
   out ddrd,temp1     ;port d 5 и 6 ножки выходы а остальные входы
   ldi temp,0x00
   ldi temp1,0x00
   ;порты настроены!!!

;создадим команды для дисплея
   ldi clear_display  ,0b00000001 ;записывать в порт b
   ldi return_home    ,0b00000010 ;записывать в порт b
   ldi display_on     ,0b00001100 ;записывать в порт b
   ldi display_off    ,0b00001000 ;записывать в порт b
   ldi function_set   ,0b00110100 ;записывать в порт b
   ldi write_data     ,0b00100000 ;записывать в порт D
   ldi write_command  ,0b00000000 ;записывать в порт D
   ;команды созданы

;инициализация дисплея
   out portd,write_command ; переводим дисплей в режим приема команд
   out portb,function_set  ; устанавливаем 8 битный интерфейс
   rcall E                 ; строб     -  (ВОТ ОТСЮДА МЫ ПЕРЕХОДИМ НА Е: И ЭТИМ ВСЁ ЗАКАНЧИВАЕТСЯ :( ...)
   out portb,display_on    ; включаем дисплей
   rcall E                 ; строб
   out portb,clear_display ; очищаем дисплей и обнуляем видеопамять
   rcall E                 ; строб

E:
   ldi temp,0b00100000
   out portd,temp
   nop
   ldi temp1,0b00000000
   out portd,temp1
   ret ;(здесь по идее должна прога Е: закончиться и перейти на строчку "out portb,display_on" ,но этого не происходит)
   

СПАСИБО!!! :)

Пн мар 03, 2008 15:44:48

где инициализация указателя стека? потому и не происходит возврат

Пн мар 03, 2008 21:47:43

Как я смотрю многие совсем совсем начинающие не понимают про векторы прерываний и даже если их не используют делают какие то не понятные прыжки в самом начале. Зачем? Если прерывания не используются, то можно начинать прямо с нулевого адреса писать программу, вот так например:
Код:
.nolist
.include "tn2313def.inc"
.list

.def Temp  = r16
.def Temp1 = r17
.def Temp2 = r18
.def Temp3 = r19
.def Temp4 = r20

.def Dig1 = r21
.def Dig2 = r22
.def Dig3 = r23
.def Dig4 = r24

.equ Dig1PortDdr = DDRD
.equ Dig1PortOut = PORTD
.equ Dig1PortBit = 2

.equ Dig2PortDdr = DDRD
.equ Dig2PortOut = PORTD
.equ Dig2PortBit = 3

.equ Dig3PortDdr = DDRD
.equ Dig3PortOut = PORTD
.equ Dig3PortBit = 4

.equ Dig4PortDdr = DDRD
.equ Dig4PortOut = PORTD
.equ Dig4PortBit = 5

.cseg
  .org 0

; начинаем программу прямо с нулевого адреса без всяких прыжков ;)
    ldi Temp, low(RAMEND)
    out SPL, Temp ; инициализируем указатель стэка

    ldi Temp,(1<<WDCE)|(1<<WDE)
    out WDTCSR,Temp
    ldi Temp,(1<<WDE)|(1<<WDP2)|(1<<WDP1)
    out WDTCSR,Temp     ;запускаем watchdog с интервалом 1 сек.

    sbi ACSR, ACD  ;отключаем аналоговый компаратор

; настраиваем порты
    ldi Temp, 0xFF
    out DDRB, Temp ; segments A-G + dot as outputs

    sbi Dig1PortDdr, Dig1PortBit
    sbi Dig2PortDdr, Dig2PortBit
    sbi Dig3PortDdr, Dig3PortBit
    sbi Dig4PortDdr, Dig4PortBit
; и так далее...

Вт мар 04, 2008 12:04:33

Brutaller писал(а):Как я смотрю многие совсем совсем начинающие не понимают про векторы прерываний и даже если их не используют делают какие то не понятные прыжки в самом начале. Зачем? Если прерывания не используются, то можно начинать прямо с нулевого адреса писать программу


А попробуйте в VMLAB напишите программу как сказали выше? _Ошибку выдаст! Вектор RESET обязательный!

Люди, Будьте добры!
Расскажите пожалуйста про инициализацию стека?
Я читал что он на аппаратном уровне! Как его использовать?
Ответить