![](/user_photo/1393_G1Syr.jpg)
- •1 Переменные
- •1.1 Базовые типы данных
- •1.1.1 Целочисленные типы
- •1.1.2 Способы записи целых чисел
- •1.1.3 Логический тип
- •1.1.4 Вещественные типы
- •1.1.5 Специальный тип void
- •1.2 Оператор sizeof
- •1.3 Константы
- •1.4 Определение и описание переменных
- •1.5 Классы памяти переменных
- •2 Функции
- •2.1 Объявления и определения функций
- •2.2 Функция main
- •3.1 Разыменование указателя и получение адреса
- •3.1.1 Операции разыменования указателя и получение адреса переменной
- •3.1.2 Инициализация и присваивание указателей
- •3.1.3 Указатели и область действия (время существования) переменных
- •4 Массивы
- •4.1 Основные сведения
- •4.2 Указатель на первый элемент массива
- •4.3 Работа с указателями как с массивами
- •4.4 Арифметика указателей
- •4.5 Разноразмерные массивы
- •5 Структуры
- •6 Логические операции
- •7 Условия
- •8 Операторы сравнения
- •9 Сдвиги
- •10 Циклы
- •10.1 Цикл с предусловием
- •10.2 Цикл с постусловием
- •10.3 Цикл со счётчиком
- •11 Оптимизация и её запрет, ключевое слово volatile
- •12.1.2 Директива #include
- •12.2 Условная компиляция
![](/html/1393/253/html_Up2kOlTPEK.Nq_4/htmlconvd-pxvkRk22x1.jpg)
5Структуры
Структуры являются механизмом, позволяющим формировать новые типы
данных из имеющихся. Структуры используются при необходимости группировки нескольких переменных для работы с ними как с единой переменной. Объявление структур производится с использованием ключевого слова struct, обычно его совмещают с объявлением нового типа, используя также ключевое слово typedef.
typedef-выражение не создаёт новый тип, а создаёт для имеющегося типа дополнительное имя. После слова typedef указывается существующий тип, а за ним новое имя для данного типа. typedef можно применять не только для объявления структур, но также для других типов, в том числе для указателей.
После объявления типа структуры его можно использовать для создания переменных этого типа (объектов структуры), массивов, а также указателей. Обращение к элементам структуры производится с использованием операторов доступа к членам структуры: «.» (точка) для обычных переменных и «->» для указателей. Пример использования структур см. в листинге 11.
Листинг 11. Пример использования структур.
// Объявление нового типа - структуры Result typedef struct
{
// Члены структуры unsigned char channel; float value;
} Result;
// Объявление нового имени для указателя на структуру typedef Result* ResultPtr;
int main (void)
{
//Создание переменной типа Result Result res;
//Обращение к переменным внутри структуры res.channel = 0;
res.value = 2.5;
//Создание массива элементов типа Result Result resultArray[10];
22
![](/html/1393/253/html_Up2kOlTPEK.Nq_4/htmlconvd-pxvkRk23x1.jpg)
//Обращение к переменным внутри структуры resultArray[2].channel = 5;
(*(resultArray + 2)).value = 3.9;
//Указатель на структуру
ResultPtr pointerToResult = &res;
// Обращение к членам структуры через указатель pointerToResult->channel = 1; // Было 0, станет 1 pointerToResult->value = 3.5; // Было 2.5, станет 3.5
}
5.1Работа с регистрами ввода-вывода через структуры данных
Вмикропроцессорной архитектуре ARM7 отсутствует отдельное адресное пространство для регистров ввода-вывода, через которые можно было бы взаимодействовать с периферийным оборудованием. Вместо этого регистры ввода-вывода отображаются в определённых областях единого адресного пространства (для AT91SAM7 – в верхних адресах памяти). Это означает, что программное чтение соответствующих ячеек памяти приводит к выполнению операции ввода, а запись – к операции вывода. Такой подход называется «Memory-Mapped I/O» (ввод-вывод, отражённый в память).
Стандарт языка предписывает компилятору при создании структур располагать в памяти содержащиеся в них переменные в том порядке, в котором они были указаны при объявлении структуры. Это означает, что можно заранее рассчитать, как будут располагаться элементы структур в памяти относительно друг друга3.
Для групп регистров, близких по назначению, в системных заголовочных файлах (о заголовочных файлах см. в п. 12.1.2), поставляемых производителем микроконтроллеров, определены такие структуры и созданы указатели на эти структуры, инициализированные адресом, начиная с которого в памяти располагаются регистры периферийных устройств4.
Это позволяет работать с регистрами ввода-вывода как с именованными
3Переменные, составляющие структуру всегда располагаются в порядке объявления. Однако, в общем случае в зависимости от конкретных типов этих переменных, версии и настроек компилятора, элементы могут выравниваться в памяти, так что между ними будут промежутки размером до нескольких байт. Поэтому для произвольной структуры предугадать смещение каждого элемента относительно начала структуры сложно.
4Все регистры периферийных устройств являются 32-разрядными, поэтому элементы структур имеют тип unsigned int, и на 32х-разрядной архитектуре выравниваются естественным образом без образования промежутков.
23
![](/html/1393/253/html_Up2kOlTPEK.Nq_4/htmlconvd-pxvkRk24x1.jpg)
элементами структур, что делает исходный код более понятным за счёт использования символических имён регистров, исключает необходимость указания адреса конкретного регистра. Присвоение нового значения переменной-члену структуры приводит к записи этого значения в регистр (операция вывода), а использование значения этой переменной – к чтению из регистра (операция ввода). Пример приведён в листинге 12.
Листинг 12. Использование структур для работы с регистрами ввода-вывода.
//Подключение (встраивание) заголовочного файла с описанием структур и
//необходимых типов данных.
#include "Board.h"
//Указатель на структуру, предназначенную для управления контроллером
//параллельного ввода-вывода (PIO)
static AT91PS_PIO pioa = AT91C_BASE_PIOA;
void setUp (void)
{
//Указываем, что ножками, к которым подключены светодиоды
//управляет PIO, а не встроенная периферия (операция вывода). pioa->PIO_PER = 0x00060000; // PIO Enable Register
//Настройка ножек как выходов (операция вывода).
pioa->PIO_OER = 0x00060000; // PIO Output Enable Register
// Прочитать состояния ножек (ввод)
unsigned int pinStatus = pioa->PIO_PDSR; //Pin Data Status Register
...
}
При работе с регистрами ввода-вывода следует помнить, что не все регистры поддерживают ввод и вывод. Некоторые из них рассчитаны только на ввод (т. е. чтение из регистра), а некоторые – только на вывод (запись в регистр).
24