Всем привет, не так давно я рассказал, да и показал на видео, как можно прошить Attiny13 при помощи Arduino, а теперь покажу практическое применение этому.
Скажу сразу, фьюзы, прошивку в виде hex-файла, код на Си, скетч для Arduino IDE, файлы для Proteus 7 можно скачать в конце статьи.
Ну, что уж тянуть, покажу как работает:
Давно хотел себе такой музыкальный дверной звонок, чтобы при нажатии на кнопку играл марш империи(Imperial March or Darth Vader's Theme) из «Звёздных войн», очень нравится эта мелодия.
Как видно из названия видео выше, главный компонент устройства — микроконтроллер Attiny13, его применение сделало возможным сделать размеры платы в несколько раз меньше по размерах чем спичечной коробок:
Диапазон питания примерно от 2 В до 6 В, то есть, от двух до четырех батареек формата AA, хотя в идеале бы обеспечить напряжение 3-4 В, то есть для этих целей идеально подходит литий ионный аккумулятор от мобильника или же аккумулятор формата 18650, правда желательно чтобы он был с защитой, так как я пока не реализовал никакой защиты от глубокого разряда.
Ну что же, скажу пару слов по схемотехнике:
Схема выглядит вот так(файлы Proteus прилагаются в конце статьи, можно даже ничего не собирать на макетке):
Так как микроконтроллер не может самостоятельно вытянуть достаточную громкость, для того чтобы было слышно звонок по всему доме, я добавил NPN транзистор 2N3904, довольно таки распространенный транзистор, в принципе может подойти любой транзистор который потянет динамик, в моём случае транзистор рассчитан на 100 мА.
При использовании 3-х батареек формата AA транзистор немножко грелся, при использовании двух — громкость осталась на приличном уровне но уже транзистор был слегка тёплым.
Резистор R2 — стандартная обвязка для микроконтроллера, служит защитой от случайных перезагрузок микроконтроллера, в принципе работать должно и без него, резистор R1 служит для ограничения тока на базе транзистора.
На фото видно ещё защитный диод, защищает он от невнимательности, а именно от переполюсовки, в моём случае, переполюсовка очень быстро выведет микроконтроллер из строя, причём вполне возможны как пиротехнические так и звуковые эффекты. Кстати, на схеме ниже я забыл указать его, подойдёт любой диод который рассчитан на напряжение от 10 В и ток от 200 мА, ставиться последовательно входу платы, или по минусу или по плюсу, у меня по минусу.
Динамик от старого Dial up модема Zyxel, кстати, про Dial up модемы этой фирмы есть один известный анекдот:
Код, скажу сразу, нагуглил, точней нашёл на просторах ютуба, вот собственно само видео:
Под видео есть ссылка на код, вот он:
Как Вы можете видеть, есть два массива frequences — в переводе из английского частота и durations — длительность, всё данные типа word, PROGMEM — данные хранятся во флеш-памяти микроконтроллера(без использования библиотеки pgmspace.h работать не будет) ну и есть генератор частоты buzz() который принимает три параметра — пин, на котором будет генерироваться частота, второй — частота в герцах, третий — длительность в миллисекундах.
Данный код должен быть Arduino совместимым и работать даже на Arduino Uno, Arduino Nano или же Arduino Pro Mini ну и и других дуинах.
Как Вы могли слышать на видео, звучание моего видео немного отличается от второго видео, дело в том, что я немного изменил длительность нот и в три раза популярным методом «научного тыка», поднял частоту, так как такой маленький динамик как у меня плохо воспроизводит те частоты что были изначально, и добавил кнопку, какой же дверной звонок без кнопки?
Как видите, добавления срабатывания при нажатии на кнопку превысило 1024 байта и пришлось вставлять кусочки кода Си чтобы уместиться в attiny13.
Частоту поднял строках buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])) * 3, 2 * pgm_read_word(&(durations[i]))); тем самим умножив генерируемые частоты, как Вы поняли на три, это чисто мой каприз, можете ничего не умножать вообще.
Если Вы опытный ардуинщик, то думаю заметите в коде что я сделал программную подтяжку PULLUP резистора к порту PB4.
Для тех кто не знает делается это так:
Выставляем порт на вход и подаём на него логическую единицу. Теперь на порту будет напряжение, примерно равно напряжению питания, если этот порт закоротить на землю то он изменит своё состояние с логической единицы на логический ноль, причём микроконтроллер при этом не будет страдать, так как используется внутренний резистор, номинал которого 10-100 кОм.
Сделал я это чисто для экономии размеров платы, можно было просто подпаять резистор на 10 кОм к плюсу питанию и нужному порту, при нажатии на кнопку мы «притягиваем порт к земле» и на нём будет логической ноль.
Добавляю код на чистом AVR-С для тру AVR'щиков:
Вроде как должен компилироваться без проблем, а вот при использовании этого кода в Arduino IDE почему-то размер hex файла как минимум удваивается «Размер скетча в двоичном коде: 1 986 байт (из 1 024 байт максимум)».
Как мне удалось выяснить всё это из за использования _delay_us(*); хотя ардуиновская функция delayMicroseconds(*); по сути делает то же самое, думаю это недочёт файлов ядра для тини13, вот ветка на буржуйском форуме ардуино откуда я и взял файлы ядра, правда самую малость доработал под себя, ссылка на доработанные мною файлы ядра есть в статье про прошивку Attiny13 при помощи Arduino.
Если кто-то поможет разобраться с этим багом буду только рад, ведь чисто теоретически Arduino IDE должна без проблем проглатывать С-шний код.
Ну и пару слов по прошивке — на первом видео запускал тиньку на частоте 1.2 мГц, как по мне, так 1.2 миллиона операций вполне достаточно чтобы играть любимую мелодию и при этом кушать совсем не много, кстати hex-файл скомпилирован именно под эту частоту.
Вот фьюзы из калькулятора фьюзов:
Теперь, каждый кто имеет AVR программатор сможет повторить это устройство.
Как было обещано в начале статьи вот все нужные файлы.
Все мои публикации.
И напоследок — «Да прибудет с Вами сила».
UPD 05.01.2015
Хаброюзер SparF сделал то, что я ленился сделать всё это время, а именно довести до ума энергопотребление и сделать проигрывание при нажатии на кнопку PB1.
Теперь после проигрывания мелодии МК не «молотит» дальше в ожидании нажатия кнопки а засыпает и при каждом нажатии на кнопку он просыпается, проигрывает любимый нами Имперский марш и засыпает дальше, потребляя при этом практически ничего, батареек хватит на десяток лет в таком режиме потребления.
Код без проблем компилируется в Arduino IDE.
Файлы.
Проверил, всё работает:
Скажу сразу, фьюзы, прошивку в виде hex-файла, код на Си, скетч для Arduino IDE, файлы для Proteus 7 можно скачать в конце статьи.
Ну, что уж тянуть, покажу как работает:
Давно хотел себе такой музыкальный дверной звонок, чтобы при нажатии на кнопку играл марш империи(Imperial March or Darth Vader's Theme) из «Звёздных войн», очень нравится эта мелодия.
Как видно из названия видео выше, главный компонент устройства — микроконтроллер Attiny13, его применение сделало возможным сделать размеры платы в несколько раз меньше по размерах чем спичечной коробок:
Размеры платы
А вот уже всё подключённое:
А вот уже всё подключённое:
Диапазон питания примерно от 2 В до 6 В, то есть, от двух до четырех батареек формата AA, хотя в идеале бы обеспечить напряжение 3-4 В, то есть для этих целей идеально подходит литий ионный аккумулятор от мобильника или же аккумулятор формата 18650, правда желательно чтобы он был с защитой, так как я пока не реализовал никакой защиты от глубокого разряда.
Ну что же, скажу пару слов по схемотехнике:
Схема выглядит вот так(файлы Proteus прилагаются в конце статьи, можно даже ничего не собирать на макетке):
Нарисована в Proteus'е
Так как микроконтроллер не может самостоятельно вытянуть достаточную громкость, для того чтобы было слышно звонок по всему доме, я добавил NPN транзистор 2N3904, довольно таки распространенный транзистор, в принципе может подойти любой транзистор который потянет динамик, в моём случае транзистор рассчитан на 100 мА.
При использовании 3-х батареек формата AA транзистор немножко грелся, при использовании двух — громкость осталась на приличном уровне но уже транзистор был слегка тёплым.
Резистор R2 — стандартная обвязка для микроконтроллера, служит защитой от случайных перезагрузок микроконтроллера, в принципе работать должно и без него, резистор R1 служит для ограничения тока на базе транзистора.
На фото видно ещё защитный диод, защищает он от невнимательности, а именно от переполюсовки, в моём случае, переполюсовка очень быстро выведет микроконтроллер из строя, причём вполне возможны как пиротехнические так и звуковые эффекты. Кстати, на схеме ниже я забыл указать его, подойдёт любой диод который рассчитан на напряжение от 10 В и ток от 200 мА, ставиться последовательно входу платы, или по минусу или по плюсу, у меня по минусу.
Динамик от старого Dial up модема Zyxel, кстати, про Dial up модемы этой фирмы есть один известный анекдот:
Анекдот
Сидят два хакера, и в комнату заходит кот. Один хакер спрашивает:
— Твой кот?
— Да, мой. Зухель зовут!
— Почему Зухель?
— Вот смотри. Берет веник, тычет им в кота и говорит: «Зухель, коннект!!!» Кот:
— Пшшшшшшшшшшшшшш!
— Твой кот?
— Да, мой. Зухель зовут!
— Почему Зухель?
— Вот смотри. Берет веник, тычет им в кота и говорит: «Зухель, коннект!!!» Кот:
— Пшшшшшшшшшшшшшш!
Код, скажу сразу, нагуглил, точней нашёл на просторах ютуба, вот собственно само видео:
Под видео есть ссылка на код, вот он:
Код из описания к видео
Размер скетча в двоичном коде: 946 байт (из 1 024 байт максимум)
#include <avr/pgmspace.h>
// by @tartakynov
// programmed for ATtiny13 in Arduino IDE using core13 http://sourceforge.net/projects/ard-core13/
#define PIN_LED 1
#define PIN_BUZZER 0
#define COUNT_NOTES 39
word frequences[COUNT_NOTES] PROGMEM = {
392, 392, 392, 311, 466, 392, 311, 466, 392,
587, 587, 587, 622, 466, 369, 311, 466, 392,
784, 392, 392, 784, 739, 698, 659, 622, 659,
415, 554, 523, 493, 466, 440, 466,
311, 369, 311, 466, 392 };
word durations[COUNT_NOTES] PROGMEM = {
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 250, 100, 350, 250, 100, 100, 100, 200,
100, 350, 250, 100, 100, 100, 200,
100, 350, 250, 100, 750 };
void setup()
{
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
}
void loop()
{
for (byte i = 0; i < COUNT_NOTES; i++)
{
buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])), 2 * pgm_read_word(&(durations[i])));
delay(100);
}
delay(3000);
}
void buzz(unsigned char pin, word frequencyInHertz, word timeInMilliseconds)
{
long delayAmount = (long)(long(1000000) / (long)frequencyInHertz);
long loopTime = (long)(((long)timeInMilliseconds * 500) / delayAmount);
for (long i = 0; i < loopTime; i++)
{
digitalWrite(pin, HIGH);
delayMicroseconds(delayAmount);
digitalWrite(pin, LOW);
delayMicroseconds(delayAmount);
}
}
Размер скетча в двоичном коде: 946 байт (из 1 024 байт максимум)
Как Вы можете видеть, есть два массива frequences — в переводе из английского частота и durations — длительность, всё данные типа word, PROGMEM — данные хранятся во флеш-памяти микроконтроллера(без использования библиотеки pgmspace.h работать не будет) ну и есть генератор частоты buzz() который принимает три параметра — пин, на котором будет генерироваться частота, второй — частота в герцах, третий — длительность в миллисекундах.
Данный код должен быть Arduino совместимым и работать даже на Arduino Uno, Arduino Nano или же Arduino Pro Mini ну и и других дуинах.
Как Вы могли слышать на видео, звучание моего видео немного отличается от второго видео, дело в том, что я немного изменил длительность нот и в три раза популярным методом «научного тыка», поднял частоту, так как такой маленький динамик как у меня плохо воспроизводит те частоты что были изначально, и добавил кнопку, какой же дверной звонок без кнопки?
Немного подправил под себя и закомментировал
Размер скетча в двоичном коде: 976 байт (из 1 024 байт максимум)
// by @tartakynov:
// http://youtu.be/5R7NeQkVS_8
// and me - vk.com/razniepodelki
#define F_CPU 1200000L // Частота МК в герцах
#include <avr/pgmspace.h> // нужно для PROGMEM
#define PIN_BUZZER 2 // PB2 Динамик
#define BUTTON 4 // PB4 Кнопка
#define COUNT_NOTES 39 // количество нот
word frequences[COUNT_NOTES] PROGMEM = { // тут лежат частоты
392, 392, 392, 311, 466, 392, 311, 466, 392,
587, 587, 587, 622, 466, 369, 311, 466, 392,
784, 392, 392, 784, 739, 698, 659, 622, 659,
415, 554, 523, 493, 466, 440, 466,
311, 369, 311, 466, 392 };
word durations[COUNT_NOTES] PROGMEM = { // тут их длительность
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 250, 100, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 750 };
//void setup()
//{
int main( void ) // это аналог void setup(), для экономии места
{
pinMode(PIN_BUZZER, OUTPUT); // инициализация пинов
pinMode(BUTTON, INPUT); // подключаем подтягивающий резистор
digitalWrite(BUTTON, HIGH); // чтобы кнопка возвращала
//LOW при нажатии
//}
//void loop()
//{
while(1){ // аналог void loop()(вечный цикл)
if (digitalRead(BUTTON) == LOW) { // когда кнопка нажата
for (byte i = 0; i < COUNT_NOTES; i++) // собственно проигрываем мелодию
{
buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])) * 3, 2 * pgm_read_word(&(durations[i])));
// изначально было:
// buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])), 2 * pgm_read_word(&(durations[i])));
// но я умножил частоту на 3
//(pgm_read_word(&(frequences[i])) * 3)
//чтобы было громче слышно на небольшом динамике
//delay(100); // этого не нужно
}
}
//delay(3000); // и этого
} // эти строчки нужны
return 0; // int main( void )
} // и while(1)
void buzz(unsigned char pin, word frequencyInHertz, word timeInMilliseconds) // по сути это
{ // генератор частоты
long delayAmount = (long)(long(1000000) / (long)frequencyInHertz); // имеет 3 параметра
long loopTime = (long)(((long)timeInMilliseconds * 500) / delayAmount); // 1 - пин
for (long i = 0; i < loopTime; i++) // 2 - частота
{ // 3 - длительность
digitalWrite(pin, HIGH); // генерируем импульсы нужной частоты
delayMicroseconds(delayAmount);
digitalWrite(pin, LOW);
delayMicroseconds(delayAmount);
}
}
Размер скетча в двоичном коде: 976 байт (из 1 024 байт максимум)
Как видите, добавления срабатывания при нажатии на кнопку превысило 1024 байта и пришлось вставлять кусочки кода Си чтобы уместиться в attiny13.
Частоту поднял строках buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])) * 3, 2 * pgm_read_word(&(durations[i]))); тем самим умножив генерируемые частоты, как Вы поняли на три, это чисто мой каприз, можете ничего не умножать вообще.
Если Вы опытный ардуинщик, то думаю заметите в коде что я сделал программную подтяжку PULLUP резистора к порту PB4.
Для тех кто не знает делается это так:
Выставляем порт на вход и подаём на него логическую единицу. Теперь на порту будет напряжение, примерно равно напряжению питания, если этот порт закоротить на землю то он изменит своё состояние с логической единицы на логический ноль, причём микроконтроллер при этом не будет страдать, так как используется внутренний резистор, номинал которого 10-100 кОм.
Сделал я это чисто для экономии размеров платы, можно было просто подпаять резистор на 10 кОм к плюсу питанию и нужному порту, при нажатии на кнопку мы «притягиваем порт к земле» и на нём будет логической ноль.
Добавляю код на чистом AVR-С для тру AVR'щиков:
Код на AVR-С
// by @tartakynov:
// http://youtu.be/5R7NeQkVS_8
// and me - vk.com/razniepodelki
#define F_CPU 1200000UL // Частота МК в герцах
#include <avr/io.h> // библиотека ввода вывода
#include <util/delay.h> // библиотека для работы с задержками
#include <avr/pgmspace.h> // нужно для PROGMEM
#define PIN_BUZZER 2 // PB2 Динамик
#define BUTTON 4 // PB4 Кнопка
#define COUNT_NOTES 39 // количество нот
word frequences[COUNT_NOTES] PROGMEM = { // тут лежат частоты
392, 392, 392, 311, 466, 392, 311, 466, 392,
587, 587, 587, 622, 466, 369, 311, 466, 392,
784, 392, 392, 784, 739, 698, 659, 622, 659,
415, 554, 523, 493, 466, 440, 466,
311, 369, 311, 466, 392 };
word durations[COUNT_NOTES] PROGMEM = { // тут их длительность
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 250, 100, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 750 };
//void setup()
//{
int main( void ) // это аналог void setup(), для экономии места
{
DDRB |= (1<<PIN_BUZZER); // иницыализация портов
DDRB &= ~(1<<BUTTON); // подключаем подтягивающий резистор
PORTB |= (1<<BUTTON); // чтобы кнопка возвращала
//0 при нажатии(замыкинии)
//}
//void loop()
//{
while(1){ // аналог void loop()(вечный цикл)
if (!(PINB & (1<<BUTTON))) { // когда кнопка нажата
for (byte i = 0; i < COUNT_NOTES; i++) // собственно проигрываем мелодию
{
buzz(pgm_read_word(&(frequences[i])) * 3, 2 * pgm_read_word(&(durations[i])));
// изначально было:
// buzz(PIN_BUZZER, pgm_read_word(&(frequences[i])), 2 * pgm_read_word(&(durations[i])));
// но я умножил частоту на 3
//(pgm_read_word(&(frequences[i])) * 3)
//чтобы было громче слышно на небольшом динамике
}
//_delay_ms(100); // для отладки
}
//_delay_ms(3000); // для отладки
} // эти строчки нужны
return 0; // int main( void )
} // и while(1)
//void buzz(unsigned char pin, word frequencyInHertz, word timeInMilliseconds)
void buzz(word frequencyInHertz, word timeInMilliseconds) // по сути это
{ // генератор частоты
long delayAmount = (long)(long(1000000) / (long)frequencyInHertz); // имеет 3 параметра
long loopTime = (long)(((long)timeInMilliseconds * 500) / delayAmount); // 1 - пин
for (long i = 0; i < loopTime; i++) // 2 - частота
{ // 3 - длительность
//digitalWrite(pin, HIGH); // генерируем импульсы нужной частоты
PORTB |= (1<<PIN_BUZZER); // для экономии вставлю строчки на Си
//delayMicroseconds(delayAmount); // мкс задержка на ардуино
_delay_us(delayAmount); // на Си
//digitalWrite(pin, LOW);
PORTB &= ~(1<<PIN_BUZZER);
//delayMicroseconds(delayAmount); // мкс задержка на ардуино
_delay_us(delayAmount); // на Си
}
}
Вроде как должен компилироваться без проблем, а вот при использовании этого кода в Arduino IDE почему-то размер hex файла как минимум удваивается «Размер скетча в двоичном коде: 1 986 байт (из 1 024 байт максимум)».
Как мне удалось выяснить всё это из за использования _delay_us(*); хотя ардуиновская функция delayMicroseconds(*); по сути делает то же самое, думаю это недочёт файлов ядра для тини13, вот ветка на буржуйском форуме ардуино откуда я и взял файлы ядра, правда самую малость доработал под себя, ссылка на доработанные мною файлы ядра есть в статье про прошивку Attiny13 при помощи Arduino.
Если кто-то поможет разобраться с этим багом буду только рад, ведь чисто теоретически Arduino IDE должна без проблем проглатывать С-шний код.
Ну и пару слов по прошивке — на первом видео запускал тиньку на частоте 1.2 мГц, как по мне, так 1.2 миллиона операций вполне достаточно чтобы играть любимую мелодию и при этом кушать совсем не много, кстати hex-файл скомпилирован именно под эту частоту.
Вот фьюзы из калькулятора фьюзов:
Скрытый текст
Теперь, каждый кто имеет AVR программатор сможет повторить это устройство.
Как было обещано в начале статьи вот все нужные файлы.
Все мои публикации.
И напоследок — «Да прибудет с Вами сила».
UPD 05.01.2015
Хаброюзер SparF сделал то, что я ленился сделать всё это время, а именно довести до ума энергопотребление и сделать проигрывание при нажатии на кнопку PB1.
Теперь после проигрывания мелодии МК не «молотит» дальше в ожидании нажатия кнопки а засыпает и при каждом нажатии на кнопку он просыпается, проигрывает любимый нами Имперский марш и засыпает дальше, потребляя при этом практически ничего, батареек хватит на десяток лет в таком режиме потребления.
Схема выглядит вот так:
Вот код:
/*
Attiny13 Star Wars melody
*/
#define F_CPU 1200000UL
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define COUNT_NOTES 39
//частоты ноты
const uint16_t frequences[COUNT_NOTES] PROGMEM = {
392, 392, 392, 311, 466, 392, 311, 466, 392,
587, 587, 587, 622, 466, 369, 311, 466, 392,
784, 392, 392, 784, 739, 698, 659, 622, 659,
415, 554, 523, 493, 466, 440, 466,
311, 369, 311, 466, 392 };
//длительность нот
const uint16_t durations[COUNT_NOTES] PROGMEM = {
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 350, 350, 250, 100, 350, 250, 100, 700,
350, 250, 100, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 100, 100, 450,
150, 350, 250, 100, 750 };
int main( void )
{
/*
вход от кнопки (фиксирован) = PB1 , т.к. от этого порта
срабатывает прерывание INT0 - единственное внешнее прерывание,
которое может пробудить контроллер из режима максимального
энергосбережения Power-down
выход на пищалку (фиксирован) = PB0, т.к. таймер может управлять
только пинами PB0 и PB1, последний из которых уже занят кнопкой
*/
DDRB = (1 << DDB0); //переключить PB0 на выход
/*
по-хорошему, даже от вывода мелодии по прерыванию INT0 можно отказаться,
если подключить кнопку на RESET: после сброса контроллер будет выполнять инициализацию,
затем тут же проигрывать мелодию и ...уходить в режим максимального
энергосбережения до следующего сброса
*/
PORTB = (1 << PORTB1); //включить подтяжку на PB1
GIMSK = (1 << INT0); //разрешить прерывание INT0 (PB1)
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //настроить энергосберегающий режим Power-down
sei(); //включить прерывания
while(1)
sleep_mode(); //войти в режим энергосбережения
}
// вывод мелодии
static inline void doSound(void)
{
//включить и настроить таймер
TCCR0A = (1 << COM0A0) | (1 << WGM01); //Toggle OC0A (PB0) on Compare Match ; mode = CTC
TCCR0B = (1 << CS01) | (1 << CS00); //Clock Select = F_CPU/64
//поочередно проигрываем ноты
for (uint8_t i = 0; i < COUNT_NOTES; i++)
{
//получить данные из памяти
int16_t freq = pgm_read_word(&(frequences[i]));
int16_t dur = pgm_read_word(&(durations[i]));
//увеличиваем длительность в 1.5 раза
dur *= 3;
dur /= 2;
//задаем частоту на выходе PB0
OCR0A = (F_CPU / (2UL * 64UL * freq)) - 1;
//ожидаем, пока играет нота
while (dur > 0)
{
_delay_ms(10);
dur -= 10;
}
}
//отключить таймер
TCCR0A = 0;
TCCR0B = 0;
}
// обработчик прерывания INT0
ISR(INT0_vect)
{
doSound();
}
Код без проблем компилируется в Arduino IDE.
Файлы.
Проверил, всё работает: