Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Методическое пособие 539

.pdf
Скачиваний:
8
Добавлен:
30.04.2022
Размер:
2.16 Mб
Скачать

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

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

#include <stdio.h> #include <REG52.H> sbit Bit0 = P1^0; void main(void)

{

SCON = 0x50; TH1 = 0xFD; TMOD |= 0x20; TR1 = 1;

TI = 1; while (1)

{

printf(“Press Enter to reverse a bit P1.0\n”); getchar();

Bit0 = ~Bit0;

}

}

При вводе символа с последовательного порта инвертируется бит 0 порта P1. Выполним сборку программы и запустим ее на выполнение через меню Debug →Start/Stop Debug Session → Run. Мы хотим посмотреть, как работает ввод символов через последовательный порт, и проверить состояние бита 0 порта P1. Чтобы просмотреть прием символов с последовательного порта с помощью функции getchar, выберем

51

меню View → Serial Window →UART #0. Желательно посмотреть, будет ли инвертироваться бит 0. Для этого нужно в меню Peripherals →I/O–Ports выбрать опцию Port 1 (рис. 2.2).

Рис. 2.2. Выбор порта ввода/вывода

После этого появится небольшое диалоговое окно с обозначениями выводов порта P1, которые будут отображать состояние битов (рис. 2.3).

Рис. 2.3. Индикация состояния выводов порта Р1

52

Теперь, если перейти в окно UART #0 и нажать несколько раз клавишу Enter, то можно наблюдать изменения в нулевом бите (рис. 2.4).

Рис. 2.4. Индикация ввода/вывода программы и состояния порта

Рассмотрим, как симулируется работа прерывания INT0 в Keil uVision. Откомпилируем и скомпонуем следующую программу.

#include <stdio.h> #include <REG52.H> sbit Bit0 = P1^0;

void INT0Isr (void) interrupt 0 using 1 { EX0 = 0;

53

Bit0 = ~Bit0;

printf(“Interrupt 0 occured.\n”);

EX0 = 1;

}

void main(void)

{

SCON = 0x50; TH1 = 0xFD; TMOD |= 0x20; TR1 = 1;

TI = 1;

IT0 = 1;

EX0 = 1;

EA = 1; while (1);

}

В этой программе используется программа-обработчик внешнего прерывания 0 (INT0). Каждый раз при возникновении прерывания в последовательный порт выводится соответствующее сообщение и инвертируется бит 0 порта P1. Поскольку вывод данных в последовательный порт занимает относительно длительное время, в течение которого могут произойти новые прерывания, то на время передачи строки функцией printf внешнее прерывание 0 блокируется.

Для симуляции работы программы помимо двух окон отладки, используемых в предыдущем примере, нужно выбрать меню Peripherals →Interrupt (рис. 2.5).

54

Рис. 2.5. Симуляция работы прерывания

Обратите внимание на диалоговое окно Interrupt System. Если выбрать строку P3.2/Int0, то внизу появится строка устанавливаемых флагов для данного прерывания. Поскольку внешнее прерывание 0 может вызываться при установке флага IE0, то для моделирования возникновения/прекращения прерываний можно ставить или снимать отметку на флажке IE0 (рис. 2.6).

55

Рис. 2.6. Имитация вызова прерывания

При вызове прерывания будет изменяться и значение бита P1.0, что можно наблюдать в диалоговом окне Parallel Port

1.

При работе с портами ввода/вывода следует учитывать аппаратные особенности микроконтроллеров 8051, связанные с записью/чтением. Для записи данных в порт нужно просто выполнить оператор присваивания (в языке C), возможно, в комбинации с логическими побитовыми операциями (если требуется оперировать с отдельными битами). Можно оперировать с отдельными битами порта, для удобства присвоив им какое-либо имя. Например, для установки бита P1.7 в единичное состояние можно выполнить оператор

P1 |= 0x80;

При этом остальные биты порта P1 остаются нетронутыми. Для той же цели можно использовать и другой подход, назначив биту P1.7 переменную, после чего просто присваивать этой переменной нужное значение, например:

56

sbit bit0 = P1.7;

. . .

bit0 = 1;

Этот фрагмент программного кода выполняет те же действия, что и предыдущий оператор, устанавливая бит P1.7 в единичное состояние. Чтение данных с портов ввода/вывода отличается от записи тем, что предварительно в бит, значение которого нужно прочитать, записывается 1. В этом случае данные будут считаны не с внутреннего регистра-защелки данного бита, а с вывода порта микроконтроллера.

Для иллюстрации чтения/записи через порты ввода/вывода рассмотрим пример программы, исходный текст которой приведен ниже:

#include <stdio.h> #include <REG52.H> sbit Bit0 = P1^7;

void INT0Isr (void) interrupt 0 using 1 { EX0 = 0;

if (Bit0)

printf(“Bit P1.7 is set.\n”); else

printf(“Bit P1.7 is reset.\n”);

EX0 = 1;

}

void main(void)

{

SCON = 0x50; TH1 = 0xFD; TMOD |= 0x20; TR1 = 1;

TI = 1;

IT0 = 1;

EX0 = 1;

57

EA = 1; while (1);

}

Здесь при вызове прерывания INT0 считывается значение бита P1.7 с вывода микроконтроллера. Если скомпилировать эту программу и запустить ее в отладчике Keil, то при записанной в регистре-защелке P1.7 единице значение бита можно прочитать; если же в защелке записан 0, бит порта работает как выходной, поэтому данные, считанные с вывода P1.7 (не с защелки!) могут быть некорректными. Симулятор Keil отслеживает подобные ситуации, выдавая сообщение

(рис. 2.7).

Рис. 2.7. Моделирование ошибочной ситуации

58

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

Откомпилируем и запустим в симуляторе программу, исходный текст которой сохранен в файле debug_memo.c и имеет вид:

#include <stdio.h> #include <REG52.H> idata char COUNTER = 0;

void INT0Isr (void) interrupt 0 using 1 { COUNTER++;

if (COUNTER == 11) COUNTER = 0;

}

void main(void)

{

SCON = 0x50; TH1 = 0xFD; TMOD |= 0x20; TR1 = 1;

TI = 1;

IT0 = 1;

EX0 = 1;

EA = 1; while (1);

}

Предположим, что нужно наблюдать за изменениями переменной COUNTER. Откомпилируем исходный текст программы и запустим на отладку абсолютный объектный модуль. В меню View выберем опции Memory Window и Symbol Window (рис. 2.8).

59

Рис. 2.8. Симуляция работы с памятью

В области Symbols найдем адрес переменной COUNTER, значение которой нужно отслеживать, и введем его в область Memory в правом нижнем углу (рис. 2.9).

60