Uploaded by vitaliy.zhdanov.3000

Порты ввода и выводы

advertisement
Цель работы: научиться программировать порты ввода-вывода,
перехватывать и обрабатывать прерывания.
Задача 1. Состояние четырех светодиодов соответствует состоянию
четырех кнопок, присутствующих на плате, таким образом, что нажимание
кнопки приводит к зажиганию светодиода, а отжимание – гасит его.
Решение
В данной работе используется плата Arduino UNO с
микроконтроллером ATMEGA128P.
Для начала необходимо обратиться к регистру и проинициализировать
пины на портах, в моем случае на порте B -светодиоды, а на порте D –
кнопки. Для того чтобы обратиться к регистру воспользуемся командой
DDRB, для обращения к порту B, и DDRD, для обращения к порту D.
Начнем с порта D, т. к. данный порт, в моем случае, должен
принимать сигнал, т. е. вход сигнала, воспользуемся и объявим порты входа
(пины 3,4,5,6) в виде шестнадцатеричного кода (0x78). Данная команда
будет выглядеть следующим образом: DDRD &= ~0x78.
Аналогично для порта B, только в данном случае объявим порты на
«выход», порты будут отдавать сигнал. Используемые пины: 2,3,4,5. В виде
шестнадцатеричного кода выглядит так: 0x3C. Данная команда будет
выглядеть следующим образом: DDRB |= 0x3C.
Для того чтобы сравнивать значение с каждого пина на порте D,
можем воспользоваться командой PIND и написать пин который хотим
сравнить. Для того чтобы отправить сигнал на порт B, воспользуемся
командой PORTB.
Далее для работы системы включим бесконечный цикл while(1). В данном
цикле мы будем сравнивать значение с пинов на порту D и сравнивать с
нулем. Если значение будет не равным нулю, тогда загорится один из
светодиодов. Так же не стоит забывать про сдвиг единицы, для 2 второго пина
на порте D необходимо единицу сдвинуть влево на два(1<<2), для третьего
пина (1<<3) и т.д.
Блок схема
Код программы
int main ()
{
DDRD &= ~0x78; //Инициализация кнопок(порты на вход)на ветке D
DDRB |= 0x3C; //Инициализация светодиодов(порты на выход) на ветке B
while(1){
if((PIND&0x40)!=0) PORTB |= 1<<5; else PORTB &= ~(1<<5);
if((PIND&0x20)!=0) PORTB |= 1<<4; else PORTB &= ~(1<<4);
if((PIND&0x10)!=0) PORTB |= 1<<3; else PORTB &= ~(1<<3);
if((PIND&0x08)!=0) PORTB |= 1<<2; else PORTB &= ~(1<<2);
}
return 0;
}
Задача 2. Состояние четырех светодиодов соответствует состоянию
четырех кнопок, присутствующих на плате, по сложной функции,
Светодиод 1
Светодиод 2
Светодиод 3
Светодиод 4
Кнопка 1
+
Кнопка 2
+
+
Кнопка 3
+
+
Кнопка 4
+
где «+» означает необходимость нахождения кнопки из строки в
состоянии «нажата» для зажигания светодиода из столбца, «-» означает
необходимость нахождения кнопки из строки в состоянии «отжата» для
зажигания светодиода, пустое место означает, что состояние кнопки из
строки не влияет на состояние светодиода из столбца.
Светодиод должен зажигаться, если выполняются все условия.
Решение
Разберем работу первого светодиода. Для того чтобы он зажегся необходимо
выполнить условие: если первая кнопка зажата, если вторая кнопка отжата,
если третья кнопка нажата, если третья кнопка отжата, то загорится первый
светодиод. Для упрощения сначала воспользуемся двоичным кодом с порта
D, где расположены кнопки: 0b01111000. По условию задачи мы должны
данное двоичное значение сравнить с 0b01010000 и светодиод загорится.
Переведем в шестнадцатеричную систему 0x78 == 0x28. Аналогично для
других светодиодов.
Блок схема
Код программы
int main ()
{
DDRD &= ~0x78; //Инициализация кнопок (порты на вход)на ветке D
DDRB |= 0x3C; //Инициализация светодиодов (порты на выход) на ветке B
while(1){
if((PIND&0x10)== 0x10) PORTB |= 1<<5; else PORTB &= ~(1<<5);
if((PIND&0x28) == 0x00) PORTB |= 1<<4; else PORTB &= ~(1<<4);
if((PIND&0x70) == 0x70) PORTB |= 1<<3; else PORTB &= ~(1<<3);
if((PIND&0x78)== 0x28) PORTB |= 1<<2; else PORTB &= ~(1<<2);
}
return 0;
}
Задача 3. Смена состояния четырех светодиодов происходит по
клику на соответствующие кнопки. Реализовать данное задание двумя
способами: с помощью периодического опроса состояний кнопок и с
помощью прерываний.
Решение
Способ 1. Инициализация пинов представлена выше. Для решение
данной задачи необходимо создать переменную, я ее назвал «saved» и
присвоим ей значение 0x00. С помощью данной переменной мы будем
сохранять значение с пинов, на которых была единица и на которых ее не
было или наоборот убрали. В основной программе мы будем сигнал
идущий с порта D и сохраненное значение. Если нажать на одну кнопку то
светодиод загорится, если нажать повторно то затухнет. Но наши тактовые
кнопки не идеальны. Во время переключения состояния наша тактовая
кнопка имеет небольшие помехи из-за которых состояние может не
переключится. Исправим это добавив ожидание в одну секунду с помощью
цикла for. Так же не забываем про текущее значение с пинов D. Мы должны
сохранять каждое текущее значение с порта D перед проверкой нажатия
клавиш.
Блок схема для 1 способа и второго
Код программы
int main ()
{
DDRD &= ~0x1E; //Инициализация кнопок(порты на вход) на ветке D 3..6
порты
DDRB |= 0x3C; //Инициализация кнопок(порты на выход) на ветке B 10..13
порты
int saved_value = 0x00, cur_value = 0x00;
int c; //константа
while(1){
cur_value = PIND;
if ((cur_value & 0x08) == 0x08 && (saved_value & 0x08) == 0x00)
PORTB ^= 0x04;
if ((cur_value & 0x10) == 0x10 && (saved_value & 0x10) == 0x00)
PORTB ^= 0x08;
if ((cur_value & 0x20) == 0x20 && (saved_value & 0x20) == 0x00)
PORTB ^= 0x10;
if ((cur_value & 0x40) == 0x40 && (saved_value & 0x40) == 0x00)
PORTB ^= 0x20;
saved_value = PIND;
for (volatile int i=0; i < 1000; i++){c++;} // ожидание одну секунду
}
}
Способ 2. Инициализация пинов представлена выше. Для решения
данной задачи необходимо воспользоваться прерыванием. Для начала
разрешим глобальное воспользуемся командой SREG и поставим 7 пин в 1,
таким образом мы разрешим глобальное прерывание. Данная команда будет
выглядить следующим образом: SREG |= 0x80. Далее разрешим глобальное
прерывание на 2 порте (порт D) с помощью команды PCICR. Данная
команда будет выглядеть следующим образом: PCICR |= 0x04. Глобальное
прерывание и прерывание на порте D разрешили, теперь необходимо
разрешить прерывание на пинах 3…6, для этого воспользуемся PCMSK2,
команды выглядит следующим образом: PCMSK2 |= 0x78. Далее
необходимо создать бесконечный цикл , для того чтобы программа не
завершалась, и воспользуемся вектором прерывания PCINT2_vect с
помощью команды обработчика прерываний ISR. Внутри обработчика
происходит прерывание порта D и сохранение значений.
Код программы
int main ()
{
DDRD &= ~0x78; //Инициализация кнопок(порты на вход) на ветке D 3..6
порты
DDRB |= 0x3C; //Инициализация кнопок(порты на выход) на ветке B 10..13
порты
SREG |= 0x80; //Глобальное разрешение прерываний
PCICR |= 0x04; //Разрежение прерываний на порте D(2 порт)
PCMSK2 |= 0x78; //Разрешение прерываний на пинах 3-6 порта D
while(1){
}
}
ISR(PCINT2_vect)
{
PCICR &=~ 0x04;
if ((PIND & 0x08) == 0x08) PORTB ^= 0x04;
if ((PIND & 0x10) == 0x10) PORTB ^= 0x08;
if ((PIND & 0x20) == 0x20) PORTB ^= 0x10;
if ((PIND & 0x40) == 0x40) PORTB ^= 0x20;
PCICR |= 0x04;
}
Download