Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проигрывание мелодии на ATmega32
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Sergey529
Имеется готовый проект для проигрывания мелодий из списка. Написан в WinAvr под ATMega8535. Для формирования различных длительностей и интервалов используется таймер-счетчик 2. Скомпилировал под ATMega32 - все отлично работает. Переделал под Т/С0 - тоже работает. Начал переделывать под ATtiny2313 c использованием Т/С0 - не работает.. Точнее мелодии звучат в несколько раз медленнее, и ниже тональностью. Частота тактирования МК - 8МГц. Ссылка на исходник проекта http://chipenable.ru/files/course/sound-li...dAvr-WINAVR.rar . Очень прошу помочь..
Мой код:
Код
#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<<TOIE0);  
  TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(0<<WGM01)|(0<<WGM00);  //режим - нормал, прескалер -
  TCCR0B = (0<<FOC0A)|(0<<WGM02)|(0<<CS02)|(0<<CS01)|(1<<CS00);
  TCNT0 = 0;    
  OCR0A = 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<<OCIE0A);
      PORT_SOUND &= ~(1<<PINX_SOUND);
      break;
      
   /*команда воспроизведение*/
    case SOUND_PLAY:
      if (state == SOUND_PAUSE){
        state = SOUND_PLAY;          
        TIMSK |= (1<<OCIE0A);
      }
      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<<OCIE0A);        
      }
      break;  
      
      /*команда пауза*/
      case SOUND_PAUSE:
        state = SOUND_PAUSE;  
        TIMSK &= ~(1<<OCIE0A);
      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<<OCIE0A);      
}




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<<OCF0A);
      }
      else{
        if (repeat == LOOP){
          indexNote = SOUND_START_SONG;
          durationNote = 0;
          return;
        }
        repeat--;
        if (!repeat){
          state = SOUND_STOP;
          TIMSK &= ~(1<<OCIE0A);
          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 {
    OCR0A = tone;
    statReg |= (1<<SOUND_GEN);
  }
}

//прерывания таймера Т2_____________________________________
ISR(TIMER0_OVF_vect)
{
  SOUND_Duration();
  BUT_Debrief();
}


ISR(TIMER0_COMPA_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     8U //тактовая частота мк
#define SOUND_TIM_PRE   1U  //зачение предделителя таймера

#include "tone.h"   //здесь определены частота и длительности нот

//пин мк на котором будет генериться звук
#define PORT_SOUND PORTD
#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
haker_fox
QUOTE (Sergey529 @ Feb 11 2012, 20:58) *
Точнее мелодии звучат в несколько раз медленнее, и ниже тональностью.

ИМХО на лицо проблема тактирования микроконтроллера... Тактовый генератор у Вас правильно настроен?
Sergey529
Цитата(haker_fox @ Feb 13 2012, 07:11) *
ИМХО на лицо проблема тактирования микроконтроллера... Тактовый генератор у Вас правильно настроен?
,
Вроде бы правильно - пробовал во фьюзах прошивать и RC-цепь 8 МГц, и внешний кварц 8 МГц. Реультат один и тот же. В Makefile указана частота - 8 МГц.. "Где собака порылась?" Сегодня вечером попробую осциллографом посмотреть, что там на ногах кварца. А в коде, в настройках таймера все в порядке?
Sergey529
Тему можно закрывать - контроллер с завода шел c установленным в 0 (enabled) фьюз-битом С - Divide Clock by 8 . Установил его в 1, стало все в порядке. Мелодии проигрываются правильно.
haker_fox
QUOTE (Sergey529 @ Feb 13 2012, 23:51) *
Тему можно закрывать - контроллер с завода шел c установленным в 0 (enabled) фьюз-битом С - Divide Clock by 8 . Установил его в 1, стало все в порядке. Мелодии проигрываются правильно.

Гм! А Вы фьюзы не проверяете перед прошивкой?

З.Ы. Тему можете самостоятельно закрыть. Внизу страницы есть опции модератора...
Sergey529
Проверяю. Просто был невнимателен, не посмотрел на "Div. clock by 8". Хотел еще задать вопрос. В вышеописанной программе хотелось бы из main обратиться к переменной STATE, находящейся в sound.c. Т.е. в main проверить то, что state стало равно SOUND_STOP.

Код
state = SOUND_STOP;
ARV
Цитата(Sergey529 @ Feb 27 2012, 19:39) *
В вышеописанной программе хотелось бы из main обратиться к переменной STATE, находящейся в sound.c. Т.е. в main проверить то, что state стало равно SOUND_STOP.
Код
state = SOUND_STOP;
убрать volatile static для state, в sound.h добавить extern unsigned char state; в главном модуле не забыть проинклюдить sound.h
Sergey529
ARV, огромное спасибо! Исправил свои ошибки, добавил ваши замечания. Все отлично получилось. Мне это нужно было для формирования задержки в 10 сек между мелодиями - т.е. по окончании проигрывания, запускается ТС1. В итоге закончил программную часть своего устройства - датчика намокания. При намокании датчика, устройство играет выбранную мелодию и мигает номер установленной мелодии на индикаторе (к проекту добавлен вывод номера мелодии на семисегментный индикатор и формирование паузы между мелодиями).
ipkentik
а вот у меня из этого примера - один сплошной звук идет. монотонный. как быть? куда смотреть?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.