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

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
}

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

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

Comments   

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

(WinForms)
private void button1_Click(o bject sender, EventArgs e)
{
????
}
# Pashgan 2010-04-14 16:34
Что сделать? Чего то не врубаюсь
# Guest 2010-04-14 18:06
Quoting Pashgan:
Что сделать? Чего то не врубаюсь

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

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

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

Например

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

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

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

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

0
# andre1i 2011-07-18 16:48
Разобрался с битами, но возникла другая пробемма.
В avr studio и proteus программа не реагирует на нажатие кнопки (постоянно проверяется условие и прерывание не возникает). Я использовал PORTA, atmega16A
# stappa 2011-07-20 11:47
Мне кажется там должно быть не
code if ((PIND & (1
# stappa 2011-07-20 11:48
Мне кажется там должно быть не
Code: if ((PIND & (1<< PD0)) == 0)

a

Code: if ((PIND & (1<< PD0)) != 0)

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

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

У вас недостаточно прав для комментирования.