Занятие 5. Технология создания собственных функций для приложений
При программировании на языке С следует создавать новые функции по единой технологии. Ниже будет рассмотрен пример создания процедуры генерации пилообразного сигнала с заданным шагом до заданного значения. Данный пример строится на базе предыдущего проекта, в котором имеется сконфигурированная ранее операционная система. Так как предполагается, что функции и данные будут объединены в структуру с одним именем, то такая структура будет носить название «объект». Для начала определим данные, которые будут использоваться объектом. Определение необходимых ресурсов происходит посредством введения заголовочного файла (название имени кроме расширения совпадает с именем файла исходного текста используемых функций, предполагается что текст функции будет содержаться в отдельном файле). Заголовочный файл состоит из 4-х частей: 1. объявление структуры как типа данных; в структуру входят все переменные функции, а также указатели на адреса процедур, применяющихся при исполнении функций, обычно это процедуры инициализации (init) и расчета (update или calc). 2. Определение типа данных для указателя на структуру п.1 3. Объявление прототипов процедур, применяемых при обслуживании и расчете функции. 4. Задание начальных констант в структуру. Подобный подход позволяет запускать несколько копий объектов, каждый использует свой набор данных, равный структуре, при этом не происходит тиражирования кода в памяти программ, так как используется для всех копий объектов один код. Сохраните следующий файл как заголовочный (с расширением *.h) в директорию «include»:
#ifndef __RAMP_H__ #define __RAMP_H__ typedef struct { int step; int ramp_out; int max_out; int (*init)(); int (*update)(); } RAMP; typedef RAMP *RAMP_handle; void RAMP_init(RAMP_handle); void RAMP_update(RAMP_handle); #define RAMP_DEFAULTS { 1,\ 0,\ 100,\ (int (*)(int))RAMP_init,\ (int (*)(int))RAMP_update} #endif
Примечание. При задании параметров по умолчанию следует четко соблюдать чередование символов «переброс каретки» и «\», в противном случае возможны ошибки компиляции. См.пример.
Для самих процедур функции необходимо создать отдельный файл, например следующего содержания:
#include "..\include\ramp.h" /* процедура инициализации */ void RAMP_init(RAMP *v) { v->step=3; } /* процедура расчета */ void RAMP_update(RAMP *v) { v->ramp_out=v->ramp_out+v->step; if (v->ramp_out>v->max_out) v->ramp_out=0; }
В основном файле программы следует объявить экземпляры объекта. RAMP ramp1=RAMP_DEFAULTS; RAMP ramp2=RAMP_DEFAULTS; В основной файл исходного текста проекта необходимо добавить вызовы функций объектов, например: int a=0; void main() { RAMP_init(&ramp1); RAMP_init(&ramp2); while (1) { a++; RAMP_update(&ramp1); RAMP_update(&ramp2); } }
В результате будут генерироваться 2 пилообразных сигнала, шаг и максимальное значение которых можно задавать индивидуально. В ходе разработки функций полезно пользоваться директивами компилятора, которые позволяют настроить ход компиляции. Рассмотрим на примере технологию применения директив. Для того чтобы избежать предупреждения о переопределении константы, необходимо в начале каждого заголовочного файла вводить следующее: #ifndef __LES1_H__ #define __LES1_H__ Для определения константы используем директиву #define. Допустим, необходимо, чтобы при компиляции происходило генерирование кода на сложение или вычитание. Для этого вводим #define ADD 0 #define SUB 1 В дальнейшем ход компиляции будет определяться в зависимости от значений констант ADD или SUB. #if ADD my1.c = my1.a + my1.b; #endif #if SUB my1.c = my1.a - my1.b; #endif Определять можно не только константы, но и макросы. Например, макрос возведения в квадрат будет выглядеть как #define quad(x) ((x)*(x)) Вызов макроса возможен следующим образом: float temp=0; temp = quad(3.5); При компиляции все строки, определенные через #define, будут подменены на заданные в директиве значения. Директива #pragma позволяет определить область памяти, куда будут размещены данные или код (например, в командном файле должна быть задана секция sect): #pragma CODE_SECTION(www, "sect"); void www(void); В данном случае при объявлении прототипа функции указывается ее размещение в памяти. Полный пример заголовочного файла les1.h:
#ifndef __LES1_H__ #define __LES1_H__ #define ADD 0 #define SUB 1 #define Uint16 unsigned int #define quad(x) ((x)*(x)) typedef struct { float a; float b; float c; } MY_STRUCT; #define MY_STRUCT_DEFAULTS {2,\ 3,\ 0} struct ABCD_bits{ Uint16 a:4; Uint16 b:4; Uint16 c:4; Uint16 d:4; }; typedef union ABCD_union { Uint16 all; struct ABCD_bits bit; } ABCD_union; #endif Полный пример файла программы les1.c: #include "les1.h" #include <float.h> MY_STRUCT my1=MY_STRUCT_DEFAULTS; #pragma CODE_SECTION(www, "sect"); void www(void); ABCD_union ax; float temp=0; void main() { while(1) { temp = quad(3.5); #if ADD my1.c = my1.a + my1.b; #endif #if SUB my1.c = my1.a - my1.b; #endif www(); } } void www() { ax.bit.c=1; }
В данном примере также показан механизм использования объединений (union), который позволяет использовать одну и ту же область памяти для различных типов данных, в данном случае – это одновременно и беззнаковое целое, и группы битов по 4 бита в каждой. Такой механизм удобно использовать, например, для конфигурирования регистров либо побитно, либо целиком загрузкой целого известного значения. Собственно разработанные процедуры полезно объединять в библиотеки, объединяющие процедуры пользователя по функциональному принципу (библиотека регуляторов, драйверов, сигналов и т.д.). Библиотека будет содержать объектный код, который будет подключен в основной проект при выполнении компоновки (выполняется при подаче команды project-build). Для этого необходимо создать проект библиотеки Project-New, в появившемся окне указать имя библиотеки (автоматически будет создан каталог библиотеки, куда необходимо сохранять все ее исходные файлы), в поле типа проекта (Project type) выбрать Library (.lib). В окне настройки опции компиляции изменятся названия закладок (появится Archiver), см.рис.1.
Рис.1
В проект необходимо добавить файл процедуры. При компиляции появится файл с расширением lib, имя которого будет одинаково с именем проекта.
Популярное: Как распознать напряжение: Говоря о мышечном напряжении, мы в первую очередь имеем в виду мускулы, прикрепленные к костям ... Почему двоичная система счисления так распространена?: Каждая цифра должна быть как-то представлена на физическом носителе... Организация как механизм и форма жизни коллектива: Организация не сможет достичь поставленных целей без соответствующей внутренней... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (550)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |