Пункт 4. Объявление переменных


Перед использованием переменной в программе на Си её необходимо объявить - т.е. указать компилятору какой тип данных она может хранить и как она называется. Наиболее подробно об этом было сказано в предидущих параграфах. Ниже сжато - самое главное:

Формат объявления переменной таков:

[<storage modifier>] <type definition> <identifier>;

[<storage modifier>]- необязательный элемент, он нужен только в некоторых случаях и может быть:

extern- если переменная может использоваться в других файлах исходного кода программы, например объявляется во внешнем файле - хидере delay.hприведенном выше, а используется в основном файле программы.

volatile - ставьте если нужно предотвратить возможность повреждения содержимого переменной в прерывании, и не позволить компилятору попытаться выкинуть её при оптимизации кода.

пример:
volatile unsigned char x;

static- если переменная локальная т.е. объявлена в какой либо функции после скобки { и должна сохранять свое значение до следующего вызова этой функции.

register- разместить переменную в регистрах AVR - это может ускорить доступ к ней. Компилятлор по-умолчаниюразмещает переменные в регистрах до их заполнения.

eeprom- разместить переменную в EEPROM. Это энергонезависимая память - значение таких переменных сохраняется при выключении питания и при перезагрузке МК.

пример:
eeprom unsigned int x;

<type definition> - тип данных которые может хранить переменная.

наиболе часто используемые типы данных :

unsigned char- хранит числа от 0 до 255 (байт)

unsigned int - хранит числа от 0 до 65535 (слово == 2 байта)

unsigned long int - хранит от 0 до 4294967295 двойное слово == 4 байта)

Вместо unsigned char - можно писать просто char, так как компилятор по-умолчанию считает char без знаковым байтом.

А если вам нужен знаковый байт то объявляйте его так :

signed char imya_peremennoi;

<identifier> - имя переменной - некоторый набор символов по вашему желанию, но не образующий зарезервированные слова языка Си.

Выше был уже пример идентификатора - имени переменной: imya_peremennoi.

Принято использовать маленькие буквы, а для отличия имен переменных от названия функций - имена переменных можно напримерначинать с буквы, а названия функций (кроме main конечно) с символа подчеркивания.

Например так :

moya_peremennaya _vasha_funkziya

Глобальные переменные, а также локальные с модификатором static - при старте и рестарте программы равны 0 если вы не присвоили им (например оператором =) иное значение при их объявлении или по ходу программы.

 

Вот несколько примеров объявления переменных:

unsigned char my_peremen = 34;
unsigned int big_peremen = 34034;

Это объявлены две переменные и им присвоены значения.

Первая my_peremen - символьного типа - это 1 байт, она может хранить
число от 0 до 255. В данном случае в ней хранится число 34.

Вторая big_peremen - целого типа, два байта, в ней может хранится
число от 0 до 65535 , а в примере в неё поместили десятичное число 34034.

КОНСТАНТЫ.

flash и const ставятся перед объявлением констант - неизменяемых данных хранящихся во флэш памяти программ. Они позволяют вам использовать не занятую программой память МК. Обычно для хранения строковых данных - различные информационные сообщения, либо чисел и массивов чисел.

Примеры объявления констант

flash int integer_constant=1234+5;
flash char char_constant=’a’;
flash long long_int_constant1=99L;
flash long long_int_constant2=0x10000000;
flash int integer_array1[ ]={1,2,3};
flash int integer_array2[10]={1,2};
flash int multidim_array[2][3]={{1,2,3},{4,5,6}};
flash char string_constant1[ ]=”This is a string constant”;

const char string_constant2[ ]=”This is also a string constant”;

пункт 5
Описание функций-обработчиков прерываний
.

/* В ЭТОЙ программе - есть только одно прерывание и значит одна функция обработчик прерывания.

Программа будет переходить на неё при возникновении прерывания :

ADC_INT - по событию "окончание АЦ преобразования" */

