- •Завдання для студентів заочного відділення
- •Р лабораторная работа №1. Азработка микропроцессорного устройства формирования звука
- •Постановка задачи
- •Предварительные сведения Физические основы музыкального ряда
- •Алгоритм работы программы
- •Выполнение работы.
- •Описание работы программы (листинг 1)
- •Формат кодируемых мелодий
- •Лабораторная работа №2. Разработка микропроцессорного синтезатора мелодий
- •Предварительные сведения
- •Алгоритм работы музыкального синтезатора выполнение работы.
- •Описание работы программы (листинг 2)
- •Iнститут «Комп’ютерних систем та iнформацiйних технолгiй»
Алгоритм работы музыкального синтезатора выполнение работы.
Программа на языке С++
Возможный вариант программы на языке С++ приведен в листинге 2. Прежде чем начинать рассмотрение текста этой программы, необходимо разобраться с одним важным вопросом. В новой программе используется такой новый элемент, как ссылочная (индексная) переменная.
C
сылочная
переменная
—
это еще одна фирменная особенность
классического С++, которая широко
применяется и позволяет сделать программы
проще и эффективнее.
Пример типичного описания ссылочной переменной: int *sper.
В приведенном примере описывается ссылочная sper переменная, которая может хранить указатель на любую другую переменную или на любой элемент любого массива, но только если эта переменная или массив имеют тип int. Рассмотрим подробнее случай, когда ссылочная переменная указывает на элемент массива. Для того, чтобы поместить в ссылочную переменную указатель, указывающий на нулевой элемент массива mass, достаточно выполнить следующую команду: sper = &mass[0].
Символ «&», поставленный перед переменной или массивом, — это операция определения ссылки на объект. Выражение &mass[0] возвращает указатель на нулевой элемент массива mass. Выражение &mass[5] возвращает указатель на пятый элемент. И так далее. Если нас интересует только начало массива, возможна и более простая запись. Допустим, ссылочной переменной sper нужно присвоить значение указателя на начало массива mass (то есть на его нулевой элемент). В этом случае можно записать sper=mass.
Другими словами, в языке С++ имя массива является одновременно и указателем на его начало. Допустим, переменная sper содержит указатель на нулевой элемент массива. Тогда sper+1 будет указывать на первый элемент того же массива, sper+2 на второй, и так далее. Если теперь переменной sper присвоить значение указателя — другой массив, то указанным выше способом мы получим доступ к новому массиву. Таким образом, используя одну и ту же ссылочную переменную можно обращаться к любому элементу любого массива.
Обращаться к разным элементам одного массива можно и по-другому. Можно увеличивать значение самой ссылочной переменной. Например, если увеличить значение переменной sper на единицу (sper=sper+l), то после этого она будет указывать уже на следующий элемент массива.
Обратите внимание на то, что ссылочная переменная хранит не адрес в памяти, где хранится элемент массива, а именно указатель. Указатель — это не совсем адрес. Если переменная имеет тип char, то она занимает в памяти один байт. Переменная типа int занимает два байта. Указатель автоматически учитывает этот факт. При увеличении значения указателя на единицу, он всегда указывает на следующий элемент массива, независимо от того, сколько байтов в памяти занимает каждый такой элемент.
Теперь посмотрим, как используются указатели в программе. Допустим, у нас есть ссылочная переменная sper, которая содержит указатель на начало массива mass. Тогда вместо выражения х = mass[1], можно записать х = *sper.
В данном случае символ * означает операцию обращения к содержимому объекта, на который ссылается переменная sper. Если теперь увеличить значение переменной sper (например, при помощи команды sper++), то после этого выражение х=*sper присвоит переменной х значение уже следующего элемента массива (mass[2]).
Применение ссылочных переменных позволяет обратиться к любому элементу массива альтернативным способом. Все удобство такого способа иллюстрирует как раз программный пример. По заданию, музыкальный синтезатор должен воспроизводить одну из нескольких мелодий. Поэтому, для каждой из мелодий мы создадим свой отдельный массив, куда поместим все коды нот.
О
днако
программа должна выбрать одну из мелодий,
то есть один из массивов, а затем именно
из него извлекать ноты. При обычном
способе доступа мы вынуждены конкретно
указывать имя массива, с которым мы
работаем. И мы не можем для разных мелодий
указывать разные массивы. Альтернативным
вариантов в таких случаях является
использование двухмерного массива.
Например, массив mass[5,10] будет состоять из пяти строк по десять элементов в каждой. Язык С++ тоже поддерживает двухмерные массивы. Для нашей задачи можно создать массив, имеющий несколько строк (по количеству мелодий), в каждой из которых будет храниться одна мелодия. Но в данном случае подобное решение будет иметь один недостаток. В двухмерном массиве все строки всегда имеют равную длину. А наши мелодии по длине разные. Конечно, можно выбрать длину для всех строк массива равную длине самой длинной мелодии. Но это приведет к нерациональному использованию памяти.
Применение ссылочной переменной сразу решает все проблемы. Каждую мелодию мы помещаем в отдельный одномерный массив типа unsigned char. Затем мы создаем ссылочную переменную с именем nota (см. строку 45 листинга 2).
Для воспроизведения первой мелодии помещаем в переменную nota указатель на начало первого массива. Затем при помощи выражения *nota читаем по порядку все элементы массива и воспроизводим ноты, соответствующие прочитанным значениям. После чтения каждого очередного элемента увеличиваем содержимое переменной nota на единицу. Если нужно воспроизвести вторую мелодию, то записываем в переменную nota указатель на начало второго массива. Воспроизводим эту мелодию таким же способом, как и первую. Подобным же образом можно воспроизводить мелодии из любого массива.
Листинг 2
1 #include <tiny2313.h>
2 #include <delаy.h>
// Объявление и инициализация массивов
// Т АБЛИЦА ЗАДЕРЖЕК
3 flаsh unsigned int tаbz[] = {16,32,64,128,256,512,1024};
// Массив коэффициентов деления
4 flаsh unsigned int tаbkd[] = {0, 4748, 4480, 4228, 3992, 3768, 3556, 3356, 3168, 2990, 2822, 2664, 2514, 2374, 2240, 2114, 1996, 1884, 1778, 1678, 1584, 1495, 1411, 1332, 1257,
1187, 1120, 1057, 998, 942, 889, 839, 792};
// ТАБЛИЦЫ МЕЛОДИЙ
// В траве сидел кузнечик
7 flаsh unsigned chаr mel1[] = {109, 104, 109, 104,109, 108, 108, 96, 108, 104, 108, 104, 108, 109, 109, 96, 109, 104, 109, 104, 109, 108, 108, 96,108,104,108,104,108,141,96,109, 111, 79, 78, 111, 111, 112, 80, 80, 112, 112, 112, 111, 109, 108, 109, 109, 96,10$,111,10 79, 79, 111, 111, 112, 80, 80, 112, 112, 112, 111, 109, 108, 141, 128, 96, 255};
… … … … … … … … … … … … … … … … … … … …
// Улыбка
32 flаsh unsigned chаr mel7[] = {107, 104, 141, 139, 102, 105, 104, 102, 164, 128, 104, 107, 109, 109, 109, 111, 114, 112, 111, 109, 144, 139, 128, 109, 111, 144, 96, 111, 109, 104, 107, 105, 173, 128, 111, 109, 112, 107, 111, 109, 109, 107, 102, 104, 134, 132, 128, 100, 103, 107, 107, 107, 107, 139, 112, 100, 103, 102, 102, 102, 134, 102, 103, 107, 105, 107, 108, 108, 108, 108, 107, 105, 107, 108, 144, 142, 128, 112, 107, 110, 140, 112, 105, 108, 107, 107, 107, 105, 140, 139, 139, 112, 103, 102, 103, 105, 108, 107, 105, 103, 128, 112, 107, 110, 108, 108, 108, 140, 112, 105, 108, 107, 107, 107, 139, 112, 103, 102, 103, 105, 108, 107, 105, 103, 105, 139, 132, 128, 96, 96,96, 255};
// ТАБЛИЦА АДРЕСОВ ВСЕХ МЕЛОДИЙ
39 flаsh unsigned chаr *tаbm[]=
{mell,mel2,mel3,mel4,mel5,mel6,mel7};
40 vоid mаin(vоid){
41 unsigned chаr cоunt; // Определяем переменную cоunt-
номер мелодии
42 unsigned chаr temp; // Определяем перемениую temp
43 unsigned chаr fnоtа; // Код тона ноты
44 unsigned chаr dnоtа; // Код длительности ноты
45 flаsh unsigned chаr *nоtа; // Ссылка на текущую ноту
46 PОRTB = 0x08; // Инициализация порта РВ
47 DDRB = 0x08;
48 PОRTD = 0x7F; // Инициализация порта PD
49 DDRD = 0x00;
50 АCSR = 0x80; // Инициализация (отключение) компаратора
51 TCCR1А=0x00; // Инициализация таймера счетчика Т1
52 TCCR1B=0x09;
53 while (1){
54 ml: temp=PIND;
55 fоr (cоunt=0;cоunt<7;cоunt++){// Цикл сканирования
датчиков
56 if ((temp&1)==0) gоtо m3; // Проверка младшего
бита переменной temp
57 temp >>= 1; // Сдвиг содержимого temp
}
58 m2: TCR1А = 0x00; // Выключение звука
59 gоtо ml; // Переход на начало
// Воспроизведение мелодии
60 m3: nоtа = tаbm[cоunt]; // Устанавливаем указатель
на первую ноту
61 m4: if (PIND==0x7F) gоtо m2 // Если ни одна кнопка не
нажата, закончить
62 if (*nоtа==0xFF) gоtо m3; // Проверка на конец мелодии
63 fnоtа =(*nоtа)&0x1F; // Определяем код тона
64 dnоtа = ((*nоtа)>>5)&0x07; // Определяем код длит-ти
65 if (fnоtа==0) gоtо m5; // Если пауза не воспр-м звук
66 ОCR1А=tаbkd[fnоtа]; // Программируем частоту звука
67 TCCR1А=0x40; // Включаем звук
68 m5: delаy_ms(tаbz[dnоtа]); // Формируем задержку
69 TCCRlА=ОxОО; // Выключаем звук
70 delаy_ms(tаbz[0]); // Задержка между нотами
71 nоtа++; // Перемещаем указатель на следующую ноту
72 gоtо m4; // Переход к началу цикла
}
}
