Пт авг 25, 2023 10:00:14
//настройка таймера T2
TIMSK |= (1<<TOIE2);
TCCR2 = (0<<WGM01)|(0<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00); //режим - нормал, прескалер -
TCNT2 = 0;
OCR2 = 0;
#include "sound.h"
#define LOOP 0xff
PROGMEM unsigned int FurElise[] =
{
18, 1,
n8,e2, n8,xd2, n8,e2, n8,xd2, n8,e2, n8,b1, n8,d2, n8,c2, n4,a1, n8,p,
n8,c1, n8,e1, n8,a1, n4,b1, n8,p, n8,e1, n8,xg1, n8,b1, n4,c2, n8,p, n8,e1,
n8,e2, n8,xd2, n8,e2, n8,xd2, n8,e2, n8,b1, n8,d2, n8,c2, n4,a1, n8,p, n8,c1,
n8,e1, n8,a1, n4,b1, n8,p, n8,e1, n8,c2, n8,b1, n4,a1,
0
};
PROGMEM unsigned int Mozart[] =
{
16, 1,
n16, xf1, n16, e1, n16,xd1, n16,e1, n4,g1, n16,a1, n16,g1, n16,xf1, n16,g1,
n4,b1, n16,c2, n16,b1, n16,xa1, n16,b1, n16,xf2, n16,e2, n16,xd2, n16,e2,
n16,xf2, n16,e2, n16,xd2, n16,e2, n4,g2, n8,e2, n8,g2, n32,d2, n32,e2,
n16,xf2, n8,e2, n8,d2, n8,e2, n32,d2, n32,e2, n16,xf2, n8,e2, n8,d2, n8,e2,
n32,d2, n32,e2, n16,xf2, n8,e2, n8,d2, n8,xc2, n4,b1,
0
};
PROGMEM unsigned int Minuet[] =
{
18, 1,
n4,d2, n8,g1, n8,a1, n8,b1, n8,c2, n4,d2, n4,g1, n4,g1, n4,e2, n8,c2,
n8,d2, n8,e2, n8,xf2, n4,g2, n4,g1, n4,g1, n4,c2, n8,d2, n8,c2, n8,b1,
n8,a1, n4,b1, n8,c2, n8,b1, n8,a1, n8,g1, n4,xf1, n8,g1, n8,a1, n8,b1,
n8,g1, n4,b1, n2,a1,
0
};
PROGMEM unsigned int Sirene2[] =
{
1, LOOP,
ms(500), c2, ms(500), g2,
0
};
//---------- модуль----------------------------------
//указатели на регистры порта
#define PIN_SOUND (*(&PORT_SOUND-2))
#define DDR_SOUND (*(&PORT_SOUND-1))
//заглушка - пустая мелодия
PROGMEM unsigned int Empty[] =
{
1, 1,
n4, p,
0
};
PROGMEM unsigned int PROGMEM* melody[] = {Empty, FurElise, Mozart, Minuet, Sirene2};
//переменные звукового модуля
volatile static unsigned int *pSong;
volatile static unsigned char state = SOUND_STOP;
volatile static unsigned int durationNote = 0;
volatile static unsigned int toneNote = 0;
volatile static unsigned char indexNote = 0;
volatile static unsigned char statReg = 0;
volatile static unsigned char repeat = 0;
#ifndef SOUND_BPM
static unsigned char bpm = 0;
#endif
//флаги
#define SOUND_VOLUME 0
#define SOUND_GEN 1
#define SOUND_BPM_SONG 0
#define SOUND_REPEAT_SONG 1
#define SOUND_START_SONG 2
#define SOUND_COUNTER_CAP 256
#define SOUND_PROG_COUNTER 31
//инициализация звукового модуля
void SOUND_Init(void)
{
//настройка вывода мк на выход
PORT_SOUND &= ~(1<<PINX_SOUND);
DDR_SOUND |= (1<<PINX_SOUND);
//настройка таймера T2
TIMSK |= (1<<TOIE2);
TCCR2 = (0<<WGM01)|(0<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00); //режим - нормал, прескалер -
TCNT2 = 0;
OCR2 = 0;
//инициализация переменных
pSong = (unsigned int *)pgm_read_word(&(Empty));
state = SOUND_STOP;
durationNote = 0;
toneNote = 0;
repeat = 0;
indexNote = 0;
statReg = 0;
#ifndef SOUND_BPM
bpm = 0;
#endif
}
void SOUND_SetSong(unsigned char numSong)
{
if (numSong <= SOUND_AMOUNT_MELODY) {
pSong = (unsigned int *)pgm_read_word(&(melody[numSong]));
}
}
//обработчик команд звукового модуля
void SOUND_Com(unsigned char com)
{
unsigned char saveSreg = SREG;
cli();
switch (com){
/*команда стоп:*/
case SOUND_STOP:
state = SOUND_STOP;
TIMSK &= ~(1<<OCIE2);
PORT_SOUND &= ~(1<<PINX_SOUND);
break;
/*команда воспроизведение*/
case SOUND_PLAY:
if (state == SOUND_PAUSE){
state = SOUND_PLAY;
TIMSK |= (1<<OCIE2);
}
else {
#ifndef SOUND_BPM
bpm = pgm_read_word(&(pSong[SOUND_BPM_SONG]));
#endif
indexNote = SOUND_START_SONG;
repeat = pgm_read_word(&(pSong[SOUND_REPEAT_SONG]));
durationNote = 0;
state = SOUND_PLAY;
TIMSK |= (1<<OCIE2);
}
break;
/*команда пауза*/
case SOUND_PAUSE:
state = SOUND_PAUSE;
TIMSK &= ~(1<<OCIE2);
break;
default:
break;
}
SREG = saveSreg;
}
//проиграть мелодию под номером numSong
void SOUND_PlaySong(unsigned char numSong)
{
if (numSong <= SOUND_AMOUNT_MELODY) {
pSong = (unsigned int *)pgm_read_word(&(melody[numSong]));
}
#ifndef SOUND_BPM
bpm = pgm_read_word(&(pSong[SOUND_BPM_SONG]));
#endif
indexNote = SOUND_START_SONG;
repeat = pgm_read_word(&(pSong[SOUND_REPEAT_SONG]));
durationNote = 0;
state = SOUND_PLAY;
TIMSK |= (1<<OCIE2);
}
inline static void SOUND_Duration(void)
{
static unsigned char counter = 0;
if (state == SOUND_PLAY){
if (durationNote){
counter++;
counter &= SOUND_PROG_COUNTER;
if (!counter){
durationNote--;
}
}
else {
durationNote = pgm_read_word(&(pSong[indexNote]));
if (durationNote) {
#ifndef SOUND_BPM
durationNote = durationNote/bpm;
#endif
indexNote++;
toneNote = pgm_read_word(&(pSong[indexNote]));
if (toneNote!=P) {
statReg |= (1<<SOUND_VOLUME);
}
else{
statReg &= ~(1<<SOUND_VOLUME);
}
indexNote++;
TIFR |=(1<<OCF2); //вот здесь сомнения
}
else{
if (repeat == LOOP){
indexNote = SOUND_START_SONG;
durationNote = 0;
return;
}
repeat--;
if (!repeat){
state = SOUND_STOP;
TIMSK &= ~(1<<OCIE2);
PORT_SOUND &= ~(1<<PINX_SOUND);
return;
}
else{
indexNote = SOUND_START_SONG;
durationNote = 0;
}
}
}
}
}
inline static void SOUND_Tone(void)
{
static unsigned int tone = 0;
if (statReg & (1<<SOUND_GEN)){
if (statReg & (1<<SOUND_VOLUME)){
PORT_SOUND ^= (1<<PINX_SOUND);
}
tone = toneNote;
statReg &= ~(1<<SOUND_GEN);
}
if (tone > SOUND_COUNTER_CAP) {
tone -= SOUND_COUNTER_CAP;
}
else {
OCR2 = tone;
statReg |= (1<<SOUND_GEN);
}
}
//прерывания таймера Т2_____________________________________
ISR(TIMER2_OVF_vect)
{
SOUND_Duration();
BUT_Debrief();
}
ISR(TIMER2_COMP_vect)
{
SOUND_Tone();
}
#ifndef SOUND_H
#define SOUND_H
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "buttons.h"
//*************************** настройки *************************************
#define SOUND_BPM 24 //если закомментировать длительность нот будет
//расчитываться из заданного в мелодии BPM`а
#define SOUND_F_CPU 16U //тактовая частота мк
#define SOUND_TIM_PRE 1U //зачение предделителя таймера
#include "tone.h" //здесь определены частота и длительности нот
//пин мк на котором будет генериться звук
#define PORT_SOUND PORTB
#define PINX_SOUND 0
//количество мелодий
#define SOUND_AMOUNT_MELODY 4
//***************************************************************************
//команды звукового модуля
#define SOUND_STOP 0
#define SOUND_PLAY 1
#define SOUND_PAUSE 2
//функции звукового модуля
void SOUND_Init(void);
void SOUND_SetSong(unsigned char numSong);
void SOUND_Com(unsigned char com);
void SOUND_PlaySong(unsigned char numSong);
#endif //SOUND_H
/*****************************************************************************
*
* Tone definition. Each tone are set up with a value which will give the
* right frequency when applied to a 16-bits timer with PWM. These values are based
* on a CLKcpu running @ 1Mhz.
*
* First find the frequency for all tones.
*
* Formula: ToneX = Bf * 2^(ToneX/12)
*
* ToneX: the actual tone, e.g. C0 = 3
* Bf: Basefrequency = 220Hz (A)
*
*
* E.g: For tone C0 this would be: C0 = 220 * 2^(3/12)
* C0 = 261,6256...
*
* Now we must find which value to put in a 16-bits timer with PWM to achieve
* this frequency
*
* Formula: Timer value = 1Mhz / ToneHz / 2
*
* E.g: For tone C0 this would be: Timer value = 1000000 / 261,6256... / 2
* Timer value = 1911
*
* Set up a 16-bits timer to run at Phase/Freq-correct PWM, top value = ICR1,
* set OC1A when upcounting, clear when downcounting.
*
*****************************************************************************/
#define f(x) (SOUND_F_CPU*1000000UL/(x*2*SOUND_TIM_PRE))
#define fn(x) ((x*SOUND_F_CPU)/SOUND_TIM_PRE)
#ifdef SOUND_BPM
#define COEF SOUND_BPM
#else
#define COEF 1
#endif
#define dn(x) ((24U*SOUND_F_CPU*1000000UL)/(x*SOUND_TIM_PRE*256UL*32UL)/COEF)
#define ms(x) (((x)*SOUND_F_CPU*1000UL)/(SOUND_TIM_PRE*256UL*32UL))
#define n1 dn(1) //целая нота
#define n2 dn(2) //половинная нота
#define n4 dn(4) //четверть
#define n8 dn(8) //восьмая
#define n3 dn(12) //восьмая триоль
#define n16 dn(16) //шестнадцатая
#define n6 dn(12) //секстоль
#define n32 dn(32) //тридцать вторая
#define A fn(2273) // tone 0
#define xA fn(2145) // tone 1
#define Ax fn(2145) // tone 1
#define B fn(2025) // tone 2
#define C0 fn(1911) // tone 3
#define xC0 fn(1804) // ...
#define Cx0 fn(1804)
#define D0 fn(1703)
#define xD0 fn(1607)
#define Dx0 fn(1607)
#define E0 fn(1517)
#define F0 fn(1432)
#define xF0 fn(1351)
#define Fx0 fn(1351)
#define G0 fn(1275)
#define xG0 fn(1204)
#define Gx0 fn(1204)
#define A0 fn(1136)
#define xA0 fn(1073)
#define Ax0 fn(1073)
#define B0 fn(1012)
#define C1 fn(956)
#define xC1 fn(902)
#define Cx1 fn(902)
#define D1 fn(851)
#define xD1 fn(804)
#define Dx1 fn(804)
#define E1 fn(758)
#define F1 fn(716)
#define xF1 fn(676)
#define Fx1 fn(676)
#define G1 fn(638)
#define xG1 fn(602)
#define Gx1 fn(602)
#define A1 fn(568)
#define xA1 fn(536)
#define Ax1 fn(536)
#define B1 fn(506)
#define C2 fn(478)
#define xC2 fn(451)
#define Cx2 fn(451)
#define D2 fn(426)
#define xD2 fn(402)
#define Dx2 fn(402)
#define E2 fn(379)
#define F2 fn(356)
#define xF2 fn(338)
#define Fx2 fn(338)
#define G2 fn(319)
#define xG2 fn(301)
#define Gx2 fn(301)
#define A2 fn(284)
#define xA2 fn(268)
#define Ax2 fn(268)
#define B2 fn(253)
#define C3 fn(239)
#define xC3 fn(225)
#define Cx3 fn(225)
#define D3 fn(213)
#define xD3 fn(201)
#define Dx3 fn(201)
#define E3 fn(190)
#define F3 fn(179)
#define xF3 fn(169)
#define Fx3 fn(169)
#define G3 fn(159)
#define xG3 fn(150)
#define Gx3 fn(150)
#define A3 fn(142)
#define xA3 fn(134)
#define Ax3 fn(134)
#define B3 fn(127)
#define C4 fn(119)
#define P 1 // pause
/******************************************************************************
*
* The tone definitions are duplicated to accept both upper and lower case
*
******************************************************************************/
#define a fn(2273) // tone 0
#define xa fn(2145) // tone 1
#define ax fn(2145) // tone 1
#define b fn(2024) // tone 2
#define c0 fn(1911) // tone 3
#define xc0 fn(1804) // ...
#define cx0 fn(1804)
#define d0 fn(1703)
#define xd0 fn(1607)
#define dx0 fn(1607)
#define e0 fn(1517)
#define f0 fn(1432)
#define xf0 fn(1351)
#define fx0 fn(1351)
#define g0 fn(1275)
#define xg0 fn(1204)
#define gx0 fn(1204)
#define a0 fn(1136)
#define xa0 fn(1073)
#define ax0 fn(1073)
#define b0 fn(1012)
#define c1 fn(956)
#define xc1 fn(902)
#define cx1 fn(902)
#define d1 fn(851)
#define xd1 fn(804)
#define dx1 fn(804)
#define e1 fn(758)
#define f1 fn(716)
#define xf1 fn(676)
#define fx1 fn(676)
#define g1 fn(638)
#define xg1 fn(602)
#define gx1 fn(602)
#define a1 fn(568)
#define xa1 fn(536)
#define ax1 fn(536)
#define b1 fn(506)
#define c2 fn(478)
#define xc2 fn(451)
#define cx2 fn(451)
#define d2 fn(426)
#define xd2 fn(402)
#define dx2 fn(402)
#define e2 fn(379)
#define f2 fn(356)
#define xf2 fn(338)
#define fx2 fn(338)
#define g2 fn(319)
#define xg2 fn(301)
#define gx2 fn(301)
#define a2 fn(284)
#define xa2 fn(268)
#define ax2 fn(268)
#define b2 fn(253)
#define c3 fn(239)
#define xc3 fn(225)
#define cx3 fn(225)
#define d3 fn(213)
#define xd3 fn(201)
#define dx3 fn(201)
#define e3 fn(190)
#define f3 fn(179)
#define xf3 fn(169)
#define fx3 fn(169)
#define g3 fn(159)
#define xg3 fn(150)
#define gx3 fn(150)
#define a3 fn(142)
#define xa3 fn(134)
#define ax3 fn(134)
#define b3 fn(127)
#define c4 fn(119)
#define p 1
#include "sound.h"
#define LOOP 0xff
const PROGMEM unsigned int FurElise[] =
{
18, 1,
n8,e2e, n8,xd2, n8,e2e, n8,xd2, n8,e2e, n8,b1, n8,d2, n8,c2, n4,a1, n8,p,
n8,c1, n8,e1e, n8,a1, n4,b1, n8,p, n8,e1e, n8,xg1, n8,b1, n4,c2, n8,p, n8,e1e,
n8,e2e, n8,xd2, n8,e2e, n8,xd2, n8,e2e, n8,b1, n8,d2, n8,c2, n4,a1, n8,p, n8,c1,
n8,e1e, n8,a1, n4,b1, n8,p, n8,e1e, n8,c2, n8,b1, n4,a1,
0
};
const PROGMEM unsigned int Mozart[] =
{
16, 1,
n16, xf1, n16, e1e, n16,xd1, n16, e1e, n4,g1, n16,a1, n16,g1, n16,xf1, n16,g1,
n4,b1, n16,c2, n16,b1, n16,xa1, n16,b1, n16,xf2, n16,e2e, n16,xd2, n16,e2e,
n16,xf2, n16,e2e, n16,xd2, n16,e2e, n4,g2, n8,e2e, n8,g2, n32,d2, n32,e2e,
n16,xf2, n8,e2e, n8,d2, n8,e2e, n32,d2, n32,e2e, n16,xf2, n8,e2e, n8,d2, n8,e2e,
n32,d2, n32,e2e, n16,xf2, n8,e2e, n8,d2, n8,xc2, n4,b1,
0
};
const PROGMEM unsigned int Minuet[] =
{
18, 1,
n4,d2, n8,g1, n8,a1, n8,b1, n8,c2, n4,d2, n4,g1, n4,g1, n4,e2e, n8,c2,
n8,d2, n8,e2e, n8,xf2, n4,g2, n4,g1, n4,g1, n4,c2, n8,d2, n8,c2, n8,b1,
n8,a1, n4,b1, n8,c2, n8,b1, n8,a1, n8,g1, n4,xf1, n8,g1, n8,a1, n8,b1,
n8,g1, n4,b1, n2,a1,
0
};
const PROGMEM unsigned int Sirene2[] =
{
1, LOOP,
ms(500), c2, ms(500), g2,
0
};
//---------- модуль----------------------------------
//указатели на регистры порта
#define PIN_SOUND (*(&PORT_SOUND-2))
#define DDR_SOUND (*(&PORT_SOUND-1))
//заглушка - пустая мелодия
const PROGMEM unsigned int Empty[] =
{
1, 1,
n4, p,
0
};
const unsigned int* const melody[] = {Empty, FurElise, Mozart, Minuet, Sirene2};
//переменные звукового модуля
volatile static unsigned int *pSong;
volatile static unsigned char state = SOUND_STOP;
volatile static unsigned int durationNote = 0;
volatile static unsigned int toneNote = 0;
volatile static unsigned char indexNote = 0;
volatile static unsigned char statReg = 0;
volatile static unsigned char repeat = 0;
#ifndef SOUND_BPM
static unsigned char bpm = 0;
#endif
//флаги
#define SOUND_VOLUME 0
#define SOUND_GEN 1
#define SOUND_BPM_SONG 0
#define SOUND_REPEAT_SONG 1
#define SOUND_START_SONG 2
#define SOUND_COUNTER_CAP 256
#define SOUND_PROG_COUNTER 31
//инициализация звукового модуля
void SOUND_Init(void)
{
//настройка вывода мк на выход
PORT_SOUND &= ~(1<<PINX_SOUND);
DDR_SOUND |= (1<<PINX_SOUND);
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 16000,000 kHz
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
// Timer Period: 0,016 ms
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20);
TCCR2B=(0<<WGM22) | (0<<CS22) | (0<<CS21) | (1<<CS20);
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=(1<<TOIE2);
//инициализация переменных
pSong = (unsigned int *)pgm_read_word(&(Empty));
state = SOUND_STOP;
durationNote = 0;
toneNote = 0;
repeat = 0;
indexNote = 0;
statReg = 0;
#ifndef SOUND_BPM
bpm = 0;
#endif
}
void SOUND_SetSong(unsigned char numSong)
{
if (numSong <= SOUND_AMOUNT_MELODY) {
pSong = (unsigned int *)pgm_read_word(&(melody[numSong]));
}
}
//обработчик команд звукового модуля
void SOUND_Com(unsigned char com)
{
unsigned char saveSreg = SREG;
cli();
switch (com){
/*команда стоп:*/
case SOUND_STOP:
state = SOUND_STOP;
TIMSK2 &= ~(1<<OCIE2A);
PORT_SOUND &= ~(1<<PINX_SOUND);
break;
/*команда воспроизведение*/
case SOUND_PLAY:
if (state == SOUND_PAUSE){
state = SOUND_PLAY;
TIMSK2 |= (1<<OCIE2A);
}
else {
#ifndef SOUND_BPM
bpm = pgm_read_word(&(pSong[SOUND_BPM_SONG]));
#endif
indexNote = SOUND_START_SONG;
repeat = pgm_read_word(&(pSong[SOUND_REPEAT_SONG]));
durationNote = 0;
state = SOUND_PLAY;
TIMSK2 |= (1<<OCIE2A);
}
break;
/*команда пауза*/
case SOUND_PAUSE:
state = SOUND_PAUSE;
TIMSK2 &= ~(1<<OCIE2A);
break;
default:
break;
}
SREG = saveSreg;
}
//проиграть мелодию под номером numSong
void SOUND_PlaySong(unsigned char numSong)
{
if (numSong <= SOUND_AMOUNT_MELODY) {
pSong = (unsigned int *)pgm_read_word(&(melody[numSong]));
}
#ifndef SOUND_BPM
bpm = pgm_read_word(&(pSong[SOUND_BPM_SONG]));
#endif
indexNote = SOUND_START_SONG;
repeat = pgm_read_word(&(pSong[SOUND_REPEAT_SONG]));
durationNote = 0;
state = SOUND_PLAY;
TIMSK2 |= (1<<OCIE2A);
}
inline static void SOUND_Duration(void)
{
static unsigned char counter = 0;
if (state == SOUND_PLAY){
if (durationNote){
counter++;
counter &= SOUND_PROG_COUNTER;
if (!counter){
durationNote--;
}
}
else {
durationNote = pgm_read_word(&(pSong[indexNote]));
if (durationNote) {
#ifndef SOUND_BPM
durationNote = durationNote/bpm;
#endif
indexNote++;
toneNote = pgm_read_word(&(pSong[indexNote]));
if (toneNote!=P) {
statReg |= (1<<SOUND_VOLUME);
}
else{
statReg &= ~(1<<SOUND_VOLUME);
}
indexNote++;
TIFR2 |=(1<<OCF2A); //вот здесь сомнения
}
else{
if (repeat == LOOP){
indexNote = SOUND_START_SONG;
durationNote = 0;
return;
}
repeat--;
if (!repeat){
state = SOUND_STOP;
TIMSK2 &= ~(1<<OCIE2A);
PORT_SOUND &= ~(1<<PINX_SOUND);
return;
}
else{
indexNote = SOUND_START_SONG;
durationNote = 0;
}
}
}
}
}
inline static void SOUND_Tone(void)
{
static unsigned int tone = 0;
if (statReg & (1<<SOUND_GEN)){
if (statReg & (1<<SOUND_VOLUME)){
PORT_SOUND ^= (1<<PINX_SOUND);
}
tone = toneNote;
statReg &= ~(1<<SOUND_GEN);
}
if (tone > SOUND_COUNTER_CAP) {
tone -= SOUND_COUNTER_CAP;
}
else {
OCR2A = tone;
statReg |= (1<<SOUND_GEN);
}
}
//прерывания таймера Т2
ISR(TIMER2_OVF_vect)
{
SOUND_Duration();
}
ISR(TIMER2_COMPA_vect)
{
SOUND_Tone();
}
Пт авг 25, 2023 10:58:37
Пт авг 25, 2023 13:25:49
Пт авг 25, 2023 15:17:16
Пт авг 25, 2023 15:58:56
OKF писал(а):Ну не красиво, конечно. Ошибся. Автору повезло в том, что в 8535 TCCR0 и TCCR2 совпадают по битам.
Пт авг 25, 2023 17:09:53