Программирование микроконтроллеров 1986ВЕ9x компании Миландр. Контрольные вопросы для самопроверки. Предназначено для студентов технических высших учебных заведений очной и заочной формы обучения, аспирантов, инженерно-технических работников
29 двух файлов: собственно модуль – файл с расширением *.с и заголовочный файл с расширением *.h. Имена же обоих файлов одинаковые. В модуле содержатся исходные коды функций и объявления глобальных переменных, а в заголовке – прототипы (предварительные описания) функций и глобальных переменных. Подключив заголовочный файл директивой #include к другому модулю, можно задействовать в одном модуле функции и переменные другого модуля. В отдельном модуле обычно располагают функции, родственные по смыслу, например, относящиеся к работе с одним устройством или к одной задаче. Заголовочный файл всегда начинается с директивы условной компиляции #ifndef с проверкой существования определенной константы. Если константа еще не объявлена, это значит, что компилятор впервые увидел этот заголовок и будет произведена его дальнейшая компиляция. Если константа уже объявлена, то дальнейшая компиляция заголовка не происходит. Это предотвращает многократное определение одних и тех же функций и переменных. Следующим шагом в заголовке директивой #define объявляется такая константа. Заканчивается заголовок директивой #endif (конец условной компиляции). Рассмотрим, к примеру, модуль led.c, отвечающий за работу со светодиодами. Вот его заголовок led.h в сокращенном виде: #ifndef __U_LED #define __U_LED #include "common.h" // Переключить указанные светодиоды void U_LED_Toggle (uint32_t Pins); #endif В качестве проверяемой константы используется имя __U_LED. Желательно давать таким константам имена по определенному правилу: __U_<имя модуля> . Это позволит избежать случайного совпадения имени константы с каким-нибудь иным идентификатором. Буква «U» означает здесь модуль (unit).
30 В нашем заголовке производится подключение еще одного заголовочного файла (common.h), нужного для работы модуля. Далее приведен фрагмент самого модуля led.c: #include "led.h" // Переключить указанные светодиоды void U_LED_Toggle (uint32_t Pins) { uint32_t data = PORT_ReadInputData (U_LED_PORT); PORT_Write (U_LED_PORT, data ^= Pins); } Первым делом подключается соответствующий заголовочный файл, а затем идут тексты всех функций, в том числе обязательно тех, которые были ранее декларированы в заголовке. Главным модулем проекта всегда является модуль main.c. В нем обязательно объявляется функция main(), с вызова которой начинается выполнение программы. Когда микроконтроллер включается, управление автоматически передается в функцию main(). При работе с микроконтроллером функция main() никогда не должна завершаться, т.е. должна в том или ином виде содержать бесконечный цикл. Перед таким циклом производится инициализация требуемых в проекте периферийных устройств микроконтроллера. В простейшем случае функция main() выглядит так: { // Инициализация устройства 1 Device1_Init (); // Инициализация устройства 2 Device2_Init (); // Инициализация устройства N DeviceN_Init (); while(1) { // Вызов задачи 1 Task1 (); // Вызов задачи 2 Task2 ();
31 // Вызов задачи M TaskM (); } return 0; } Функции Device1_Init, Task1 и другие определяются в отдельных модулях. Оператор return здесь поставлен для строгости, на самом деле выполнение программы до него никогда не дойдет. Описанию функции main, как правило, предшествуют директивы подключения заголовков модулей, принадлежащих проекту, а также необходимых проекту заголовков библиотечных модулей. Чтобы можно было нормально работать возможностями микроконтроллера, обязательно подключается заголовок common.h. В нем, в свою очередь, содержатся директивы подключения заголовков всех модулей периферийной библиотеки, а также системных заголовков MDR32Fx.h и RTL.h: // Работа с RTX #include // Библиотеки для работы с периферией микроконтроллера 1986ВЕ9х #include "MDR32Fx.h" #include "MDR32F9Qx_config.h" #include "MDR32F9Qx_rst_clk.h" #include "MDR32F9Qx_port.h" #include "MDR32F9Qx_dac.h" #include "MDR32F9Qx_bkp.h" #include "MDR32F9Qx_ssp.h" #include "MDR32F9Qx_uart.h" #include "MDR32F9Qx_dma.h" #include "MDR32F9Qx_adc.h" #include "MDR32F9Qx_wwdg.h" #include "MDR32F9Qx_adc.h" #include "MDR32F9Qx_timer.h" В заголовке MDR32Fx.h определены имена всех регистров, портов, устройств и т.д. В нашем проекте задействована многозадачная операционная система реального времени (ОСРВ) RTX, интегрированная в среду Keil. ОСРВ выполняет важное дело – реализует вытесняющую многозадачность, сильно облегчая труд программиста. Функции, доступные в RTX описаны в заголовке RTL.h.