Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка пргр МП.docx
Скачиваний:
11
Добавлен:
01.07.2025
Размер:
16 Мб
Скачать
☆

Б.2.3.2 Пояснения для вариантов заданий с использованием звукового излучателя

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

Для управления звуковым излучателем используется регистр ПЛИС ENA (адрес 080004h). 2-4 биты регистра ENA управляют величиной напряжения на динамике, т.е. позволяют задавать громкость звука2: чем больше «единиц» выставлено в этих битах, тем громче звук. Частота звука задается частотой смены нулей и единиц в управляющих битах регистра ENA. Ниже, в табл. 15, приведены частоты нот первой октавы.

Таблица 15. Частоты музыкальных нот

Нота

Частота, Гц

До

261,63

Ре

293,67

Ми

329,63

Фа

349,22

Соль

391,99

Ля

440,00

Си

493,88

Частоты нот каждой соседней октавы отличаются в 2 раза. Например, частота ноты «ля» второй октавы 880 Гц.

Б.2.4 Особенности обработки прерываний в стенде SDK-1.1

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

Таблица 16. Адреса векторов прерывания микроконтроллера ADuC812

Прерывание

Наименование

Адрес вектора

PSMI

Монитор источника питания ADuC812

43H

IE0

Внешнее прерывание INT0

03H

ADCI

Конец преобразования АЦП

33H

TF0

Переполнение таймера/счетчика 0

0BH

IE1

Внешнее прерывание INT1

13H

TF1

Переполнение таймера/счетчика 1

1BH

I2CI/ISPI

Прерывание от I2C/SPI

3BH

RI/TI

Прерывание от UART

23H

TF2/EXF2

Переполнение таймера/счетчика 2

2BH

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

Таблица 17. Порядок обработки прерываний с одинаковым уровнем приоритета

Источник

Очередность

Описание

PSMI

1 (Наивысшая)

Монитор источника питания ADuC812

IE0

2

Внешнее прерывание INT0

ADCI

3

Конец преобразования АЦП

TF0

4

Переполнение таймера/счетчика 0

IE1

5

Внешнее прерывание INT1

TF1

6

Переполнение таймера/счетчика 1

I2CI+ISPI

7

Прерывание от I2C/SPI

RI+TI

8

Прерывание от UART

TF2+EXF2

9 (Низшая)

Переполнение таймера/счетчика 2

Прерывания ADuC812 имеют вектора в диапазоне 0003h-0043h, которые попадают в область младших адресов памяти программ. Это пространство соответствует 8Кб (0000h-2000h) FLASH-памяти.

В стенде SDK-1.1 пользователь не имеет возможности записи во FLASHпамять (запись программ осуществляется во внешнюю память программ и данных), следовательно, не может подставить свои процедуры обработки прерываний (точнее, команды перехода к процедурам) по адресам, соответствующим векторам прерываний.

Проблема использования прерываний в пользовательских программах решается следующим образом (см. рис. 128):

  1. По адресам (0003h-0043h) векторов прерываний во FLASH-памяти SDK-1.1 располагаются команды переходов на вектора пользовательской таблицы, размещенной в адресах 2003h-2043h.

  2. По адресам векторов пользовательской таблицы пользователем указываются команды переходов на процедуры обработки прерываний.

Приведем пример помещения собственного вектора в пользовательскую таблицу. Программа использует прерывание от таймера 0 (прерывание 0Bh) для зажигания линейки светодиодов. Данный пример адаптирован для компилятора SDCC. По сравнению с компилятором Keil C51 изменения коснулись функции SetVector (в связи с тем, что компилятор SDCC и микроконтроллер ADuC812 используют различные способы записи многобайтовых чисел в памяти; SDCC – little-endian, ADuC812 – big-endian) и заголовка функции обработчика прерывания (T0_ISR).

#include "aduc812.h"

#define MAXBASE 8

///////////////////////// WriteMax /////////////////////////// // Запись байта в регистр ПЛИС

// Вход:

// regnum – адрес регистра ПЛИС, // val – записываемое значение.

// Выход: нет.

// Результат: нет.

////////////////////////////////////////////////////////////// void WriteMax (unsigned char xdata *regnum, unsigned char val)

{

// Сохранение текущего значения регистра страниц unsigned char oldDPP = DPP;

DPP = MAXBASE;

// Установка адреса страницы ПЛИС

*regnum = val;

// Запись значения в регистр ПЛИС

DPP = oldDPP;

// Восстановление сохраненного значения

// регистра страниц

}

//////////////////////// WriteLED ///////////////////////////

// Функция установки состояния линейки светодиодов.

// Вход:

// value – состояния светодиодов.

// Выход: нет.

// Результат: нет.

////////////////////////////////////////////////////////////// void WriteLED(unsigned char value)

{

// Запись состояния светодиодов в регистр 7-й регистр ПЛИС

WriteMax( 7, value );

}

//////////////////////// T0_ISR //////////////////////////////

// Обработчик прерывания от таймера 0.

// Вход: нет.

// Выход: нет.

// Результат: нет.

////////////////////////////////////////////////////////////// void T0_ISR( void ) __interrupt ( 1 )

{

WriteLED( 0x55 ); // Зажигание светодиодов (через один) }

//////////////////////// SetVector ////////////////////////// // Функция, устанавливающая вектор прерывания в

// пользовательской таблице прерываний.

// Вход:

// Vector – адрес обработчика прерывания,

// Address – вектор пользовательской таблицы прерываний.

// Выход: нет.

// Результат: нет.

////////////////////////////////////////////////////////////// void SetVector(unsigned char xdata * Address, void * Vector)

{ unsigned char xdata * TmpVector; // Временная переменная

// Первым байтом по указанному адресу записывается

// код команды передачи управления ljmp, равный 02h

*Address = 0x02;

// Далее записывается адрес перехода Vector

TmpVector = (unsigned char xdata *) (Address + 1);

*TmpVector = (unsigned char) ((unsigned short)Vector >> 8);

++TmpVector;

*TmpVector = (unsigned char) Vector;

// Таким образом, по адресу Address теперь

// располагается инструкция ljmp Vector

}

//////////////////////// Main ////////////////////////////////

// Главная функция

////////////////////////////////////////////////////////////// void main( void )

{

TH0 = 0xFF;

// Инициализация таймера 0

TL0 = 0xF0;

//

TMOD = 0x01;

//

TCON = 0x10;

//

// Установка вектора в пользовательской таблице

SetVector( 0x200B, (void *)T0_ISR );

// Разрешение прерываний от таймера 0

ET0 = 1; EA = 1;

while( 1 );

}

В ходе выполнения лабораторной работы производится ознакомление с организацией и принципом работы не только таймеров/счетчиков по прерываниям, но и внешних прерываний INT0/INT1. Необходимо отметить, что в случае последних возможны следующие настройки: по перепаду (фронт или спад напряжения) или по уровню напряжения на внешнем входе. В контроллере SDK-1.1 линии счетного входа таймера/счетчика 0/1 (T0/1) и внешних прерываний INT0/INT1 выведены на DIP-переключатели SW3-1 (см. рис. 129).

Рис. 129. Расположение линий T0/1 и INT0/1 МК ADuC812 (справа) и их вывод на DIP-переключатели