Описание лабораторной установки и примеры программ

      Комментарии к записи Описание лабораторной установки и примеры программ отключены

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

Рис. 2.2. Схема подключения светодиодной шкалы

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

Приведем пример программы, выполняющей подобное действие.

#include// включить заголовочный файл

void main(){ // основная программа

DDRC = 0xFF; // все выводы порта PORTС — выходы

PORTC = 0x00; // погасить все светодиоды

PORTC = PORTC | 1

while(1); // бесконечный цикл

}

Назначение операторов программы описано в комментариях, однако некоторые из них требуют уточнений.

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

sfrb DDRC=0x14;

sfrb PORTC=0x15;

Хотя в нашей программе этих описаний нет, но, тем не менее, при компиляции никаких ошибок выявлено не будет. Связано это с тем, что все символические имена регистров ввода-вывода определены в специальных заголовочных файлах, поставляемых с CodeVisionAVR для всех поддерживаемых им МК. Вся информация из этих файлов включается в программу с помощью директивы #include, что и сделано в первой строке нашей программы. Файл mega128a.hи содержит сопоставление символических имен с адресами и другую информацию, относящуюся к МК ATmega128A.

Организация бесконечного цикла (в данном случае с помощью оператора while) характерна для большинства программ встроенных систем. Дело в том, что при отсутствии подобного цикла МК, выбрав из памяти последнюю команду программы и закончив ее выполнение, автоматически занесет в счетчик команд адрес следующей ячейки памяти программ, выберет хранящийся в ней код и начнет его выполнение. Естественно, что подобная попытка выполнения кода, не относящегося к рабочей программе, чревата непредсказуемыми последствиями.

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

#include// включить заголовочный файл

#define D_LED DDRC // рабочий порт направления

#define P_LED PORTC // рабочий порт данных

void led (unsigned char n) { // определение функции

//[]———————————————[]

//| Назначение: зажигание светодиода c номером n |

//[]———————————————[]

D_LED = 0xFF; // все выводы P_LED — выходы

P_LED = P_LED|(1

}

void main(){ // основная программа

P_LED = 0x00; // погасить все светодиоды

led (0); // зажечь светодиод 0

while(1); // бесконечный цикл

}

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

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

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

void delay_us(unsigned int n); // задержка в микросекундах

void delay_ms(unsigned int n); // задержка в миллисекундах

Прототипы данных функций заданы в заголовочном файле delay.h, и при их использовании в программе необходимо подключить этот файл с помощью директивы

#include

Составим теперь нашу первую тестовую программу, которая будет выполнять в бесконечном цикле следующие действия:

1. погасить все светодиоды;

2. сделать паузу 1 с;

3. зажечь нечетные светодиоды 1-3-5-7;

4. сделать паузу 1 с;

5. перейти к п. 1.

При составлении программы полагаем, что для зажигания комбинации светодиодов 1-3-5-7 в порт PORTC должна быть занесено двоичное число 0b10101010 (0xAA в шестнадцатеричном представлении).

Листинг программы, написанной с учетом заданного алгоритма, может быть представлен в следующем виде:

#include// включить заголовочный файл

#include

// определение функций

void Bar(unsigned char led) {

//[]————————————————[]

//| Назначение: зажигание светодиодов шкалы |

//| led – комбинация зажигаемых светодиодов |

//[]————————————————[]

DDRC = 0xFF; // все выводы PORTС — выходы

PORTC = led // зажечь светодиоды

}

void main(){ // основная программа

while(1){ // бесконечный цикл

Bar(0x00); // погасить все светодиоды

delay_ms(1000); // пауза 1 секунда

bar(0xAA); // зажечь комбинацию

delay_ms(1000) // пауза 1 секунда

}

}

HackRF One + SDRSharp настройка и описание программы