Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
МПС_проект2007.doc
Скачиваний:
88
Добавлен:
12.04.2015
Размер:
2.02 Mб
Скачать

Void init(void) // инициализация контроллера

{

// Настройка таймера 1

TCCR1B | = 0x02; // коэффициент деления частоты генератора = 8

TCCR1B & = 0xFA;

TCNT1H = 0x3C; TCNT1L = 0xB0; //10Гц при частоте кварца 4МГц

// 4МГц/8/10Гц = 50000 = 0xC350;

//так как 16р таймер работает на увеличение,

//то загрузка его = 0x10000 – 0xC350 = 0x3CB0

// Настройка WATCHDOG - период сработки 2.0 с

_WDR(); // Сброс охранного таймера

WDTCSR | = 0x0F; // Разрешение работы охранного таймера и настройка

WDTCSR & = 0xDF; // период сработки 2.0 с

// Настройка портов

DDRD = 0x7B; //РD6, PD5, PD4, PD3, PD1, P0 – на выход, РD2 – на вход

// Начальные значения

Q=1; // задание начального состояния задачи "Управление выходными сигналами"

//Установка выходного вектора Z1 на PORTD

PORTD | =0x18 ; // зажечь Зг и Кв

PORTD & = 0x9C; // погасить Кг, Жг, Жв, Зв

// Настройка прерываний

TIMSK | = 0x80; // Таймер 1 - разрешение прерываний, bit1=1

GIMSK | = 0x40; // INT0 - разрешение прерывания, bit6=1

_SEI(); // Разрешение глобального прерывания

}

Задача "Обработка входных сигналов"

Задача активизируется по нажатию на кнопку или при сработке датчика. Результатом выполнения задачи является установка признака сработки/нажатия для задачи "Управление выходными сигналами" и сброс счетчика времени цикла переключения работы светофора (разрешение движения по второстепенной улице и обратное переключение по истечению времени) в начальное положение. Для обеспечения условия технического задания – не реагировать на нажатия кнопок до полного окончания цикла переключения с учетом того, что реакция на очередное нажатие кнопки или на сработку датчика возможна не ранее 1мин после включения зеленого света для главной улицы – задача должна устанавливать запрет по данному прерыванию. Разрешение прерывания по внешнему входу устанавливается по истечению заданного времени в задаче "Управление выходными сигналами".

Рис.6.20. Алгоритм функционирования состояния задачи

"Обработка входных сигналов"

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

Третий этап – представление состояния в виде формальной структуры функций. На рис.6.20 представлена структура функций для задачи "Обработка входных сигналов". Здесь обозначены:xStart- признак сработки/нажатия,xdSec– счетчик времени цикла переключения. В данной структуре имеются толькофункциидействий, отсутствуютфункции входа, функции проверки и функции выхода.

Код программы прерывания по входу INT0 будет выглядеть следующим образом:

// Внешнее прерывание по входу INT0

interrupt [INT0_vect] void Int0(void)

{

хStart = 1; //Разрешение цикла переключения светофора

хdSec = 0; //Начало отсчета цикла переключения светофора

GIMSK & = 0xBF; // Запрет прерывания по входу INT0, "0" – bit6

}

GIMSK – регистр масок внешних прерываний, bit6 – бит разрешения прерывания по входуINT0.

Задача "Отсчет времени"

Задача активизируется по импульсу переполнения внутреннего таймера микроконтроллера. Запрограммировав частоту переполнения таймера равной, например, 10Гц, можно осуществить вычисление временных интервалов с точностью 100мс. В теле подпрограммы должна располагаться переменная – счетчик текущего времени (xdSec), значение которой будет увеличиваться с каждым вызовом прерывания. Так как длительность цикла переключения не превышает 100с, то величинаxdSecограничена значением в 1000 дискрет (1000 дискретов по 0,1с составляет 100с).

Синхронизация текущего времени с временем сработки кнопки/датчика осуществляется в задаче "Обработка входных сигналов"путем сброса счетчика времени в ноль. При входе в процедуру необходимо осуществлять перезагрузку таймера для задания очередного времени вызова прерывания по его переполнению – через 100мс.

Результатом выполнения задачи является увеличение значения счетчика текущего времени xdSecна единицу.

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

Рис.6.21. Алгоритм функционирования состояния задачи

"Отсчет времени"

Третий этап – представление состояния в виде формальной структуры функций. На рис.6.21 представлена структура функций для задачи "Обработка входных сигналов". Здесь обозначены:xdSec– счетчик текущего времени. В данной структуре имеются толькофункциидействий, отсутствуютфункции входа, функции проверки и функции выхода.

Код программы прерывания по переполнению таймера Т1 будет выглядеть следующим образом:

// Прерывание по переполнению таймера Т1 (частота вызова – 10Гц)

interrupt [TIMER1_OVF1_vect] void TimerOverflow(void)

{

TCNT1H = 0x3C; TCNT1L = 0xB0; //10Гц при частоте кварца 4МГц и предделителе 8

// 4МГц/8/10Гц = 50000 = 0xC350;

//так как 16р таймер работает на увеличение,

//то загрузка его = 0x10000 – 0xC350 = 0x3CB0

хdSec++; //Счетчик тактов длительностью 0.1 с

if (хdSec >1000) хdSec = 1000; // Ограничение счетчика времени

}

TCNT1H и TCNT1L – старший и младший байты таймера счетчика Т1.

Задача "Сброс WDT"

Задача сброса охранного таймера реализуется через вызов стандартной процедуры, имеющейся в библиотеке семейства AVR:

_WDR(); // Сброс охранного таймера

Задача "Управление выходными сигналами"

Рис.6.22. Граф состояний задачи "Управление выходными сигналами"

Представим граф состояний задачи. Входными величинами задачи являются: признак сработки/нажатия и текущее время цикла переключения. Выходные величины – векторы Z1 ÷Z4 (см. табл.6.1), определяющие включение/выключение ламп светофора:

  • Z1 – исходный выходной вектор;

  • при срабатывании кнопок или датчиков устанавливается выходной вектор Z2;

  • через 10с устанавливается выходной вектор Z3;

  • через 20с устанавливается выходной вектор Z4;

  • через 10с устанавливается выходной вектор Z1;

  • в течение 1 мин – отсутствие реакции на срабатывания кнопок или датчиков.

На рис.6.22 представлен граф состояний задачи "Управление выходными сигналами".

В соответствии с логикой работы светофора можно выделить пять состояний задачи: Q0 ÷Q4:

Q0 – состояние инициализации задачи;

Q1 – состояние разрешения движения по главной дороге. Выходной векторZ1. Выход из состояния по установке признака сработки/нажатия (X1=1), переход в состояниеQ2. Сброс текущего времени (t=0) осуществляется в задаче "Обработка входных сигналов" при нажатии кнопки;

Q2 – состояние запрета движения по обеим дорогам. Выходной вектор Z2. Выход из состояния по истечении 10с (t ≥ 10с) и переход в состояние Q3;

Q3 – состояние разрешения движения по второстепенной дороге. Выходной вектор Z3. Пребывание в состоянии в течение 20с. Выход из состояния по достижении текущего времени от начала цикла переключения светофораt=(10+20)=30с и переход в состояниеQ4;

Q4 – состояние запрета движения по обеим дорогам в течение 10с (выходной вектор Z4) и разрешения движение по главной дороге в следующие 20с (выходной векторZ1). Выход из состояния по истечении 100с от начала цикла переключения светофора (t=(30+10+60)=100с), разрешение прерывания по входуINT0 и переход в состояниеQ1.

Алгоритм функционирования состояния Q1 приведен на рис.6.23. В данной структуре имеются толькофункция проверки и функция выхода, отсутствуютфункции входа и функциидействий. Если условия проверки не выполняются, то в следующем периоде активизации задачи будет выполняться прежнее состояние Q1. При выполнении условия (есть признак сработки/нажатия) устанавливается новый выходной вектор Z2 и задается новое состояние Q2, которое будет выполняться в следующем периоде активизации задачи.

Рис.6.23. Алгоритм функционирования состояния Q1 задачи

"Управление выходными сигналами"

Алгоритмы функционирования состояний Q2 ÷ Q3 отличаются только порогом сравнения в условии проверки, номером выходного вектора и номером нового состояния при выполнении условия. Общий алгоритм приведен на рис.6.24.

Алгоритм функционирования состояния Q4 приведен на рис.6.25. Он содержит две функции проверки выхода и две функции выполнения выхода. Функция проверки t ≥ 40с?определяет время горения желтого света перед переключением на разрешение движения по главной дороге. Функция проверкиt ≥ 100с? задает время запрета реакции на нажатие кнопки после переключения на разрешение движения по главной дороге. Функция выполнения выхода после окончания времени запрета содержит разрешение прерывания по входуINT0, позволяя системе реагировать на нажатие кнопки.

Рис.6.24. Алгоритм функционирования состояний Q2 ÷ Q3 задачи

"Управление выходными сигналами"

Код задачи "Управление выходными сигналами" представлен ниже. Как было отмечено ранее, состояния инициализации для всех задач лучше сгруппировать в одной процедуре, поэтому код для Q0 в задачу не помещен. Код задачи реализован с использованием оператораswitch(Q), который анализирует текущее состояние для перехода на его выполнение. После выполнения очередного состояния осуществляется переключение на выполнение другой задачи. Отсчет текущего времени ведется с дискретностью 0,1с, поэтому сравнение с 10с означает сравнение с числом 100.

Для защиты критических областей в программе использованы операторы запрета прерывания при присвоении значения глобальной переменной xdSecзначению локальнойt. Так как переменнаяxdSecизменяется только в подпрограмме обработки прерывания по переполнению таймера, то запрещается для организации критической области только прерывание от таймера.

Рис.6.25. Алгоритм функционирования состояний Q4 задачи

"Управление выходными сигналами"

void CONTR_OUT(void) // Задача "Управление выходными сигналами"

{

char t;

// Защита критической области

GIMSK &= 0xBF; // Запрет прерывания по входу INT0 -

t = xdSec; // Значение глобальной переменной в локальную

GIMSK | = 0x40; // Разрешение прерывания по входу INT0

switch (Q) // Проверка номера текущего состояния

{

case Q1: /* Состояние Q1 */

if (Start)

{

Z = Z2; //Установка выходного вектора Z2

Q = Q2; //Установка нового состояния Q2

}

break;

case Q2: /* Состояние Q2 */

if (t>100)

{

Z = Z3; //Установка выходного вектора Z3

Q = Q3; //Установка нового состояния Q3

}

break;

case Q3: /* Состояние Q3 */

if (t>=300)

{

Z = Z4; //Установка выходного вектора Z4

Q = Q4; //Установка нового состояния Q4

}

break;

case Q4: /* Состояние Q4 */

if (t>=1000)

{

GIMSK |= Bit(MskInt0); //Разрешение прерывания по входу INT0

Q = Q1; //Установка нового состояния Q1

}

else if (t>=400) Z = Z1; //Установка выходного вектора Z1

break;

} // switch (Q)

}

Ниже приведена окончательная программа управления движением на перекрестке. Для простоты дальнейшей модификации программы все константы заменены идентификаторами при помощи командной строки #define, например:

PORTD | = 0x18; // зажечь Зг и Кв

PORTD & = 0x9C; // погасить Кг, Жг, Жв, Зв

GIMSK | = 0x40; // INT0 - разрешение прерывания, bit6=1

GIMSK & = 0xBF; // INT0 – запрет прерывания, bit6=0

реализовано путем определения констант:

#define Z1_On 0x18 // Включение ламп "1" выходного вектора Z1 – Зг и Кв

#define Z1_Off 0x9C // Выключение ламп "0" вых. вектора Z1 – Кг, Жг, Жв, Зв Кв

#define Z1 (Z1_On | PORTD & Z1_Off) // Выходной вектор Z1

#define MskInt0 0x40 // Маска прерывания по INT0 – разрешение прерывания

с соответствующим изменением в программе:

PORTD = Z1; //В порт PD установить выходной вектор Z1

GIMSK | = MskInt0 //Разрешение прерывания по входу INT0, установка bit6

GIMSK & = ~MskInt0 //Запрет прерывания по входу INT0, сброс бита bit6

// Программа управления движением на перекрестке

#include <io2313.h> //файл описания регистров tyni2313

#include <ina90.h> //файл процедур семейства АТ90Sxxxx

// Определение временных отрезков

#define Ligh_10 10*10 // 10 секунд – длительность горения желтого света

#define Ligh_30 10*30 // 30 секунд от начала цикла переключения

#define Ligh_40 10*40 // 40 секунд от начала цикла переключения

#define Ligh_100 10*100 //100 секунд от начала цикла переключения

// Определение выходных векторов по порту PORTD: bit6 – Кг, bit5 – Жг, bit4 – Зг,

// bit3– Кв, bit1 – Жв, bit0 – Зв

#define Z1_On 0x18 // Включение ламп "1" выходного вектора Z1 – Зг и Кв

#define Z1_Off 0x9C // Выключение ламп "0" вых. вектора Z1 – Кг, Жг, Жв, Зв

#define Z1 (Z1_On | PORTD & Z1_Off) // Выходной вектор Z1

#define Z2_On 0x2A // Включение ламп "1" выходного вектора Z2 – Жг, Кв и Жв

#define Z2_Off 0xAE // Выключение ламп "0" вых. вектора Z2 – Кг, Зг, Зв

#define Z2 (Z2_On | PORTD & Z2_Off) // Выходной вектор Z2

