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

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15553
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

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

Сообщение BOB51 »

afz писал(а):Вообще, создается впечатление, что авторы АВР Студии ничего, кроме писюка не видели, все богатство идей, реализованных в ассемблерах до-писюшных времен осталось за бортом...


ММдяааа... а у меня впечатление, что Вам не слишком хорошо сам предмет обсуждения (ассемблер АВР) известен весьма... посредственно. 8)
Все необходимое для работы там имеется. Некоторые "заковыки" вызваны структурными особенностями ядра семейства, но не более того.
:beer:
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

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

Сообщение Jack_A »

ARV писал(а):вы же слыхали про магические числа и их вред в программировании? так вот, фиксированные адреса - это магические числа.

При чем тут "магические числа" ? Смешались в кучу кони, люди... Еще немного, и МК начнет по прерыванию выскакивать не на прописанный ему "железом" адрес, а на заботливо предложенное ему символьное имя. Но это уже будет следующее поколение МК со встроенным телепатором.
Кажется, я начинаю спорить . А ведь я никогда не спорю :)
И напоследок. Может, кто-то изучал МК по сказкам и слухам, а я так все больше по даташитам. И десяток успешных немаленьких проектов подтвердят, что читал ДШ я внимательно.
Break. Game over. Kondec .
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

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

Сообщение ARV »

Jack_A писал(а):При чем тут "магические числа" ?

:)))
когда вы делаете

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

.org 0
jmp start
jmp vector0
jmp vector1
...

вы жестко привязываете команду jmp vector0 к адресу, равному 0+sizeof(jmp) (если, конечно, так можно выразиться). размер команды jmp вам, условно говоря, неизвестен, так как зависит от типа МК. то есть вы получаете код, который "гуляет" по адресному пространству, а вы об этом не подозреваете даже. в один прекрасный момент вы пишите то же самое для другого МК и вдруг внезапно оказывается, то вся стройная таблица разрушена, потому что размер jmp стал не таким, как был ранее, то есть у вас обработчики прерываний будут хрен знает куда попадать, а компилятор вам даже предупреждения не выдаст.

в то же самое время в каждом описании МК, данном вам в соответствующем inc-файле, определены константы символьные, обозначающие адрес вектора прерывания (по идее, для однотипных прерываний разных МК эти символьные константы должны быть одинаковыми, хоть это и не всегда так)
то есть разработчик МК и ассемблера как бы вам намекает - используй это!

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

.org 0
jmp start

.org vector0_addr
jmp vector0

.org vector1_addr
jmp vector1

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

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

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

.org 0
jmp start

.org vector10_addr
jmp vector10

start:
и все будет правильно. более того, вы можете вдруг "вспомнить" о нужном вам векторе, и написать в любом месте перед меткой start переход на этот вектор - и снова все будет отлично!!!

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

.org 0
jmp start

.org vector10_addr
jmp vector10

.org vector3_addr
jmp vector3

start:
вы получаете вариант, за которым следит компилятор, давая вам больше свободы. пользоваться этим или нет - дело ваше, но в наставлениях по masm и tasm было строго-настрого указано, что программист обязан определять вектора прерываний исключительно при помощи директивы ORG - не надеясь на фиксированные адреса в адресном пространстве! я к этому привык еще в ту пору, и пока что ничего лучше не видел (для ассемблера).

наконец, при предлагаемом подходе вы имеете полное право делать заглушки "лишних" прерываний, например так:

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

.org vector0_addr
reti

.org vector1_addr
reti
или так:

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

.org 0
reset:
jmp start

.org vector0_addr
rjmp reset

.org vector5_addr
rjmp reset
надеюсь, вы понимаете и согласитесь, что в варианте "табличных джампов" замена jmp на reti может быть настолько черевата, что рискнувшего это сделать можно только пожалеть?

что касается самого ассемблера AVR, то из-под пера Атмела он вышел на редкость кривеньким и убогоньким, сравнивать его даже с avr-as из комплекта avr-gcc просто нельзя! макросы даже в древнейшем ассемблере для 51-ых микроконтроллеров были во много раз более эффективными!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15553
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

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

Сообщение BOB51 »

