Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С - Стивен Барретт 8 стр.


Спецификация типаОписаниеРазмер, байтДопустимый диапазон чисел
charОднобайтовое целое со знаком1–128 ÷ +127
unsigned charОднобайтовое целое без знака или символ из набора символов системы ASCII10 до 255
intЦелое значение естественного размера (машинное слово) со знаком2–32768 ÷ +32767
short intЦелое значение естественного размера (машинное слово) со знаком2–32768 ÷ +32767
unsigned intЦелое значение естественного размера без знака2от 0 до 65535
long intЦелое значение двойного естественного размера (два машинных слова) со знаком4–2147483648 ÷ +2147483647
floatЧисло в формате с плавающей запятой4±1,176E–38 ÷ ±3,40E+38
doubleНе рекомендуется для использования8±1,7E–308 ÷ ±1,7E+308

Табл. 3.1. Спецификация типов данных языка Си, используемых компилятором ICC12

Область памяти, отводимая для хранения объекта типа char, всегда составляет один байт. Размер области памяти, отводимой для хранения объектов int и long, определяется типом используемого компилятора. Как правило, int - машинное слово длиною в 16 бит, long двойное машинное слово, т.е. 32 бита. Формат и размер области памяти объектов float и double также зависит от типа используемого компилятора. В данном случае приведены значения для компилятора Си из среды разработки ICC12.

Служебные слово unsigned (без знака) используется вместе с целочисленными типами. Указание служебного слова unsigned перед спецификацией типа целочисленного значения определяет использование его старшего разряда. Для целых чисел со знаком старший разряд используется для хранения знака, что приводит к сужению диапазона модуля допустимых значений. В целых числах без знака старший разряд используется как дополнительный разряд числа, следовательно, диапазон допустимых значений расширяется. По умолчанию, т.е. без указания служебного слова unsigned, переменные типа char, int и long всегда считаются знаковыми. Числа в формате с плавающей запятой типов float и double также всегда знаковые.

В сочетании со спецификацией типа int возможно применение служебного слова short (короткий). Служебное слово short используется для сужения типа int до "короткого" целого. Применение служебного слова short имеет смысл, когда длина машинного слова микроконтроллера составляет четыре и более байтов. В этом случае спецификация типа short int соответствует целому числу, разрядностью в половину машинного слова. В случаях, когда машинное слово составляет два байта, спецификации типов int и short int совпадают (например, в 16-ти разрядном микроконтроллере HCS12). В некоторых компиляторах языка Си разрешается опускать слово int в спецификации типа short int и использовать одно слово short.

Слово long, обозначающее целое число, соответствующее двойному машинному слову, является таким же служебным словом как unsigned и применяется перед спецификацией типа int для его расширения до "длинного" целого (до двойного машинного слова). Однако в языке Си разрешается опускать слово int в спецификации типа long int и использовать одно слово long.

В дополнение к рассмотренным выше основным типам данных в языке Си существуют пять дополнительных типов данных:

• Array - массив, набор элементов одного типа;

• Pointer - указатель, переменная, которая содержит адрес переменной определенного типа;

• Structure - структура, набор элементов различного типа;

• Union - объединение, одна область памяти для двух различных типов данных;

• Function - функция, являясь сама определенным типом данных, может генерировать типы данных и возвращать типы данных.

Иногда эти пять типов данных характеризуют как производные типы, поскольку для их описания используются основные типы данных из табл. 3.1. Мы рассмотрим эти пять типов данных более подробно в этой главе, а также в главе 8.

В языке Си в простейшем случае синтаксис определения переменной или какого либо другого объекта данных выглядит так:

<спецификация типа> <идентификатор>

В более сложных случаях указывается также способ доступа к переменной и/или класс ее хранения:

<способ доступа/класс хранения> <спецификация типа> <идентификатор>

При объявлении массива может быть задано число элементов и их значения:

char a[10]

int m[] = {5,10,4000,34}

Первое поле, <способ доступа/класс хранения>, используется для задания типа памяти, куда должна быть помещена переменная. Второе поле, спецификация типа, содержит определение типа из табл. 3.1. Третье поле, идентификатор, содержит в себе придуманное программистом имя переменной. Четвертое поле, в котором проставлено численное значение или строка символов для массива, необязательное. Оно необходимо, если программист в строке объявления переменной желает также задать ее начальное значение, т.е. инициализировать переменную. Ниже приведен пример определения двухбайтовой переменной с именем "change" в целочисленном формате со знаком (тип int в соответствии с табл. 3.1):

int change;

Точка с запятой в конце строки должна быть проставлена обязательно, поскольку она обозначает завершения выражения в тексте программы на Си.

Имя переменной может быть произвольным, но оно не должно совпадать с зарезервированными в языке Си служебными словами:

auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long, register, return, short, signed, sizeof, struct, switch, typedef, union, unsigned, void, volatile, while

Шесть слов из приведенного списка используются в Си для определения класса хранения переменной:

extern, auto, static, register, const, volatile

Программист может управлять размещением данных, поместив их либо в сегмент данных, либо в сегмент стека. Осуществляется это путём размещения объявлений данных в различных частях модуля программы на языке Си, что определяет так называемый класс хранения объекта, который в свою очередь задаёт время его жизни и область действия.

К внешнему классу хранения (extern) относятся переменные, определения которых в тексте программы размещены вне текста некоторого программного модуля, т.е. в другом файле. Переменные с внешним классом хранения размещаются в сегменте данных (т.е. в ОЗУ микроконтроллера) и сохраняются в течение всего времени выполнения программы. Областью действия переменной с внешним классом хранения является вся программа. Т.е. такая переменная доступна во всех функциях данного модуля и во всех других модулях программы.

Служебное слово auto определяет автоматический класс хранения переменной. Если при определении переменной указание на ее класс хранения отсутствует, т.е. ни одно из служебных слов не предшествует спецификации типа переменной, то по умолчанию переменной назначается автоматический класс хранения. Областью действия переменных с автоматическим классом хранения является функция (блок), в которой они определены, а также все вложенные функции (блоки). Автоматические переменные размещаются в сегменте стека на время выполнения функции, в которой они определены. После окончания выполнения функции память, отводимая под эти переменные (стек) освобождается и может быть использована для размещения других переменных. Таким образом, время жизни переменных с автоматическим классом хранения является время выполнения функции, в которой они определены. Эти переменные доступны для чтения или изменения только в тех функциях, в которых определены.

Служебное слово static в строке определения переменной обозначает статический класс ее хранения. Переменные с этим классом хранения имеют только одно отличие от переменных с автоматическим классом хранения. Статические переменные размещаются в сегменте данных (ОЗУ микроконтроллера) и сохраняют свои значения в промежутках между выполнением функций или блоков, в которых они определены. Таким образом, время жизни данных, относящихся к статическому классу хранения, совпадает с временем выполнения всей программы.

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

Служебное слово const указывается в определении переменных, значения которых не изменяются на протяжении исполнения программы. Эти переменные обычно помещаются в область ПЗУ микроконтроллера. Следует обратить внимание, что в некоторых аппаратных средствах отладки для инициализации начального значения переменной типа const должен быть использован режим программирования постоянной памяти микроконтроллера.

Класс хранения volatile назначается для тех переменных, которые могут изменять свое значение не в результате действия программы, а под управлением аппаратных средств микроконтроллера. Мы рассмотрим примеры с использованием переменных класса volatile при обсуждении приложений с использованием периферийных модулей МК 68HC12.

В процессе определения переменной, которое назначает область памяти и число байтов для ее хранения, можно также установить начальное численное значение этой переменной, т.е. инициализировать переменную. Например, определение целочисленной константы "change" со значением 23 может быть проведено посредством записи:

const int change = 23

После того, как мы научились задавать необходимые для использования в прикладной программе переменные, следует научиться выполнять арифметические и логические операции над этими переменными. Этим мы займемся в следующем параграфе.

3.3. Операторы языка Си

Язык Си обладает некоторым набором операторов, которые представлены в табл. 3.2. Полное множество операторов разбито на пять групп: общие, арифметические, логические, битовые манипуляции, унарные.

Операторы общей группы предназначаются для записи выражений на языке Си. Арифметические операторы предназначены для выполнения математических действий над переменными, таких как сложение, вычитание, умножение и деление. Логические операторы используются в выражениях для определения истинности некоторого условия. Битовые операции предназначены для модификации одного или нескольких битов переменной. Унарные операции используются для выполнения действий только над одной переменной.

В первой колонке табл. 3.2. указан приоритет оператора в том случае, если выражение содержит сразу несколько операторов. Приведем примеры последовательности применения операторов.

Приоритет в выраженияхИмя оператораСимвол для обозначения
Общие
1Скобки(), {}
1Разделители-> , .
11Условие?:
12Присваивание=, +=, *= и т.д.
Арифметические
3Умножение*
3Деление/
3Получение целочисленного остатка от деления%
4Сложение+
4Вычитание-
Логические
6Меньше<
6Меньше или равно<=
6Больше>
6Больше или равно>=
7Равно==
7Не равно!=
9Логическое И&&
10Логическое ИЛИ||
Битовые манипуляции
5Сдвиг влево<<
5Сдвиг вправо>>
8Поразрядное И&
8Поразрядное исключающее ИЛИ^
8Поразрядное ИЛИ|
Унарные
2Инверсия!
2Взятие обратного кода числа~
2Инкремент++
2Декремент--
2Минус-
2Привести к типу(type)
2Указатель*
2Взять адрес&
2Определить размерsizeof

Табл. 3.2. Операторы языка Си

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

2 * 23 + 15

Оператор умножения имеет приоритет над оператором сложения, поэтому результат вычисления выражения будет равен 61. Какие изменения мы должны внести в выражение, если хотим сначала сложить 23 и 15, и лишь затем умножить сумму на 2? Для изменения порядка действий над операндами мы воспользуемся круглыми скобками:

2 * (23 + 15)

И результат вычислений станет равным 76.

Фигурные скобки следует использовать для объединения некоторого множества операторов в законченный смысловой блок, например в функцию или цикл "loop". Примеры использования фигурных скобок, а также других операторов из группы общих рассматриваются в разделе 3.4.

Операторы группы арифметических операций. Рассмотрим последовательность выполнения действий над операндами при исполнении микроконтроллером следующего выражения:

Sum = 2 + 3;

Для вычисления значения переменной sum сначала реализуется оператор сложения "+", а затем оператор присваивания "=". В колонке 1 табл. 3.2 отражено, что оператор сложения имеет приоритет над оператором присваивания. При этом необходимо, чтобы переменная sum ранее была определена как int. Что произойдет в случае, если переменная sum ранее была объявлена как переменная другого типа, например float? После сложения результат будет преобразован к тому формату представления числа, который был объявлен при определении переменной sum.

Рассматриваемый пример может быть реализован с использованием другого синтаксиса:

num1 = 2;

num2 = 3;

sum = num1 + num2;

Подразумевается, что все упомянутые переменные num1, num2 и sum ранее были определены.

Операторы инкремента и декремента производят действия только над одной переменной. При этом, три приведенных ниже записи, отличаются синтаксисом выражения, но производят одинаковые действия:

number = number + 1;

number++;

++number;

Аналогично, три следующих записи реализуют операцию декремента, т.е. уменьшения на единицу переменной number.

number = number - 1;

number--;

--number;

Операция получения целочисленного остатка от деления 2%3 возвращает 2, так как целочисленное деление 2 на 3 не может быть произведено. Результат операции 14%3 также равен 2, поскольку результат целочисленного деления 14 на 3 равен 4 с остатком 2.

Операторы логической группы. Операторы этой группы используются для определения условий, по которым реализуется ветвление алгоритма. Операторы логической группы возвращают в виде результата 1, если результат операции "правда", и 0, если результат операции "ложь". Допустим, мы хотим сравнить текущее значение некоторой переменной с пороговым значением 82. Для этого могут быть использованы операторы больше ">", меньше "<", больше или равно ">=", меньше или равно "<=", не равно "!=" или равно "==". Рассмотрим следующую запись на Си:

value = temperature > 82;

После исполнения приведенной строки программы переменной value будет присвоено значение 1 или 0. Уместно вспомнить, что логические операции имеют приоритет над операцией присваивания. Поскольку результатом "вычисления" выражения справа может быть только 0 или 1, то и переменная value должна быть ранее объявлена соответствующим образом.

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

number = 24;

new_number_one = number << 1;

new_number_two = number >> 1;

Допустим, что три используемые в примере переменные определены как int. В первой строке переменной number присваивается значение 24 в десятичной системе счисления. Это же значение в двоичной системе счисления будет равно 00000000 00011000. Результатом действия оператора "<<" будет сдвиг влево на один разряд значения переменной number, т.е. 00000000 00110000 или 48 в десятичной системе счисления. Это значение и будем присвоено переменной new_number_one. В третьей строке оператор ">>" реализует сдвиг вправо числа number. Получится новое двоичное число 00000000 00001100 или 12 в десятичной системе счисления. В результате, значение переменной new_number_one будет равно удвоенному значению переменной number, в то время как переменная new_number_two будет равна поделенному на 2 значению number. С использованием рассматриваемых операторов мы можем также выполнить сдвиг на несколько разрядов, тогда результат операции будет эквивалентен умножению или делению на 2. Например, если n = 3, то после выполнения следующих трех операторов:

number = 24;

new_number_one = number << 3;

new_number_two = number >> 3;

значение переменной new_number_one будет равно 192 (двоичный код 00000000 11000000), а значение переменной new_number_two - 3 (двоичный код 00000000 00000011).

Рассмотрим два других логических оператора: поразрядное логическое И и поразрядное логическое ИЛИ.

Назад Дальше