Учебный курс. Понятие прерывания. Подаем голос микроконтроллером.

21/09/2009 - 21:00
   Сегодня будем разбирать понятие прерывания и как его использовать. Естественно не обойдется без учебной программы, но на этот раз моргать светодиодами не будем. Хорош уже. Сделаем подобие дверного звонка.

Задача: заставить микроконтроллер по нажатию кнопки издавать звуковой сигнал.
Схема для нашего примера здесь. Файлы проекта здесь.

Создаем в старом workspace проект ring.
Задаем настройки проекта для конфигурации Release:


Выбираем тип микроконтроллера.
General Options > Target > Processor configuration
У меня это ATmega8535.  

Разрешаем использование имен битов определенных в хидер файле
В General Options > System ставим галочку Enable bit definitions in I/O-Include files
До сих пор мы не пользовались именами битов, но сегодня они нам понадобятся.   

Меняем тип выходного файла.
Linker > Output.
B поле Output file cтавим галочку Override default и заменяем расширение d90 на hex
В поле Format выбираем Other и в выпадающем меню Output format выбираем тип файла intel-standart

Сохраняем проект и workspace.

______________________________  Прерывание  ___________________________

    Представьте себе ситуацию. Вы сидите на работе и корпите над очередной микроконтроллерной програмулиной. Подходит к вам начальник и говорит: “Слушай, Паш, нам  осциллографы в отдел закупили - Tektronix, четырехканальные. Помоги Васе  притащить их”. Вы думаете: ”Ну, е-мое, только мысль поперла.. и на тебе”. А начальник так смотрит на вас, а глаза у него такие добрые, такие добрые. Как тут ему откажешь. Ну, вы все бросаете и идете с другом за осциллографами. Притащили. Отчитались. И снова сели за свою программу. Вот примерно так и выглядит механизм прерывания.

    Довольно просто, но есть ряд принципиальных моментов.
Во-первых:
-    вы делали свою работу
-    параллельно кто-то покупал осциллографы
-    по наступлению события «осциллографы закупили» - вы прерываете выполнение своей работы
-    некоторое время вы занимаетесь другой работой – тащите осциллографы
-    потом вы возвращаетесь на рабочее место и продолжаете делать свою работу с того места, на котором остановились

Во-вторых:
-    вы вполне могли бы послать начальника и никуда не идти
-    уйдя за осциллографами, вы могли задержаться там надолго, а то и вовсе не вернуться
-    вернувшись на рабочее место, вы могли бы уже позабыть свои гениальные идеи

    Все это очень похоже на то, что происходит в микроконтроллере. Микроконтроллеры AVR имеют в своем составе целую тучу периферийных устройств (таймеры/счетчики, аналого-цифровой преобразователь, аналоговый компаратор, асинхронный приемопередатчик…и т.д). Мощь микроконтроллера в том, что все эти устройства могут работать параллельно и независимо друг от друга, а также параллельно выполняемой программе. Каждое периферийное устройство может вызывать прерывание по наступлению определенного события. Прерывание будет происходить только в том случае, если оно разрешено. Разрешение прерываний устанавливается для каждого устройства отдельно. Помимо этого есть флаг глобального разрешения/запрещения всех прерываний – это I флаг в регистре SREG. При возникновении прерывания микроконтроллер сохраняет содержимое счетчика команд PC в стеке, то есть запоминает место, на котором его прервали.  Загружает в счетчик команд адрес соответствующего вектора прерывания и переходит на этот адрес. Попадает на команду безусловного перехода по которой переходит на подпрограмму обработки прерывания. Запрещает прерывания сбросом флага I, выполняет подпрограмму. Выполнив подпрограмму обработки прерывания, микроконтроллер разрешает прерывания, устанавливая флаг I, и восстанавливает содержимое счетчика команд, то есть возвращается на то же место программы, на котором его прервали.
    По идее, обработчик прерывания не должен повреждать содержимое регистров микроконтроллера, потому что они могут содержать данные программы выполняемой в тот момент. Для этого в начале подпрограммы обработки прерывания содержимое регистров микроконтроллера сохраняют в стеке, а в конце подпрограммы восстанавливают. Таким образом, выйдя из прерывания, микроконтроллер сможет продолжить выполнение программы, как ни в чем не бывало. Программируя на ассемблере, сохранение регистров прописывает сам программист, на Си – это делает компилятор.