Все вопросы учитывались в avrssm2...
И не столько таблица векторов.... то уже совсем примитив... всем давно приелось...
:(
Аватара пользователя
Дима_Медвед
Открыл глаза
Сообщения: 73
Зарегистрирован: Сб авг 23, 2014 21:49:24

Указатель Z

Сообщение Дима_Медвед »

Всем привет. Есть такой вопрос. Указатель Z, он ведь 16-розрадный. Значит при такой записи:
Спойлерset_frequency: ldi ZH, high(1<<speed_tabl)
ldi ZL, low(1<<speed_tabl)
ldi YH, 0
mov YH, SV
add ZL, YL
adc ZH, YH
lpm r16, high(Z)
lpm r17, low(Z)
mov speedH, r16
mov speedL, r17
rjmp main

в speedL идёт младшая часть значения с таблици, а в speedH старшая часть. Почему тогда АВРстудио не компилирует код???
таблица:
Спойлерspeed_tabl:
.dw 61629 ; 1 Sec
.dw 62019 ; 0.9 Sec
.dw 62410 ; 0.8 Sec
.dw 62800 ; 0.7 Sec
.dw 63191 ; 0.6 Sec
.dw 63581 ; 0.5 Sec
.dw 63973 ; 0.4 Sec
.dw 64363 ; 0.3 Sec
.dw 64753 ; 0.2 Sec
.dw 65144 ; 0.1 Sec
.dw 65340 ; 0.05 Sec
.dw 65437 ; 0.025 Sec
.dw 65530 ; 0.001 Sec
.dw 65535 ; 0.0005 Sec

Ах да, SV это номер значения из таблици.
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

Бля, так сложно что ли написать как ругается компилятор?

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

lpm r16, high(Z)
Это хуйня. Синтаксис:
LPM;
LPM Rd, Z;
LPM Rd, Z+;
на выбор.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Alkul
Держит паяльник хвостом
Сообщения: 933
Зарегистрирован: Ср апр 13, 2011 11:09:20
Откуда: Екатеринбург

Re: Указатель Z

Сообщение Alkul »

Дима_Медвед писал(а):Почему тогда АВРстудио не компилирует код???

Да потому, что бред Вы написали, а не код.
Вот такая запись:

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

ldi ZH, high(1<<speed_tabl)
ldi ZL, low(1<<speed_tabl)

занесет в рег.пару Z не содержимое таблицы speed_tabl, а вот здесь

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

ldi ZH, high(1<<speed_tabl)

возьмет 1, сдвинет её влево на столько раз, чему равен адрес метки speed_tabl, а потом возьмет старший байт получившегося числа и занесет его в рег. ZH.

Вот эта строчка

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

ldi ZL, low(1<<speed_tabl)

сделает все то же самое, но в рег.ZL будет помещен младший байт получившегося числа.
Как Вы думаете, какое значение в итоге занесется в рег.пару Z, если учесть, что адрес наверняка будет больше 10h?

Вот это что за команда?

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

mov YH, SV

Вы в курсе, что оператор mov копирует содержимое одного регистра в другой?

Прежде, чем начинать программировать, надо выучить язык программирования.
Последний раз редактировалось Alkul Чт май 28, 2015 14:53:19, всего редактировалось 1 раз.
Alkul
Держит паяльник хвостом
Сообщения: 933
Зарегистрирован: Ср апр 13, 2011 11:09:20
Откуда: Екатеринбург

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

Сообщение Alkul »

Gudd-Head писал(а):Это хуйня.

Грубо, но в целом верно. :))
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

Должно быть как-то так:

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

ldi ZH, high(speed_tabl*2);
ldi ZL, low(speed_tabl*2);   загрузили в Z адрес таблицы
add ZL, SV;         прибавили смещение [0...255]
adc ZH, zeroreg;      прибавили к старшему байту указателя бит переноса С если есть
lpm r16, Z+;         загрузили первый байт с пост-инкрементом указателя
lpm r17, Z;      загрузили следующий байт из таблицы
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

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

Сообщение Kavka »

Gudd-Head, там, в таблице, вроде, два байта на число. Смещение подкоректировть надо будет.
Ну да ладно, пусть автор вопроса додумает хоть что-то сам... :)

