Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

Продолжение урока затянулось, оно и понятно, пришлось освоить работу с картами памяти и файловой системой FAT. Но все таки, оно свершилось, урок готов — фактически новогоднее чудо.
petushokLogo

Дабы не перегружать статью информацией, я не буду описывать структуру формата wav файла, информации в поисковиках более чем предостаточно. Достаточно сказать, что если открыть файл, каким либо Hex редактором, то в первых 44 байтах содержится вся информация о типе файла, частоте дискретизации, количестве каналов и пр. Если нужно анализировать файл, читайте этот заголовок и будет вам счастье.

wav_format

Полезные данные начинаются с 44 байта, по сути они содержат уровни напряжений, из которых формируется звук. Мы уже говорили про ступени напряжения, в прошлой части урока. Таким образом, все просто, нужно эти ступеньки вывести на динамик с частотой дискретизации файла.

Как физически заставить динамик дрыгаться? Нужно выводить эти уровни напряжения, при помощи ШИМ, либо использовать R2R. В любом случае, использовать очень просто, прочитал число, засунул его либо в OCR, либо в PORTx. Далее через определенное время, подставил следующее значение и так до конца файла.

Пример, некий wav файл, данные идут с 44=0х2С байта, там записано число 0х80, воспроизводим звук например ШИМом первого таймера, пишем OCR1A=0х80; Допустим, частота дискретизации вавки 8кГц, соответственно прерывание должно быть настроено на эту же частоту. В прерывании, подставляем следующее значение 0x85 через 1/8000=125мкс.
wav_format2

Как настроить прерывание на 8кГц? Вспоминаем, если таймер работает на частоте 250кГц, то регистр сравнения прерывания нужно подставить (250/8)-1=31-1 или 0x1E. С ШИМом тоже все просто, чем выше частота на которой он работает тем лучше.

Чтобы прошивка работала, условимся, что флешка отформатирована в FAT32, используется либа PetitFat из урока 23.2. Файл в формате wav либо 8кГц, либо 22,050кГц, моно. Название файла 1.wav. Анализируем прошивку.

#include <mega8.h>
#include "diskio.h"
#include "pff.h"
 
unsigned char buffer[512];   /* буфер в который копируется инфа с флешки */
volatile unsigned int count; //счетчик скопированных данных
 
interrupt [TIM2_COMP] void timer2_comp_isr(void) //прерывание в котором подставляются значения
{
    OCR1A = buffer[count]; //выводим звук на динамик
	if (++count >= 512) //увеличиваем счетчик
		count = 0;  //если 512 обнуляем 
}
 
void main(void)
{    
    unsigned int br;         /* счетчик чтения/записи файла */      
    unsigned char buf = 0;   //переменная определяющая какая часть буфера читается
    FATFS fs;         /* Рабочая область (file system object) для логических дисков */
 
PORTB=0x00;
DDRB=0x02;  //дрыгаем шимом ocr1a
 
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Fast PWM top=0x00FF
// OC1A output: Non-Inv.
TCCR1A=0x81;
TCCR1B=0x09;
TCNT1=0x00;
OCR1A=0x00;
 
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 250,000 kHz
// Mode: CTC top=OCR2
TCCR2=0x0B;
TCNT2=0x00;
//OCR2=0x1E; //настройка регистра сравнения для 8кГц
OCR2=0xA;    //для 22кГц
 
#asm("sei")
// Timer(s)/Counter(s) Interrupt(s) initialization
 
 
if(disk_initialize()==0) //инициализируем флешку
{
  pf_mount(&fs);  //монтируем файловую систему      
  pf_open("1.wav");  //открываем вавку 
  pf_lseek(44);     //перемещаем указатель на 44  
  pf_read(buffer, 512,&br); //в первый раз заглатываем сразу 512байт
  TIMSK=0x80; //врубаем музон
  while(1) 
  {
     if(!buf && count>255) //если воспроизвелось больше 255 байт,  
     {                     
        pf_read(&buffer[0], 256,&br);//то читаем в первую половину буфера инфу с флешки
        buf=1; 
        if (br < 256) //если буфер не содержит 256 значений значит конец файла
	break;
     }  
     if(buf && count<256)
     {
        pf_read(&buffer[256], 256,&br); // читаем во вторую часть буфера с флешки
        buf = 0; 
        if (br < 256)
	break;
     }
 
  }
  TIMSK = 0x00; //глушим все
  pf_mount(0x00); //демонтируем фат
}
 
while (1)
      {
 
 
      }
}

Для проверки, на ножку OCR1A подключаем динамик через конденсатор 100мкФ, «+» на ножку микроконтроллера, «-» на динамик. «-» динамика на землю, «+» на конденсатор.
sch_sdfat2

Не ждите громкого сигнала на выходе, чтобы звучало громко, необходим усилитель. На видео это хорошо видно. Для теста залил петуха 8кГц и трек 22кГц.