_______________________________________________________________

   Теперь поговорим о таймере. ATmega8535 имеет на борту три  таймера/счетчика - два восьмиразрядных (T0, T2) и один шестнадцатиразрядный (T1). Мы будем использовать восьмиразрядный таймер/счетчик T0. В состав этого таймера входят три регистра - регистр управления TCCR0, счетный регистр TCNT0 и регистр сравнения OCR0. Когда таймер запущен, счетный регистр TCNT0 увеличивает свое значение на единицу на каждый перепад тактового сигнала. Частота тактового сигнала выбирается из нескольких возможных значений в регистре управления TCCR0. Также с помощью этого регистра устанавливается режим работы таймера. Таймер T0 может вызвать прерывание по наступлению события “переполнение” – это когда переполняется счетный регистр TCNT0 и по наступлению события “совпадение” – это когда значение счетного регистра TCNT0 становится равным значению регистра сравнения OCR0. Флаги разрешающие эти прерывания находятся в регистре TIMSK. 
    Мы настроим таймер/счетчик Т0 так, чтобы он вызывал прерывание по событию “совпадение” с частотой 5 кГц. В функции обработчике будем инвертировать состояние вывода микроконтроллера, к которому подключен пьезодинамик. Таким образом, частота пищания пьезика будет равна 2,5 кГц.  (Подключен именно пьезодинамик! Не перепутайте. У пьезодинамика сопротивление зависит от частоты и на 2,5 КГц оно обычно еденицы Ком, поэтому его можно подключать к выводу микроконтроллера напрямую, без ограничительного резистора).

    Теперь о программе. Построчно писать программу уже не получится, поэтому я сразу приведу ее текст. Ниже мы последовательно разберем все ее строки, и все станет понятно. Макросы я намеренно не стал использовать, программа маленькая, не хочется ее загромождать.

//Подаем голос микроконтроллером AVR
#include <ioavr.h>
#include <intrinsics.h>


int main(void)
{
//настраиваем порты ввода-вывода
  DDRD = (0<<PD1)|(1<<P0);
  PORTD = (1<<PD1)|(0<<PD);

//настраиваем таймер Т0
  TCCR0 = (1<<WGM01)|(0<<GM00)|(0<<CS02)(1<<CS01)(0<<CS00)
  TCNT0 = 0;
  OCR0 = 0xc8;
 
//разрешаем прерывания  
  __enable_interrupt();
 
//основной цикл программы – опрос кнопки
  while(1){
       if ((PIND & (1<<PD0)) == 0)
            TIMSK = (1<<OCIE0);
       else
            TIMSK = 0;
  }
  return 0;
}

//обработчик прерывания таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
        PORTD ^= (1<<PD1); //инвертируем сигнал на выводе PD1
}


Настройка портов

    В нашей схеме к порту D подключена кнопка и пьезодинамик. Вывод, к которому подключена кнопка, нужно настроить на вход и включить подтягивающий резистор. Вывод, к которому подключен пьезодинамик, нужно настроить на выход.

    DDRD = (0<<PD1)|(1<<PD0);
    PORTD = (1<<PD1)|(0<<PD0);

Настройка таймера
    
    Режим работы таймера Т0 – СТС(сброс при совпадении), тактовый сигнал – clk/8. Отражаем это в регистре TCCR0

    TCCR0 = (1<<WGM01)|(0<<WGM0)|(0<<CS02)(1<<CS01)(0<<CS00)

Обнуляем на всякий случай счетный регистр TCNT0

    TCNT0 = 0;

В регистр сравнения OCR0 записываем 0xc8. Почему? Потому что я посчитал это на калькуляторе. Ну а на бумаге этот расчет выглядит так.
Тактовая частота микроконтроллера 8 МГц
Тактовый сигнал таймера равен 8000000 Гц/8 = 1000000 Гц.    
Время одного такта таймера 1/1000000 = 1 мкс
Время одного такта нужной нам частоты 1/5000 Гц = 200 мкс
Сколько тактов таймера укладывается в 200  мкс?   200/1 = 200 тактов
200 в шестнадцатеричной системе = 0xс8

    OCR0 = 0xс8;

Подробное описание таймера T0 смотрите в документации на ATMega8535.

Таймер мы настроили, разрешаем общее прерывание, используя встроенную функцию.

    __enable_interrupt();