Дима_Медвед, настоятельно рекомендую ознакомиться со следующим документом: Atmel AVR 8-bit Instruction Set.
Если "нихт парле инглиш" :) , то вот. Но это не первоисточник.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

Kavka писал(а):там, в таблице, вроде, два байта на число.
Ну да, смещение сделать чётным.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Programmer86
Родился
Сообщения: 3
Зарегистрирован: Вс дек 23, 2012 12:36:11

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

Сообщение Programmer86 »

Здравствуйте, коты! Прошу вас сразу не ругаться, я понимаю что код ну очень кривой. Я раньше с асм не общаялся.
Я написал прошивку для ATmega8A-PU, которая должна управлять серво-приводами с ПК. Не использовал готовые библиотеки, чтоб как бы посмотреть на все изнутри. Все вроде работает, но через какое-то время серво-приводы пересатют работать. Они все также удерживают свою позицию(рукой не крутятся, сопротивляются), но перестают реагировать на команды с ПК. Код под спойлером. Также приложил архив с проектом в AtmelStudio, т.к. код под спойлером получается не структурированным.
Не много про то как это работает. С компьютера посылаются 2 байта:
1) Первый байт это номер команды. Но до команд я не дошёл, по этому это попросту номер сервы.
2 ) Это как бы угол, отклонения сервы.
После этого, команда посылается обратно в компьютер, для проверки, того что принял МК. Вот когда зависат МК, то всеравно ответ от МК приходит.
Код писал, давненько, уже сам по забывал откуда некоторые числа. Ну там некоторые числа подобранны опытным путем.

Вы меня подтолкните, что может быть, я сам подправлю код.

Спойлер/*
* AssemblerApplication2.asm
*
* Created: 07.02.2015 14:12:09
* Author: ?????
*/

.include "m8Adef.inc"

.equ XTAL =1000000
.equ Baud_Rate = 4800
.equ Baud_Divider = XTAL/(16*Baud_Rate)-1
.equ MaxAngle = 233

.equ SubAngle = 255 - MaxAngle - 1

.def Temp = R16
.def Temp1 = R17
.def Temp2 = R18
.def Temp3 = R19
.def Data1 = R20
.def Data2 = R21
.def Servo1 = R22
.def Servo2 = R23
.cseg
.org 0

;Вектора прерываний
RJMP EXT_MAIN
RJMP EXT_INT0
RJMP EXT_INT1
RJMP EXT_TIMER2_COMP
RJMP EXT_TIMER2_OVF
RJMP EXT_TIMER1_CAPT
RJMP EXT_TIMER1_COMPA
RJMP EXT_TIMER1_COMPB
RJMP EXT_TIMER1_OVF
RJMP EXT_TIMER0_OVF
RJMP EXT_SPI_STC
RJMP EXT_USART_RXC
RJMP EXT_USART_UDRE
RJMP EXT_USART_TXC
RJMP EXT_ADC
RJMP EXT_EE_RDY
RJMP EXT_ANA_COMP
RJMP EXT_TWI
RJMP EXT_SPM_RDY

;---------- функция
EXT_MAIN:
;Инициализируем стек
LDI Temp, low(RAMEND)
OUT SPL, Temp
LDI Temp, high(RAMEND)
OUT SPH, Temp

;Настраиваем наш МК
RCALL UART_INIT

;Настраиваем порт С на выход
ldi Temp1, 0b11111111
out DDRC, Temp1
ldi Temp1, 0b00000000
out PortC, Temp1

;Сбрасываеп переменные, устанавливаем начальный угол серв
LDI Data1, 0
LDI Data2, 0
LDI Servo1, 0x94 ; как бы "угол сервы" в диапозоне: 41-254
LDI Servo2, 0x94

Begin:
;---------- серва
ldi Temp1, 0b000101
out PortC, Temp1

MOV Temp1, Servo1
Loop_1: dec Temp1
brne Loop_1
MOV Temp1, Servo1
Loop2_1: dec Temp1
brne Loop2_1
MOV Temp1, Servo1
Loop3_1: dec Temp1
brne Loop3_1

ldi Temp1, 0b00000000
out PortC, Temp1

SEI

ldi Temp1,60
ldi Temp2,11
Loop4_1: dec Temp1
brne Loop4_1

