Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Voprosy_i_otvety_MPT.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
3.94 Mб
Скачать

Функции

Определение функции. Программа на языке Си состоит из одной или нескольких функций. Функция – это логически самостоятельная именованная часть программы, которой могут передаваться параметры и которая может возвращать какое-то значение. Современный стиль языка Си предполагает следующий формат определения функции:

возвращаемый_тип имя_функции(тип параметр_1, …,тип параметр_n)

{

описание данных;

оператор_1;

……

оператор_m;

return (выражение);

}

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

Поле «возвращаемый_тип» задает тип возвращаемого функцией значения (char, int, float и т.д.). Если функция не возвращает никакого значения, то в поле «возвращаемый_тип» записывается ключевое слово void (пустой).

После имени функции в скобках помещаются аргументы (или по-другому параметры), передаваемые в функцию, они содержат любую комбинацию типов и имен. Это поле в определении функции называется списком формальных аргументов (или параметров). Поле «список аргументов» - не обязательная часть в определении функции. Если в функцию не передаются никакие аргументы. То это поле – пустое или содержит ключевое слово void.

Пример определения функции:

int mul(int a, int b)

{

int y;

y = a * b;

return y;

}

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

Прототип функции. Стандарт языка Си требует, чтобы функции были объявлены до первой ссылки на них. Это «предварительное» объявление называется прототипом функции. Оно извещает компилятор о типе возвращаемого значения, количестве и типе аргументов. Используя прототип, компилятор может выполнить тщательный контроль числа аргументов и соответствие их типов в вызовах функции и ее определении.

Современный стиль записи прототипа имеет следующий формат:

возвращаемый_тип имя_функции(тип параметр_1, …., тип параметр_n);

Сравнивая формат прототипа с определением функции, можно сделать вывод о том, что прототип точно повторяет первую строку определения функции. Пример прототипа для рассмотренной ранее функции:

int mul(int a, int b);

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

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

Библиотечные функции. MPLAB C18 имеет обширные библиотеки, содержащие функции для решения часто встречающихся задач. Использование таких готовых функций избавляет пользователя от необходимости разработки соответствующих средств и предоставляет ему дополнительный сервис.

Стандартные функции языка Си оформлены в соответствующие программные модули, включены в библиотеки и поставляются с системой программирования. Их прототипы даны в файлах типа *.h. Поэтому в начале программы с библиотечными функциями должны быть строки вида #include<включаемый файл вида *.h>.

30. Программирование на языке Си типовых функций управления и контроля: вывод информации в порт, управление отдельными разрядами портов, опрос переключателя, формирование временных задержек. Примеры аппаратно-программной реализации.

Для рассмотрения примеров программирования типовых функций управления будем использовать микроконтроллер PIC18F242, который имеет три порта ввода/вывода (PORTA, PORTB, PORTC). Принципиальная схема МКУ приведена на рисунке.

Рассмотрим пример программы, которая после включения питания выводит высокие уровни (логические 1) на линии RC0-RC3 и низкие уровни (логические 0) на линии RC4-RC7 порта С.

/***********************

output.c – программа вывода байта в порт С

*************************************************/

#include<p18f242.h> // подключить файл описания регистров МК

#pragma config WDT = OFF, OSC = HS // отключить сторожевой таймер, генератор МК –

// кварцевый высокочастотный

void main(void)

{

PORTC = 0; // очистить регистр данных порта С

TRISC = 0; // настроить все линии порта С на вывод

PORTC = 0b11110000; // вывести число 11110000 в порт С

while( 1 ) // зацикливание программы

;

}

Компилятор С18 позволяет управлять отдельными битами регистров специальных функций. Имена регистров и отдельных их разрядов определены в заголовочном файле p18f242.h.

Можно задать значение любого разряда порта МК, используя формат

PORTxbits.Rxy,

где x обозначает порт (A, B, C); y – номер разряда этого порта.

Например:

PORTAbits.RA0 = 1; // установить разряд порта RA0 = 1

PORTBbits.RB1 = 0; // сбросить разряд порта RB1 = 0

Рассмотрим пример программы, в которой производится попеременное включение светодиода VD1.

#include<p18f242.h>

#pragma config WDT = OFF, OSC = HS

void main(void)

{

PORTC = 0;

TRISC = 0;

while( 1 )

{

PORTCbits.RC0 = 1; // включить VD1

PORTCbits.RC0 = 0; // выключить VD1

}

}

Рассмотрим теперь, как производится на Си опрос контактов переключателя. Пусть в рассматриваемом МКУ управление светодиодом VD1 выполняется от переключателя SA1. Когда контакт SA1 замкнут, светодиод VD1 горит. Когда разомкнут – не горит. Программа с именем led_but.c сожжет иметь следующий вид.

#include<p18f242.h>

#pragma config WDT = OFF, OSC = HS

void main(void)

{

PORTB = 0; // очистить регистр данных порта В

PORTC = 0; // очистить регистр данных порта С

TRISB = 0b10000001; // настроить разряды RB0 и RB7 на ввод, остальные на вывод

TRISC = 0; // настроить все линии порта С на вывод

while( 1 )

{

if(PORTBbits.RB0 == 0)

PORTCbits.RC0 = 1;

else

PORTCbits.RC0 = 0;

}

}

Рассмотрим теперь программу, в которой управление светодиодом VD1 производится от переключателя SA1, а светодиодом VD2 – от переключателя SA2. Программа может иметь имя led_but2.c.

#include<p18f242.h>

#pragma config WDT = OFF, OSC = HS

void main(void)

{

PORTB = 0;

PORTC = 0;

TRISB = 0b10000001;

TRISC = 0;

while( 1 )

{

if(PORTBbits.RB0 == 0) // проверка переключателя SA1

PORTCbits.RC0 = 1;

else

PORTCbits.RC0 = 0;

if(PORTBbits.RB7 ==0) // проверка переключателя SA2

PORTCbits.RC7 = 1;

else

PORTCbits.RC7 =0;

}

}

Теперь рассмотрим, как на Си получить временную задержку, которая позволит формировать управляющие сигналы с различными временными параметрами.

Допустим, что в схеме МКУ надо получить мигающий режим работы VD1. Чтобы мигание светодиода было хорошо видно, примем частоту смены данных на RC0 около 1 Гц. Задержку организуем с помощью программного цикла for, который будет выполняться определенное число раз. Время выполнения этого цикла и будет определять задержку. Программа может иметь следующий вид.

#include<p18f242.h>

#pragma config WDT = OFF, OSC = HS

void delay(void) // функция временной задержки

{

unsigned int i; // переменная цикла – двухбайтное целое беззнаковое число

for(i = 0; i < 50000; i++)

;

}

void main(void)

{

PORTC = 0;

TRISC = 0;

while( 1 )

{

PORTCbits.RC0 = 1;

delay( );

PORTCbits.RC0 = 0;

delay( );

}

}

Определить величину временной задержки, реализуемой функцией delay можно лишь приблизительно следующим образом. Время выполнения команды в PIC18 занимает 1 машинный (командный) цикл TCY , который определяется частотой тактового генератора МК следующим образом:

TCY = 4/FOSC .

При частоте FOSC, равной 4 Мгц длительность машинного цикла будет TCY = 1 мкс.

При реализации цикла for выполняется 50000 раз инкремент переменной i и столько же раз ее проверка на равенство числу 50000. Так что примерное время задержки составит 100000 мкс или 0,1 с.

В компиляторе C18 имеются библиотечные функции задержки, которые позволяют реализовать временные задержки с большой точностью. Для нашего случая можно выбрать функцию Delay10KTCYx(n), которая позволяет получить задержку, кратную 10000 машинных циклов TCY.

Если надо получить задержку на 0,5 с, т.е. 500000 мкс, то при частоте 4 Мгц и TCY = 1 мкс надо в функцию записать число n, равное 500000 / 10000 = 50. Таким образом, окончательно функция задержки будет иметь вид:

Delay10KTCYx(50).

Так как функции задержки находятся в библиотеках С18, то необходимо их подключить с помощью заголовочного файла delays.h. Текст программы управления светодиодом с частотой мигания 1 Гц может иметь вид:

#include<p18f242.h>

#include<delays.h>

#pragma config WDT = OFF, OSC = HS

void main(void)

{

PORTC = 0;

TRISC = 0;

while ( 1 )

{

PORTCbits.RC0 = 1; // включить VD1

Delay10KTCYx(50); // задержка на 0,5 с

PORTCbits.RC0 = 0; // выключить VD1

Delay10KTCYx(50); // задержка на 0,с

}

}

102

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]