interrupt [ADC_INT] void adc_isr(void)
{
PORTB=(unsigned char) (~(ADCW>>2));
/* отобразить горящими светодиодами подключенными от питания МК через резисторы 560 Ом к ножкам порта_B старшие 8 бит результата аналого-цифрового преобразования Сделаем паузу 127 МСек - просто как пример пауз */
delay_ms(127);

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

/* начать новое АЦПреобразование, установив в 1 бит 6 в регистре ADCSRA*/ ADCSRA|=0x40; } // закрывающая скобка обработчика прерывания Эта строка означает следующее: - берем значение переменной ADCSRA (это регистр МК - значит программа прочитает его, возьмет число из него) - выполняем с этим числом операцию обозначаемую вертикальной черточкой | ( это поразрядная операция ИЛИ) с числом 0x40 - присвоим или поместим результат поразрядного ИЛИ обратно в переменную ADCSRA - т.е. запишем результат в регистр ADCSRA 0x40 это в двоичном виде: 0100 0000 так как в результате поразрядного ИЛИ биты в ADCSRA напротив нулей не изменятся, а вот бит_6 в ADCSRA оказывается напротив "1" и теперь он станет "1" не зависимо от того каким он был до этого ! т.е. смысл рассматриваемой строки программы ADCSRA|=0x40; "установить" (т.е. сделать "1") бит_6 в регистре ADCSRA (флаг запуска АЦП)   Функция обработчик прерывания может быть названа вами роизвольно - как и любая функция кроме main. Здесь она названа : adc_isr При каком прерывании ее вызывать - компилятор узнает из строчки : interrupt[ADC_INT] По первому зарезервированному слову - interrupt - он узнаёт, что речь идет об обработчике прерывания, а номер вектора прерывания (адрес куда физически, внутри МК перескочит программа при возникновении прерывания) будет подставлен вместо ADC_INT препроцессором компилятора перед компиляцией - этот номер указан в подключенном нами ранее заголовочном файле ("хидере") описания МК - mega16.h - это число сопоставленное слову ADC_INT. Очень информативна следующая строка программы: PORTB = (unsigned char) (~(ADCW >> 2)); Проанализируем как она работает. Нужно вычислить выражение справа и поместить его в переменную PORTB. Вычислим что справа от оператора присваивания. ADCW - это переменная слово (двухбайтовая величина - так она объявлена в файле mega16.h) в котором компилятор AVR сохраняет 10-битный результат АЦП - а именно в битах9_0 (биты с 9-го по 0-й) т.е. результат выровнен обычно - вправо. Схема имеет только 8 светодиодов - следовательно нужно отобразить 8 старших бит результата - т.е. биты_9_2 - для этого мы сдвигаем все биты слова ADCW вправо на 2 позиции ADCW >> 2 /* биты 1 и 0 выходят вправо из числа, бит_9 перемещается в позицию бит_7, бит_8 в позицию бит_6 и так далее до бит_2 становится бит_0 */ Теперь старшие 8 бит результата АЦП встали в биты 7_0 младшего байта слова ADCW. >> n означает все биты числа сдвинуть вправо на n позиции. Это равносильно делению на 2 в степени n; << nозначает сдвинуть все биты влево на n позиции умножению на 2 в степени n.
Светодиоды загораются ( показывая “1”) при «0”на соответствующем выводе МК - следовательно нужно выводить в PORTB число в котором "1" заменены "0" и наоборот. Это выполняет операция побитного инвертирования ( ~ ) . Следовательно результатом выражения ~(ADCW >> 2) будут инвертированные 8 старших бит результата АЦП находящиеся в младшем (правом) байте двух байтового слова ADCW. Так как PORTB это байт, а ADCW - это два байта, то прежде чем выполнить оператор присваивания нужно преобразовать слово (слово - это два байта) ADCW в без знаковый байт. Преобразование типов данных - делают так : перед тем что надо преобразовать записывают в скобках ( ) тип данных к которому нужно преобразовать. Пишем ... (unsigned char) (~(ADCW>>2)) Результат этой строки - один байт и мы можем поместить его в PORTB Если в регистре DDRB все биты равны "1" - т.е. все ножки порта_B выходы, мы безусловно увидим старшие 8 бит результата АЦП горящими светодиодами. Управление отдельными битами в переменной или регистре. Как изменить только некоторые биты не изменяя остальные. Для обнуления нужных бит используют обозначаемое знаком & поразрядное логическое И - только "1" и "1" дает "1" PEREM &=(~0x04); // обнулить бит_2 в переменной PEREM А вот так более понятно: PEREM &=(~(1 << 2)); // обнулить бит_2 в переменной PEREM Обнулить биты 5, 3 и 0 в переменной PEREM PEREM &=(~ ( (1 << 5)|(1 << 3)|(1 << 0) ) ); конечно здесь вместо (1 << 0) можно написать просто (1) "Установить" - сделать "1" - биты 7, 5 и 3 в переменной PEREM PEREM |=(1 << 7)|(1 << 5)|(1 << 3); Например (1 << 4) означает: взять число 1 и все его биты сдвинуть в лево на 4 позиции - в итоге мы получим двоичное 10000. Эти вычисления компилятор сделает сам и в программе заменит всё, что правее = на число-результат. Вместо номеров битов вы можете использовать их названия WDTCR |= (1 << WDTOE) | (1 <<WDE); эта строка программы "Установит" - сделает "1" биты WDTOE и WDE в регистре WDTCR . /* Пункт 6 Функции используемые в программе */ // их может быть столько сколько вам нужно. // у нас будет одна, кроме main и // обработчика прерывания. /* ================================= Это будет функция в которой описано начальное конфигурирование МК в соответствии с поставленной задачей . Удобно над функцией сделать заголовок подробно поясняющий назначение функции ! (void)_init_mk(void) { /* Вначале любой функции объявляются ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ - если конечно они вам нужны */ /* void - означает пусто. Перед названием функции - void - означает что функция не возвращает ни какого значения. А в скобках после названия означает что при вызове в функцию не передаются никакие значения. */ // инициализация Port_B DDRB=0xFF; // все ножки сделать выходами PORTB=0xFF; // вывести на все ножки "1" /* настройка АЦП - производится записью определенного числа в регистр – ADCSRA в соответствне с его описанием. - Включить модуль АЦП; - Установить допустимую частоту тактирования АЦП при частоте кварца 3.69 МГц - мы выберем коэф. деления 64 - это даст частоту такта для процессов в АЦП 57.656 КГц; - Включить прерывание по завершению АЦ преобразования. По описанию для этого нужно записать в регистр ADCSRA число: 1000 1110 или 0х8E */ ADCSRA=0x8E; /* Теперь выбираем вход АЦП ADC0 (ножка PA0) и внешнее опорное напряжение (это напряжение код АЦП которого будет 1023) с ножки AREF /* для этого в регистр мультиплексора (выбора входа) АЦП ADMUX нужно записать 0 (он там по-умолчанию)*/ ADMUX=0; /* Разрешаем ГЛОБАЛЬНО все прерывания разрешенные индивидуально*/ #asm("sei") //это ассемблерная вставка глобального разрешения прерывания
} // скобка закрывающая для функции _init_mk()  
   