Опрос кнопки

    Когда кнопка не нажата, вывод микроконтроллера через внутренний подтягивающий резистор подключен к питанию, то есть на выводе присутствует  единичка, когда кнопка нажата, вывод замкнут на землю, то есть на выводе ноль. Чтобы определить нажата ли кнопка, нужно считать содержимое регистра PIND и проверить значение нулевого бита (к PD0 подключена кнопка). Опрашивать кнопку будем в бесконечном цикле.


  while(1)
  {
        if ((PIND & (1<<PD0)) == 0){
                        //если кнопка нажата – микроконтроллер должен верещать
       }
       else {
                         //если нет - молчать как рыба
       }
  }

Не забывайте == это не оператор присваивания =.

Обработка нажатия/отпускания кнопки

    По нажатию кнопки мы будем разрешать прерывание таймера T0, по отпусканию  - запрещать. Для этого будем манипулировать битом OCIE0 регистра TIMSK

TIMSK = (1<<OCIE1); // разрешаем прерывание таймера Т0 по событию совпадение

TIMSK = 0; //запрещаем прерывание

Поскольку мы используем всего один таймер, то нет нужды в установке или сбросе отдельных битов.

Функция прерывания

Это не совсем простая функция, поскольку ее вызывает микроконтроллер, и она имеет особенный синтаксис.

_____________________ Cинтаксис функции прерывания _____________________


Функция прерывания задается с помощью директивы #pragma vector= и служебного слова __interrupt. Функция должна иметь тип void и не должна принимать никаких параметров.

#pragma vector = Address
__interrupt void Name(void)
{
    //здесь располагается наш код
}

Name – имя функции, выбираем на наше усмотрение
Address – адрес вектора прерывания, можно задавать числом, можно именами определенными в заголовочном файле микроконтроллера (iom8535.h – раздел Interrupt Vector Definitions)

______________________________________________________________

Для нашей задачи функция-обработчик прерывания выглядит так

#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
        PORTD ^= (1<<PD1); //инвертируем сигнал на выводе PD1
}

Ну вот собственно и все. Надеюсь все понятно.
В следующий статье заставим микроконтроллер играть мелодию.

Схема для нашего примера здесь. Файлы проекта здесь.

Комментарии   

# skiff 23.09.2009 03:17
Вот и пролился свет в тайну прерываний...
Все оказывается не так уж и сложно!
Ответить | Ответить с цитатой | Цитировать
# Guest 04.12.2009 05:51
//обработчик прерывания таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
PORTD ^= (1
Ответить | Ответить с цитатой | Цитировать
# Guest 04.12.2009 05:53
если не вставить обнуление счетчика в прерывании то программа должна встать при переполнении счетчика...
Ответить | Ответить с цитатой | Цитировать
# Pashgan 04.12.2009 22:55
в режиме СТС счетный регистр обнуляется автоматически
Ответить | Ответить с цитатой | Цитировать
# Guest 12.12.2009 05:04
А на tiny26 почему-то не сбрасывается. вроде и регистры также настроил... :-?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 16.12.2009 19:27
сделай тему на форуме и выложи код... может я или кто-нибудь еще разберется в чем дело
Ответить | Ответить с цитатой | Цитировать
# Guest 14.04.2010 15:52
хорошо, а как сделать это с кнопкой на компьютере?
допустим МК подключён к com-порту

(WinForms)
private void button1_Click(o bject sender, EventArgs e)
{
????
}
Ответить | Ответить с цитатой | Цитировать
# Pashgan 14.04.2010 16:34
Что сделать? Чего то не врубаюсь
Ответить | Ответить с цитатой | Цитировать
# Guest 14.04.2010 18:06
Цитирую Pashgan:
Что сделать? Чего то не врубаюсь

в примере тут кнопка подсоединена прямо к МК, а мне хочется, чтобы это было, например, событие нажатия кнопки в моей проге на компьютере.
Нашел тут http://www.activexperts.com/files/activcomport/manual.htm#chap_using_activecomport какой-то фреймворк по COM-порту, но как им "достучаться" до МК, я без понятия.
Ответить | Ответить с цитатой | Цитировать
# Guest 14.04.2010 18:54
вот нашел видео: http://www.youtube.com/watch?v=9RWstg3FAzg
мне нужно именно так
Ответить | Ответить с цитатой | Цитировать
# Guest 30.04.2010 20:38
Позвольте поблагодарить Вас за хороший цикл статьей, и внести предложение по улучшению в Ваш код. Предлагаю заменить
else
TIMSK = 0;
на
else{
TIMSK = 0;
ClearBit(PORTD, PD1);
}
а то иначе при отпускании кнопки регистр PD1 может оказаться в 1.
Ответить | Ответить с цитатой | Цитировать
# Fuzzy 01.09.2010 09:49
Заранее простите за глупый вопрос, не могли бы вы объяснить "физику процесса" в строках настройки портов ввода-вывода.
Ответить | Ответить с цитатой | Цитировать
# Pashgan 02.09.2010 20:02
Физику.. ммм
Физика в том, что вывод микроконтроллер а может работать как вход или как выход. Для настройки его режима работы есть два регистра DDRx и PORTx (вместо x - буквы A,B,C,D). Чтобы настроить пин на вход нужно в DDRx записать 0 в соответствующее место. Чтобы настроить пин на выход нужно записать 1. В режиме входа пин микроконтроллер а может находиться в третьем состоянии или быть подтянут с помощью внутреннего резистора к плюсу питания. Это выполняется записью 0 или 1 в регистр PORTx
Ответить | Ответить с цитатой | Цитировать
# Fuzzy 03.09.2010 10:08
Спасибо, но это то как раз и понятно - прочитал предыдущие ваши уроки. :-) Не совсем понятно вот что -
здесь:
DDRD = (1 сдвиг влево PD1);
PORTD = (1 сдвиг влево PD0);
в предыдущем же уроке где задаются макроопределени я здорово всё объяснено:
reg |= (1 сдвиг влево bit)
Так вот не понятно почему здесь нет опреатора "|" ? Пишу сдвиг влево, потому что где стоит стрелка влево обрезает сообщение ;-)
Ответить | Ответить с цитатой | Цитировать
# Pashgan 05.09.2010 17:12
Оператор | используется для установки разрядов в 1, при этом остальные разряды не меняются. А в данном случае мы настраиваем порт записывая в регистры число. Предыдущее содержимое регистров затирается, но здесь это не играет роли. Вот если бы другие выводы порта уже были настроены раньше и нам нужно было сохранить эти данные, мы бы воспользовались оператором поразрядного ИЛИ.
Ответить | Ответить с цитатой | Цитировать
# Yoruk 08.09.2010 03:27
Объясните пжл. Директива Enable bit definitions in I/O-Include files ее мы используем зачем ? Чтоб разрешить использование #define ?
Без нее компилятор выдает множество ошибок, а с ней все как по маслу.
Ответить | Ответить с цитатой | Цитировать
# Pashgan 12.09.2010 19:33
Для того чтобы разрешить использование имен битов определенных в специальном хидер файле. Директива #define здесь не причем.
Ответить | Ответить с цитатой | Цитировать
# Guest 16.09.2010 18:18
//настраиваем порты ввода-вывода
DDRD = (0
Ответить | Ответить с цитатой | Цитировать
# Guest 25.09.2010 19:02
//настроить порты ввода-вывода можно и так
DDRD.0=0;PORTD.0=1;DDDRD.1=1;
Я не ошибаюсь?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 29.09.2010 20:37
Нет, это в CodeVision так можно.
Ответить | Ответить с цитатой | Цитировать
# Guest 20.09.2010 06:06
а можно поподробней рассказать, что именно делается в строке:

TCCR0 = (1
Ответить | Ответить с цитатой | Цитировать
# Pashgan 20.09.2010 16:20
Плагин комментов режет сообщения со сдвигами. Задолбало уже, надо что-то с этим делать.
По поводу этой строчки.
Биты WGM01 и WGM00 определяют режим работы таймера - 10 это режим СТС. Биты CS02,CS01,CS00 определяют коэффициент предделителя. В данном случае он будет равен 8. Об этом всем написано в datasheet на микроконтроллер .
Ответить | Ответить с цитатой | Цитировать
# Guest 23.09.2010 15:36
Здравствуйте меня интересует вопрос о природе прерывания.
При возникновении прерывания скаже по событию А может ли его обработку перебить прерывание по тому же событию А. Или же сброшеный,в момент выполнения процедуры обработки прерывания, флаг I регистра SREG не даст этого сделать, игнорировав повторное прерывание А. :-?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 29.09.2010 20:41
Сброшенный флаг не даст этого сделать. Будет выполняться уже запущенный обработчик. Однако после выхода из него, он может быть снова запущен, если установлен соответствующий флаг.
Ответить | Ответить с цитатой | Цитировать
# Guest 30.09.2010 21:57
Не понятно зачем подключается
Код:
#include <intrinsics.h>

вроде программные задержки не используются
Ответить | Ответить с цитатой | Цитировать
# Pashgan 01.10.2010 14:22
Чтобы можно было пользоваться функцией __enable_interr upt();
Ответить | Ответить с цитатой | Цитировать
# sergei_ 11.11.2010 18:13
Открываю datasheet на 8535, смотрю на таймеры... В 8535 не нахожу для байтового таймера Т0 регистра OCR0 - есть TCCR0 и есть TCNT0.
Вот для байтового T2 - действительно, есть.
Либо я что-то не понимаю, либо надо поправить.
Ответить | Ответить с цитатой | Цитировать
# JoJo 14.11.2010 20:39
http://www.atmel.com/dyn/resources/prod_documents/doc2502.pdf на странице 85
Ответить | Ответить с цитатой | Цитировать
# Gena572 16.11.2010 14:16
Функция __enable_interr upt() как я понял разрешает все прерывания. А если нужно разрешить только определенные прерывания, то как это сделать?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 17.11.2010 21:07
У каждого периферийного модуля (таймера, АЦП, UARTa..) есть конфигурационны й регистр или несколько регистров. В этих регистрах есть специальные биты, отвечающие за разрешение/запр ещение прерываний.

Например

Код:TIMSK = (1<<OCIE0);
бит OCIE0 разрешает прерывание таймера Т0 по событию совпадение
Ответить | Ответить с цитатой | Цитировать
# Gena572 22.11.2010 13:32
Спасибо, все понял
Ответить | Ответить с цитатой | Цитировать
# man-1982 30.11.2010 17:39
Тактовый сигнал таймера равен 8000000 Гц/8 = 1000000 Гц.
Почему делим на 8.. и можно ли про систему расчета по подробнее
Ответить | Ответить с цитатой | Цитировать
# Pashgan 30.11.2010 18:02
биты CS02, CS01, CS00 - определяют источник тактового сигнала таймера Т0
Код:
(0<<CS02)|(1<<CS01)|(0<<CS00);

означает, что тактовый сигнал таймера равен clk/8
Ответить | Ответить с цитатой | Цитировать
# werter 31.01.2011 20:12
Код://настраиваем порты ввода-вывода
DDRD = (0<<PD1)|(1<<PD0);
PORTD = (1<<PD1)|(0<<PD0);

Добрый вечер!на схеме PD0-кнопка а PD1-буззер.А в программе наоборот
Ответить | Ответить с цитатой | Цитировать
# Anti 13.05.2011 19:42
Точно! А я голову ломал почему не пашет!
Ответить | Ответить с цитатой | Цитировать
# Nastya 16.02.2011 18:56
Здравствуйте, очень нравится как написаны ваши статьи. читаю, разбираюсь. работаю с CodeVision. Открыла ваш файл с этой программой, а он заругался на все строки, где есть побитовые смещения, умножения и сложения. как исправить?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 16.02.2011 22:15
Спасибо. Какую версию CodeVision ты используешь? Мои проекты написаны в CodeVision 2.04. В старой версии компилятора проекты могут не работать из-за отсутствия в нем описания битов регистров микроконтроллер а AVR.
Ответить | Ответить с цитатой | Цитировать
# Nastya 17.02.2011 15:46
У меня более ранняя версия CodeVision. Я по-другому биты попробовала задать. На пример в основном цикле программы вместо TIMSK = (1
Ответить | Ответить с цитатой | Цитировать
# Nastya 17.02.2011 15:52
//TIMSK=0b00000010
И вот ещё что не понятно, каким образом частота пищания пьезодинамика будет равна 2,5 кГц. В протеусе не запищал, но сигнал пошёл.
Ответить | Ответить с цитатой | Цитировать
# MICHAELtex 20.03.2011 00:43
Ребята спасибо за столь содержательные статьи , проливающие свет на темень AVR ...
Читая комментарии под статьями понял что вы делаете еще большую работу чем просто статьи, из за этого хочется аплодировать вам стоя.... Так держать!!!
Ответить | Ответить с цитатой | Цитировать
# Гость2 22.05.2011 23:53
Здравствуйте! Мне вот не понятно, - почему в основном коде при инициализации, вы присвоили биту 1 порта D логическое 1. Получается что когда мы заходим в обработчик прерывания ,он обнулит этот бит, и на выходе ни чего не будет для пьезодинамика.
Вот:

{
//настраиваем порты ввода-вывода
DDRD = (0
Ответить | Ответить с цитатой | Цитировать
# Гость2 22.05.2011 23:54
PORTD ^= (1
Ответить | Ответить с цитатой | Цитировать
# Димка 08.07.2011 15:03
Нее, ну так не канает, надо чо то с дребезгом делать, даже кнопку нажимать не обязательно, достаточно к пину пинцетом прикоснуться... .
Ответить | Ответить с цитатой | Цитировать
# andre1i 15.07.2011 09:00
Объясните пожалуйсто ПОДРОБНО (на пальцах):
//настраиваем порты ввода-вывода
DDRD = (0
Ответить | Ответить с цитатой | Цитировать
# andre1i 15.07.2011 09:03
Упс, извинаюсь в перредущем сообщении не добавил code.
Объясните пожалуйсто ПОДРОБНО (на пальцах):
Код://настраиваем порты ввода-вывода
DDRD = (0<<PD1)|(1<<PD0);
PORTD = (1<<PD1)|(0<<PD0);

0
Ответить | Ответить с цитатой | Цитировать
# andre1i 18.07.2011 16:48
Разобрался с битами, но возникла другая пробемма.
В avr studio и proteus программа не реагирует на нажатие кнопки (постоянно проверяется условие и прерывание не возникает). Я использовал PORTA, atmega16A
Ответить | Ответить с цитатой | Цитировать
# stappa 20.07.2011 11:47
Мне кажется там должно быть не
code if ((PIND & (1
Ответить | Ответить с цитатой | Цитировать
# stappa 20.07.2011 11:48
Мне кажется там должно быть не
Код: if ((PIND & (1<< PD0)) == 0)

a

Код: if ((PIND & (1<< PD0)) != 0)

Хотя могу ошибиться, сам разбраться пытаюсь.
Ответить | Ответить с цитатой | Цитировать
# Palach 15.11.2011 10:51
Здравствуйте. Я написал эту программу на IAR AVR, но она так и не заработала. Поковырялся и пришёл к выводу, что у меня почему-то не вызывается функция прерывания. Вроде в TCCR0 и TIMSK всё, что надо, выставил. Почему такое может быть? В Ассемблере, например, в начале программы метки на прерывания выставляются. Может, и здесь какую метку ставить надо?
Ответить | Ответить с цитатой | Цитировать
# Саня 11.12.2011 20:41
А существует прерывание от кнопки?
Ответить | Ответить с цитатой | Цитировать
# Илья 13.01.2012 04:13
http://chipenable.ru/index.php/programming-c/105-vneshnie-preryvaniya-avr.html
Ответить | Ответить с цитатой | Цитировать
# Georgy 05.01.2012 15:29
Не знаю как версия 5.11, но 5.3 и выше не компилируется, не видит битовых названий. Изучение вопроса показало, что надо включать строку
[#define ENABLE_BIT_DEFINITIONS]
в начале проекта, зачем они это сделали не понятно, наверно мысля была. Если речь идет об IAR,неплохо бы это вставить в примеры, дабы народ не парился, как я.
Ответить | Ответить с цитатой | Цитировать
# wukrlvy 08.02.2012 18:18
В пакете IAR Embedded Workbench в опциях вашего проекта (закладка General Option / System) есть галочка Enable bib definition in IO-include files. Установка этой галочки равносильна Вашей команде #define. Об этом ранее говорилось.
Ответить | Ответить с цитатой | Цитировать
# IseMan 10.01.2012 08:21
Скажите пожалуйста почему ошибка в этой строчке [#include ]
Ответить | Ответить с цитатой | Цитировать
# IseMan 10.01.2012 08:29
[intrinsics.h]в от это я имел ввиду
Ответить | Ответить с цитатой | Цитировать
# Vov4ik 27.01.2012 14:55
Такая же проблема. Нету библиотеки "intrinsics.h". Код пишу в "AvrStudio4", версия "AVR toolchain" - 3.3.0.710. Схему составил в Proteus 7.4, прошивку беру с архива выложенного тут по пути "ring\Release\E xe\ring1.hex" при симуляции динамик не пищит((
Ответить | Ответить с цитатой | Цитировать
# Vov4ik 31.01.2012 11:49
Для таких же новичков как я...
Юзанием гугла кое как разобрался с прерываниями.
Для тех кто пишет в AVR Studio, вместо библиотеки нужно подключить библиотеку . Чтобы разрешить все прерывания используется функция sei().
Событие прерывания:
void TIMER0_COMP_vec t(void) __attribute__((interrupt))
И функция прерывания:
void TIMER0_COMP_vect(){...}

Объясните плиз что значит WGM01 и CS01?
Ответить | Ответить с цитатой | Цитировать
# Vov4ik 31.01.2012 11:51
*вместо библиотеки "intrinsics.h" нужно подключить библиотеку "avr/interrupt. h"
Ответить | Ответить с цитатой | Цитировать
# ЕмДм 02.03.2012 20:01
На железе этот код для ATmega32A,работ ает некорректно. При нажатии на кнопки на выходной порт попадает сигнал, но при отпускании кнопки не пропадает. Висит и все. За статью спасибо.
Ответить | Ответить с цитатой | Цитировать
# MS 19.03.2012 13:41
А в функцию обработчика прерывания можно встроить функцию которая будет что-то возвращать? Т.е я хочу сказать, можно каким либо способом с помощью прерывания что-то вернуть?
Ответить | Ответить с цитатой | Цитировать
# radiolomaster 18.12.2012 19:33
Подскажите, как в AVR Studio разрешить использование имен битов, а то ругается что WGM00, OCR0, OCIE0 undeclared.
Ответить | Ответить с цитатой | Цитировать
# alec220 04.03.2013 08:30
Если ввести текст из поста в IAR, то компилятор находит аж 16! ошибок, несколько ошибок - отсутствие ; и т.п. я найти смог. Открыл прилагаемый файл, там как-то совсем все по другому. Чему верить?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 04.03.2013 09:01
Исправлю. При обновлении движка сайта, пострадал код в статье - часть символов была просто удалена. Ориентируйтесь на архив проекта, там все должно быть правильно.
Ответить | Ответить с цитатой | Цитировать
# alec220 04.03.2013 09:18
Файл скомпилировался нормально, значит ошибки только на странице.
Ответить | Ответить с цитатой | Цитировать
# alec220 04.03.2013 10:25
не писчить! выше писали про несоответствие схемы и программы при назначении выходов/входов. Оно устранено или нет? куда кнопку, а куда бузер?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 04.03.2013 11:00
По коду PD1 - вывод для бузера
Ответить | Ответить с цитатой | Цитировать
# alec220 04.03.2013 18:42
никак не сдается. А мог ли я выход спалить, перепутав кнопку и бузер? т.е. замкнув выход для бузера кнопкой на землю? мега в общем-то живая в остальном. Светодиодиками моргает, но они на другом порту... а как надо изменить программу, чтобы назначить не 0и1 пин а, допустим, 2 и 3?
Код: DDRD=(1<<PD3)
PORTD=(1<<PD2)
так? и соответственно ниже тоже поменять соответственно после if и в прерывании?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 04.03.2013 20:31
Теоретически - да. Переназначить на другой вывод можно, заменив PD0 на PD3 во всех местах кода.
Ответить | Ответить с цитатой | Цитировать
# alec220 05.03.2013 04:04
Попробовал, переназначил, не помогло... Я использую мегу 48РА - вроде посмотрел, таймер такой же есть, и все остальное."родс твенное".
Вы пишете: Вывод, к которому подключена кнопка, нужно настроить на вход и включить подтягивающий резистор. т.е. при не нажатой кнопке на этом входе тестер должен показать 5v? Осцилограф у меня как-то остался в "прошлой жизни", пытаюсь тестером выявить неисправность. Монтаж исключается, файл использую Ваш, бузеров попробовал 3 разных. На выход этого приходит меандр 2.5 кГц, я правильно понял? ...Заблудился в трех соснаххххх
Ответить | Ответить с цитатой | Цитировать

Добавить комментарий

Защитный код
Обновить