dec Temp2
brne Loop4_1

MOV Temp1, Servo1
COM Temp1
SUBI Temp1, SubAngle
Loop_2: dec Temp1
brne Loop_2
MOV Temp1, Servo1
COM Temp1
SUBI Temp1, SubAngle
Loop2_2: dec Temp1
brne Loop2_2
MOV Temp1, Servo1
COM Temp1
SUBI Temp1, SubAngle
Loop3_2: dec Temp1
brne Loop3_2

CLI

;---------- серва
ldi Temp1, 0b000110
out PortC, Temp1

MOV Temp1, Servo2
Loop_3: dec Temp1
brne Loop_3
MOV Temp1, Servo2
Loop2_3: dec Temp1
brne Loop2_3
MOV Temp1, Servo2
Loop3_3: dec Temp1
brne Loop3_3

ldi Temp1, 0b00000100

SEI

out PortC, Temp1

ldi Temp1,60
ldi Temp2,11
Loop4_2: dec Temp1
brne Loop4_2

dec Temp2
brne Loop4_2

MOV Temp1, Servo2
COM Temp1
SUBI Temp1, SubAngle
Loop_4: dec Temp1
brne Loop_4
MOV Temp1, Servo2
COM Temp1
SUBI Temp1, SubAngle
Loop2_4: dec Temp1
brne Loop2_4
MOV Temp1, Servo1
COM Temp1
SUBI Temp1, SubAngle
Loop3_4: dec Temp1
brne Loop3_4
; Начинаем все с начала

CLI

rjmp Begin

LDI Temp1, 0x00
;----------
EXT_INT0:
EXT_INT1:
EXT_TIMER2_COMP:
EXT_TIMER2_OVF:
EXT_TIMER1_CAPT:
EXT_TIMER1_COMPA:
EXT_TIMER1_COMPB:
EXT_TIMER1_OVF:
EXT_TIMER0_OVF:
EXT_SPI_STC:
;---------- по приему байта
EXT_USART_RXC:
CLI
CPI Data1, 0
BRNE Set_Data_2
Set_Data_1:
IN Data1, UDR
SEI
RET
Set_Data_2:
IN Data2, UDR
RCALL Read_COMMAND
RET
;----------
EXT_USART_UDRE:
EXT_USART_TXC:
EXT_ADC:
EXT_EE_RDY:
EXT_ANA_COMP:
EXT_TWI:
EXT_SPM_RDY:

;Вспомогательные функции
;----------
UART_INIT:
LDI R16, low(Baud_Divider)
OUT UBRRL,R16
LDI R16, high(Baud_Divider)
OUT UBRRH,R16
LDI R16,0
OUT UCSRA, R16
LDI R16, (1 << RXEN)|(1 << TXEN)|(1 << RXCIE)|(0 << TXCIE) ; Прерывание по приему разрешенно, по передаче запрещены, прием-передача разрешен.
OUT UCSRB, R16
LDI R16, (1 << URSEL)|(1 << UCSZ0)|(1 << UCSZ1) ; Формат кадра - 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор
OUT UCSRC, R16
ldi R16, 1
RET
;----------

;----------
READ_COMMAND:
uart_snt:
SBIS UCSRA,UDRE
RJMP uart_snt
OUT UDR, Data1
uart_snt2:
SBIS UCSRA,UDRE
RJMP uart_snt2
OUT UDR, Data2

CPI Data1, 0
BREQ END_READ_COMMAND

CPI Data1, 1
BREQ Set_Servo_1

CPI Data1, 2
BREQ Set_Servo_2

rjmp END_READ_COMMAND
Set_Servo_1:
MOV Servo1, Data2
rjmp END_READ_COMMAND
Set_Servo_2:
MOV Servo2, Data2
rjmp END_READ_COMMAND

END_READ_COMMAND:
LDI Data1, 0
LDI Data2, 0
SEI
RET
;----------

LDI Temp1, 0x00
LDI Temp2, 0x00
LDI Temp3, 10
inc R16

;Loop: dec Temp1
; brne Loop

; dec Temp2
; brne Loop