/*
Пункт 7 Главная функция main() - обязательная ! Си программа начинает выполнятся с нее!
*/

void main(void){
/* Вначале любой функции объявляются (если нужны) ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ */

init_mk(); /*Вызываем функцию инициализации, настроийки аппаратуры МК. Выполнив ее программа вернется сюда и будет выполнять следующую строку */

// запускаем АЦП
ADCSRA|=0x40;

// бесконечный цикл в ожидании прерываний
while(1);

/* Программа будет крутится на этой строчке постоянно проверяя истинно ли условие в скобках после while а так как там константа 1 - то условие будет истинно всегда!

// функция mainзакончена
} // скобка закрывающая для функции main()

Эта программа на Си будет работать так :

По завершении АЦП будет возникать прерывание и программа будет перескакивать в функцию обработчик прерывания adc_isr()

При этом будут автоматически запрещены все прерывания ГЛОБАЛЬНО !

В конце adc_isr() запускается новое АЦ преобразование и при выходе из обработчика прерывания снова разрешаются глобально прерывания, и программа возвращается опять в бесконечный цикл while(1) . Цикл будет продолжаться пока есть питание МК и не будет сброса. Светодиоды будут высвечивать 8-ми битный код АЦП напряжения на ножке PA0.

 



Дата добавления: 2016-12-27; просмотров: 1781;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.01 сек.