#define Z3_On 0x41 // Включение ламп "1" выходного вектора Z3 – Кг и Зв

#define Z3_Off 0xC5 // Выключение ламп "0" вых. вектора Z3 –Жг, Зг, Кв, Жв

#define Z3 (Z3_On | PORTD & Z3_Off) // Выходной вектор Z3

#define Z4_On 0x18 // Включение ламп "1" выходного вектора Z4 – Кг, Жг и Жв

#define Z4_Off 0x9C // Выключение ламп "0" вых. вектора Z4 – Зг, Кв, Зв

#define Z4 (Z4_On | PORTD & Z4_Off) // Выходной вектор Z4

// Определение масок прерывания

#define MskInt0 0x40 // Маска прерывания по INT0 – разрешение прерывания

#define MskTIE1 0x80 // Маска прерыв.по переполнению. таймера 1 – разреш. прер.

// Определение номеров состояний

#define Q1 1 // номер состояния Q1

#define Q2 2 // номер состояния Q2

#define Q3 3 // номер состояния Q3

#define Q4 4 // номер состояния Q4

// Определение периода счета таймера 1 равной 0,1с (частота 10Гц)

#define T1_H 0x3C // число для загрузки старшего байта таймера

#define T1_L 0xB0 // число для загрузки младшего байта таймера

// Определение

#define Z PORTD // определим переменную Z как порт PD

// Переменные

unsigned int xdSec; //xdSec - счетчик интервалов по 0,1с

char xStart; //признак начала цикла переключения светофора

char Q; // текущее значение номера состояния

// Прерывание по переполнению таймера Т1 (частота вызова – 10Гц)

interrupt [TIMER1_OVF1_vect] void TimerOverflow(void)

{

TCNT1H = T1_H; TCNT1L = T1_L; //Задание периода работы таймера – 10 Гц

хdSec++; //Счетчик тактов длительностью 0,1 с

if (хdSec > Ligh_100) хdSec = Ligh_100; // Ограничение счетчика времени

}

// Внешнее прерывание по входу INT0

interrupt [INT0_vect] void Int0(void)

{

хStart = 1; //Разрешение цикла переключения светофора

хdSec = 0; //Начало отсчета цикла переключения светофора

GIMSK &= ~MskInt0; // Запрет прерывания по входу INT0

}

// Инициализация контроллера

void INIT(void)

{

// Настройка таймера 1

TCCR1B | = 0x02; // коэффициент деления частоты генератора = 8

TCCR1B & = 0xFA;

TCNT1H = T1_H; TCNT1L = T1_L; //10Гц при частоте кварца 4МГц

// 4МГц/8/10Гц = 50000 = 0xC350;

//так как 16р таймер работает на увеличение,

//то загрузка его = 0x10000 – 0xC350 = 0x3CB0

// Настройка WATCHDOG - период сработки 2,0 с

_WDR(); // Сброс охранного таймера

WDTCSR | = 0x0F; // Разрешение работы охранного таймера и настройка

WDTCSR & = 0xDF; // период сработки 2,0 с

// Настройка портов

DDRD = 0x7B; //РD6, PD5, PD4, PD3, PD1, P0 – на выход, РD2 – на вход

// Начальные значения

//Установка выходного вектора Z1 на PORTD

Z = Z1; // зажечь Зг и Кв погасить Кг, Жг, Жв, Зв

Q=Q1; // задание начального состояния

// Настройка прерываний

TIMSK | = MskTIE1; // Таймер 1 - разрешение прерываний

GIMSK | = MskInt0; // INT0 - разрешение прерывания

_SEI(); // Разрешение глобального прерывания

}

// Задача "Управление выходными сигналами"

void CONTR_OUT (void)

{

char t; // текущее время

// Защита критической области

GIMSK & = ~ MskInt0; // Запрет прерывания по входу INT0 -

t = xdSec;

GIMSK | = MskInt0; // Разрешение прерывания по входу INT0

switch (Q) // Проверка номера текущего состояния

{

case Q1: /* Состояние Q1 */

if (Start)

{

Z = Z2; //Установка выходного вектора Z2

Q = Q2; //Установка нового состояния Q2

}

break;

case Q2: /* Состояние Q2 */

if (t> Ligh_10)

{

Z = Z3; //Установка выходного вектора Z3

Q = Q3; /Установка нового состояния Q3

}

break;

case Q3: /* Состояние Q3 */

if (t>= Ligh_30)

{

Z = Z4; //Установка выходного вектора Z4

Q = Q4; /Установка нового состояния Q4

}

break;

case Q4: /* Состояние Q4 */

if (t>= Ligh_100)

{

GIMSK | = MskInt0; //Разрешение прерывания по входу INT0

Q = Q1; //Установка нового состояния Q1

}

else if (t>= Ligh_40) Z = Z1; //Установка выходного вектора Z1

break;

} // switch (Q)

}

