Обучение : Программирование на Си для PIC


Массивы.

Массив – это хранилище переменных или констант (далее элементы массива). Мы говорим об элементах во множественном числе, соответственно, массив имеет некую размерность, т.е. указатель на количество элементов.

 

Рассмотрим несколько примеров.

 

unsigned int array [3];

массив array состоит из переменных типа unsigned int в количестве 3 шт.

unsigned char arr_per [5] =
{12, 23, 34, 45, 56};

 

инициализированный массив arr_per состоит из переменных типа unsigned char в количестве 5 шт.

const unsigned char arr_all [4] = {12, 0xEF, 0b00001111, ‘A’};

массив arr_all состоит из констант типа unsigned char в количестве 4 шт.

extern unsigned char arr_per [5];

внешний массив arr_per состоит из переменных типа unsigned char в количестве 5 шт.

extern const unsigned char arr_all [4];

внешний массив arr_all состоит из констант типа unsigned char в количестве 4 шт.

 

Всё просто. Указываем тип элементов, затем некое имя и затем в квадратных скобках количество элементов. Если нам нужно инициализировать массив (т.е. определить содержимое), то ставим знак равно и в фигурных скобках через запятую перечисляем элементы.

 

Перечисление элементов в любом удобном для нас виде, как в этом примере const unsigned char arr_all [4] = {12, 0xEF, 0b00001111, ‘A’} .

 

Указатель const с одной стороны говорит нам о том, что это константы (неизменяемые значения), а с другой стороны благодаря этому указателю массив располагается в памяти программ (во флеши). Массивы без указателя располагаются в оперативке (регистрах общего назначения).

 

 

В чём удобство массива? В нумерации элементов массива. Зачитывание элемента или изменение переменной в массиве будет происходить через её номер. Нумерация элементов начинается с нуля. Например

 

arr_all [4] = {12, 0xEF, 0b00001111, ‘A’}

0й элемент = 12

1й элемент = 0xEF

2й элемент = 0b00001111

3й элемент = ‘A’ (символ ‘A’ = 0x41; см по таблице).

 

Следующие пример показывает, как прописать значения в массив

 

unsigned char arr_per [5] = {12, 23, 34, 45, 56};

// пропишем новые значения

arr_per [4] = 98;

arr_per [2] = 87;

arr_per [3] = 76;

arr_per [0] = 65;

arr_per [1] = 54;

 

Как видим, любой элемент массива можно изменить в любом месте и в любой последовательности. Но, как показывает практика, массив организуется с целью упорядочивания обращения к элементам, что и рассмотрим в следующем примере:

 

unsigned char arr_per [5] = {12, 23, 34, 45, 56};

 

void primer void{ // начало функции «пример»

unsigned char tmp; // некая локальная переменная tmp

for (tmp=0; tmp<4; tmp++) // цикл на основе tmp

// инкрементировать tmp пока tmp<4 и начать с нуля

PORTB = arr_per [tmp]; // в порт число из массива по номеру tmp

} // конец функции «пример»

 

 

Что мы прописываем в порт? Правильно – числа. А какие числа? Правильно – от нулевого до четвертого числа из массива. А какие нужны нам числа в массиве? Ну тут по ситуации в зависимости от того что подключено к порту. Рассмотрим пример подключения 1 разрядного семисегментного индикатора к порту.

 

/* электрические соединения

RB7 сегмент A

RB6 сегмент B

RB5 сегмент C

RB4 сегмент D

RB3 сегмент E

RB2 сегмент F

RB1 сегмент G

RB0 сегмент H

*/

 

// === массив констант с описанием 7-сегментных символов

const unsigned char arr_seg[12]={ // начало массива

// 0bABCDEFGH <– расположение сегментов по битам

   0b11111100, // 0й элемент, символ «0»

   0b01100000, // 1й элемент, символ «1»

   0b11011010, // 2й элемент, символ «2»

   0b11110010, // 3й элемент, символ «3»

   0b01100110, // 4й элемент, символ «4»

   0b10110110, // 5й элемент, символ «5»

   0b10111110, // 6й элемент, символ «6»

   0b11100000, // 7й элемент, символ «7»

   0b11111110, // 8й элемент, символ «8»

   0b11110110, // 9й элемент, символ «9»

   0b11000110, //10й элемент, символ градуса

   0b00000000  //11й элемент, пробел

}; // конец массива

 

// === функция отрисовки числа на порту

void ris_sim (unsigned char tmp) { // начало функции «отрисовка»

// в функцию передается параметр tmp

PORTB = arr_seg [tmp]; // прописать в порт число из массива по номеру tmp

} // конец функции «отрисовка»

 

// === используемые далее функции

void ris_sim (unsigned char tmp); // функция отрисовки числа на порту

void pauza (void); // функция паузы

 

// === функция перебора цифр

// (планируется вызывать из бесконечного цикла)

void perebor void{ // начало функции «перебор»

unsigned char tmp; // некая локальная переменная tmp

for (tmp=0; tmp<9; tmp++) // цикл на основе tmp

// инкрементировать tmp пока tmp<11 и начать с нуля

{ // начало цикла, т.к. в теле цикла несколько строк

ris_sim (tmp); // вызвать и передать в функцию ris_sim число tmp

pauza (); // функция паузы

} // конец цикла, т.к. в теле цикла несколько строк

} // конец функции «перебор»

 

// === функция паузы

void pauza (void){ // начало функции

unsigned int tmp; // локальная переменная

tmp = 0xffff; // в tmp поместить некое максимальное число

while (tmp-->0); /* выполнять декрементирование tmp

до тех пор, т.е. ПОКА tmp больше нуля */

}// конец функции

 

Смотрим. Мы имеем три функции

 

