Страница 1 из 399
Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Пт авг 03, 2007 17:25:54
Mr.Moss
Доброго времени суток всем.
Вопрос конечно нужно было задать в обучалке, но боюсь меня там не услышат, по этому прошу простить меня и помоч
Вопрос в следующем, пришел тот злащасный день когда мне понадобилась работа с не целыми числами типа 1,5 в ассемблере, ести ли какие либо стандартные варианты работы с такими числами или нужно чегото мудрить, если мудрить то как???
Может у кого есть заготовки для работы с такими числами.
Заранее спасибо.
Добавлено: Пт авг 03, 2007 17:52:19
ARV
воспользуйся поиском - на эту тему были разговоры...
Добавлено: Пт авг 03, 2007 19:56:47
Aheir
Добавлено: Пт авг 03, 2007 23:35:18
Tohey
На офф.сайте Атмел находил какие то экзамплы...
Добавлено: Сб авг 04, 2007 11:08:48
Кошкелот
Я бы начал с выяснения, ассемблер КАКОГО таракана рассматривается. PIC, Atmel... да их же много. Вот в ассемблере IBM PC

вполне можно работать с IEEE-шной плавучкой и командами сопроцессора

.
Второй вопрос - в каком диапазоне нужны числа и с какой точностью. По секрету: иногда помогаат ужасный прием: просто перейти в другой масштаб. Нужно "полтора"? Пиши 15 или 150... или 1500... Держи делитель в уме и не забудь скорректировать масштаб при выводе числа куда надо.
Добавлено: Сб авг 04, 2007 19:25:59
Mr.Moss
Всем большое спасибо за советы, вроде разобрался, использую вариант с масштабом, работает!
Добавлено: Ср дек 05, 2007 20:08:52
Инженер
Здравствуйте!
Помогите пожалуйста в ассемблере. Нужно запустить 16 битный таймер, и в определенный момент его считать и сбросить. (ATTiny2313) Я смотрел datasheet и несколько переведенных статей. Мне нужны только CS12, CS11 и CS10 (001)-делитель частоты. А что делать с остальными битами настройки? В ноль их всех? И надо ли их вообще устанавливать если они мне не нужны?
Как устанавливать параметры таймера?
Так?
ldi r17,0b00000001
out TCCR1B,r17
Чтение и установка в даташите вроде понятно написано (с примером)
Как таймер запустить? Или он запускается автоматически? (вместе с МК)
Добавлено: Ср дек 05, 2007 20:21:49
tych
Добавлено: Ср дек 05, 2007 20:29:46
Инженер
Да я нашел его. Нужная вещь. Но это три бита из байта TCCR1B а остальные биты как ставить? Какие настройки нужно ОБЯЗАТЕЛЬНО настроить у таймера? Как насчет остальных вопросов?
Добавлено: Ср дек 05, 2007 20:56:20
Инженер
Там код не ассемблековский. Как установить параметры в ассемблере? Если кто может подсказать конкретней буду рад почитать ответ.
Добавлено: Ср дек 05, 2007 21:51:25
ARV
Инженер писал(а):Как таймер запустить? Или он запускается автоматически? (вместе с МК)
таймер запускается сразу после установки нужного коэффициента предделителя. останавливается при задании
CS10=CS11=CS12=0
Добавлено: Вт янв 29, 2008 12:57:40
Mamonth
Артур писал(а):Здравствуйте! Помогите разобраться пожалуйста? Я хочу чтоб контроллер установил порт В в высокий уровень и через 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...
А вообще есть два способа:
1. Поставить перед loop: оператор sleep и контроллер будет спать.
2. Перед loop написать:
тогда МК зациклиться на этом месте.
Добавлено: Вт янв 29, 2008 14:35:30
Артур
Спасибо Mamonth за идею! Можно действительно так поступить
Но всётаки с чем простите связана эта аномалия выполнения программы циклически? Ведь в моём коде нет перехода на начало!
Конечно мы обманем и зациклим её в этом месте но хотелось бы всетаки с этим разобраться. Я уже и компиляторы разные попробовал - не в них дело!
Добавлено: Вт янв 29, 2008 16:02:40
ARV
никакой аномалии нет - RET в конце твоего кода и заставляет программу начаться заново
Добавлено: Ср янв 30, 2008 10:53:37
Артур
ARV писал(а):никакой аномалии нет - RET в конце твоего кода и заставляет программу начаться заново
Спасибо! А как зделать так чтоб она не начиналась заново? А я мог потом использовать задержку из любого другого места программы ну типа так
Добавлено: Ср янв 30, 2008 11:36:33
ARV
структура программы должна быть такой:
Код: Выделить всё
; объявления констант, переменных и т.п.
.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
ARV
где инициализация указателя стека? потому и не происходит возврат
Добавлено: Пн мар 03, 2008 21:47:43
Brutaller
Как я смотрю многие совсем совсем начинающие не понимают про векторы прерываний и даже если их не используют делают какие то не понятные прыжки в самом начале. Зачем? Если прерывания не используются, то можно начинать прямо с нулевого адреса писать программу, вот так например:
Код: Выделить всё
.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 обязательный!
Люди, Будьте добры!
Расскажите пожалуйста про инициализацию стека?
Я читал что он на аппаратном уровне! Как его использовать?