Views: 2033
Часть четвертая – это может показаться немного сложно.
Структура проекта.
Для облегчения конфигурирования проекты MPLAB Harmony обычно структурированы таким образом, чтобы изолировать код, необходимый для настройки «системы», от кода библиотеки и кода вашего приложения, как показано на следующем рисунке.
На следующем рисунке показано, как файлы приложения, библиотеки и конфигурации организованы в проекте MPLAB X IDE.
В проекте MPLAB Harmony файл main.c поддерживается очень простым и согласованным (просто “супер цикл”, ранее я говорил о нём). Файлы приложения (app.c и app.h на предыдущем рисунке) отделены от файлов конфигурации в подпапках system_config, поэтому у одного приложения может быть несколько конфигураций, для разных микроконтроллеров или для разных схематических конфигураций проекта. (Использование этой возможности можно увидеть на примерах в демонстрационных проектах, включенных в установку MPLAB Harmony). Модули библиотеки, которые составляют платформу MPLAB Harmony (в папке framework (конструкция)), используют определения, предоставленные в выбранном заголовке (system_config.h, выделенный серым фоном на предыдущем рисунке), чтобы указать параметры конфигурации, выбранные при настройке проекта. Наконец, специфичные для процессора периферийные библиотеки предоставляются как в виде предварительно скомпилированного двоичного файла (.a файл компоновщика), так и в виде встроенного исходного кода, чтобы обеспечить максимальную эффективность сборки для вашего проекта.
План проекта или как организован проект MPLAB Harmony.
Заголовочные файлы и папки с исходными файлами
Среда MPLAB X IDE разделяет файлы на языке C на заголовочные (.h) и исходные (.c) файлы, помещая заголовочные файлы в логическую папку Header Files верхнего уровня, а исходные файлы – в логическую папку Source Files верхнего уровня. Это различие предназначено только для отображения в среде MPLAB X IDE, и эти папки не отображаются на диске. Кроме того, в большинстве случаев логические папки, которые отображаются как подпапки этих папок, дублируются, как в логических папках верхнего уровня, так и в файлах верхнего уровня, поскольку заголовочные и исходные файлы хранятся в одном вместе на диске.
Папка приложения
Эта папка содержит исходные файлы main.c и app.c и заголовочный файл app.h.
Папка app (то есть application) и ее подпапки содержат все исходные и заголовочные файлы, зависящие от проекта (но не общие файлы, хранящиеся в папке framework, которые разберем позже). В простом проекте папка app содержит файлы main.c, app.c и app.h и подпапка system_config. Более сложные проекты, будут содержать дополнительные файлы по мере необходимости. В проекте MPLAB Harmony файл main.c обычно содержит основную функцию языка C и ничего или почти ничего более. Логика основной функции одинакова во всех проектах MPLAB Harmony и не требует изменений. Файл app.c обычно содержит логику самого приложения. Именно здесь обычно реализуется желаемое общее поведение вашей системы (хотя сложные системы могут иметь несколько приложений). Файл app.h определяет типы данных и другие определения, требуемые прототипами приложения или интерфейса для функций, которые приложение хочет предоставить другим приложениям или системе.
Папка system_config
Папка system_config содержит один или несколько подкаталогов, каждый из которых соответствует отдельной конфигурации вашего проекта. Проекты MPLAB Harmony могут иметь несколько конфигураций. Каждая конфигурация проекта создает различные варианты вашей встроенной системы с потенциально различным оборудованием или функциями. В каждой конфигурации вы можете выбрать разные наборы библиотек или модулей, выбрать разные параметры сборки для каждого модуля и даже выбрать разные исходные файлы для вашего приложения. Конфигурация состоит из определенного набора свойств (настройки инструментов) в MPLAB X IDE, набор исходных файлов, которые определяют параметры сборки, и набор исходных файлов и заголовочных файлов, которые контролируют, какие модули инициализируются и поддерживаются в вашей системе.
В MPLAB X IDE конфигурацию проекта можно выбрать с помощью раскрывающегося меню на панели инструментов, в верхней части окна или щелкнув правой кнопкой мыши имя проекта и выбрав «Свойства». В большинстве примеров и демонстрационных проектов, распространяемых с MPLAB Harmony, имя каждой конфигурации MPLAB X IDE будет совпадать с именем связанной папки в папке system_config в проекте (папка 795_pim_e16 в примере проекта). Когда выбрана конкретная конфигурация MPLAB X IDE, файлы конфигурации для этой конфигурации включаются в сборку, а файлы конфигурации в других папках конфигурации исключаются из сборки. Рекомендуется следовать этому соглашению, если вы используете несколько конфигураций в своих проектах.
Файлы конфигурации:
- system_config.h
- system_init.c
- system_tasks.c
- system_interrupt.c
- system_exceptions.c
- system_definitions.h
Этот набор файлов определяет конфигурацию системы. Назначение каждого из этих файлов будет более подробно описано в следующих разделах. Но основная идея заключается в том, что вам могут потребоваться разные конфигурации вашего приложения для разных аппаратных плат, разных микроконтроллеров Microchip или разных наборов функций, в зависимости от ваших конкретных потребностей.
Разрешение разных конфигураций одной и той же логики приложения делает ваше приложение более гибким и обеспечивает хорошо организованный способ справляться с разновидностями, которые обычно возникают в любом проекте достаточного размера и сложности. Эта техника помогает устранить дублирование кода (и непродуктивный труд), которые в противном случае были бы необходимы для управления несколькими смежными проектами. Конечно, если вам не нужно или не нужна такая гибкость, все эти файлы специально созданы для вашего проекта, и вы можете вносить в них любые изменения, которые вам нравятся. Выбор всегда за вами.
Относительный путь от папки проекта MPLAB X IDE к папке конфигурации (содержащей файл system_config.h) для каждой конфигурации проекта автоматически помещается в список «Включает каталоги» в свойствах компилятора для каждой конфигурации проекта MPLAB X IDE MHC (MPLAB Harmony configurator).
Структура папок
Логическая папка фреймворка содержит исходные файлы для фреймворка MPLAB Harmony и библиотек. В зависимости от конфигурации вашего проекта, в этой папке может быть много-много файлов и подпапок. Эти файлы предназначены для библиотек MPLAB Harmony, которые вам не нужно редактировать. На самом деле исходные файлы фреймворка обычно не находятся в вашем проекте. Вместо этого эти файлы включаются в ваш проект непосредственно из установки MPLAB Harmony (с использованием относительных путей к каталогам). Все настоящие файлы остаются в папке установки MPLAB Harmony.
1. У вас всегда есть возможность скопировать файлы инфраструктуры непосредственно в исходную папку вашего проекта, если это необходимо. Фактически, это хорошая идея, если вы планируете перемещать или распространять свой проект отдельно от установки MPLAB Harmony.
2. В большинстве случаев организация «логическая папка» в проекте MPEAB X IDE в точности совпадает с организацией физической директории в рамках установки MPLAB Harmony (и в каталоге вашего проекта) на вашем жестком диске. Это сделано для того, чтобы все было просто и согласованно, поэтому вам нужно выучить только один макет. Но есть несколько заметных исключений.
• MPLAB X IDE имеет соглашение о разделении «Заголовочные файлы» (.h) и «Исходные файлы» (.c), чтобы организация виртуальных папок в проекте разделяла файлы на эти две группы и не делайте это на диске с физическими каталогами.
• В примере или демонстрационном проекте MPLAB Harmony папка приложения будет соответствовать каталогу src на диске внутри папки прошивки проекта.
Основной файл
Точка входа на языке C для встроенного приложения MPLAB Harmony является основной функцией. Эта функция определена в файле main.c, созданном MHC в папке приложения проекта (или в каталоге src на диске). Основная функция (см. Следующий пример) реализует простой «супер цикл», обычно используемый во встроенных приложениях, которые не используют операционную систему.
Example main Function Logic – Пример функции логики main.
int main ( void ) { /* Инициализируйте все модули MPLAB Harmony, включая приложения. */ SYS_Initialize ( NULL ); while ( true ) { /* Ведение конечных автоматов всех опрошенных модулей MPLAB Harmony. */ SYS_Tasks ( ); } /* Выполнение не должно никогда попадать сюда во время нормальной работы. */ return ( EXIT_FAILURE ); }
Функция SYS_Initialize
Первое, что делает основная функция, это вызывает функцию с именем SYS_Initialize. Цель функции SYS_Initialize – инициализировать каждый программный модуль в системе. MPLAB Harmony основан на модели взаимодействующих конечных автоматов. Следовательно, эта функция должна гарантировать, что конечный автомат каждого модуля находится в допустимом начальном состоянии. Реализация этой функции является одной из вещей, сгенерированных MHC для конфигурирования системы MPLAB Harmony. Определение этой функции генерируется в файле system_init.c, описанном в system_init.c секции.
Сигнатура функции SYS_Initialize имеет входной параметр «void *». Это сделано для того, чтобы впоследствии она могла быть реализована в библиотеке, и в нее можно передать произвольную структуру данных инициализации. Однако для статически реализуемой функции SYS_Initialize (которая обычно будет иметь место, если вы реализуете ее самостоятельно), этот параметр не нужен и может быть передан как «NULL».
The “Super Loop” – “Супер Луп” – “Супер петля” – “Супер цикл”
После того, как все модули в системе были инициализированы, основная функция выполняет бесконечный цикл, чтобы поддерживать работу системы. Это обычно называется «супер циклом», так как это самый внешний цикл, внутри которого работает вся система. Эта петля никогда не не должна прерываться. Таким образом, код, который существует после окончания этого цикла, никогда не должен выполняться и включается в него только для безопасности, ясности и синтаксической полноты.
Файл SYS_Tasks и функция SYS_Tasks
Внутри «супер цикла» основная функция вызывает функцию SYS_Tasks. Цель функции SYS_Tasks – опросить каждый программный модуль в системе, чтобы убедиться, что он продолжает работать. Таким образом система поддерживает конечные автоматы всех опрошенных модулей.
(Обратите внимание, что некоторые модули могут управляться прерываниями и, следовательно, не вызываться из функции SYS_Tasks.) Реализация функции SYS_Tasks генерируется MHC в файле system_tasks.c, который описан в секции system_tasks.c.
Файлы приложения.
С точки зрения системы MPLAB Harmony, приложение состоит из двух основных функций:
- APP_Initialize
- APP_Tasks
Функция инициализации приложения (APP_Initialize) обычно вызывается из функции SYS_Initialize, которая вызывается из main перед входом в цикл верхнего уровня. Функция приложения «задачи» (APP_Tasks) обычно вызывается из функции SYS_Tasks, которая вызывается из main из цикла верхнего уровня. Вот как конечный автомат приложения инициализируется и «опрашивается», чтобы оно могло выполнять свою работу.
Функция SYS_Initialize обычно реализуется в файле system_init.c, а функция SYS_Tasks обычно реализуется в файле system_tasks.c. Это соглашение актуально, например, для демонстрационных проектов, распространяемые вместе с MPLAB Harmony, и это относится к проектам, созданным MHC. Вы конечно можете делать все, что угодно, в своих собственных проектах, но рекомендуется следовать этому соглашению, поскольку это облегчит управление несколькими конфигурациями, если они вам понадобятся, и будет соответствовать MHC и другим инструментам.
Инициализация приложения.
Функция инициализации приложения, переводит конечный автомат приложения в исходное состояние и может при необходимости выполнить дополнительную инициализацию. Эта функция не должна блокировать и не должна вызывать подпрограммы любых других модулей, которые могут блокировать работу. Если что-то нужно инициализировать, что может потребовать времени для завершения, то эта инициализация должна быть выполнена на конечном автомате приложения (то есть в его функции «Задачи» “Tasks function“).
Функция инициализации примера приложения:
void APP_Initialize ( void ) { /* Поместите конечный автомат приложения в его исходное состояние. */ appData.state = APP_STATE_INIT; appData.usartHandle = DRV_HANDLE_INVALID; }
Функция инициализации примера проекта инициализирует внутреннюю переменную и переводит конечный автомат приложения в исходное состояние, присваивая значение перечисления APP_STATE_INIT в элементе «state» структуры данных, которая содержит все данные, требуемые приложением (appData). Эта структура определена глобально, но доступна только приложению. Функция инициализации приложения вызывается из функции SYS_Initialize (определенной в system_init.c), которая вызывается из main после сброса системы. Используя эту технику, приложение инициализируется (вместе с остальной частью системы) всякий раз, когда система выходит из состояния Сброс.
Задачи приложения.
Конечный автомат приложения разбивает работу, которую приложение должно выполнять, на несколько коротких «задач», которые оно может быстро выполнить, но между которыми оно должно ждать, пока какой-то другой модуль завершит некоторые свои собственные задачи. (В этом случае другой модуль является драйвером USART в примере.) Как только каждая короткая задача успешно завершена, приложение переходит в другое состояние для выполнения следующей короткой задачи.
Example Application Tasks Function: Пример приложения Функции задачи:
void APP_Tasks ( void ) { /* Дескриптор, возвращаемый USART для буфера передачи*/ DRV_HANDLE usartBufferHandle; /* Проверьте текущее состояние приложения. */ switch ( appData.state ) { /* Продолжайте пытаться открыть драйвер, пока мы не добьемся успеха. */ case APP_STATE_INIT: { /* открыть экземпляр драйвера USART */ appData.usartHandle = DRV_USART_Open(APP_UART_DRIVER_INDEX, DRV_IO_INTENT_WRITE); if (appData.usartHandle != DRV_HANDLE_INVALID ) { /* Обновить состояние */ appData.state = APP_STATE_SEND_MESSAGE; } break; } /* Отправьте сообщение, когда драйвер будет готов. */ case APP_STATE_SEND_MESSAGE: { /* Отправить сообщение в USART */ DRV_USART_BufferAddWrite(appData.usartHandle, &usartBufferHandle, APP_HELLO_STRING, strlen(APP_HELLO_STRING)); if ( usartBufferHandle != DRV_HANDLE_INVALID ) { /* Сообщение принято. Драйвер передает. */ appData.state = APP_STATE_IDLE; } break; } /* Состояние простоя*/ case APP_STATE_IDLE: default: { /* Ничего не делать. */ break; } } }
Примеры состояний приложения.
Функция «задачи» (Tasks) в примере приложения разбивает работу приложения на следующие состояния с помощью оператора «switch» со следующими «случаями».
- APP_STATE_INIT
- APP_STATE_SEND_MESSAGE
- APP_STATE_IDLE
В примере, приложение переводится в состояние APP_STATE_INIT с помощью функции инициализации приложения до того, как будет вызвана функция «tasks». Итак, при первом вызове функции APP_Tasks выполняет код оператора switch и первая короткая «задача», которую пытается выполнить пример приложения, – это открыть драйвер USART, чтобы получить дескриптор, чтобы он мог передавать данные через USART. Обратите внимание, что приложение проверяет значение дескриптора, возвращенного функцией DRV_USART_Open, чтобы убедиться, что он является действительным до его перехода в состояние APP_STATE_SEND_MESSAGE. Если значение дескриптора, перенастроенного на то, что функция «открытия» драйвера недействительна (равно DRV_HANDLE_INVALID), приложение остается в состоянии APP_STATE_INIT и продолжает пытаться открывать драйвер USART каждый раз, когда вызывается его функция «tasks». Эта техника позволяет опрашиваемому конечному автомату ждать чего-то, что ему требуется, и избегать неуместного перехода в новые состояния, до тех пор пока модуль USART не готов выполнять требуемые задания..
Как только приложение имеет действительный дескриптор драйвера USART, оно выполняет код в случае APP_STATE_SEND_MESSAGE при следующем вызове его функции APP_Tasks. В этом состоянии приложение вызывает процедуру передачи данных драйвера USART (DRV_USART_BufferAdd) для отправки строки буфера данных, определенной в заголовке system_config.h. Затем он проверяет дескриптор, возвращенный функцией DRV_USART_BufferAddWrite, чтобы убедиться, что он действителен. Если дескриптор буфера действителен, это означает, что драйвер USART принял буфер и будет нести ответственность за передачу данных с этого момента. Приложению не нужно ничего делать, чтобы вызвать передачу данных. Однако, если буфер не принят драйвером (в этом случае дескриптор, возвращенный функцией DRV_USART_BufferAddWrite, будет недействительным), приложение остается в APP_STATE_SEND_MESSAGE и повторяет попытку при следующем вызове функции APP_Tasks.
После того, как приложение успешно передало буфер в драйвер USART, оно переходит в состояние APP_STATE_IDLE, где оно находится и ничего не делает каждый раз, когда вызывается его функция «tasks». Его работа выполнена! Более сложное приложение может перейти к какой-либо другой задаче или потенциально начать процесс заново. Но это простой пример приложения “Hello World“.
Приложение пользователя обычно инициализируется последним после всех других модулей в системе. Но никогда не следует предполагать, что какой-либо другой модуль завершит свою инициализацию во время инициализации приложения пользователя или при первом вызове функции «Задачи». Вместо этого он всегда должен проверять возвращаемое значение или состояние любого другого вызываемого им модуля, чтобы убедиться, что вызов выполнен успешно, прежде чем перейти к следующему состоянию. Следование этому правилу делает приложение пользователя более надежным и позволяет ему более эффективно обрабатывать ошибки.
Конфигурации системы.
В MPLAB Harmony конфигурация системы состоит из набора файлов, которые определяют параметры сборки, как система инициализируется и как она работает после ее инициализации. Назначение каждого из этих файлов описано в темах этого раздела.
system_config.h
В MPLAB Harmony большинству библиотечных модулей требуется набор параметров конфигурации времени сборки, которые определяют различные параметры (например, размеры буфера, максимальные или минимальные ограничения и поведение по умолчанию). Чтобы настроить библиотеку для ваших конкретных потребностей, ее параметры конфигурации могут быть определены с помощью операторов препроцессора языка C #define. Набор поддерживаемых параметров конфигурации надо искать, для каждой библиотеки, в разделе «Конфигурирование библиотеки» его справочного документа, и большинство библиотек предоставляют шаблоны и примеры файлов заголовков конфигурации в подпапке config, в папке src.
Чтобы получить параметры конфигурации своей сборки, каждая библиотека включает в себя один и тот же общий файл конфигурации верхнего уровня с именем system_config.h, и он создается MHC как часть конфигурации вашей системы. Относительный путь к каталогу конфигурации, который содержит этот файл, определяется в свойствах сборки конфигурации вашего проекта MHC, чтобы компилятор мог найти его в своем пути поиска включаемого файла.
Example Configuration system_config.h Header // ***************************************************************************** // ***************************************************************************** // Раздел: Конфигурация системной службы // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Общие параметры конфигурации системного сервиса */ #define SYS_VERSION_STR "1.07" #define SYS_VERSION 10700 // ***************************************************************************** /* Опции конфигурации, службы тактового генератора */ 80000000ul 80000000ul 7999992ul 8000000ul 32768ul #define SYS_CLK_FREQ #define SYS_CLK_BUS_PERIPHERAL_1 #define SYS_CLK_UPLL_BEFORE_DIV2_FREQ #define SYS_CLK_CONFIG_PRIMARY_XTAL #define SYS_CLK_CONFIG_SECONDARY_XTAL /*** Служба конфигурации системы портов ***/ #define SYS_PORT_AD1PCFG ~0xffff #define SYS_PORT_CNPUE 0x0 #define SYS_PORT_CNEN 0x0 // ***************************************************************************** // ***************************************************************************** // Section: Конфигурация драйвера // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Параметры конфигурации драйвера USART */ #define DRV_USART_INTERRUPT_MODE false #define DRV_USART_BYTE_MODEL_SUPPORT false #define DRV_USART_READ_WRITE_MODEL_SUPPORT true #define DRV_USART_BUFFER_QUEUE_SUPPORT true #define DRV_USART_QUEUE_DEPTH_COMBINED 16 #define DRV_USART_CLIENTS_NUMBER 1 #define DRV_USART_SUPPORT_TRANSMIT_DMA false #define DRV_USART_SUPPORT_RECEIVE_DMA false #define DRV_USART_INSTANCES_NUMBER 1 #define DRV_USART_PERIPHERAL_ID_IDX0 USART_ID_2 #define DRV_USART_OPER_MODE_IDX0 DRV_USART_OPERATION_MODE_NORMAL #define DRV_USART_OPER_MODE_DATA_IDX0 0x00 #define DRV_USART_INIT_FLAG_WAKE_ON_START_IDX0 false #define DRV_USART_INIT_FLAG_AUTO_BAUD_IDX0 false #define DRV_USART_INIT_FLAG_STOP_IN_IDLE_IDX0 false #define DRV_USART_INIT_FLAGS_IDX0 0 #define DRV_USART_BRG_CLOCK_IDX0 80000000 #define DRV_USART_BAUD_RATE_IDX0 9600 #define DRV_USART_LINE_CNTRL_IDX0 DRV_USART_LINE_CONTROL_8NONE1 #define DRV_USART_HANDSHAKE_MODE_IDX0 DRV_USART_HANDSHAKE_NONE #define DRV_USART_XMIT_INT_SRC_IDX0 INT_SOURCE_USART_2_TRANSMIT #define DRV_USART_RCV_INT_SRC_IDX0 INT_SOURCE_USART_2_RECEIVE #define DRV_USART_ERR_INT_SRC_IDX0 INT_SOURCE_USART_2_ERROR #define DRV_USART_XMIT_QUEUE_SIZE_IDX0 10 #define DRV_USART_RCV_QUEUE_SIZE_IDX0 10 #define DRV_USART_POWER_STATE_IDX0 SYS_MODULE_POWER_RUN_FULL // ***************************************************************************** // ***************************************************************************** // Section: Конфигурация приложения // ***************************************************************************** // ***************************************************************************** #define APP_UART_DRIVER_INDEX DRV_USART_INDEX_0 #define APP_HELLO_STRING "Hello World\r\n"
В выбранном примере определяются параметры конфигурации для приложения, системных служб и драйвера USART, используемого в конфигурации «pic32mx795_pim_e16» проекта.
system_init.c
В проекте MPLAB Harmony функция SYS_Initialization вызывается из основной функции для инициализации всех модулей в системе. Эта функция реализована как часть конфигурации системы MHC в файле с именем system_init.c. Этот файл может также включать другие необходимые глобальные системные элементы, которые должны быть реализованы для инициализации системы, такие как биты конфигурации процессора и глобальные структуры данных инициализации модуля.
Example system_init.c File // **************************************************************************** // **************************************************************************** // Section: Биты конфигурации // **************************************************************************** // **************************************************************************** /*** DEVCFG0 ***/ #pragma config DEBUG = OFF #pragma config ICESEL = ICS_PGx2 #pragma config PWP = OFF #pragma config BWP = OFF #pragma config CP = OFF /*** DEVCFG1 ***/ #pragma config FNOSC = PRIPLL #pragma config FSOSCEN = OFF #pragma config IESO = ON #pragma config POSCMOD = XT #pragma config OSCIOFNC = OFF #pragma config FPBDIV = DIV_1 #pragma config FCKSM = CSDCMD #pragma config WDTPS = PS1048576 #pragma config FWDTEN = OFF /*** DEVCFG2 ***/ #pragma config FPLLIDIV = DIV_2 #pragma config FPLLMUL = MUL_20 #pragma config FPLLODIV = DIV_1 #pragma config UPLLIDIV = DIV_12 #pragma config UPLLEN = OFF /*** DEVCFG3 ***/ #pragma config USERID = 0xffff #pragma config FSRSSEL = PRIORITY_7 #pragma config FMIIEN = OFF #pragma config FETHIO = OFF #pragma config FCANIO = OFF #pragma config FUSBIDIO = OFF #pragma config FVBUSONIO = OFF // ***************************************************************************** // ***************************************************************************** // Section: Данные инициализации драйвера // ***************************************************************************** // ***************************************************************************** const DRV_USART_INIT drvUsart0InitData = { .moduleInit.value = DRV_USART_POWER_STATE_IDX0, .usartID = DRV_USART_PERIPHERAL_ID_IDX0, .mode = DRV_USART_OPER_MODE_IDX0, .modeData.AddressedModeInit.address = DRV_USART_OPER_MODE_DATA_IDX0, .flags = DRV_USART_INIT_FLAGS_IDX0, .brgClock = DRV_USART_BRG_CLOCK_IDX0, .lineControl = DRV_USART_LINE_CNTRL_IDX0, .baud = DRV_USART_BAUD_RATE_IDX0, .handshake = DRV_USART_HANDSHAKE_MODE_IDX0, .interruptTransmit = DRV_USART_XMIT_INT_SRC_IDX0, .interruptReceive = DRV_USART_RCV_INT_SRC_IDX0, .queueSizeTransmit = DRV_USART_XMIT_QUEUE_SIZE_IDX0, .queueSizeReceive = DRV_USART_RCV_QUEUE_SIZE_IDX0, }; // ***************************************************************************** // ***************************************************************************** // Section: Данные инициализации модуля // ***************************************************************************** // ***************************************************************************** const SYS_DEVCON_INIT sysDevconInit = { .moduleInit = {0}, }; // ***************************************************************************** // ***************************************************************************** // Section: Системные данные // ***************************************************************************** // ***************************************************************************** /* Структура для хранения дескрипторов объектов для модулей в системе. */ SYSTEM_OBJECTS sysObj; // **************************************************************************** // **************************************************************************** // Section: Инициализация системы // **************************************************************************** // **************************************************************************** void SYS_Initialize ( void* data ) { /* Инициализация основного процессора */ SYS_CLK_Initialize( NULL ); sysObj.sysDevcon = SYS_DEVCON_Initialize(SYS_DEVCON_INDEX_0, (SYS_MODULE_INIT*)&sysDevconInit); SYS_DEVCON_PerformanceConfig(SYS_CLK_SystemFrequencyGet()); SYS_PORTS_Initialize(); /* Инициализировать драйверы*/ sysObj.drvUsart0 = DRV_USART_Initialize(DRV_USART_INDEX_0, (SYS_MODULE_INIT *)&drvUsart0InitData); /* Инициализировать приложение */ APP_Initialize(); }
В дополнение к реализации функции SYS_Initialize в предыдущем примере файл system_init.c из конфигурации «pic32mx_795_pim_e16» проекта, определяет биты конфигурации процессора, структуры данных, используемые для инициализации драйвера USART и службы управления устройством, и глобальная структура данных sysObj, используемая для службы системы управления устройствами драйвера USART, возвращаемой их функциями инициализации.
Обратите внимание, что тип данных SYSTEM_OBJECTS для структуры даты sysObj определен в секции system_definitions.h.
system_tasks.c
Поскольку модули MPLAB Harmony управляются конечным автоматом, у каждого из них есть функция «Задачи» (“Tasks”), которая должна вызываться повторно (из общесистемного «супер цикла» в основном или из потока ISR или ОС). Все функции «Задачи» вызываются из функции SYS_Initialize верхнего уровня, которая обычно реализуется в файле system_tasks.c, который генерируется MHC как часть конфигурации системы.
Example system_tasks.c File void SYS_Tasks ( void ) { /* Поддерживать системные сервисы */ SYS_DEVCON_Tasks(sysObj.sysDevcon); /* Поддержка драйверов устройств */ DRV_USART_TasksTransmit(sysObj.drvUsart0); DRV_USART_TasksReceive(sysObj.drvUsart0); DRV_USART_TasksError (sysObj.drvUsart0); /* Поддерживать конечный автомат приложения. */ APP_Tasks(); }
Файл system_tasks.c для конфигурации «pic32mx_795_pim_e16» проекта содержит только реализацию функции SYS_Tasks для этой конфигурации. Эта функция вызывает функцию задач службы системы управления устройствами, функции задач драйвера USART (у нее три функции, по одной для задач передатчика, приемника и обработки ошибок), передачу дескриптора объекта, возвращенного из процедуры инициализации драйвера, и он вызывает функцию задач приложения APP_Tasks, чтобы поддерживать конечные автоматы всех трех модулей.
system_interrupt.c
В конфигурации, управляемой прерываниями, любые модули (такие как драйверы или системные службы), которые могут управляться из прерывания, должны иметь свою функцию (и) задач с возможностью прерывания, вызываемую из «векторной» функции подпрограммы обработки прерывания (ISR) вместо из функции SYS_Tasks. Форма определения векторной функции ISR зависит от типа микроконтроллера PIC32, на котором работает система. Таким образом, любые требуемые векторные функции обычно реализуются как часть определенной конфигурации системы в файле, обычно называемом system_interrupt.c.
Поскольку образец приложения полностью опрашивается, его файл system_interrupt.c не содержит векторных функций ISR. Обратитесь к любому демонстрационному или примерному приложению, управляемому прерываниями, чтобы увидеть, как реализованы векторные функции.
system_definitions.h
Все исходные файлы конфигурации системы (system_init.c, system_tasks.c и system_interrupt.c) требуют определения структуры данных системных объектов и ее внешнего объявления. MHC генерирует эти элементы в заголовочном файле system_definitions.h, и все исходные файлы системы включают этот заголовочный файл.
Например, пример приложения определяет следующее определение структуры и внешнее объявление.
typedef struct { SYS_MODULE_OBJ sysDevcon; SYS_MODULE_OBJ drvUsart0; } SYSTEM_OBJECTS; extern SYSTEM_OBJECTS sysObj;
Эта структура содержит дескрипторы объектов, возвращаемые функциями Initialize для элемента управления устройства и модулей USART (в system_init.c), потому что они должны быть переданы в связанные функции Tasks (вызываемые в system_tasks.c), поэтому глобальная структура sysObj системы требует внешнего объявления. MHC генерирует переменные дескриптора объекта в этой структуре для каждого экземпляра активного модуля в системе.
Кроме того, исходные файлы конфигурации системы требуют заголовков интерфейса для всех библиотек и приложений, включенных в систему, чтобы у них были прототипы для их функций Initialize и Tasks. В примере приложения файл system_definitions.h содержит следующие заголовки интерфейса (и стандартные заголовки языка Си).
#include <stdint.h> #include <stddef.h> #include <stdbool.h> #include "system/common/sys_common.h" #include "system/common/sys_module.h" #include "system/clk/sys_clk.h" #include "system/clk/sys_clk_static.h" #include "system/devcon/sys_devcon.h" #include "driver/usart/drv_usart.h" #include "system/ports/sys_ports.h"
Внимание: Заголовочный файл system_configuration.h не должен включаться в исходные файлы приложения (app.c, app.h или другие), поскольку он обеспечивает прямой внешний доступ к системным объектам, и эти объекты не должны использоваться приложением напрямую. Приложение (или другие модули) должно взаимодействовать с модулем только через его определенный прикладной программный интерфейс (API) или клиентский интерфейс, а не через системные объекты или системные функции, которым требуется этот объект.
system_exceptions.c
Исходный файл system_exceptions.c предоставляет скелетную реализацию общей функции обработчика исключений (показанной ниже), переопределяя слабую реализацию функции, предоставляемую компилятором C/C++ MPLAB XC32, который просто зависает в бесконечном цикле.
void _general_exception_handler ( void ) { /* Маскируйте поле ExcCode из регистра причин (Cause Register). Обратитесь к руководству пользователя программного обеспечения MIPs.*/ _excep_code = (_CP0_GET_CAUSE() & 0x0000007C) >> 2; _excep_addr = _CP0_GET_EPC(); _cause_str = cause[_excep_code]; SYS_DEBUG_PRINT(SYS_ERROR_ERROR, "\nGeneral Exception %s (cause=%d, addr=%x).\n", _cause_str, _excep_code, _excep_addr); while (1) { SYS_DEBUG_BreakPoint(); } }
Если возникает общее исключение, эта реализация захватывает адрес инструкции, вызвавшей исключение, в переменной _excep_addr, код причины в переменной _excep_code и использует таблицу поиска, проиндексированную причиной, для предоставления отладочного сообщения, описывающего исключение если включена поддержка отладочных сообщений. Затем функция попадет в жестко запрограммированную точку останова отладки (в режиме отладки) и зависнет в цикле, чтобы предотвратить быстрое выполнение.
Эта реализация предназначена для помощи в разработке и отладке. Пользователю рекомендуется изменить эту реализацию в соответствии с потребностями своей системы.
Использование этого обработчика исключений вместо встроенного обработчика компилятора включается в MHC путем выбора вкладки «Параметры», а затем «Конфигурация приложения»> «Обработка исключений»> «Использовать шаблон обработчика исключений MPLAB Harmony» (Application Configuration > Exception Handling > Use MPLAB Harmony Exception Handler Template). Расширенные обработчики исключений, которые предоставляют дополнительную информацию об исключении, доступны на вкладке «Параметры», выбрав «Расширенное исключение» и «Обработка ошибок» (Advanced Exception and Error Handling).
The Configuration-specific “framework” Folder.
Заголовки интерфейса (т. е. API) и исходные файлы для динамических реализаций всех библиотек MPLAB Harmony содержатся в основной папке фреймворка (<install-dir>\framework). Однако MHC генерирует любые статические реализации библиотек MPLAB Harmony. Эти сгенерированные исходные файлы являются специфичными для конфигурации, потому что они генерируются со знанием выбора конфигурации. Таким образом, они помещаются в специфическую для конфигурации структуру фреймворка. Для обеспечения согласованности организация дерева подпапок в папке инфраструктуры, зависящей от конфигурации, совпадает с организацией основной папки платформы.
Например, специфичная для конфигурации папка фреймворка для конфигурации pic32mx795_pim_e16 примера проекта содержит источник файлы для статических, сгенерированных MHC реализаций системной службы часов и системной службы портов, как показано на следующем рисунке.
Other Configuration-specific Files – Другие специфические файлы конфигурации.
Есть два дополнительных файла (не на языке C), сгенерированных MHC и помещенных в папку для конкретной конфигурации. Первый файл, <имя-конфигурации>.mhc (<config-name>.mhc), фиксирует выбор конфигурации, сделанный пользователем. Второй файл, который всегда называется configuration.xml, содержит различные контрольные суммы и дополнительную информацию, необходимую MHC для определения того, какие сгенерированные файлы были отредактированы извне, и для хранения другой разной информации, которая ему требуется (например, путь к установке MPLAB Harmony).
Итак как правильно должен был выглядеть наш проект в MPLAB Harmony.
В файле main.c мы не делаем ничего, он должен выглядеть так:
int main ( void ) { /* Initialize all MPLAB Harmony modules, including application(s). */ SYS_Initialize ( NULL ); //------------------------------------------------------------------------------ while ( true ) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks ( ); } //------------------------------------------------------------------------------ /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); }
Все изменения будут относиться к файлам app.c и app.h именно эти файлы предназначены для состыковки системных модулей построчных MHC и модулей пользователя.
В файле app.h в секции определения, добавим описание портов светодиодов.
// ***************************************************************************** // ***************************************************************************** // Section: Type Definitions // ***************************************************************************** // ***************************************************************************** #define LED1 LATBbits.LATB0 #define LED2 LATBbits.LATB1 // *****************************************************************************
В файле app.c в функцию APP_Initialize добавим начальную инициализацию светодиода, для получения эффекта перемигивания светодиодов.
void APP_Initialize ( void ) { /* Place the App state machine in its initial state. */ appData.state = APP_STATE_INIT; /* TODO: Initialize your application's state machine and other * parameters. */ //------------------------------------------------------------------------------ LED1=1; // предустановка для "перемигивания"светодиодов //------------------------------------------------------------------------------ }
В функцию APP_Tasks впишем в операторе switch в case APP_STATE_SERVICE_TASKS: исполнительный код пользователя (или функции):
void APP_Tasks ( void ) { /* Check the application's current state. */ switch ( appData.state ) { /* Application's initial state. */ case APP_STATE_INIT: { bool appInitialized = true; if (appInitialized) { appData.state = APP_STATE_SERVICE_TASKS; } break; } case APP_STATE_SERVICE_TASKS: { //------------------------------------------------------------------------------ // функция приложения пользователя if(TMR1>50000) { TMR1=0; LED1 = !LED1; LED2 = !LED2; } //------------------------------------------------------------------------------ break; } /* TODO: implement your application state machine.*/ /* The default state should never be executed. */ default: { /* TODO: Handle error in application's state machine. */ break; } } }
Так как так, может быть выглядеть первая программа с использованием MHC для мигания двух светодиодов. Готовый проект можно загрузить:
MPLAB® Harmony – или как это просто! Часть 4. Итоговый проект 305.78 KB 21 downloads
MPLAB® Harmony – или как это просто! Часть 4. Итоговый...По мере выполнения проектов, буду описывать интересные решение с использованием MHC.
Это может быть интересно
- MPLAB® Code Configurator and EncoderViews: 1419 Еще раз про энкодер… Для некоторых приложений очень удобно и экономически выгодно, для настройки и управления использовать энкодер. Такие энкодеры имеют строенную тактовую кнопку которую можно применить для выбора …
- Простой цифровой регулятор мощностиViews: 6637 Простой регулятор мощности с цифровой индикацией. Этот проект создан как обучающий, для ознакомления с основами построения сетевых регуляторов мощности. Устройства подобного типа можно использовать для управления освещением, скоростью …
- WiFi ESP8266 ESP-202 (ESP-12F)Views: 7693 Первое знакомство, сначала надо его купить… http://voron.ua/catalog/024404 Схема для подключения и тестирования По схеме ставим две кнопки, сброс и кнопку BT2, для перевода в режим обновления прошивки. Если надо сделать …
- ch-светомузыка от теории до реализацииViews: 695 Сразу оговоримся технология или теория ch-светомузыки, это постоянно развивающийся процесс и то что будет сказано сегодня завтра может быть опровергнуто и считаться ошибочным. Назовем само решение проблемы автоматического …
- Проект с использованием MCC часть 05Views: 1927 Эту часть назовем так как избавься от delay, там где а это реально не надо. Для это нам потребуется научиться использовать прерывания и работать с таймерами. Что такое …
- Оптосимистор и его применениеViews: 19556 Эрве Кадино “Цветомузыкальные установки” Ответ на вопрос – управление мощным тиристором или симистором, от терморегулятора. Статья в pdf[wpdm_file id=129 template=”link-template-calltoaction3.php”] Оптосимистор принадлежат к классу оптронов и обеспечивают очень хорошую …
- PIC32MZ – Core Timer (библиотека)Views: 547 Переработанные файлы от Microchip, библиотека для работы с Core Timer.
- Проект с использованием MCC часть 14Views: 831 С выводом данных на дисплей мы справились (но могу сразу сказать библиотеку графики к этой статьи пришлось доработать, поэтому в этом проекте она обновлена). У нас на текущем …
- Применение typedef, struct и unionViews: 8726 Полезные описания переменных Часто необходимо в памяти расположить последовательно разные виды данных, что бы потом можно было их использовать. Полезные ссылки Взято и переработано с сайта http://www.butovo.com/~zss/cpp/struct.htm http://cppstudio.com/post/9172/ …
- I2C MODULE – PIC18F25K42 Device ID Revision = A001Views: 1080 I2C MODULE Обход ошибок в версии I2C MODULE – PIC18F25K42 Device ID Revision = A001 В Серии K42 применен совершенно новый модуль шины I2C, который позволяет поддерживать все …
Комментарии