Желающие могут смело увеличить частоту таймера2, чтобы проигрывать файлы 44кГц, опыты показывают, что можно добиться вполне неплохого качества звучания. На видео звук слабый и качество плохое, но на самом деле это из-за того, что снимал на фотоаппарат.

Также выкладываю материалы любезно предоставленные Аппаратчиком — исходник для GCC, с которого была написана прошивка под CAVR.

И видео с воспроизведением 44кГц.

Пользуясь случаем поздравляю Всех с Наступающим, желаю чтобы все прошивки и девайсы у вас работали 🙂

Проект wav плеера на Atmega8

115 комментариев: Урок 22.2 Воспроизведение wav. Продолжение.

  • С резистором я сам знаю 😛 а вот как организовать регулировку с контроллера?

  • каждая точка это амплитуда, если домножать все точки на коэффициент, то общая амплитуда будет изменяться

  • Подскажите, правильно я понимаю, что:
    1) Программирование программатором, использующим MISO и т.д. будет далее не доступно?

  • нет, в момент программирования контроллер находится в состоянии сброса, поэтому основная прога никак не повлияет

  • Для использования на Atmega32a нужно только порты поменять на соответствующие и библиотеку mega32?

  • и настройки spi

  • Скачал проект при компиляции выводит кучу Warning`ов. Это нормально или искать где ошибка?

  • нормально

  • Доброго времени суток!
    Очень понравился ваш проект! Я его решил перенести на arduino2560 и при компиляции всплывает ошибка
    invalid conversion from ‘unsigned int*’ to ‘WORD* {aka short unsigned int*}’ [-fpermissive]
    С чем это может быть связано? Все типы выставлены вроде правильно
    #include
    #include
    #include
    unsigned int buffer[512]; /* буфер в который копируется инфа с флешки */
    volatile unsigned int count; //счетчик скопированных данных
    extern unsigned int br;
    //volatile unsigned int tcnt2;
    void setup()
    { pinMode(53, OUTPUT);
    pinMode(51, OUTPUT);
    digitalWrite(53, LOW);
    digitalWrite(51, LOW);
    }
    //***************Настройка таймера-счётчика****************
    void Timer1_init()
    { TCCR1B |= ((1<<WGM12) | (1<<CS12));
    TIMSK1 |= (1<255) //если воспроизвелось больше 255 байт,
    { //pf_read(buffer[0], 256, br);//то читаем в первую половину буфера инфу с флешки
    buf=1;
    if (br < 256) break; //если буфер не содержит 256 значений значит конец файла
    }
    if(buf && count<256)
    { pf_read(&buffer[256], 256,&br); // читаем во вторую часть буфера с флешки
    buf = 0;
    if (br < 256) break;
    }

    }
    //TIMSK = 0x00; //глушим все
    pf_mount(0x00); //демонтируем фат
    }

    }
    }

  • читайте не unsigned int а unsigned char

  • Правильно ли я понимаю что ШИМ в данном примере работает на частоте 31250 Гц?
    Какую роль играет частота ШИМа, или важно только чтобы прерывание было настроено на частоту дискретизации файла?

  • чем быстрее шим, тем быстрее вы можете перейти от одного уровня напряжения к другому. если скорость будет не достаточная, то тупо напряжение не будет успевать меняться, вместо ожидаемого звука вы услышите совсем не то

  • Кстати о петухах, новый язык прогирования Petooh появился

  • А разве не нужно согласование уровней с SD картой? Или MCU от трех вольт запитан?

  • от 3.3В

  • Собрал всё работает,не получается таймер 2 настроить чтоб проигрывать файлы на 44кГц,,поставил кварц на 16мГц, дайте пожалуйста код настройки таймера

  • в статье есть формула, подставьте значения. теорию можно почитать тут http://avr-start.ru/?p=4500

  • Доброй ночи.
    Есть вопрос по схеме. При использовании прошивки wav_player.7z и аудио записи в формате wav 8кГц — звук идет через динамик, но на фоне воспроизведения идет сильный гул в результате которого слушать мелодию не реально. В чем может быть проблема?

  • кондер стоит для отвязки?

  • Да, конденсатор тоже ставил согласно схемы, но результат не изменился в лучшую сторону. Может ли быть это из за используемого усилителя? Я использовал усилитель вот такой: ardu.net/ru/moduli/41-usilitel-zvuka-2kh3w-25-5-5v-miniatyurnyj-pam8403-190871911.html
    При его использовании в других схемах такого шума нет.

  • возможно, попробуйте подтянуть выход с мк на землю через 100кОм.

  • Добрый вечер!

    Каким образом в данном проекте заставить воспроизводить один из двух звуковых файлов (1.wav и 2.wav) по нажатию на одну из двух кнопок?

  • в конце статьи есть что то вроде вав плеера

  • Здравствуйте! Спасибо огромное за Ваши уроки. Собрал схему данного урока — работает!
    Подскажите пожалуйста, как сделать так, чтобы воспроизведение начиналось не с момента подачи питания, а через некоторое время? Создал прерывание по переполнению таймера 0, в нем веду отсчет времени, а где подставить условие на начало воспроизведения не знаю. Помогите пожалуйста.

  • сделайте флаг while(play!= 1);

  • Файл WAV должен быть в PCM 8бит а не 16 бит, при 16 бит ВЧ шум.

  • Полезные данные начинаются с 44 байта)))),народ то не путайте

  • если формат файла известен заранее, то все так и есть, оттуда начинаются сырые pcm отсчеты.

  • привет благодарю вас за код, но я хочу, чтобы иметь возможность воспроизводить разные файлы для разных событий, например, когда значение adc становится ниже определенного уровня. Я хочу, чтобы иметь возможность выбрать конкретный wav-файл, это мой модифицированный код. Любая помощь будет очень благодарен спасибо

    /*i used 8mhz internal oscillatot
    i am playing at 8bit mono 16khz
    */
    #include
    #include «diskio.h»
    #include «pff.h»
    #include
    #define sw1 PIND.2
    #define sw2 PIND.3

    unsigned char buffer[512]; /* * the buffer into which the infa is copied from the flash drive */
    volatile unsigned int count; //copied data counter
    unsigned int br; /* counter read / write file */
    unsigned char buf = 0; // the variable that determines which part of the buffer is read by
    FATFS fs; /* The working area (file system object) for logical disks */
    bit flag1=0,flag2=0;

    interrupt [TIM2_COMP] void timer2_comp_isr(void)
    {
    OCR1A = buffer[count]; //output the sound to the speaker
    if (++count >= 512) // increase the counter (1 sector)
    count = 0;
    }

    void playfile(char *mywav){
    if(disk_initialize()==0) // initialize the flash drive
    {
    pf_mount(&fs); //mount the drive
    pf_open(mywav); //open the wav file
    pf_lseek(44); // move the pointer to 44th byte of the wav file
    pf_read(buffer, 512,&br); // the first time we swallow 512bytes
    TIMSK=0x80;

    while(1)
    {
    if(!buf && count>255) // if more than 255 bytes were reproduced
    {
    pf_read(&buffer[0], 256,&br); // then read the first half of the buffer from the sd card
    buf=1;
    if (br < 256) // if the buffer does not contain 256 values, then the end of the file
    break;
    }
    if(buf && count<256)
    {
    pf_read(&buffer[256], 256,&br); // read the second part of the buffer from the sd card
    buf = 0;
    if (br < 256)
    break;
    } }

    TIMSK = 0x00; // turn off all
    pf_mount(0x00);
    }

    }

    void main(void) //main program
    {

    PORTB=0x00;
    DDRB=0x02;

    PORTD=0x0C; //ENABLE INTERNAL PULLUPS
    DDRD=(0<<DDD2) | (0<<DDD3);

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 8000,000 kHz
    // Mode: Fast PWM top=0x00FF
    // OC1A output: Non-Inv.
    TCCR1A=0x81;
    TCCR1B=0x09;
    TCNT1H=0x00;
    TCNT1L=0x00;
    OCR1A=0x00;

    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: 250,000 kHz
    // Mode: CTC top=OCR2
    // OC2 output: Disconnected
    TCCR2=0x0B;
    TCNT2=0x00;
    //OCR2=0x1E; /for 8khz (250/(8-1)=0x1E)
    OCR2=0x0E; //for 16khz (250/(16-1)=0x0E) —best result
    //OCR2=0xA; //for 22khz

    #asm("sei") //enable global interrupts
    // Timer(s)/Counter(s) Interrupt(s) initialization
    delay_ms(100);

    while (1)
    {
    if (!sw1 && flag1==0){
    playfile("3.wav");
    flag1=1; }

    if (!sw2 && flag2==0){
    playfile("4.wav");
    flag2=1; }
    } }

  • так вроде просто, условие if и читайте значение ADC

  • Здравствуйте!
    Можете отправить подробную схему которая показано на втором видео?

  • Admin почитайте внимательно статью «http://microsin.net/programming/PC/wav-format.html»
    полезные данные в wav начинаются с «data» (0x64617461)+4байта, но никак не с 44 байта,я уже не раз на это налетал.

  • Точнее после «data» (0x64617461)+4байта 🙂

  • Здравствуйте! Подскажите, как решить вопрос с памятью. Я хочу один раз записать и проигрывать только одну мелодию. Целую флешку для этого дела отдавать жалко. Какие есть варианты?

  • можно spi флешку поставить, или eeprom. если мелодия короткая, можно попробовать во внутреннюю память мк ее утолкать

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика