ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 23.11.2023
Просмотров: 124
Скачиваний: 8
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
14
Рассмотрим конечный автомат на примере программы, которая подсчи- тывает во вводимом тексте количество слов, состоящих только из заглавных букв. Основная идея в том, чтобы следить, были ли все уже введённые буквы текущего слова заглавными, и сохранять эту информацию в переменной, кото- рая называется “состояние”. Состояний у нас будет три: после ввода одного или нескольких пробелов, все введённые буквы текущего слова заглавные, и не
все введённые буквы слова заглавные.
Рисунок 1. Схема, поясняющая принцип работы конечного автомата
Эту схему нетрудно перенести в код на Си. После считывания символа со стандартного ввода мы сначала проверяем, в каком состоянии мы находимся, затем, в зависимости от состояния и поступившего символа, совершаем пере- ход в другое состояние или остаёмся в текущем.
Для использования конечных автоматов в Си есть оператор switch: int x; x = get_some_value(); switch(x) { case 0:
// Действие 0. break; case 1:
// Действие 1. break; case 2:
// Действие 2. break;
15 case 3:
// Действие 3. break; default:
// Действие для всех остальных x. break;
}
Из описанного выше происхождения оператора switch следуют некоторые его ограничения:
в switch(x) x должно быть переменной целого типа или выражением с результатом целого типа;
в case могут стоять только целые числа, и они должны быть константа- ми. Иначе при компиляции не получится сформировать таблицу переходов.
Кроме того, стоит обратить внимание на break в конце каждого действия.
Если его не поставить, то произойдёт переход к первой инструкции следующе- го действия. break в конце ветки default, которая выполнится, если не подошёл ни один case, поставлен просто для аккуратности. Отсутствие break является одной из частых ошибок. Чтобы не забывать break, рекомендуется писать его сразу же, как только написан case, а уже потом добавлять в case действия.
3.ПОРЯДОК ВЫПОЛНЕНИЯ ПРАКТИЧЕСКОЙ РАБОТЫ
Напишем программу с тремя вариантами горения четырех светодиодов.
Вариант будет выбираться пользователем командой с ПК. При отправке «1» светодиоды будут последовательно загораться через каждые четверть секунды, при отправке «2» светодиоды будут последовательно загораться в обратном по- рядке через каждые четверть секунды, при отправке «3» светодиоды будут за- гораться в порядке 1 – 4 – 3 – 2 с интервалом времени равном пол секунды. Для ввода команд необходимо открыть Serial Monitor (Инструменты – Монитор порта). Также в мониторе необходимо выставить скорость передачи данных как в написанной программе. int value = 0; int led1 = 2; int led2 = 4; int led3 = 6; int led4 = 3; void setup()
{
Serial.begin(9600); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT);
16 pinMode(led4, OUTPUT);
} void loop()
{ if (Serial.available())
{ value = Serial.read();
} switch(value)
{ case(1):
{ digitalWrite(led1, HIGH); delay(250); digitalWrite(led2, HIGH); delay(250); digitalWrite(led3, HIGH); delay(250); digitalWrite(led4, HIGH); delay(250); break;
} case(2):
{ digitalWrite(led4, HIGH); delay(250); digitalWrite(led3, HIGH); delay(250); digitalWrite(led2, HIGH); delay(250); digitalWrite(led1, HIGH); delay(250); break;
} case(3):
{ digitalWrite(led1, HIGH); delay(500); digitalWrite(led2, HIGH); delay(500); digitalWrite(led3, HIGH); delay(500); digitalWrite(led4, HIGH); delay(500);
17 break;
}
} digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, LOW); digitalWrite(led4, LOW);
}
Сначала объявляем переменную value, в которую будет записываться значение варианта горения светодиодов, и переменные ПИНов светодиодов.
Далее инициализируем UART со скоростью 9600 и настраиваем ПИНы свето- диодов на выход. В бесконечном цикле мы считываем данные из UART и запи- сываем их в переменную value. После, в зависимости от значения value, выпол- няется определенный вариант горения светодиодов.
4. ВАРИАНТЫ
Варианты горения светодиодов, выдержки времени и номера ПИНы (см.
Практическое занятие №3, рисунок 2) выбрать самостоятельно.
5. ОТЧЕТ
Отчет по практической работе должен содержать:
1. Наименование и цель работы.
2. Краткие теоретические данные по практической работе.
3. Код программы, написанной в соответствии с вариантом.
4. Вывод по проделанной работе.
ПРАКТИЧЕСКОЕ ЗАНЯТИЕ №5
Создание программы «бегущие огни»
с использованием прерываний по таймеру
1. ЦЕЛЬ ЗАНЯТИЯ
1. Изучить реализацию прерываний по таймеру в микроконтроллерах
ATmega328;
2. Написать программу по использованию прерываний по таймеру;
18 2. КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
Прерывание — это сигнал, который сообщает процессору, что нужно не- медленно остановить то, что он в настоящий момент делает, и произве- сти некоторые операции, имеющие высокий приоритет. Эта обработка с высо- ким приоритетом называется обработчиком прерываний (interrupt handler).
Обработчик прерывания (функция обработки прерывания, процедура об- работки прерывания) по-английски называется Interrupt Service Routine, или со- кращенно ISR, реагирует на событие и обслуживает его, после чего возвращает управление в прерванный код.
Если мы реализуем некоторую функцию и присоединим ее к прерыва- нию, то эта функция будет вызвана всякий раз, когда появится сигнал прерыва- ния. По возвращении из обработчика прерывания, процессор продолжит обра- батывать то, что он делал до прерывания.
Прерывания могут быть созданы несколькими источниками:
Одним из таймеров, формируя прерывания по таймеру;
Изменением состояния одного из входов внешних прерываний;
Изменение состояния одного из группы ПИНов.
2.1. ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА
Для начала работы с таймером необходимо его инициализировать путем настройки необходимых регистров. Разберем регистры таймера Т0 – TCNT0 и
TCNT0 (Счетный регистр), OCR0A и OCR0A (Регистры сравнения A и B),
TCCR0A и TCCR0B (Конфигурационные регистры A и B), TIMSK0 (Регистр по управлению прерываниями от таймера) и TIFR0 (Регистр флагов прерываний таймера).
1) Регистр TCNT0 (Счетный регистр)
Это 8-ми разрядный счетный регистр. Когда таймер работает, по каждому импульсу тактового сигнала значение TCNT0 изменяется на единицу. В зави- симости от режима работы таймера, счетный регистр может или увеличиваться, или уменьшаться. Регистр TCNT0 можно как читать, так и записывать. Послед- нее используется, когда требуется задать его начальное значение. Когда таймер работает, изменять его содержимое TCNT0 не рекомендуется, так как это бло- кирует схему сравнения на один такт.
2) Регистры OCR0A и OCR0B (Регистры сравнения)
19
Это 8-разрядные регистры сравнения. Его значение постоянно сравнива- ется со счетным регистром TCNT0, и в случае совпадения таймер может вы- полнять какие-то действия - вызывать прерывание, менять состояние вывода
OC0 и т.д. в зависимости от режима работы. Значение OCR0 можно как читать, так и записывать.
3) TCCR0A (Конфигурационный регистр А)
Биты 7:6 – COM1A 1:0: контролируют поведение выхода OC1A в зависи- мости от режима работы таймера (см. Таблицы 1, 2, 3, 4).
Таблица 1 – Нормальный режим
COM0A1 COM0A0
Описание состояния выхода
0 0 вывод OC0A не функционирует
0 1 изменение состояния вывода OC0A на противоположное при совпадении с A
1 0 сброс вывода OC0A в 0 при совпадении с A
1 1 установка вывода OC0A в 1 при совпадении с A
20
Таблица 2 – Режим коррекции фазы ШИМ
COM0A1 COM0A0
Описание состояния выхода
0 0 вывод OC0A не функционирует
0 1 если бит WGM02 регистра TCCR0B установлен в 0, вывод OC0A не функционирует если бит WGM02 ре- гистра TCCR0B установлен в 0, изменение состояния вывода OC0A на противоположное
1 0 сброс вывода OC0A в 0 при совпадении с A во время увеличения значения счетчика, установка вывода
OC0A в 1 при совпадении с A во время уменьшения значения счетчика
1 1 установка вывода OC0A в 1 при совпадении с A во время увеличения значения счетчика, сброс вывода
OC0A в 0 при совпадении с A во время уменьшения значения счетчика
Таблица 3 – CTC режим работы таймера
COM0A1 COM0A0
Описание состояния выхода
0 0 вывод OC0A не функционирует
0 1 изменение состояния вывода OC0A на противоположное при совпадении с A
1 0 сброс вывода OC0A в 0 при совпадении с A
1 1 установка вывода OC0A в 1 при совпадении с A
Таблица 4 – Работа таймера в режиме ШИМ
COM0A1 COM0A0
Описание состояния выхода
0 0 вывод OC0A не функционирует
0 1 если бит WGM02 регистра TCCR0B установлен в 0, вывод OC0A не функционирует если бит WGM02 регистра TCCR0B установлен в 1, изменение состояния вывода OC0A на противополож- ное при совпадении с A
1 0 сброс вывода OC0A в 0 при совпадении с A, установка вывода OC0A в 1 если регистр TCNT0 принимает зна- чение 0x00 (неинверсный режим)
1 1 установка вывода OC0A в 1 при совпадении с A, установка вывода OC0A в 0 если регистр TCNT0 принимает значение 0x00 (инверсный режим)
Биты 5:4 – COM1B 1:0: контролируют поведение выхода OC1B в зависи- мости от режима работы таймера (см. Таблицы 5, 6, 7, 8).
21
Таблица 5 – Нормальный режим
COM0B1 COM0B0
Описание состояния выхода
0 0 вывод OC0B не функционирует
0 1 изменение состояния вывода OC0B на противоположное при совпадении с B
1 0 сброс вывода OC0B в 0 при совпадении с B
1 1 установка вывода OC0B в 1 при совпадении с B
Таблица 6 – Режим коррекции фазы ШИМ
COM0B1 COM0B0
Описание состояния выхода
0 0 вывод OC0B не функционирует
0 1 резерв
1 0 сброс вывода OC0B в 0 при совпадении с B во время увеличения значения счетчика, установка вывода
OC0B в 1 при совпадении с B во время уменьшения значения счетчика
1 1 установка вывода OC0B в 1 при совпадении с B во время увеличения значения счетчика, сброс вывода
OC0B в 0 при совпадении с B во время уменьшения значения счетчика
Таблица 7 – CTC режим работы таймера
COM0B1 COM0B0
Описание состояния выхода
0 0 вывод OC0B не функционирует
0 1 изменение состояния вывода OC0B на противоположное при совпадении с B
1 0 сброс вывода OC0B в 0 при совпадении с B
1 1 установка вывода OC0B в 1 при совпадении с B
Таблица 8 – Работа таймера в режиме ШИМ
COM0B1 COM0B0
Описание состояния выхода
0 0 вывод OC0B не функционирует
0 1 резерв
1 0 сброс вывода OC0B в 0 при совпадении с B, установка вывода OC0B в 1 если регистр TCNT0 принимает зна- чение 0x00 (неинверсный режим)
1 1 установка вывода OC0B в 1 при совпадении с B, уста- новка вывода OC0B в 0 если регистр TCNT0 прини- мает значение 0x00 (инверсный режим)ывода OC0B в
0 если регистр TCNT0 принимает значение 0x00 (ин- версный режим)
22
Биты 3:2 – Не используются.
Биты 1:0 – WGM01, WGM00 служат для настройки режима работы. Всего их может быть четыре - нормальный режим (normal), сброс таймера при совпа- дении (CTC), и два режима широтно-импульсной модуляции (FastPWM(Режим
ШИМ) и Phase Correct PWM (Режим коррекции фазы ШИМ)). Все возможные значения описаны в таблице 9.
Таблица 9 – Настройка режима работы
WGM02
WGM01
WGM00
Режим работы таймера
0 0
0
Normal
0 0
1
Phase Correct PWM
0 1
0
CTC
0 1
1
Fast PWM
1 0
0
Резерв
1 0
1
Phase Correct PWM
1 1
0
Резерв
1 1
1
Fast PWM
4) TCCR0B (Конфигурационный регистр А)
Биты 7:6 –
FOC0A и FOC0B принудительно устанавливают значение на выводах OC0A и OC0B.
Бит 3 – WGM00 служит для настройки режима работы (см. Таблицу 9)
Биты 2:0 – CS02, CS01, CS00 устанавливают режим тактирования и пред- делителя тактовой частоты таймера/счетчика T0:
Таблица 10 – Режимы тактирования
CS02
CS01
CS00
Режимы тактирования
0 0
0 таймер/счетчик T0 остановлен
0 0
1 тактовый генератор CLK
0 1
0
CLK/8 0
1 1
CLK/64 1
0 0
CLK/256 1
0 1
CLK/1024 1
1 0 внешний источник на выводе T0 по спаду сигнала
1 1
1 внешний источник на выводе T0 по возрастанию сигнала
23 5) TIMSK0 (Регистр управления прерываний таймеров)
Биты 2:1 –
OCIEB и OCIEA разрешают прерывания при совпадении с A и
B, а бит 0 – TOIE разрешает прерывание по переполнению при установке 1. Ес- ли в эти биты записать 0, прерывания от таймера/счетчика будут запрещены.
6) TIFR0 (Регистр флагов прерываний таймеров)
Биты 2:1 –
OCFB и OCFA устанавливаются в 1 при совпадении с счетного регистра с регистром сравнения (A и B), а бит 0 – TOV устанавливается в 1 при переполнении счетного регистра.
2.2. ПРЕРЫВАНИЯ ПО ТАЙМЕРУ
В микроконтроллере ATmega328 прерывания по таймеру можно произво- дить двумя способами:
По переполнению таймера;
По совпадении значения с регистром сравнения OCR**.
За активацию прерывания по таймеру отвечает регистр TIMSK*.
Биты 2:1 –
OCIEB и OCIEA разрешают прерывания при совпадении с ка- налом A и каналом B, а бит 0 – TOIE разрешает прерывание по переполнению при установке 1. Если в эти биты записать 0, прерывания от таймера/счетчика будут запрещены.
3.ПОРЯДОК ВЫПОЛНЕНИЯ ПРАКТИЧЕСКОЙ РАБОТЫ
Напишем программу, которая каждую секунду будет зажигать последова- тельно каждый из четырех светодиодов. После зажигания последнего светоди- ода цикл повторяется.
24
#include
#include
{
TCCR1A |= (1<
TCNT1 = 0;
OCR1A = 1999;
} void setup()
{ long counter = 1; int led1 = 2; int led2 = 4; int led3 = 6; int led4 = 3;
InitTimer (); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(led4, OUTPUT);
}
ISR(TIMER0_COMPA_vect)
{ if (counter <= 4000)
{ counter++;
} else
{ counter = 0;
}
} void loop()
{ switch(counter)
{ case(1000):
{ digitalWrite(led1, HIGH); digitalWrite(led2, LOW);