; dec Temp3
; brne Loop
Вложения
USART_SERVO.rar
(20.32 КБ) 121 скачивание
Последний раз редактировалось Programmer86 Пт май 29, 2015 15:29:06, всего редактировалось 1 раз.
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

Окуеть. Целых 2 комментария :)))
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
afz
Опытный кот
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

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

Сообщение afz »

Programmer86 писал(а): Код под спойлером. Также приложил архив с проектом в AtmelStudio, т.к. код под спойлером получается не структурированным.
Он и в проекте ни разу не структурированный...
Programmer86 писал(а): Вы меня подтолкните, что может быть, я сам подправлю код.
Первая грубая ошибка - из прерываний выходят по RETI, а не по RET'у. В результате код, который выполнялся при открытых прерываниях после выполнения программы прерывания продолжит исполнение при закрытых прерываниях и следующего прерывания может не произойти. То есть здесь, скорее всего, до этого успеет выполниться SEI в другом месте и до зависания дело не дойдет, но, тем не менее, в общем случае так делать нельзя.

Вторая, и еще более грубая ошибка - это то, что прерывающая программа обязана сохранять и восстанавливать регистры, которыми она пользуется. Здесь ничего подобного нет. В частности, здесь в любой момент исполнения основной программы (от SEI до CLI) могут внезапно измениться регистры Data1, Data2, Servo1 и Servo2 и, самое главное, регистр статуса SREG. Не вникал, может быть изменение регистров данных и предусмотрено, но забытый SREG приведет к тому, что, допустим, цикл Loop4_1 досчитал до конца, выполнилась команда dec TEMP2, результат получился ноль, тут прерывание, которое испортит признак Z, и вперед, цикл будет исполняться еще 256 раз. Совпадение, конечно, достаточно редкое, но рано или поздно оно произойдет и, поскольку оно редкое, будет похоже на случайный сбой.

Третья ошибка - это как раз, в тему того, о чем я вел дискуссию страницей раньше. Если полностью заполнить таблицу векторов командами (r)jmp, то нужна и вторая таблица с объявлением меток, на которые ссылаются эти RJMP. Та самая:

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

 EXT_INT0:
 EXT_INT1:
 EXT_TIMER2_COMP:
 EXT_TIMER2_OVF:
...
Только она должна быть сплошной, в нее должны входить все метки, на которые ссылаются RJMP из таблицы векторов, они указывают на один и тот же адрес, а по нему должна находиться ловушка для незапланированных прерываний, которую следует написать после этой таблицы, типа rjmp .-1 или, на худой конец, RETI. А, собравшись использовать какое-либо прерывание, надо выдернуть его строчку из таблицы и вставить в нужное место программы. Ну, или скопипастить, а в таблице закомментировать. А так, как сделано у тебя, если вдруг произойдет незапланированное прерывание от INT0 до SPI_STC, запустится программа приема с UART, а от USART_UDRE до SPM_RDY - программа USART_INIT.

Это то, что бросилось в глаза. А про структурирование... На асме принято метки писать с первой позиции, а коды операций от меток через один или несколько tab'ов, чтобы они шли в колонку. Ну и комментариев в программе на асме надо писать раз в 10 больше, чем у тебя, причем структурировать в C-стиле следует именно комментарии...
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Programmer86
Родился
Сообщения: 3
Зарегистрирован: Вс дек 23, 2012 12:36:11

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

Сообщение Programmer86 »

Спасибо, afz, что откликнулись. Я понял, что все работает. Это все ошибка в коде программы на ПК, она перестает посылать байты к МК. Но я все же хочу исправить ошибки про которые вы писали.
Заменил RET на RETI.
По второй ошибки я вас не понял. Мне надо сохранить регистр SREG? Не могли бы вы написать примерчик?
На счет третьей ошибки, вы имели сделать нечто подобное?
EXT_INT0: RETI
EXT_INT1: RETI
EXT_TIMER2_COMP: RETI
EXT_TIMER2_OVF: RETI
EXT_TIMER1_CAPT: RETI
Аватара пользователя
afz
Опытный кот
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

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

Сообщение afz »