void main(void)

{

INIT(); //инициализация контроллера

// Бесконечный цикл

while (1)

{

CONTR_OUT; // Проверка сработки/нажатия и установка выходного вектора

_WDR(); // Сброс охранного таймера

}

}

Руководство программиста

Программа управления светофором написана на языке Си. Программа создана в соответствии с разработанным алгоритмом и состоит из четырех модулей: обработки прерывания таймера –TimerOverflow, обработки внешнего прерывания по входуINT0 -Int0,проверки флага сработки/нажатия и установки выходного состояния –CONTR_OUT, сброса охранного таймера –_WDR() и процедуры инициализации –INIT. Модули представляют собой отдельные задачи. С целью организации простой системы переключения задач в каждой из них выполняется только одно состояние, после чего осуществляется выход из задачи. Для организации приоритетного обслуживания использована система прерываний – две задачи (TimerOverflow и Int0) организованы как подпрограммы обработки прерываний. Переключение задач организовано путем помещения их в бесконечный циклwhile (1)в основной программеmain. Процедуры инициализации каждой задачи объединены в одной процедуреINIT.

Пояснения к программе. Период вызова прерыванияTIMERвыбран равным 0,1с (частота 10Гц);xdSec– переменная подсчета временных интервалов с дискретом в 0,1с. Временные задержки осуществляются путем сравнения содержимого переменнойxdSecс порогами перехода к очередному состоянию процесса. Пороги вычисляются суммированием заданных в ТЗ задержек, определяются в программе идентификаторамиLidht_10, …Lidht_100.

Период счета 16-разрядного таймера 10Гц при тактовой частоте 4МГц определяется числом А, перезагружаемым в подпрограмме прерывания TimerOverflow, и коэффициентом предделителя таймера =8. Так как таймер считает в режиме увеличения, то данное число вычисляется следующим образом:

4МГц/8/10Гц = 50000 = 0xC350 (шестнадцатеричная система);

А= 0x10000-0xC350 = 0x3CB0.

Сигналы управления светофором Кг…Зв обозначены константами Zi_On и Zi_Off для i-го выходного вектора. Zi_On определяет включаемые лампы, а Zi_Off – выключаемые. Полностью выходной вектор Zi определен в виде выражения, содержащего логические операции над константами Zi_On и Zi_Off. Это сделано, чтобы не изменялось текущее состояние остальных разрядов порта, не управляющих лампами светофора.

Сброс охранного таймера осуществляется библиотечной процедурой _WDR(). Период сброса установлен 2,0с в процедуре INIT.

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

Процедура interrupt [TIMER1_OVF1_vect]. Вызов процедуры осуществляется периодически, с частотой 10Гц. Входных и выходных параметров не имеет. В теле процедуры происходит увеличение переменной – текущего времени – xdSec на единицу.

Процедура interrupt [INT0_vect]. Вызов процедуры осуществляется отрицательным перепадом на входе INT0 микроконтроллера. Входных и выходных параметров не имеет. В теле процедуры устанавливается флаг разрешения цикла работы светофора (xStart = 1), сбрасывается счетчик времени цикла (xdSec = 0) и запрещается прерывание по входу INT0.

Процедура INIT. Процедура не имеет входных и выходных параметров. В теле процедуры осуществляется настройка таймера 1 на частоту переполнения 10Гц; программируется порт РD: РD2 – на вход, РD6...РD3, РD1, РD0 – на выход, устанавливается на его выходе вектор Z1; задается начальное значение состояния задачи управления выходными сигналами – Q = Q1; настраивается охранный таймер на период сработки 2,0с; разрешаются прерывания по векторам INT0 и TIMER1_OVF1 и разрешается глобальное прерывание _SEI().

Процедура CONTR_OUT. Процедура не имеет входных и выходных параметров. В теле процедуры осуществляется переход на текущее состояние, которое было задано в предыдущем цикле выполнения задачи. Цикл переключения состояний задается в подпрограммеInt0путем установкиxStart= 1. В каждом состоянии проверяются условия выхода (сравненияxdSecс порогом) и устанавливается выходной векторZи новое значение состоянияQдля периода выполнения задачи.

Основная программа main начинается с вызова процедурыINITи перехода к бесконечному циклу, в котором вызывается задача проверки флага сработки/нажатия и установления выходного состояния CONTR_OUT. В этом же цикле осуществляется сброс охранного таймера _WDR.