Заголовок сообщения: atmega 128 прерывание по таймеру
Добавлено: Вс май 20, 2012 15:31:11
Встал на лапы
Зарегистрирован: Чт мар 08, 2012 01:13:30 Сообщений: 103
Рейтинг сообщения:0
Здравствуйте. Подскажите пожалуйста как сделать программу где срабатывает прерывание при TCNT0=OCR0. Как я понимаю нужно создать вектор прерывания типа .ORG $XXX ?
OC0addr: ; Output Compare0 Interrupt Vector Address ;Ваш код обработчика прерывания по совпадению reti
RESET: ;Основная программа
Те обработчики прерываний, которые Вам понадобятся, Вы "вытаскиваете из "заглушек", создаете свою подпрограмму-обработчик. А в блоке "заглушек" перед этим адресом ставите точку с запятой. Так Вы никогда не "потеряетесь" в обработчиках и не перепутаете адреса векторов.
Alkul, вот это как раз и есть классическая ошибка... в стандартном заголовочном файле avr studio обычно всегда подключается шаблон (в данном случае m128def.inc) - а там уже заявлены адреса векторов под собственными именами, которые повторно использовать не рекомендуется! А вот пользоваться этими именами весьма полезно: "шапка" проекта (avrasm2)
Код:
;---------- ;_____ ; .nolist .include "m128def.inc" .list :---------- ; .cseg .org 0x0000 ;_____ ; здесь размещаются вектора прерываний ; или короткие подпрограммы их обслуживания ; irq_res: rjmp init ; вектор RESET, если небыло переконфигурации таблицы векторов и самого Вектора сброса (см. config fuse) .org (irq_res+OC0addr) rjmp ISR_OC0 ; или как я его хочу обозвать ;_____ ; .org (irq_res+INT_VECTORS_SIZE) ; обход блока векторов прерываний ; блок начальной инициализации кристалла init: ; точка входа в модуль начальной инициализации ;---------- ISR_OC0: ; а здесь уже сам обработчик данного прерывания
Alkul, вот это как раз и есть классическая ошибка... в стандартном заголовочном файле avr studio обычно всегда подключается шаблон (в данном случае m128def.inc) - а там уже заявлены адреса векторов под собственными именами, которые повторно использовать не рекомендуется!
Во-первых, я показал лишь подход. Имена можно написать свои, убрав окончания "addr", это неважно. А в файле-описателе микросхемы прописаны соответствия имен обработчиков прерываний с адресами их расположения в памяти, но это не освобождает от необходимости расписывать всю таблицу векторов с командами jmp или rjmp (в зависимости от модели памяти контроллера) на адрес конкретного обработчика. Написание блока "заглушек" неиспользуемых прерываний очень важно, так как по невнимательности программист может разрешить то или иное прерывание случайно. И если не будет "заглушки", то программа при вызове "незапланированного" обработчика перейдет Бог знает куда.
То, что предлагаете Вы, как раз и является ошибкой. Вы предлагаете размещать в таблице векторов только те, которые реально используются, высчитывая их адреса, правильно я Вас понял? И размещать в памяти программ только те обработчики, которые реально существуют? А на месте неиспользуемых векторов будет "мусор"? Ошибки в программах бывают такими изощренными, что разрешение неиспользуемого прерывания - это "семечки". И куда будет сделан переход в этом случае? Если Вы не инициализируете ВСЮ область векторов прерываний, то в свободных участках, скорее всего, будут либо нули, либо единицы. Я не нашел в командах AVRовского ассемблера команды 0xFFFF, её нет либо она недокументирована. Как поведет себя контроллер в этом случае, я не знаю. А вот если там будут 0x0000, то это банальная команда NOP. Контроллер "пробежится" по Вашим NOPам, пока не дойдет до команды перехода на реально существующий обработчик, на который с удовольствием и перейдет. Либо выполнение NOPов дойдет до первой подпрограммы, расположенной за таблицей векторов, и контроллер радостно начнет выполнять эту подпрограмму. И Вы будете долго отлавливать причину этих странных "глюков".
Во-вторых, с чего Вы взяли, что не рекомендуется повторно использовать адреса векторов? Если при ассемблировании не выдается ошибок, то это вполне допустимо. Иногда (редко) при использовании чужих подпрограмм пользуешься теми именами регистров, которые использовал автор. В этом случае, естественно, вместе с подпрограммой прилагаются описания типа .def - ничего криминального в этом нет. Компилятор, естественно, выдаст предупреждения о дублировании имен, но это просто предупреждения разработчику о самом факте - а вдруг он сделал это по ошибке? На генерации же выходного кода это не сказывается совершенно никак.
а с чего Вы взяли, что будут произвольно выполняться какие-либо из запрещенных прерываний? ведь для того, чтобы прерывание было активировано, его предварительно еще разрешить надобно! причем многоступенчато - сначала условия, затем маску и в конце - общее разрешение... естественно при работе с ассемблером (особенно на "нафаршированных" ИС) задача начальной конфигурации весьма тяжелая, однако управление прерываниями строго регламентировано и случайностей там не бывает - если чего "не разрешено" - то того и не будет, даже при сбое (тут уж смотри схемотехнику внешней обвязки как источник проблем, а не МК) в документации на каждую ИС всегда есть подробное описание состояния всех критических регистров по аппаратному сбросу, включению питания и выходу из режимов энергосбережения - просто прежде чем писать программу datasheet надо весьма внимательно изучить и свои заметки на распечатанном образце на лениться делать кстати, "чего прийдется" в программной памяти без ведома программиста быть также не может (исключение - "убитая" ИС) т.к. при стирании все ячейки заполняются кодом 0xFF, а при записи - тем чего мы сами нарисовали теперь о метках - фрагмент того-же m128def.inc: ; ***** INTERRUPT VECTORS ************************************************ .equ INT0addr = 0x0002 ; External Interrupt Request 0 .equ INT1addr = 0x0004 ; External Interrupt Request 1 и описание директивы .equ: The EQU directive assigns a value to a label. This label can then be used in later expressions. A label assigned to a value by the EQU directive is a constant and can not be changed or redefined. кстати, когда-то сам подобным образом таблицы векторов "забивал", пока не ознакомился с возможностями ассемблеров из avr studio, mplab и c51asm.exe - теперь использую лучшие решения из всего освоенного
а с чего Вы взяли, что будут произвольно выполняться какие-либо из запрещенных прерываний?
Имеется ввиду ошибка программиста-нуба. Кстати, давно хотел проверить в железе как выполняется опкод 0xFFFF? Протеус ругается и встает, AVR студия предупреждает, но едет дальше... Как до макетки доберусь, проверю. Что касается моего варианта - я просто перепечатываю таблицу прерываний из даташита и в ненужных строчках пишу RETI, а в нужных JMP/RJMP, может это и не удобно или не правильно, но мне пофиг, я в этом месте ни разу не накосячил, и все равно сначала все проверяю в симуляторе... Я не знал что в инклудах есть адреса векторов, с тех пор привык все писать сам.
Код:
.cseg RJMP RESET ;RESET RETI ;INT0 RJMP PIN_READ ;PCINT RETI ;T0_OV RETI ;EE_RDY RETI ;ANA_COMP RJMP CALC_BEMF ;T0=A RETI ;T0=B RETI ;WDT RETI ;ADC RESET:
... ... с и м у л я т о р ... ... хорошая штука, если предварительно прочитать тамошние erratы... припомнился недавный кошмар с таймером... макетка- последняя инстанция!
а с чего Вы взяли, что будут произвольно выполняться какие-либо из запрещенных прерываний?
Имеется ввиду ошибка программиста-нуба.
Совершенно верно. К примеру, если в программе определен какой-то байт состояния, хранящийся, допустим, в ОЗУ, бит 0 которого, к примеру, определяет разрешение прерываний таймера 0. А другие биты определяют какие-то флаги состояния программы. Если забыть маскировать незначащие биты и напрямую занести содержимое байта состояния в регистр TIMSK, то окажутся разрешенными и другие прерывания таймеров. Ошибка, вполне достойная начинающего.
Engineer_Keen писал(а):
Что касается моего варианта - я просто перепечатываю таблицу прерываний из даташита и в ненужных строчках пишу RETI, а в нужных JMP/RJMP,
Код:
.cseg RJMP RESET ;RESET RETI ;INT0 RJMP PIN_READ ;PCINT
Все верно, только следует помнить, что у контроллеров с объемом памяти программ больше 16 килобайт на каждый вектор отводится не одно слово, а два. Поэтому у неиспользуемых прерываний нужно писать не просто RETI, а NOP RETI на каждый вектор прерывания.
А еще лучше делать так, как показал я. Сначала вся таблица векторов, состоящая из команд JMP или RJMP, в зависимости от типа контроллера, а потом ниже отдельный блок "заглушек".
Engineer_Keen писал(а):
Я не знал что в инклудах есть адреса векторов, с тех пор привык все писать сам.
Вот именно, что в инклюдах есть только записи вида:
Эта запись всего лишь определяет соответствие символьной строки, к примеру, INT0addr числу 0х0002. Это значит, что обратившись к памяти по адресу INT0addr, я обращусь к адресу 0х0002. Не более того. Это никоим образом не означает, что эти записи имеют хоть какое-то отношение к таблице векторов.
Последний раз редактировалось Alkul Вт май 22, 2012 20:01:57, всего редактировалось 3 раз(а).
Вот сейчас специально создал в AVR Studio проект на ATmega128 в режиме AVRSimulator2, подключил соответствующий инклюд. Компилирую, ошибок нет, хотя я специально написал команду
Код:
out TIMSK,R16
Если бы инклюд не подключился, то компилятор бы "ругнулся" на имя TIMSK, ан нет - принял. Вот такой "проект" я написал:
Код:
.include "m128def.inc"
.cseg .org 0x00 jmp RESET
.org 0x30 RESET: nop nop ldi R16,0x10 out TIMSK,R16
Запускаю симуляцию и что вижу - в памяти программ создался только один вектор - тот, который располагается с нулевого адреса и переходит на метку RESET. Дальше вместо таблицы сплошь 0xFF, чего и следовало ожидать.
Внесу свою лепту в Ваш разговор . Я делаю так Всё лишнее (не нужное для данной программы) для остаётся "за бортом"
Если при этом Вы не описываете каждый вектор, а пишете только те, которые используете, то чем Ваш способ принципиально отличается от способа, предложенного BOB51? И все потенциальные возможности для ошибок, описанные мной, полностью относятся и к Вашему способу.
Заголовок сообщения: Re: atmega 128 прерывание по таймеру
Добавлено: Вт май 22, 2012 21:22:37
Держит паяльник хвостом
Карма: 15
Рейтинг сообщений: 70
Зарегистрирован: Ср мар 28, 2012 21:45:24 Сообщений: 906 Откуда: ВО
Рейтинг сообщения:0
Alkul писал(а):
[ли при этом Вы не описываете каждый вектор, а пишете только те, которые используете, то чем Ваш способ принципиально отличается от способа, предложенного BOB51? И все потенциальные возможности для ошибок, описанные мной, полностью относятся и к Вашему способу.
Не внимательно посмотрел его код , да похоже. И полностью принимаю его аргументы в его защиту. От себя добавлю , ни разу не было ни одного сбоя при такой организации адресов прерывания, правда место это не зкономит во FLASH, но вы можете убрать в def адреса по умолчанию и присвоить свои тем же прерываниям расположив их как Вам удобно , например только используемые и подряд учитывая специфику адресации применяемого процессора
Не внимательно посмотрел его код , да похоже. И полностью принимаю его аргументы в его защиту. От себя добавлю , ни разу не было ни одного сбоя при такой организации адресов прерывания
Вы невнимательно прочли то, что писал я о проблемах, могущих возникнуть при использовании такого способа. Разве я говорил о сбоях? Понятно, что не бывает таких сбоев, которые заставят перейти на запрещенное прерывание (иначе контроллер дефектный). Я говорил о возможных ошибках в программе, которые вполне может допустить начинающий программист (даже пример такой ошибки привел). А уже эти ошибки могут стать причиной того, что запрещенное прерывание будет разрешено. Мы же говорим о рекомендациях начинающему программисту! Такие ошибки будет очень сложно отлавливать, потому что не будет видна причинно-следственная связь ошибки и её внешних проявлений. Конечно, для профессионала такая предосторожность, возможно, и лишняя. Он отслеживает каждый бит в 16-ти килобайтной программе и в уме делает арифметические действия над шестнадцатеричными числами Но новичку этот способ записи таблицы векторов сэкономит много времени и нервов.
Что-то опять, практически, холивар пошёл. Народ, нет чтобы скомбинировать всё лучшее, так вы воду толчёте. Между прочим вариант предложенный ILYAUL и дополненный как писал Alkul будет ещё лучше. (И об этом на форуме уже писали, и сдаётся мне, что уже не раз.) А именно - определить все точки входа в прерывания с помощью директивы .org с метками векторов прерываний из "инклюдника". В таком случае не имеет значения какая команда стоит непосредственно в векторе - jmp(там где допустимо), rjmp или reti. Так же не имеет значения последовательность определения векторов, так как есть директивы .org (обратите внимание на .org INT_VECTORS_SIZE перед основным кодом).
В качестве примера чуть-чуть дополненный (но далеко не полный ) кусочек кода от ILYAUL
_________________ Когда уже ничего не помогает - прочтите, наконец, инструкцию. Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII) Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
а замечания-то насчет ограничений симулятора относительно таймеров и прочего народ не воспринял... кстати о питичках... в коде от Alkul при компиляции должна была бы выскочить ошибка "двойное определение метки", но... второе определение по сути дублирует значения первого и... спасибо за обнаруженную "пакость" в работе асма теперь о "ошибках начинающих" "случайно" включить не тот бит конечно можно, если кто матчасть или двоичную математику перед тем, как лезть в программирование, не учил... только вот... стандартное правило - считай то, чего было, замени целевой бит и запиши назад - никто пока не отменял (да еще запрети на всякий случай все прерывания перед тем, как чего менять и флажки возможных "возмущений" скинь для страховки), а прямое управление битами для AVRок доступно только относительно портов 0x00-0x1F Kavka, а в случае применения "перемещенной" таблицы векторов такой подход всегда сработает?(см. адреса переконфигурации таблиц для "больших" мег - язва я) кстати об оформлении программ - весьма правильно описано в http://pic24.ru/doku.php/osa/articles/mpasm_formatting , хотя это и относительно PICов (там своя заморочка с прерываниями и довольно серьёзная) зато общий план подхода к вопросу очень хороший досадно, что обилие "грязи" и неполное знание возможностей ассемблера ( отчасти и за счет довольно смутного их описания) заставляет в дальнейшем "прыгать на С" при более-менее сложных проектах
Заголовок сообщения: Re: atmega 128 прерывание по таймеру
Добавлено: Ср май 23, 2012 10:48:25
Держит паяльник хвостом
Карма: 15
Рейтинг сообщений: 70
Зарегистрирован: Ср мар 28, 2012 21:45:24 Сообщений: 906 Откуда: ВО
Рейтинг сообщения:0
Цитата:
BOB51 а замечания-то насчет ограничений симулятора относительно таймеров и прочего народ не воспринял...
Симмулятор Atmel "до ума" всё таки довести пока не может . И перед его использованием для любого MC надо обязательно лезть в его описание и смотреть , что он поддерживает , а что нет именно для данного MC. В том числе и прерывания. Вот математику ( о чём здесь писалось) да , можно его использовать для отладки матемаического куска кода. Ну ещё посмотреть , что пишется в порты и регистры переферии . Но доверять всецело его действиям с переферией я бы не стал. А для начинающих - один раз потратится ( если серьёзно хочется заниматься MC и писать свои программы) купить отладчик ( он же и программатор - как доп. функция) , коих кстати не так уж и много и под необходимый проект делать макетку. Что всестороне развивает навыки програмирования , чтения схем и держания паяльника. Кстати, их получится не так уж и много т.к. использование макросов позволяет перенести проект отработанный на одном MC на другой MC практически без серьёзной правки кода.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения