Массив
Массив – это однородная структура данных, широко применяемая в программировании. Все элементы массива имеют одинаковый тип данных (отсюда и название однородная структура) и к любому из них можно обратиться, используя имя массива и индекс элемента.
Для того чтобы использовать массив, его нужно предварительно объявить – указать тип данных массива, имя и размер, который определяет, сколько элементов может содержать массив. Размер массива указывается в квадратных скобках [] после имени.
unsigned char Array[12];
//массив из 12-ти элементов типа unsigned char int OtherArray[8];
//массив из 8-ми элементов типа int
Первому элементу массива соответствует индекс 0, второму – 1, третьему – 2 .. и так далее. Последний элемент имеет индекс – (размер массива -1). Может показаться, что это несколько неудобно... ничего, дело привычки.
Array[0] = 255;
//присвоить первому элементу массива значение 255 Array[11] = 15;
//присвоить двенадцатому элементу массива значение 15
При объявлении массива его можно инициализировать, то есть присвоить конкретные значения его элементам. Значения элементов перечисляются в фигурных скобках {} через запятую. После последнего значения запятую ставить не нужно.
unsigned char Data[3] = {13, 8, 57};
//объявляем массив из 3-ех элементов //и присваиваем им всем значения unsigned char Counters[6] = {0, 0, 0, 0, 0, 0};
//объявляем массив из 6-ти элементов и обнуляем все элементы
Си допускает не указывать размерность массива при его объявлении, при этом размерность массива определяется автоматически по числу инициализированных элементов.
unsigned char Counters[] = {0, 0, 0, 0, 0, 0};
//размерность массива будет равна 6
Массив может располагаться в ОЗУ, EEPROM или flash памяти микроконтроллера. По умолчанию компилятор размещает массив в оперативной памяти. Если элементы массива неизменны на протяжении всей программы (константы) то flash память лучше всего подходит для его хранения. Для того чтобы указать компилятору IARа, что массив должен располагаться во flash памяти - перед типом данных массива нужно использовать ключевое слово __flash (два символа подчеркивания подряд!).
__flash unsigned char Array[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
//объявляем массив из 8-ми элементов во flash памяти микроконтроллера
Ключевое слово __flash автоматически определяет массив как константный. Если вы попытаетесь в программе изменить содержимое массива компилятор выдаст ошибку.
Задача: написать программу проигрывающую мелодию по нажатию кнопки.
Схема для нашего примера.
Мелодия – это последовательность нот, и массив как нельзя кстати подходит для ее хранения. Нота имеет две характеристики – длительность звучания и высоту тона. По идее для каждой ноты мелодии мы должны хранить в памяти микроконтроллера эти данные. Но я для простоты выбрал мелодию, где все ноты имеют одинаковую длительность, поэтому в массиве мы будем хранить только тон ноты.
Каждой ноте соответствует своя частота колебаний. Для того чтобы микроконтроллер мог воспроизводить ноты, нужно пересчитать эти частоты в константы для таймера Т0. Как это делать мы уже разбирали.
Я рассчитал константы для двух октав и записал их в отдельный файл note.h. Дополнительно добавил две константы pause и end. Думаю, что смысл их понятен из названия.
Код нашей программы
//программирование микроконтроллеров AVR на Си
//микроконтроллер играет мелодию
//пример использования массива#include <ioavr.h>
#include <intrinsics.h>
#include "note.h"
#include "bits_macros.h"
#define button 0
#define buzer 1
__flash unsigned char Sound[] = {n1E,n1Fd,n1G,n1A,n1B,n1G,n1B,n1B,
n1Ad,n1Fd,n1Ad,n1Ad,n1A,n1F,n1A,pause,
n1E,n1Fd,n1G,n1A,n1B,n1G,n1B,n2E,
n2D,n1B,n1G,n1B,n2D,n2D,pause,pause,end};
int main(void)
{
unsigned char CurrentNote;
unsigned char index;
//инициализация периферии
DDRD = (1<<buzer);
PORTD = (1<<button);
TIMSK = 0;
TCCR0 = (1<<WGM01)|(0<<WGM00)|(0<<CS02)|(1<<CS01)|(1<<CS00);
TCNT0 = 0;
OCR0 = 0;
//разрешение прерываний
__enable_interrupt();
//опрашиваем кнопку в бесконечном цикле
//если кнопка нажата - микроконтроллер будет играть
//мелодию пока не дойдет до конца
while(1)
{
if (BitIsClear(PIND,button))
{
index = 0;
CurrentNote = Sound[index];
while (CurrentNote != end)
{
if (CurrentNote != pause)
{
OCR0 = CurrentNote;
SetBit(TIMSK, OCIE0);
}else{
TIMSK = 0;
}
index++;
CurrentNote = Sound[index];
__delay_cycles(2000000);
}
}
}
return 0;
}
//обработчик прерывания таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
InvBit(PORTD,buzer);
}
Пояснения к коду
В начале программы мы как обычно подключаем заголовочные файлы. Стандартные IARовские и 2 своих.
С помощью директивы define задаем символические имена выводам микроконтроллера к которым у нас подключены кнопка и бузер.
Определяем константный массив во флэш памяти микроконтроллера, в котором содержится наша мелодия.
__flash unsigned char Sound[] = ....
Пришлось немного помучаться, когда я переводил нотную партитуру. Не скажу, что это за мелодия, соберите макет и узнаете. Очень известная тема, слышал ее на уроках музыки, когда учился в школе.
В функции main() объявляем две переменных
unsigned char CurrentNote;
unsigned char index;
В CurrentNote микроконтроллер считывает ноту мелодии, проверяет, что она не последняя (то есть не равна константе end) и не является паузой и загружает ее в регистр сравнения таймера Т0. Переменная index – нужна для доступа к очередной ноте мелодии (к элемент массива).
С инициализацией периферии все понятно.
Разрешаем прерывания и попадаем в наш любимый
while(1).
В цикле AVR опращивает кнопку. Если кнопка нажата, то обнуляет переменную index, чтобы она указывала на первую ноту мелодии (на нулевой элемент массива), а в CurrentNote считывает из массива значение ноты.
while(1)
{
if (BitIsClear(PIND,button))
{
index = 0;
CurrentNote = Sound[index];
...
}
}
}
Попадаем в другой цикл while (Current Note != end). Он выполняется пока микроконтроллер не дойдет до конца мелодии.
В цикле микроконтроллер проверяет является Current Note нотой или паузой, и в зависимости от этого загружает переменную в регистр сравнения и разрешает прерывание таймера Т0 или наоборот запрещает его.
if (CurrentNote != pause){
OCR0 = CurrentNote;
SetBit(TIMSK, OCIE0);
}else{
TIMSK = 0;
}
Затем инкрементирует index, считывает следующую ноту и ждет. Программная задержка здесь определяет длительность ноты/паузы.
index++;
CurrentNote = Sound[index];
__delay_cycles(2000000);
В обработчике прерывания микроконтроллер дергает ножкой.
Схема для нашего примера.
Ring-IAR.rar - проект для IAR
Ring-WinAvr.rar - проект для WinAvr
Comments
"Микроконтролле р играет мелодию" .
В текст программы включается заголовочный файл pgmspace.h. Перед объявлением массива пишется PROGMEM. Для доступа к элементам массива используется макрос pgm_read_byte(&имя_переменной)
Например:
#include "pgmspace.h"
...
PROGMEM unsigned char array[]={10,2,5};
...
tmp = pgm_read_byte(& array);
pgm_read_byte(&array[2]);
все также, меняю на 10000000 // 1 MHz и ничег не изменяется... Я правильно задаю частоту внутреннего генератора?
только возник вопрос, по отладке программ в Proteus. Как в IAR получить .coff, .asm файлы для отладки.
запрограммированную таким образом
записать в файд какого нибудь аудио формата
Спасибо! Мало кто пользует IAR поэтому очень сложно учиться работать с AVR. Изза этого даже много раз пытался спрыгнуть на CV.
А где можно найти массивов с мелодиями?
Пользуют RTTL формат, то что было в старых сотиках аля нокия 3310
Если разбиваю этот массив на два массива, то программа работает. Т.е. дело не в нехватки памяти.
И еще почему когда я создаю два массива общим колличеством элементов 2500 размером в один байт каждый (т.е. __flash char Array1[1872]=
{ 0xB5 , 0xD9 , 0xB5 , 0xB5 , 0x70 , 0x90 , 0x94 ...1872штук) и еще массив на 650 элементов ), заполнение памяти МК при этом увеличивается на 6Кб гдето, а должно ведь на 2,5 Кб
__flash unsigned char
{
почему здесь кавычек нет а в проекте есть ,и выдаёт ошибку о ковычках?
В коде вашей программы ,работаю в CodeVisionAVR C Compiler
Если заменить строчку if (BitIsClear(PIN D,button)) на if (BitIsClear(POR TD,button)) в AVR Studio вроде нормально симулируется (нажатие кнопки,т.к в первом варианте PIND0 всегда =0). Так же неработает строчка OCR0=CurrentNot e; (OCR0 всегда равен 0). Первый раз(проход F11 в avr studio) прерывание возникает - потом нет. Навернека потому, что OCR0 не изменяется. Процессор Atmega16a.
Code:
unsigned int array[10];
....
if (array[0] > 511) {
...
}
Если не сложно, то растолкуйте пожалуйста, что это за массив: tab[][8]={.....};?
Интересуют первые квадратные скобки.
С уважением Георгий.
Code:
tab[2][3] =
{
{1,2,3,}
{4,5,6,}
};
В квадратных скобках задается размерность массива.
Только начал изучать АВР,и такой вопрос,а есть полный вариант этой проги для ВинАвр?
RSS feed for comments to this post