Теперь попробуем озвучить нашу ёлочку чудесными звуками звонка от старого телефона. Качества звука нам на этом этапе не добиться, из-за примитивности железной части, но программную реализацию отработать удастся.
Будем развивать написанный ранее скелет приложения.
ШИМ - Широтно-импульсная модуляция один из методов преобразования цифорового сигнала в аналоговый. В нашем случае мы будет преобразовывать цифровую величину сигнала в отклонение диафрагмы динамика, и следовательно в звук. Желающие, могут ознакомится с популярным изложением принципов работы ШИМ.
Подробное описание можно найти в LPC210x User Manual 'Chapter 15: LPC2104/05/06 Pulse Width Modulator (PWM)'.
Изменения в программном коде коснулись файла main.c
main.c
... // Расположение и размер звукового семпла записанного во FLASH память процессора. char* phonebell_raw = (char *)0x010000; unsigned int phonebell_raw_len = 43866; // Инициализация PWM void initSound(void) { // При отключенном PWM мы должны отключать и устройства им управляемые IODIR |= (1<<7) | (1<<21); IOSET = (1<<7); // Выключаем динамик IOCLR = (1<<21); // Выключаем светодиод //initialize PWM unit and start PWM2 PWM_PR = 0x00; // Настраиваем предделитель счётчика PWM (0 - нет деления) PWM_MCR = 0x02; // Сброс счётчика PWM при совпадении с MR0 PWM_MR0 = 256; // Период счёта 256 шагов, при достижении этого значения произойдёт сброс счётчика PWM_MR2 = 0; // Ширина импульса PWM2 PWM_MR5 = 0; // Ширина импульса PWM5 PWM_LER = (1<<5) | (1<<2) | (1<<0); // Защёлкиваем значения из MR0, MR2, MR5 во внутренние регистры сравнения PWM_PCR = (1<<10) | (1<<13); // Разрешаем вывод импульсов PWM2, PWM5 на выводы процессора PWM_TCR = 0x09; // Разрешаем счёт (bit 0), разрешаем режим PWM (bit 3) // Подробное описание регистров смотрите в официальном User Manual } void playSound(void) { unsigned int i, j; char v; char* p = phonebell_raw; // Подключаем выводы процессора к выходам ШИМ // Enable PWM2 on P0.7 PINSEL0 &= ~(3<<14); PINSEL0 |= (2<<14); // Enable PWM5 on P0.21 PINSEL1 &= ~(3<<10); PINSEL1 |= (1<<10); for(i=0; i<phonebell_raw_len; ++i) { v = *p; //v = i & 0xff; PWM_MR2 = v; // Выставляем новую ширину импульсов PWM_MR5 = v; PWM_LER = (1<<5) | (1<<2); // Защелкиваем новые значения p++; for (j = 0; j < 400; j++ ); // "Ленивая" задержка } // Отключаем выводы от PWM PINSEL0 &= ~(3<<14); PINSEL1 &= ~(3<<10); } ...
И в Makefile у нас появилась новая цель, для прошивки звукового фрагмента во вторую половину памяти:
Makefile
... loadwav: $(LPCFLASH) $(LPCFLAGS) -e 4:4 $(LPCFLASH) $(LPCFLAGS) -p 0x10000 -l phonebell.raw
После приведённых манипуляций проект примет следующий вид: 03-pwm-use.tar.gz (см. также репозиторий).
Отметим следующие моменты:
PINSELx управляют подключением внутренней преферии процессора к внешним выводам (см. LPC210x User Manual 'Chapter 7: LPC2104/05/06 Pin connect block')PWMMRx необходимо защёлкнуть их содержимое во внутренние регистры сравнения записав регистр PWMLER.
Дискуссия