// === функция отрисовки числа на порту

// === функция перебора цифр (планируется вызывать из бесконечного цикла)

// === функция паузы

 

Запускаем из бесконечного цикла перебор цифр. В переборе запускается однократный цикл генерации числа tmp от 0 до 9. Это число передается в функцию отрисовки. Далее переданное число указывает, какой элемент взять из массива. В массиве у нас такие числа, которые при прописывании в порт формируют символы чисел от 0 до 9 (как видим, бинарные числа (битовые последовательности) в массиве гораздо нагляднее говорят нам о том, какие линии на порту будут включены). Для того чтобы перебор не был слишком быстрым, то мы вставляем задержку в виде функции паузы. Собственно и всё.

 

На что обратить внимание? Во всех функция фигурирует некая переменная tmp . Необходимо понимать, что в каждом конкретном месте это не одно и тоже. И об этом мы говорили, когда давали определение глобальных и локальных переменных. Нам так удобно называть однократно используемую локальную переменную. Можно сделать уникальное имя этой переменной в каждой взятой функции, но смысла напрягать мозг по именованию подобных переменных я не вижу.

 

Давайте упростим (сократим по содержанию) написанное выше, т.е. три функции объединим в одну.

 

// === функция перебора цифр (планируется вызывать из бесконечного цикла)

void perebor void{ // начало функции «перебор»

unsigned char tmp; // некая локальная переменная tmp

unsigned int tmp2; // локальная переменная tmp2

for (tmp=0; tmp<9; tmp++) // цикл на основе tmp

// инкрементировать tmp пока tmp<9 и начать с нуля

{ // начало цикла, т.к. в теле цикла несколько строк

PORTB = arr_seg [tmp]; // прописать в порт число из массива по номеру tmp

tmp2 = 0xffff; // в tmp2 поместить некое максимальное число

while (tmp2-->0); /* выполнять декрементирование tmp2

до тех пор, т.е. ПОКА tmp больше нуля */

} // конец цикла, т.к. в теле цикла несколько строк

} // конец функции «перебор»

 

Как-то так. Почему сразу не написали так? Вам нужно набивать руку в комбинировании функций и одновременно видеть и сравнивать одни с другими решениями. Выходной код уменьшится, но это не должно быть определяющим фактором в написании. Для вас важна прозрачность. Возможно, расписанный вариант из трех функций в каком-то месте окажется более полезным. Ну, например, если вам нужно использовать функцию задержки другими функциями. Или, например, если вам нужно на индикатор вывести какой-то определенный символ в любом месте программы, например «пятёрку», для этого достаточно в коде написать ris_sim (5); что означает нарисовать символ 5. Необходимо понимать, что кроме символов цифр, мы можем в массив прописать и символы некоторых букв, например, A b C d E F УРА и даже пробел (увеличив размерность массива) J.

 

Не расслабляемся. Рассмотрим еще двухмерный массив.

 

unsigned int array [5][6];

массив array состоит из переменных типа unsigned int в котором 5 строк по 6 элементов.

const unsigned char arr_all [2][3]={

{1,2,3},

{4,5,6}

};

массив констант arr_all состоит из переменных типа unsigned char в котором 2 строки по 3 элемента в каждой строке.

 

и другие варианты по аналогии с предыдущими.

 

Исключительно интересная вещь – двухмерный массив. Например, мы имеем графический индикатор 64*128 пикселей. Организуем соответствующий массив, в который можем поместить некий графический образ. Через простейшие циклы несложно организовать обмен с массивом (матрицей) вида array [Y][X] , где по YX будет число, определяющее включен или нет пиксель, а для цветных индикаторов возможен и цвет.

 

Приведем пример для начинающих. Представим что у нас два семисегментных индикатора. Представим, что у них разная распиновка. Усложним задачу – они разного типа (один с общим анодом, другой с общим катодом). Можно два массива – для одного и для другого индикатора. А можно сделать компактно и красиво, с помощью двухмерного массива. Array [Y][X] – по Y будем различать первый и второй индикатор, а по X выводимые символы. Нам нужно будет только один раз напрячь мозг, чтобы прописать соответствующие битовые последовательности каждого символа для каждого разряда.

 

Вы можете возразить, что в практике вы такого не допустите. Ой, не зарекайтесь. Вот один из моих примеров печатной платы.

 

 

Это двухразрядный индикатор. Каждая линия управления объединяет разноименные сегменты (ну может где-то и одноименные). Удобно? Несомненно, односторонняя печатная плата с толстыми дорожками это всегда удобно (хоть маркером рисуй). Такой тип разводки индикатора я называю «греческим» рисунком, когда разноименные сегменты разных разрядов соединяются на плате одной дорожкой без перемычек.

 

На что обратить внимание? Посмотрите как в двухмерном массиве перечисляются элементы и как расставлены фигурные скобки. Строго говоря, можно перечислить в одну строчку.

 

Необходимо отметить, что массивы позволяют эффективно организовывать хранение и доступ к элементам с минимальными затратами программного кода. Так или иначе, в практике может возникнуть ситуация, когда объем массива глобальных переменных может физически не уместиться в текущем банке памяти (в нулевом банке). Для этого следует использовать префикс указывающий другой банк.

 

unsigned char bank1 arr_begushaya_stroka[180];

 

На этом краткое введение в массивы закончим. Знание двух основных видов и практическое их использование значительно облегчат ваш кодинг.

 


<<< назад далее >>>

Просмотров: 52845

 








 
 
 

В русском Интернете бестолку защищать свои права. Хотите использовать материалы - используйте,
но с письменного согласия авторов. В противном случае будут высланы соответствующие письма
в поисковые системы об ограничении индексации ваших сайтов. Не доводите до греха.