Programmer86 писал(а): По второй ошибки я вас не понял. Мне надо сохранить регистр SREG? Не могли бы вы написать примерчик?
Регистры общего назначения (R0 - R31) положено сохранять в стеке. Сохраняем командой PUSH. восстанавливаем командой POP. Естественно, необязательно сохранять и восстанавливать все 32 РОНа, если какие-то регистры в этом конкретном прерывании не используются, или используются для передачи параметров из прерывания в основную программу, их сохранять и потом восстанавливать не надо. А так, все сохранения и восстановления должны быть согласованы, какие регистры сохранялись, те же надо и восстанавливать. Восстанавливаем в порядке обратном тому, в котором сохраняли. Это о РОНах.

А вот SREG - это регистр, целиком доступный только по командам IN/OUT. для его сохранения надо сначала освободить какой-нибудь РОН, сохранив в стеке его значение, затем прочитать в него SREG командой IN и сохранить это значение в стеке. То есть в начале программы обслуживания прерывания ставим:

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

   PUSH   Rx
   IN     Rx,SREG
   PUSH   Rx

Далее добавляем сохранение тех регистров, которые используются в этом прерывании в качестве рабочих (чтобы их изменение в прерывании не привело к их изменению в основной задаче) и только потом пишем собственно программу обслуживания прерывания. В ее конце восстанавливаем все сохраненные при входе регистры, завершаем это восстановление командами

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

   POP     Rx
   OUT     SREG,Rx
   POP     Rx
   RETI
которые восстановят SREG и Rx.

Rx здесь - любой РОН, поскольку он сохраняется, его тоже можно использовать в качестве рабочего.


Programmer86 писал(а): На счет третьей ошибки, вы имели сделать нечто подобное?
EXT_INT0: RETI
EXT_INT1: RETI
EXT_TIMER2_COMP: RETI
EXT_TIMER2_OVF: RETI
EXT_TIMER1_CAPT: RETI
Так следует делать только в том случае, если незапланированное прерывание таки обнаружится и начинаешь его поиск под отладчиком, только тогда надо писать не RETI, а, допустим, зацикленный сам на себя RJMP. тогда смотрим в отладчике, где она повисла, и находим, кто это нас прервал и по какой причине. А так вполне достаточно перечислить все эти метки по одной в строку, а после них написать RETI или зацикленный на себя RJMP. Все метки этой таблицы будут ссылаться на один и тот же адрес - адрес этой команды RETI/RJMP, в отлаженной программе это вполне допустимо. Если же оно таки улетит на эту команду, тогда уже предпринимаем действия по выявлению причины путем прописывания зацикленных RJMP по каждой метке.

А программы обслуживания используемых прерываний располагаем где-нибудь в другом месте, из расчета, чтобы на нее не "наехало" управление в естественном порядке.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Programmer86
Родился
Сообщения: 3
Зарегистрирован: Вс дек 23, 2012 12:36:11

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

Сообщение Programmer86 »

Спасибо, afz. Разжевали доступно. Спасибо! Буду пробовать.
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

У кого-нибудь есть код перевода 16-битного числа в формате DS18B20 во что-нибудь удобоваримое для вывода со знаком с точностью 0,5 градуса?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
afz
Опытный кот
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

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

Сообщение afz »

Gudd-Head писал(а):У кого-нибудь есть код перевода 16-битного числа в формате DS18B20 во что-нибудь удобоваримое для вывода со знаком с точностью 0,5 градуса?
Есть только такое.
Спойлер

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

; **************************************************************

.macro   ZLDA
   ldi   @0l,low(@1)
   ldi   @0h,High(@1)
.endm


   ; Перевод 32-разрядного двоичного числа в десятичное (BCD).
ZF210:
   ; Регистры

   ; R3, R4, R5, R6 - исходное число, R3 - младший байт, R6 - старший.

   ; Сначала очистим ZFRX
   ZLDA   x,zfrx
   clr   r2
   ldi   r16,zfex-zfrx
L10:   st   x+,r2
   dec   r16
   brne   L10
   nop   

   ldi   R17,32 ; Количество битов в преобразуемом числе
   
L11:   
   ; Возьмем очередной бит исходного числа и в соответствии с его значением
   ; установим бит переноса для ZFAdd10 (младший бит R2)

   clr   r2
   lsl   r3
   rol   r4
   rol   r5
   rol   r6
   brcc   L12
   inc   R2
L12:   ldi   R18,zfex-zfrx

   ; Сложим содержимое ZFRX само с собой (* 2)
   ; и добавим из переноса (R2) значение очередного бита.

   ZLDA   x,zfex
L13:   ld   r0,-X
   mov   r1,r0
   rcall   ZFAdd10
   st   X,r0
   dec   r18   ; Повторим для всех байтов ZFRX
   brne   L13
   dec   r17   ; и для всех битов исходного числа
   brne   L11
   ret




; ******************************************************************

ZFAdd10:      ; Сложение двух однобайтовых десятичных чисео в BCD.

         ; R0 - первое слагаемое, результат
         ; R1 - второе слагаемое
         ; R2 - входной перенос - выходной перенос
         ; R16 - тоже рабочий
   mov   r16,r2
   clr   r2
   sbrc   r16,0
   sec
   adc   r0,r1
   brhs   L4
   brcs   L6
   ldi   r16,0x66
   add   r0,r16
   brhs   L1
   brcs   L2
   sub   r0,r16
   
   ret
L1:   brcs   L3
   ldi   R16,0x60
   sub   r0,r16
   ret
L2:   ldi   r16,6
   sub   r0,r16
L3:   inc   r2
   ret
L4:   brcs   l7
   ldi   r16,0x66
   add   r0,r16
   brcs   L5
   ldi   r16,0x60
   sub   r0,r16
   ret
L5:   inc   r2
   ret
L6:   ldi   r16,0x66
   add   r0,r16
   brhs   l8
   ldi   r16,6
   sub   r0,r16
L8:   inc   r2
   ret
L7:   ldi   r16,0x66
   add   r0,r16
   inc   r2
   ret
Нужно, во-первых, уменьшить число битов до 16 (ИМХО - легко), а с числом из 1820 разобраться так: во-первых, запоминаем знак, если минус - взять дополнение до 2 от числа, затем к нему прибавить 0x04 и сдвинуть на 3 разряда вправо (это округление), затем умножить его на 10 (оно уже сдвинутое на 1 разряд влево, т.е. умноженное на 2, его надо скопировать в другую пару паре регистров, сдвинуть еще на 2 разряда, т.е. итого умножить на 8 и сложить эти две пары оегистров), после чего отдать моей программе, модифицированной до 16 бит.

Я тут поначалу ошибся, сейчас поправил
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Аватара пользователя
ILYAUL
Держит паяльник хвостом
Сообщения: 906
Зарегистрирован: Ср мар 28, 2012 21:45:24
Откуда: ВО

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

Сообщение ILYAUL »

Вот

Там есть

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

brne   X1
      swap   SHIFT_REG               // Значения собираются в старшей тетраде , готовим их к дальнейшему расчёту
;/    ***********************
      out      GPIOR0,SHIFT_REG         ;= а пока запоминаем их
....................................
ldwi   Z,Accuracy               // В Accuracy значение с которой вычисляется температура после запятой
      in      count,GPIOR0            // Вот и потребовалось значение которое мы запомнили
      cpse   count,zero               // Если оно вдруг 0х00 то пропускаем вычисление
      rjmp   Add_Thousandths            // Иначе вычисляем
      st      Y+,zero                  // Но и записываем 0х00 для вывода на дисплей
NEW_FIND_or_OUT:


Так вот , значения температуры ( самой) укладываются в подпрограмму преобразования в BCD от 1-100 и такая как у меня тебе не нужна, у меня в проекте преобразования больше чем 1000.

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

in      count,GPIOR0            // Вот и потребовалось значение которое мы запомнили
В этом регистре собственно само значение после запятой - т.е смещение от начала таблицы до нужного тебе значения . Только надо просто переделать таблицу - сразу занести в нее значения в BCD и все. Будет типа

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

ldi ZH,high(XXXXX*2)
Ldi ZL, low(XXXXX+(например) 4)*2)
add ZL,count
adc ZH,zero
lpm.....

где 4 это добавка к смещению т.к. при точности 0,0625 в таблице будет h30,h36,h32,h35
Вложения
ALARM_SEARCH.rar
(2.32 КБ) 139 скачиваний
ALARM_SEARCH.asm
(5.97 КБ) 464 скачивания
Ответить

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