Нужно не перебирать, а зайти в винавр и в папке avr\include\avr - найти заголовочный файл Вашего камня. Оттуда переписать правильное название прерывания.
Нужно не перебирать, а зайти в винавр и в папке avr\include\avr - найти заголовочный файл Вашего камня. Оттуда переписать правильное название прерывания.
Спасибо urry, я нашел что искал: /* USART, Tx Complete */ #define USART_TXC_vect _VECTOR(13) #define SIG_UART_TRANS _VECTOR(13)
PS: Кстати правильный пример прерывания по таймеру ты написал на этом форуме, а я его переписал. Спасибо тебе.
_________________ Кот должен прожить жизнь без сожаления.
Кстати, по поводу прерываний и WINAVR. ... инициализация функции прерывания по таймеру старой версии WINAVR. INTERRUPT (SIG_OVERFLOW1) Сейчас эти функции пишутся по другому. ISR(TIMER1_OVF_vect)
Поищите в директории, где установлен WinAVR, файл с руководством (у меня сейчас под рукой версия с именем avr-libc-user-manual-1.6.5.pdf, у Вас, возможно, цифры версии будут другими). В нем в разделе <avr/interrupt.h>: Interrupts есть таблица с описанием всех векторов прерываний и их доступности по моделям МК (в моем экземпляре она начинается на стр. 217). Перед таблицей приведен ряд ценных указаний по обработке прерываний в WinAVR в общем.
DruidCat писал(а):
По предыдущему примеру таймеров, могу написать для USART прерывание. ... #include <avr/interrupt.h>//Для доступа к функции sei() ISR(USART_TXC_vect){ ........ }
int main(void){ UCSRB = (0<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN);//Активизируем прерывание по завершении передачи, приемник и передатчик
Несколько замечаний.
Во-первых, Вы разрешили прерывание по готовности приемника, но не определили функцию для его обработки. Это приведет к неприятным последствиям, если кто-то не просто ограничится наблюдением выводимых на терминал сообщений, но и попробует потыкать клавиши в ответ. Каждый принятый байт будет приводить к переходу на вектор сброса, т.е. перезапуску программы. Не следует разрешать лишние прерывания, которые в данный момент не задействованы.
Далее, я бы не рекомендовал разрешать прерывания по готовности передатчика в самом начале программы. Получается такая ситуация: сначала передатчик готов, но данные для передачи еще не подготовлены; вызывается обработчик прерывания, а делать ему пока еще нечего. Потом программа подготовит данные, но прерывания уже не будет (т.к. оно было обработано вхолостую), и придется опрашивать флаг готовности. Лучше разрешать прерывания в тот момент, когда есть данные для передачи, и запрещать, когда их нет.
И последнее. Прерывания нужны для того, чтобы исключить непродуктивное зацикливание процессора на ожидании готовности устройства и заставить процессор заняться чем-то более полезным. Наиболее эффективно сочетать работу по прерыванием с буферизацией данных. Для этого в памяти выделяется буферная очередь с дисциплиной доступа FIFO (First In First Out, т.е. "первым пришел - первым ушел"). Главная программа заносит текст сообщения в буфер и инициирует передачу (разрешает прерывания от передатчика). Далее программа занимается своим делом, а обработчик прерываний извлекает байты из очереди по одному и отправляет в линию. После передачи последнего байта из очереди прерывание от передатчика следует снова запретить до лучших времен.
Если дружите с английским, рекомендую пару хороших книг:
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
Вот тут я нашел таблицу прерываний <avr/interrupt.h>: Interrupts в WINAVR WinAVR-20100110\doc\avr-libc\avr-libc-user-manual\group__avr__interrupts.html
А по поводу прерываний, буду учиться и читать. Спасибо за помощь. Как будут успехи, я отпишу переделанный листинг с itoa и прерываниями со всеми вашими замечаниями. Вдруг, кому понадобится из новичков.
_________________ Кот должен прожить жизнь без сожаления.
Компания MEAN WELL пополнила ассортимент своей широкой линейки светодиодных драйверов новым семейством XLC для внутреннего освещения. Главное отличие – поддержка широкого спектра проводных и беспроводных технологий диммирования. Новинки представлены в MEANWELL.market моделями с мощностями 25 Вт, 40 Вт и 60 Вт. В линейке есть модели, работающие как в режиме стабилизации тока (СС), так и в режиме стабилизации напряжения (CV) значением 12, 24 и 48 В.
Каждый принятый байт будет приводить к переходу на вектор сброса, т.е. перезапуску программы. Не следует разрешать лишние прерывания, которые в данный момент не задействованы.
Вот тут хочу поправить, не на вектор сброса, а на вектор прерывания, как правило в конце всех векторов стоит заглушка в виде reti таким образом возвращая в выполняемый код даже если обработка прерывания пропущена. Но это опять же пустая трата времени на переход к прерыванию и обратно.К тому же компилятор может еще и запихать в обработку прерывания сохранение регистров, то тогда еще и на это время тратится бесполезно.
Хм кстати я не пробовал нужно посмотреть как себя ведет программа, если пропущена обработка.
_________________ В поисках истины человек развивается.
«Вот тут хочу поправить»™, именно у WinAVR в стартапе на всех неиспользуемых векторах стоит переход на weak-метку __bad_interrupt, по которой находится переход на тоже weak-метку __vector_default , которая приравнена метке __vectors, которая является адресом начала таблицы векторов. Т.е. в конечном итоге будет переход на вектор сброса (но не сброс! периферия остаётся непроинициализированной).
Можно объявить ISR(__vector_default) и в ней перехватывать не имеющие обработчика, но разрешённые прерывания.
А reti для прерываний без обработчика — это заметание проблемы под коврик. Особо весело с прерываниями, не сбрасываемыми самим фактом входа в обработчик (например, внешнее прерывание по уровню или даже UDRE). При этом программа будет после каждой команды бегать на reti, замедлясь в 7..9 раз в зависимости от того, reti прямо в векторе или до него ещё по jmp добираться.
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Каждый принятый байт будет приводить к переходу на вектор сброса, т.е. перезапуску программы. Не следует разрешать лишние прерывания, которые в данный момент не задействованы.
Вот тут хочу поправить, не на вектор сброса, а на вектор прерывания, как правило в конце всех векторов стоит заглушка в виде reti таким образом возвращая в выполняемый код даже если обработка прерывания пропущена.
Ну, давайте поучим разработчиков, которые написали документацию. Они, конечно же, хуже знают, как работает их же продукт, и будут рады поправке:
Цитата:
Catch-all interrupt vector If an unexpected interrupt occurs (interrupt is enabled and no handler is installed, which usually indicates a bug), then the default action is to reset the device by jumping to the reset vector. You can override this by supplying a function named BADISR_vect which should be defined with ISR() as such. (The name BADISR_vect is actually an alias for __vector_default. The latter must be used inside assembly code in case <avr/interrupt.h> is not included.)
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
Можно объявить ISR(__vector_default) и в ней перехватывать не имеющие обработчика, но разрешённые прерывания.
А reti для прерываний без обработчика — это заметание проблемы под коврик.
Совершенно верно, золотые слова.
И самое разумное, что можно сделать в ISR(__vector_default), - это аварийный останов программы с соответствующей диагностикой. Ибо поверхностное заштукатуривание провороненных прерываний пустыми reti - весьма отчетливый индикатор дефектного кода.
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
Вот тут я дал маху, будем исправляться. Просто я в листинге видел после векторов такую фичу вот и подумал. Только не додумал, что проектировщики winavr были более прозорливые и отправили всех невнимательных в нужное место.Так сразу становится видно ошибку. Goldsmith, avreal плюсую вам. только я не понял, если на сброс кидает, значит инициализация снова происходит или как при нажатии на кнопку сброса?Но опять же для разделения причины сброса нужно код писать.
Вообще получается в любом случае, если используются прерывания реально необходимо прорабатывать вектор корявых прерываний. Наверно можно даже через тот же Юсарт слать для определения проблемы.Или светодиод зажечь в качестве индикатора. А можно ли еще какие нибудь данные отправить?Получается вроде только глобальные переменные можно.
_________________ В поисках истины человек развивается.
Только не додумал, что проектировщики winavr были более прозорливые и отправили всех невнимательных в нужное место.
Недооценивать сообразительность разработчиков продуктов уровня WinAVR - очень большая ошибка.
vitalik_1984 писал(а):
только я не понял, если на сброс кидает, значит инициализация снова происходит или как при нажатии на кнопку сброса?
При нажатии на кнопку сброса сначала происходит аппаратный сброс, а уже затем переход на вектор сброса. Что именно происходит в момент аппаратного сброса, лучше смотреть в описании конкретного устройства. Например, для Mega16 указано:
Цитата:
Resetting the AVR During Reset, all I/O Registers are set to their initial values, and the program starts execution from the Reset Vector. ... The I/O ports of the AVR are immediately reset to their initial state when a reset source goes active. This does not require any clock source to be running.
В случае программного перехода на вектор сброса аппаратная инициализация регистров ввода/вывода не произойдет, они сохранят прежние значения. Программная инициализация в обоих случаях (аппаратный сброс и переход по вектору сброса) будет происходить одинаково:
.init0 - если __init() определена пользователем; .init1 - не используется; .init2 - инициализация стека, обнуление r1; .init3 - не используется; .init4 - используется лишь в старших моделях (ROM > 64K); .init5 - не используется; .init6 - используется для конструкторов C++: .init7, .init8 - не используются; .init9 - переход на main().
vitalik_1984 писал(а):
Но опять же для разделения причины сброса нужно код писать.
Можно отделить аппаратный сброс от программного (из-за перехода по неожиданному прерыванию), например, путем анализа содержимого MCUCSR (для Mega16). Но лучше все же перехватывать все лишние прерывания и аварийно останавливать программу по ним (если это не свистелка/перделка/мигалка светодиодами и подобный шедевр человеческого гения). Устройства, в которых возникают такие прерывания, живут своей жизнью независимо от автора, и лучше выявлять это при первой возможности, возвращая на доработку. Так что такое отделение возможно, но вряд ли будет реально полезным на практике.
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
А я видел как делали кнопку на ресет, и нажимая на нее получается тоже происходит аппаратный сброс, только переменные все сохраняются.Потом анализируется повод ресета и выполняются нужные действия.Получается на mega16 так не получится сделать?
_________________ В поисках истины человек развивается.
Вот зараза, ещё вчера вечером упал сервер, где я в гостях у нескольких толстых сайтов «хощусь». У меня на сайте есть примеры использования этих «не используется» (они специально вставлены для программы пользователя).
vitalik_1984 писал(а):
А я видел как делали кнопку на ресет, и нажимая на нее получается тоже происходит аппаратный сброс, только переменные все сохраняются.Потом анализируется повод ресета и выполняются нужные действия.Получается на mega16 так не получится сделать?
Можно, только переменные надо заводить в секции .noinit. Пример выдёргивания MCUSR в неинициализируемую переменную в .noinit для последующего анализа причины сброса (перед ранним сбросом WDT в секции .init3, там нужно занулить MCUSR, поэтому нужно сохранить исходное значение для анализа) приведён в avr/wdt.h http://www.nongnu.org/avr-libc/user-man ... chdog.html
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Немного о секциях в gcc вообще и avr-gcc (aka WinAVR aka Atmel toolchain) в частности.
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Эх, жалко, что я в 1998году выбрал профессию инженера-электрика а не программиста, когда поступал в университет. Так бы я сейчас понимал о чем вы говорите. К слову, сегодня ночью я дописал исходный код своего листинга, в котором используется стандартная функция itoa. И выводится число и символьный массив разной длины через универсальную функцию вывода по USART. Вы мне в прошлых постах помогли с прерываниями по USART и у меня заработала функция вывода, которую я переписывал из учебника Шпака. Данный листинг будет, наверное, полезен новичкам, типо меня. Он экономичнее в три раза функции printf. Чего я и добивался. //******************************************************************************** // // Автор : DruidCat // // МК : ATMega8L // // Компилятор : WinAVR // // Назначение : Выводим число и строку по USART через универсальную функцию // // Дата : 18.08.2012 // //******************************************************************************** #include <avr/io.h> #include <util/delay.h> //Для вызова функции _delay_ms() #include <avr/interrupt.h> //Для доступа к функции sei() #define F_CPU 8000000UL //Частота МК #define USART_SPEED 9600 //Скорость USART желаемая #define BAUD ((F_CPU/(USART_SPEED*16UL)) + 1) //Формула расчета БОД #include <stdlib.h> //Вызов функции itoa, ltoa
ISR(USART_TXC_vect){ //Подпрограмма обработки прерывания при завершении передачи очередного символа if (queueC != sendC) UDR = queue[sendC++]; //Если был передан не последний символ, то передаем текущий и увеличиваем счетчик переданных на 1 }
void SEND_USART(char *s){ //Функция формирования очереди символов из строки queueC = 0; //Текущий символ - первый sendC = 1; //Первый символ считаем уже переданным queue[queueC++] = 0x0D; //Добавляем в конец очереди символы queue[queueC++] = 0x0A; //возврата каретки и переноса строки while (*s) queue[queueC++] = *s++; //Просматриваем строку и помещаем в очередь символы UDR = queue[0]; //Передаем первый символ, чтоб начать процесс }
void INIT_USART(void){ //Функция настройка USART UCSRB = (0<<RXCIE)|(1<<TXCIE)|(0<<RXEN)|(1<<TXEN); //Активизируем прерывание по окончание передачи и передатчик UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //размер слова 8 разрядов UBRRH = (unsigned char)(BAUD >> 8 ); //Скорость передач UBRRL = (unsigned char)BAUD; //Скорость передач }
int main (void){ INIT_USART(); //Вызываем функцию для настройки USART char HIGHT[] = "Высота 239"; //Массив символов HIGHT long int NUMBERS = 1234567; //Число для преобразования NUMBERS char *CHAR_NUMBERS; //Результат преобразования будет сюда записываться CHAR_NUMBERS char BUFFER[20]; //Символьный буфер преобразуемого числа CHAR_NUMBERS = ltoa(NUMBERS, BUFFER, 10); //Отсылаем в функцию ltoa число sei(); //Разрешаем прерывание while (1){ //Бесконечный цикл SEND_USART(CHAR_NUMBERS); //Отсылаем массив CHAR_NUMBERS в функцию SEND_USART _delay_ms(1000); //Пауза в 1сек SEND_USART(HIGHT); //Отсылаем массив HIGHT в функцию SEND_USART _delay_ms(1000); //Пауза в 1сек } }
PS: Спасибо всем кто мне помогал, приятно понимать, что такие грамотные ребята помогают новичкам, типо меня.
_________________ Кот должен прожить жизнь без сожаления.
У меня на сайте есть примеры использования этих «не используется» (они специально вставлены для программы пользователя).
Каюсь, несколько упростил для уровня начинающих.
На самом деле, конечно, все эти секции в документации объявлены как ".initN: Unused. User definable", а не просто "unused". Но для того, чтобы действительно возникла потребность в их использовании, нужны задачи потоньше. Например, собственный менеджер управления "кучей", который обязан быть готовым к работе перед входом в main(). На данном этапе не хотел запутывать.
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
DruidCat , вам же уже писали, что при инициализации не нужно активировать передатчик и прерывания от него.Там столько много текста было, видать ускользнуло от внимания.
Мне кажется это лучше сделать когда поместили в буфер строку. Потом в прерывании передачи проверяете есть ли в буфере символы, если нет- отключать нафиг лишние потребители.
Есть еще пара замечаний. 1.Как будет очищаться буфер передачи? Везде только добавляем к счетчику, где сброс?
2.Что будет, если в буфер поместить еще фрагмент до того, как буфер опустошится? На место первого массива встанет второй?Причем может даже произойти замена символов первого прямо перед передачей, таким образом принятыми будут вначале символы часть от первой строки,и оставшаяся часть от второй.И возможно еще часть от первой, если вторая строка короче первой.Хотя нет, там конец строки добавится.
_________________ В поисках истины человек развивается.
Эх, жалко, что я в 1998году выбрал профессию инженера-электрика а не программиста, когда поступал в университет. Так бы я сейчас понимал о чем вы говорите.
Ничего страшного, если действительно захотите - быстро освоите. Лучшие программисты, создавшие информатику, тоже не имели таких дипломов (а Никлаус Вирт, кстати, имеет степень доктора в области электротехники). Зато еще знаете и электричество, а это для разработки на МК не менее важно, чем жонглировать переменными. Далеко не все программисты знают, с какого конца браться за паяльник. (Знаю не понаслышке, в нашем отделе из 15 человек таких всего двое).
Еще пара советов. Во-первых, Ваш код в цитатах очень трудно воспринимается визуально, поскольку отступы удаляются форумским движком, и полностью теряется структура кода. Заключите код между тэгами [соde] и [/соde], и структура сохранится (над окном ввода текста есть кнопка Code для этого). Если структура изначально была "не очень", можно быстро привести ее в порядок, обработав утилитами вроде Indent или Artistic Style (обе они бесплатны, легко найдете их в Сети).
Во-вторых, Вы сразу же выработали очень полезную привычку не лениться писать комментарии как к отдельным фрагментам кода, так и к модулю целиком. Рекомендую сделать еще один шаг в этом направлении и применить утилиту Doxygen, который позволяет генерировать из комментариев довольно удобную документацию. Утилита простая (и, кстати, тоже бесплатная), освоить ее легко, и в ее составе есть удобная графическая оболочка; а чем раньше начнете писать правильные комментарии, тем меньше потом придется переписывать.
_________________ Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет. J. Ganssle
Здравствуйте, пишу под at90usb162 в code:blocks+WinAVR. Прошиваю flip'ом. Светодиод мигает по таймеру. Столкнулся с проблемой, что частота процессора(вычислил по периоду миганий) получается 1MHz(встроенный генератор видимо), хотя стоит кварц на 8. Аналогичный код, скомпилированный в CVAVR, работает в 8 раз быстрей, то есть как надо. В avr studio 6 тот же 1MHz. Подскажите пожалуйста в чем может быть проблема?
1.Как будет очищаться буфер передачи? Везде только добавляем к счетчику, где сброс?
А как очищать буфер? Нулей в его записать?
Goldsmith писал(а):
Если структура изначально была "не очень", можно быстро привести ее в порядок, обработав утилитами вроде Indent или Artistic Style (обе они бесплатны, легко найдете их в Сети).
Осилил еле еле Indent для WinAVR, лежит он в WinAVR-20100110\utils\bin\ Настроил так в WinAVR: Tools -> Options ->Tools -> add и настроил как на рисунке. Прикольная утилита, а я все думал, как сделать как в AVRStudio 5 формотирование исходного кода. Ответ Indent/
Я человек новый в AVR, но хочу задать тебе вопрос, а ты Fuses (Фьюзы) прошил в своем МК на внешний кварц 8 Мгц? Если ты это не сделал, то у тебя все будет работать в 8 раз медленнее. Так как по умолчанию в некоторых МК заводские настройки выставленны на 1 Мгц внутреннего резонатора.
_________________ Кот должен прожить жизнь без сожаления.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения