Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
/*
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();
}
Музыкальный дверной звонок в стиле Star Wars на Arduino