afz писал(а):Только у меня более-менее универсальная, а здесь под каждый проект нужно клепать отдельную
Зачем? Ты, видимо, нифига не понял. Второе окошко с кодом - это и есть содержание файла vectors.asm. Первое - сам код.
И вот у тебя есть несколько камней, с которыми работаешь. Для этих камней за 5 минут стряпаются нужные заготовки, которые потом методом Ctrl+С/Ctrl+V самого .inc/.asm (без разницы) файла подключаются к нужному проекту.
Вместо RETI пропсываешь путь к обработчику прерывания по мере написания кода.
А у тебя куча прыжков непонятно откуда и куда, а потом такая-же куча заглушек. Смотрится вырвиглазно и если
переносить на другой камень
то действительно очень легко
можно допустить ошибку, которую долго придется искать.
Прибор, защищённый предохранителем, сгорает первым, защитив предохранитель. Закон Мерфи.
вообще-то для векторов прерываний правильная практика - задавать адрес вектора директивой .org и указанием символьного имени соответствующего вектора - см. соответствующий inc-файл для вашего типа МК. в этом случае достаточно задавать только задействованные векторы, причем в любом порядке - ассемблер сам расставит их в нужном порядке, заодно не надо помнить о размере команды jmp. заодно может быть и экономия памяти за счет использования неиспользуемой части таблицы векторов под полезный код.
а то, что предлагаете вы в последних постах - это костыльки лакированные.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV писал(а): заодно может быть и экономия памяти за счет использования неиспользуемой части таблицы векторов под полезный код.
Конечно, каждому - свое, но я бы так не делал. Экономия мизерная ( как сгоревшие лампочки - вместо поплавка в сливном бачке ) А гемору может добавить, если случайно инициализировалось одно из неиспользуемых прерываний, можем получить трудно уловимый глюк. Мне возразят - не должно быть случайной инициализации. Согласен, в отлаженной проге. А так к сырому исходнику еще добавлять потенциальный баго-генратор ...
Но, повторюсь : Jedem - das Seine.
вы начитались детских страшных сказок про трудноуловимые глюки. если мы говорим про AVR studio (а мы ведь про этот ассемблер говорим, верно?), то никаких трудноуловимых глюков там в принципе быть не может - максимум две-три попытки запуска отладчика, чтобы все эти "глюки" выловить.
что касается "я бы так не делал", то отвечу так: каждый волен сам выбирать себе способ выстрелить в ногу... глюков с размером jmp на больших и маленьких МК гораздо больше встречается, и отловить их существенно сложнее, ибо в случае "случайного" возникновения незапланированного прерывания переход происходит на непредсказуемый адрес с неизвестным опкодом - вот тут и профессионал сильно задумается, чего там говорить о начинающем...
ну и последний аргумент: вы же слыхали про магические числа и их вред в программировании? так вот, фиксированные адреса - это магические числа. когда вы размещаете команды, надеясь на то, что они окажутся в нужных адресах - вы используете магию этих чисел. а когда вы указываете символьные имена нужных адресов - это уже правильная практика. и не ради экономии шести байт это следует делать, а ради порядка и спокойствия.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV писал(а):вообще-то для векторов прерываний правильная практика - задавать адрес вектора директивой .org и указанием символьного имени соответствующего вектора
Вот эта правильная практика мне, как раз и не нравится. В том числе и тем, что я или должен прописать руками каждый, вектор, причем не одной строчкой, или оставить потенциальный глюкодром для неотлаженной программы. Мой вариант предполагает чисто механические действия над листингом ассемблерного примера из даташита, легко поддающиеся "механизации", собственно, я уже сочинил соответствующую программу для писюка. Я, правда, надеялся сделать вторую часть в виде макрокоманды, но, раз нельзя, буду копипастить кусочек с закомментированными заглушками и .include для генерации заглушек для тех прерываний, которые не используются.
Вариант, который предлагает Seriyvolk тоже неплох, но там нужен большой объем ручной работы и, ИМХО, мой вариант таки нагляднее. Я считаю главной ценностью своего варианта именно наличие той самой таблицы заглушек. Все прерывания на виду, не нужно помнить метку из AVR-овского инклудника. Что это за прерывание, прописано в комментарии от AVR, скопипастил куда надо из этой таблицы один элемент вместе с комментарием, закомментировал оригинал (или, наоборот, раскомментировал копию, как я сейчас предполагаю делать), и вперед. Можно, конечно, сделать нечто подобное и из того кусочка инклудника, который описывает вектора, но там надо самому сочинять метки для переходов, а так вполне информативный набор меток любезно предоставлен авторами даташита (кроме метки ADC, которую я, обычно, подправляю до iADC).
Вообще, создается впечатление, что авторы АВР Студии ничего, кроме писюка не видели, все богатство идей, реализованных в ассемблерах до-писюшных времен осталось за бортом...
Последний раз редактировалось afz Вт май 26, 2015 09:09:19, всего редактировалось 1 раз.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
afz писал(а):
Вообще, создается впечатление, что авторы АВР Студии ничего, кроме писюка не видели, все богатство идей, реализованных в ассемблерах до-писюшных времен осталось за бортом...
ММдяааа... а у меня впечатление, что Вам не слишком хорошо сам предмет обсуждения (ассемблер АВР) известен весьма... посредственно.
Все необходимое для работы там имеется. Некоторые "заковыки" вызваны структурными особенностями ядра семейства, но не более того.
ARV писал(а):вы же слыхали про магические числа и их вред в программировании? так вот, фиксированные адреса - это магические числа.
При чем тут "магические числа" ? Смешались в кучу кони, люди... Еще немного, и МК начнет по прерыванию выскакивать не на прописанный ему "железом" адрес, а на заботливо предложенное ему символьное имя. Но это уже будет следующее поколение МК со встроенным телепатором.
Кажется, я начинаю спорить . А ведь я никогда не спорю
И напоследок. Может, кто-то изучал МК по сказкам и слухам, а я так все больше по даташитам. И десяток успешных немаленьких проектов подтвердят, что читал ДШ я внимательно.
Break. Game over. Kondec .
вы жестко привязываете команду jmp vector0 к адресу, равному 0+sizeof(jmp) (если, конечно, так можно выразиться). размер команды jmp вам, условно говоря, неизвестен, так как зависит от типа МК. то есть вы получаете код, который "гуляет" по адресному пространству, а вы об этом не подозреваете даже. в один прекрасный момент вы пишите то же самое для другого МК и вдруг внезапно оказывается, то вся стройная таблица разрушена, потому что размер jmp стал не таким, как был ранее, то есть у вас обработчики прерываний будут хрен знает куда попадать, а компилятор вам даже предупреждения не выдаст.
в то же самое время в каждом описании МК, данном вам в соответствующем inc-файле, определены константы символьные, обозначающие адрес вектора прерывания (по идее, для однотипных прерываний разных МК эти символьные константы должны быть одинаковыми, хоть это и не всегда так)
то есть разработчик МК и ассемблера как бы вам намекает - используй это!
в этом случае вы получаете таблицу, не зависящую от размера команды jmp, и можете ее таскать из проекта в проект. как минимум, если в таблице будет непорядок, компилятор вам об этом сможет сказать.
ну и, что лично мне всегда больше нравилось, вы получаете возможность работать только с нужными вам векторами, а не со всеми подряд, т.е. можете написать
и все будет правильно. более того, вы можете вдруг "вспомнить" о нужном вам векторе, и написать в любом месте перед меткой start переход на этот вектор - и снова все будет отлично!!!
вы получаете вариант, за которым следит компилятор, давая вам больше свободы. пользоваться этим или нет - дело ваше, но в наставлениях по masm и tasm было строго-настрого указано, что программист обязан определять вектора прерываний исключительно при помощи директивы ORG - не надеясь на фиксированные адреса в адресном пространстве! я к этому привык еще в ту пору, и пока что ничего лучше не видел (для ассемблера).
наконец, при предлагаемом подходе вы имеете полное право делать заглушки "лишних" прерываний, например так:
надеюсь, вы понимаете и согласитесь, что в варианте "табличных джампов" замена jmp на reti может быть настолько черевата, что рискнувшего это сделать можно только пожалеть?
что касается самого ассемблера AVR, то из-под пера Атмела он вышел на редкость кривеньким и убогоньким, сравнивать его даже с avr-as из комплекта avr-gcc просто нельзя! макросы даже в древнейшем ассемблере для 51-ых микроконтроллеров были во много раз более эффективными!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
возьмет 1, сдвинет её влево на столько раз, чему равен адрес метки speed_tabl, а потом возьмет старший байт получившегося числа и занесет его в рег. ZH.
сделает все то же самое, но в рег.ZL будет помещен младший байт получившегося числа.
Как Вы думаете, какое значение в итоге занесется в рег.пару Z, если учесть, что адрес наверняка будет больше 10h?
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; загрузили следующий байт из таблицы
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Gudd-Head, там, в таблице, вроде, два байта на число. Смещение подкоректировть надо будет.
Ну да ладно, пусть автор вопроса додумает хоть что-то сам...
Дима_Медвед, настоятельно рекомендую ознакомиться со следующим документом: Atmel AVR 8-bit Instruction Set.
Если "нихт парле инглиш" , то вот. Но это не первоисточник.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Здравствуйте, коты! Прошу вас сразу не ругаться, я понимаю что код ну очень кривой. Я раньше с асм не общаялся.
Я написал прошивку для ATmega8A-PU, которая должна управлять серво-приводами с ПК. Не использовал готовые библиотеки, чтоб как бы посмотреть на все изнутри. Все вроде работает, но через какое-то время серво-приводы пересатют работать. Они все также удерживают свою позицию(рукой не крутятся, сопротивляются), но перестают реагировать на команды с ПК. Код под спойлером. Также приложил архив с проектом в AtmelStudio, т.к. код под спойлером получается не структурированным.
Не много про то как это работает. С компьютера посылаются 2 байта:
1) Первый байт это номер команды. Но до команд я не дошёл, по этому это попросту номер сервы.
2 ) Это как бы угол, отклонения сервы.
После этого, команда посылается обратно в компьютер, для проверки, того что принял МК. Вот когда зависат МК, то всеравно ответ от МК приходит.
Код писал, давненько, уже сам по забывал откуда некоторые числа. Ну там некоторые числа подобранны опытным путем.
Вы меня подтолкните, что может быть, я сам подправлю код. Спойлер/*
* AssemblerApplication2.asm
*
* Created: 07.02.2015 14:12:09
* Author: ?????
*/
;-------------------------------------------------- функция
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