Скачиваний:
35
Добавлен:
09.05.2014
Размер:
347.14 Кб
Скачать

Санкт-Петербургский государственный университет

информационных технологий, механики и оптики

(СПбГУ ИТМО)

Кафедра вычислительной техники

Лабораторная работа № 4

«Последовательный интерфейс I2C»

Вариант № 4

Работу выполнили:

Студенты группы 4103

Голубцов Евгений

Рябинина Александра

Санкт-Петербург

2010

Задание

Разработать и написать драйвер интерфейса I2C для учебно-лабораторного стенда SDK-1.1. Написать программу для разработанного драйвера, которая выполняет определенную вариантом прикладную задачу.

Описание работы

Данная лабораторная работа посвящена изучению последовательного интерфейса I2С и устройств, подключенных по этому интерфейсу к микроконтроллеру ADuC812 стенда SDK-1.1, – энергонезависимая память EEPROM и часы реального времени (RTC).

В рамках лабораторной работы необходимо разработать программу для контроллера SDK-1.1, которая выполняет конкретную прикладную задачу (см. варианты задания). Реализация задачи требует знания материалов предыдущих лабораторных работ: таймеры микроконтроллера ADuC812, последовательный канал, светодиодные индикаторы, клавиатура, ЖКИ, звуковой излучатель и др.

4. “Будильник”. На одной из строк ЖКИ отображается текущее время в формате «hh:mm:ss». На другой строке ЖКИ отображается время срабатывания будильника в таком же формате. Чтобы отличать одну строку от другой, можно использовать какой-нибудь специальный символ. Введение текущего времени и нового времени срабатывания будильника организовано по последовательному каналу со стороны персонального компьютера с помощью терминальной программы. Для этого нужно реализовать систему меню из соответствующих двух пунктов. Формат ввода времени такой же, как и на ЖКИ. Некорректный ввод должен быть блокирован.

При наступлении времени срабатывания будильника запускается проигрывание мелодии с помощью звукового пьезоизлучателя контроллера SDK-1.1. После нажатия кнопки клавиатуры контроллера SDK-1.1 сигнал будильника перестает звучать.

Следует уделить особое внимание тому, что функция будильника реализуется на основе часов реального времени.

В рамках задания необходимо реализовать:

• драйвер I2C;

• драйвер часов реального времени (RTC);

• драйвер последовательного канала по прерыванию;

• драйвер ЖКИ;

• драйвер таймера;

• драйвер звукового излучателя;

• драйвер клавиатуры.

Текст программы.

• драйвер I2C

#include "aduc812.h"

#include "i2c.h"

/*----------------------------------------------------------------------------

Функции

-----------------------------------------------------------------------------*/

/**-

Задержка на время порядка 25 мкс.

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

static void delay( void )

{

char ch = 0;

while( ch++ < 2 );

}

/**----------------------------------------------------------------------------

send_byte()

-------------------------------------------------------------------------------

Посылка по I2C байта (8 бит) и ожидание подтверждения (acknowledge).

Вход: uchar ch - байт, который нужно послать.

Выход: нет

Результат: 0 - подтверждение (acknowledge) получено

1 - не было подтверждения

----------------------------------------------------------------------------- */

static bit send_byte( unsigned char ch ) //Returns ack (0 = acknowledged)

{

char i;

bit ack;

MDE = 1; //Бит разрешения передачи данных (1- передача, 0 - прием)

MCO = 0; //Бит выходного синхроимпульса

for( i = 0 ; i < 8; i++, ch <<= 1 )

{

MDO = ( ch & 0x80 ) ? 1 : 0 ; // передаем по биту на линию SDATA

MCO = 1;

delay();

MCO = 0;

}

MDE = 0; //Бит разрешения передачи данных (1- передача, 0 - прием)

MCO = 1;

delay();

ack = MDI; // Бит входных данных

MCO = 0;

return ack;

}

/**----------------------------------------------------------------------------

start()

-------------------------------------------------------------------------------

Установка состояния Start интерфейса i2c.

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

static void start(void)

{

MDE = 1; //Бит разрешения передачи данных (1- передача, 0 - прием)

MDO = 1; //Бит выходных данных (выдвигаются на линию SDATA)

MCO = 1; //Бит выходного синхроимпульса

delay();

MDO = 0;

delay();

MCO = 0;

}

/**----------------------------------------------------------------------------

stop()

-------------------------------------------------------------------------------

Установка состояния Stop интерфейса i2c.

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

static void stop(void)

{

MDE = 1; //Бит разрешения передачи данных (1- передача, 0 - прием)

MCO = 0; //Бит выходного синхроимпульса

MDO = 0; //Бит выходных данных (выдвигаются на линию SDATA)

MCO = 1;

delay();

MDO = 1;

delay();

MDE = 0; //Бит разрешения передачи данных (1- передача, 0 - прием)

}

/**----------------------------------------------------------------------------

begin()

-------------------------------------------------------------------------------

Начало сессии на интерфейсе i2c (Start + посылка i2c-адреса slave-устройства).

Вход: uchar addr - i2c-адрес slave-устройства

Выход: нет

Результат: 0 - устройство откликнулось (получено acknowledge)

1 - устройство не откликнулось

----------------------------------------------------------------------------- */

static bit begin( unsigned char addr )//Returns ack (0 = acknowledged)

{

start();

return send_byte( addr );

}

/**----------------------------------------------------------------------------

Ack()

-------------------------------------------------------------------------------

Посылка подтверждения (acknowledge) устройству.

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

static void ack( void )//Sends ack

{

MDE = 1; //Бит разрешения передачи данных (1- передача, 0 - прием)

MCO = 0; //Бит выходного синхроимпульса

MDO = 0; //Бит выходных данных (выдвигаются на линию SDATA)

MCO = 1;

delay();

MCO = 0;

}

/**----------------------------------------------------------------------------

Nack()

-------------------------------------------------------------------------------

Посылка "неподтверждения" (not acknowledged) устройству.

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

static void nack(void) //Sends NAck

{

MDE = 1;

MCO = 0;

MDO = 1;

MCO = 1;

delay();

MCO = 0;

}

/**----------------------------------------------------------------------------

get_ack()

-------------------------------------------------------------------------------

Проверка на готовность slave-устройства к обмену (начало + получение отклика +

завершение сессии)

Вход: нет

Выход: нет

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

----------------------------------------------------------------------------- */

bit get_ack( unsigned char address ) //Returns 1 if there was an ACK

{

I2CM = 1; //I2C Выбор режима ведущий/ведомый (0 – аппаратно ведомый, 1 – программный ведущий)

if( begin( address & 0xFE ) ) // Адрес ведомого устройства

{

stop();

return 0;

}

stop();

return 1;

}

/**----------------------------------------------------------------------------

recv_byte()

-------------------------------------------------------------------------------

Получение 8 бит с шины данных i2c без подтверждения или неподтверждения приема.

Вход: нет

Выход: нет

Результат: принятые 8 бит.

----------------------------------------------------------------------------- */

unsigned char recv_byte(void)

{

char i;

unsigned char ch = 0;

MDE = 0; //Бит разрешения передачи данных (1- передача, 0 - прием)

MCO = 0; //Бит выходного синхроимпульса

for( i = 0; i < 8; i++ )

{

ch <<= 1;

MCO = 1;

delay();

ch |= MDI;// Бит входных данных

MCO = 0;

}

return ch;

}

/**----------------------------------------------------------------------------

receive_block()

-------------------------------------------------------------------------------

Получение блока данных от i2c-устройства с 8-разрядным внутренним адресным

пространством. Принятый блок помещается в область памяти xdata.

Вход: uchar address - I2C-адрес устройства;

uchar addr - адрес во внутреннем адресном пространстве устройства;

uchar *block - адрес в области xdata, куда будет помещен принятый

блок данных;

uchar len - длина принимаемого блока.

Выход: нет

Результат: 0 - успешно;

1 - устройство не откликается.

----------------------------------------------------------------------------- */

bit receive_block(unsigned char address, unsigned char addr, unsigned char xdata * block,unsigned char len)

{ //addr - address in target

unsigned char i, ch;

I2CM = 1; // I2C Выбор режима ведущий/ведомый (0 – аппаратно ведомый, 1 – программный ведущий)

address = ( address & 0xFE ); //Адрес ведомого устройства

if( begin( address ) )

{

stop();

return 1;

} //Error - No ACK

if( send_byte( addr ) )

{

stop();

return 1;

}

delay();

delay();

address |= 1; //Читаем

if( begin( address ) )

{

stop();

return 1;

}

delay();

if( len-1 )

{

for( i = 0; i< ( len - 1 ) ;i++)

{

ch = recv_byte();

ack();

*block++ = ch; //Записываем в xdata принятый символ

}

}

ch = recv_byte();

nack();

*block = ch;

stop();

return 0;

}

/**----------------------------------------------------------------------------

send_block()

-------------------------------------------------------------------------------

Запись блока данных во внутреннюю память i2c-устройства с 8-разрядным адресным

пространством.

Вход: uchar address - I2C-адрес устройства;

uchar addr - адрес во внутреннем адресном пространстве устройства,

куда будет помещен блок;

uchar *block - адрес в области xdata, где располагаются данные для

пересылки;

uchar len - длина записываемого блока.

Выход: нет

Результат: 0 - успешно;

1 - устройство не откликается.

----------------------------------------------------------------------------- */

bit transmit_block(unsigned char address, unsigned char addr, unsigned char xdata * block,unsigned char len)

{ //addr - address in target

unsigned char ch, i;

I2CM = 1; // Выбор режима ведущий/ведомый (0 – аппаратно ведомый, 1 – программный ведущий)

address = address & 0xFE; //Запись

if( begin( address ) )

{

stop();

return 1;

} //Error - no Ack

if( send_byte( addr ) )

{

stop();

return 1;

}

for( i = 0; i < len; i++,block++)

{

ch = *block;

if( send_byte( ch ) )

{

stop();

return 1;

} //Not to the end of the block

}

stop();

return 0;

}

• драйвер часов реального времени (RTC);

#include "i2c.h"

#include "rtc.h"

#include <stdio.h>

/*----------------------------------------------------------------------------

Функции

-----------------------------------------------------------------------------*/

/**----------------------------------------------------------------------------

BCD2Bin()

-------------------------------------------------------------------------------

Перевод числа из формата BCD (binary-coded decimal) в обычный двоичный формат

Вход: uchar val - число в BCD-формате

Выход: нет

Результат: двоичный аналог

----------------------------------------------------------------------------- */

#define BCD2Bin(val) ( ((val)&0xF) + ( (((val)&0xF0)>>4) * 10 ) )

/**----------------------------------------------------------------------------

Bin2BCD()

-------------------------------------------------------------------------------

Перевод числа в формат BCD (binary-coded decimal) из обычного двоичного формата

Вход: uchar val - двоичное число

Выход: нет

Результат: BCD-аналог

----------------------------------------------------------------------------- */

#define Bin2BCD(val) ( ((val) % 10) + (((val) / 10)<<4) )

/**----------------------------------------------------------------------------

get_time()

-------------------------------------------------------------------------------

Получение текущего времени

Вход: TIME xdata * time - указатель на структуру в области xdata, куда

будет помещено текущее время.

Выход: нет

Результат: 0 - успешно;

1 - часы не откликаются

----------------------------------------------------------------------------- */

bit get_time( TIME xdata * time )

{

unsigned char h;

if( !get_ack( RTC_ADDRESS ) ) return 1; // RTC failed to respond

if( receive_block( RTC_ADDRESS, 1, ( unsigned char xdata * ) time, 4) ) return 1; // Error reading

time->hsec = BCD2Bin( time->hsec );

time->sec = BCD2Bin( time->sec );

time->min = BCD2Bin( time->min );

h = BCD2Bin( time->hour & 0x3F);

if( (time->hour & 0xC0) == 0xC0 ) // 12h format and pm flag

{

if( time->hour < 12 )

time->hour = h + 12;

else

time->hour = 0;

}

else

time->hour = h;

return 0;

}

/**----------------------------------------------------------------------------

set_time()

-------------------------------------------------------------------------------

Установка текущего времени

Вход: TIME xdata * time - указатель на структуру в области xdata, с

новым временем.

Выход: нет

Результат: 0 - успешно;

1 - часы не откликаются

----------------------------------------------------------------------------- */

bit set_time( TIME xdata * time )

{

static TIME xdata t;

if( !get_ack( RTC_ADDRESS ) ) return 1; //RTC failed to respond

t.hsec = Bin2BCD( time->hsec );

t.sec = Bin2BCD( time->sec );

t.min = Bin2BCD( time->min );

t.hour = Bin2BCD( time->hour & 0x3F );

if( transmit_block( RTC_ADDRESS, 1, ( unsigned char xdata * ) &t, 4 ) ) return 1; //Error reading

return 0;

}

• драйвер последовательного канала по прерыванию;

#include "aduc812.h"

#define FIFOSize 16

void SIO_ISR( void ) __interrupt ( 4 );

struct FIFOb{

unsigned char buf[FIFOSize];

char RP;

char WP;

};

struct FIFOb wFIFO, rFIFO;

bit TRANSFER_NOW; //Флаг для разрешения проблемы начальной передачи

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

//Вход:

//Vector - адрес обработчика прерываний

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

//Выход: нет

void setVector(unsigned char xdata * Address, void * Vector)

{

unsigned char xdata * TmpVector;

*Address = 0x02;

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

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

++TmpVector;

*TmpVector = (unsigned char) Vector;

}

/*----------------------------------------------------------------------------

init_sio()

-------------------------------------------------------------------------------

Инициализирует последовательный канал на заданной скорости. Использует таймер 1

Вход: char speed - скорость. Задается константами, описанными в

заголовочном файле sio.h

bit sdouble - дублирование скорости: 0 - не дублировать скорость,

заданную аргументом speed; 1 - дублировать.

Выход: нет

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

----------------------------------------------------------------------------- */

void init_sio( unsigned char speed )

{

TH1 = speed;

TMOD |= 0x20; //Таймер 1 будет работать в режиме автоперезагрузки (счетчик)

TCON |= 0x40; //Запуск таймера 1

PCON |= 0x00; //SMOD = 0

SCON = 0x50; //Настройки последовательного канала: Режим 1(8 бит данных, асинхронный, переменная скорость)

ES = 0; //Запрещение прерываний от приемопередатчика

wFIFO.RP = wFIFO.WP = rFIFO.RP = rFIFO.WP = 0;

TRANSFER_NOW = 0;

setVector(0x2023, (void *) SIO_ISR);

}

//Функция записи элемента в буфер

//Вход: FIFOb* а - буфер

//Выход: 1 - успешно записан

// 0 - буфер полон

bit PushFIFO(struct FIFOb* a, unsigned char c)

{

if(! ((a->RP==0 && a->WP == FIFOSize - 1) || ((a->RP - a->WP) == 1))) //если буфер не полон

{

a->buf[a->WP] = c; //записываем в буфер элемент c индексом WP

if (++a->WP > FIFOSize - 1) a->WP = 0; //проверка выхода указателя за границы буфера

return 1;

}

else return 0;

}

//Функция извлечения элемента из буфера

//Вход: FIFOb* а - буфер

//Выход: элемент буфера при удачном извлечении

// 0 - если буфер пуст

unsigned char PopFIFO(struct FIFOb* a)

{

unsigned char c;

if (a->WP == a->RP) return 0; //если буфер пуст, возвращаем 0

c = a->buf[a->RP]; //извлекаем элемент с индексом RP

if(++(a->RP) > FIFOSize - 1) a->RP=0; //проверка выхода указателя за границы буфера

return c;

}

//Обработчик прерывания от последовательного канала

//Вход: нет

//Выход: нет

void SIO_ISR( void ) __interrupt ( 4 )

{

unsigned char c;

if(TI)

{

c = PopFIFO(&wFIFO);

TRANSFER_NOW = 1;

if(c){ //если буфер непуст

SBUF = c;

TI=0;

}

else TRANSFER_NOW = 0; //завершаем цикл передачи - больше нечего передавать

}

if(RI)

{

PushFIFO(&rFIFO, SBUF);

RI=0;

}

}

//API - функция отправки символа в последовательный канал

//Вход: нет

//Выход: принятый символ или 0 в случае пустого буфер

bit writeUART(unsigned char c)

{

ES = 0; //отключаем прерывание от UART - работа с разделяемыми ресурсами

if (PushFIFO(&wFIFO, c))

{

ES = 1;

if (!TRANSFER_NOW) TI = 1; //если цикл передачи не начат, искусственно вызываем прерывание установкой флага

return 1;

}

else

{

ES = 1;

return 0; //если буфер полон

}

}

//API - функция отправки ASCIIZ строки в последовательный канал

//Вход: нет

//Выход: принятый символ или 0 в случае пустого буфер

void APIString(const unsigned char* str)

{

unsigned char i=0;

while(i<80)

{

if (str[i]=='\0') break;

writeUART(str[i++]);

}

}

//API - функция приема символа из последовательного канала

//Вход: нет

//Выход: принятый символ или 0 в случае пустого буфера

unsigned char ReadUART(void)

{

unsigned char c;

ES = 0;

c = PopFIFO(&rFIFO);

ES = 1;

return c;

}

• драйвер ЖКИ;

#include "aduc812.h"

#include "led.h"

#include "max.h"

#include "async.h"

#include "keyboard.h"

unsigned char GetBF() // Чтение флага занятости

{

unsigned char request_flag;

writeMax(C_IND,0x03);

request_flag=readMax(DATA_IND);

writeMax(C_IND,0x02);

request_flag&=0x80;

return request_flag;

}

void Clear(void) // Очистка экрана

{

while (GetBF()) ;

writeMax(DATA_IND,0x01);

writeMax(C_IND,0x01);

writeMax(C_IND,0x00);

}

void Start(void) // Перевод курсора в начальную позицию

{

while (GetBF()) ;

writeMax(DATA_IND,0x02);

writeMax(C_IND,0x01);

writeMax(C_IND,0x00);

}

void InitLCD() // Инициализация ЖКИ

{

while (GetBF()) ;

writeMax(DATA_IND, 0x00);

writeMax(C_IND,0x01);

writeMax(C_IND,0x00);

Clear();

Start();

}

unsigned char GetAC() //Получение счетчика адреса

{

unsigned char address_counter;

writeMax(C_IND,0x03);

address_counter=readMax(DATA_IND);

writeMax(C_IND,0x02);

address_counter&=0x7F;

return address_counter;

}

void DDRAM(unsigned char data_address) //Заносим адрес

//таблица адресов

// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

// 1 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

// 2 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

{

while (GetBF()) ;

data_address|=0x80;

writeMax(DATA_IND,data_address);

writeMax(C_IND,0x01);

writeMax(C_IND,0x00);

}

void PrintChar(unsigned char char_value) // Выведение символа на экран

{

//коды символов

//0 - 00110000

//1 - 00110001

//2 - 00110010

//3 - 00110011

//4 - 00110100

//5 - 00110101

//6 - 00110110

//7 - 00110111

//8 - 00111000

//9 - 00111001

//: - 00111010

//, - 00101100

while (GetBF()) ;

writeMax(DATA_IND,char_value);

writeMax(C_IND,0x05);

writeMax(C_IND,0x04);

}

void GotoXY(unsigned char X, unsigned char Y) Переходим в заданную позицию на дисплее

{

int koordXY[2][16]={{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F},{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F}};

while (GetBF()) ;

if ((X <&& X>=1) && (Y<=2 && Y >=1))

{

DDRAM(koordXY[Y-1][X-1]);

}

}

void PrintString(const unsigned char* string_value) //Вывод строки на экран

{

unsigned char i=0;

while(i<32)

{

if (string_value[i]=='\0') break;

PrintChar(string_value[i++]);

}

}

• Драйвер таймера;

#include "aduc812.h"

#include "rtc.h"

#include "i2c.h"

#include "lcd.h"

#include "timers.h"

#include "sound.h"

TIME xdata alarm_time;

TIME xdata time;

bit IsFinish = 0;

int i = 0;

const unsigned int tone_tick[] = {

30578, // C

28862, // C sharp or D flat

27242, // D

25713, // D sharp or E flat

24270, // E

22907, // F

21622, // F sharp or G flat

20409, // G

19263, // G sharp or A flat

18182, // A

17161, // A sharp or H flat

16198 // H

};

void tm_ms_delay (unsigned long delay) // Задержка

{

unsigned long d;

unsigned char i;

for(d=0; d<delay; d++)

for(i=0; i<50; i++);

}

void timer_handler1() interrupt 3

{

if (!IsFinish)

{

i++;

if (i == 800)

{

print_time1();

PrintAlarmTime1();

i = 0;

}

}

}

void setVector1(unsigned char xdata * Address, void * Vector)

{

unsigned char xdata * TmpVector;

*Address = 0x02;

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

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

*TmpVector = (unsigned char) Vector;

}

void init_timer2( unsigned char speed )

{

TH1 = speed;

TMOD |= 0x20; //Таймер 1 будет работать в режиме autoreload

TCON |= 0x40; //Запуск таймера 1

// PCON |= 0x00; //SMOD = 0

// SCON = 0x50; //Настройки последовательного канала: Режим 1(8 бит данных, асинхронный, переменная скорость)

// ES = 0; //Запрещение прерываний от приемопередатчика

setVector1(0x201B, (void *) timer_handler1);

ET1 = 1;

}

void print_time1( void )

{

static TIME xdata t;

if( get_time( &t ) )

{

GotoXY(1,1); PrintChar('?');

return;

}

GotoXY(1,1); PrintChar (t.hour / 10 + 0x30);

GotoXY(2,1); PrintChar (t.hour % 10 + 0x30);

GotoXY(3,1); PrintChar (':');

GotoXY(4,1); PrintChar (t.min / 10 + 0x30);

GotoXY(5,1); PrintChar (t.min % 10 + 0x30);

GotoXY(6,1); PrintChar (':');

GotoXY(7,1); PrintChar (t.sec / 10 + 0x30);

GotoXY(8,1); PrintChar (t.sec % 10 + 0x30);

if (t.hour == alarm_time.hour && t.min == alarm_time.min && t.sec == alarm_time.sec)

DoFinish();

}

void DoFinish()

{

unsigned char tone;

Clear();

GotoXY(1,1);

PrintChar('!');

IsFinish = 1;

snd_init();

tone = 1;

while(tone > 0)

{

snd_beep(tone_tick[tone-1]>>4, 7);

tm_ms_delay(1000);

tone--;

}

}

void PrintAlarmTime1()

{

GotoXY(1,2); PrintChar (alarm_time.hour / 10 + 0x30);

GotoXY(2,2); PrintChar (alarm_time.hour % 10 + 0x30);

GotoXY(3,2); PrintChar (':');

GotoXY(4,2); PrintChar (alarm_time.min / 10 + 0x30);

GotoXY(5,2); PrintChar (alarm_time.min % 10 + 0x30);

GotoXY(6,2); PrintChar (':');

GotoXY(7,2); PrintChar (alarm_time.sec / 10 + 0x30);

GotoXY(8,2); PrintChar (alarm_time.sec % 10 + 0x30);

}

• драйвер звукового излучателя;

#include "async.h"

#include "sound.h"

#include "timers.h"

#include "use_max.h"

unsigned char snd_volume;

bit snd_level;

void snd_intr() interrupt 3

{

snd_level = !snd_level;

USE_MAX(

if(!snd_level)

ENA &= ~VOLUME_MASK;

else

ENA |= VOLUME_MASK &(snd_volume<<2);

)

TM_INIT(1, TM_MODE_8_AUTO_RELOAD, snd_t);

}

void snd_init()

{

TM_ENABLED(1) = 0;

setVector(0x201B, (void *)snd_intr);

snd_volume = 3;

snd_level = 0;

}

void snd_beep(unsigned int t, unsigned char vol)

{

TM_RUN(1) = 0;

snd_t = t;

snd_volume = vol;

snd_level = 0;

TM_INIT(1, TM_MODE_8_AUTO_RELOAD, snd_t);

}

void snd_shut_up()

{

TM_ENABLED(1) = 0;

USE_MAX(

ENA &= ~VOLUME_MASK

)

}

• драйвер клавиатуры

#include "async.h"

#include "max.h"

#include "lcd.h"

#include "led.h"

#define BUFFER_SIZE 30 // размер буфера 64 байта

#define ERR_OVERFLOW_STOPWATCH "\n\rOVERFLOW STOPWATCH\n\r\0"

int repeatDelay; // переменная для обработки задержки в первом повторе

int repeatSpeed; // переменная для обработки задержки во втором и последующих повторах

int delay; // счетчик задержки

char drebezgWait = 1;// флаг наличия дребезга

char firstRepeat = 1; // флаг первого повтора

char keyPress = 0; // флаг нажатия клавиши (1 - нажата, 0 - не нажата)

char firstPress = 1; // флаг первого нажатия (1 - клавиатура еще не использовалась)

// (0 - было хотя-бы одно нажатие на клавишу)

unsigned char key = 0; // переменная для хранения символа нажатой клавиши

unsigned char previousKey = 0; // предыдущая нажатая клавиша

unsigned char prevRow = 0xF0; // маска для обработки нажатия двух клавиш

unsigned char kbBuffer[BUFFER_SIZE]; // буфер клавиатуры

unsigned char kb_wp = 0; // указатель записи буфера клавиатуры

unsigned char kb_rp = 0; // указатель чтения буфера клавиатуры

int oldValue;

/*

Функция: сканирование клавиатуры

Входные параметры: key - указатель клавиши

Выходные параметры: нет

*/

char keyboardScan(unsigned char* key) {

unsigned char cols[4] = {0x0E, 0x0D, 0x0B, 0x07}; // массив столбцов

unsigned char row; // переменная, в которую читается ряд

int i; // счетчик для цикла for

unsigned char symb[16] = {'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'}; // массив символов

unsigned char symbInd; // индекс в массиве symb[]

symbInd = 0; // обнуляем индекс массива symb[]

*key = 0; // обнуляем указатель на область памяти для хранения нажатой кнопки

for (i = 0; i < 4; i++) {

writeMax(KB, cols[i]); // записываем значение столбца в младшие 4 бита регистра клавиатуры

row = readMax(KB) & 0xF0; // считываем значение ряда из регистра клавиатуры

// symbInd =0;

// какой ряд в столбце нажат?

switch (row) {

case 0xE0: prevRow = row; symbInd = symbInd + 1; break; // нажата клавиша в верхнем ряду

case 0xD0: prevRow = row; symbInd = symbInd + 2; break; // нажата клавиша во втором сверху ряду

case 0xB0: prevRow = row; symbInd = symbInd + 3; break; // нажата клавиша во втором снизу ряду

case 0x70: prevRow = row; symbInd = symbInd + 4; break; // нажата клавиша в нижнем ряду

// если нажаты сразу две клавиши, то default:

// побитово сравниваем текущий ряд с предыдущим нажатым рядом (row & prevRow),

// если они не равны предыдущему нажатому ряду( != prevRow), т.е. нажаты сразу две клавиши,

// то выводим ту, которая была нажата первой

default: if ((firstPress == 0) && ((row & prevRow) != prevRow)) {*key = previousKey; return 1;} break;

};

if (symbInd > 0) {

symbInd = symbInd + i*4 - 1; // вычисляем индекс элемента массива

*key = symb[symbInd]; // key = символ на клавише

return 1;

}

}

return 0;

}

/*

Функция: чтение буфера клавиатуры

Входные параметры: symbol - указатель читаемого символа

Выходные параметры: нет

*/

char readKeyBuffer(unsigned char* symbol) {

EA = 0; // запрещаем прерывания от всех источников

if ((kb_wp - kb_rp) > 0) {

*symbol = kbBuffer[kb_rp % BUFFER_SIZE]; // читаем из буфера клавиатуры

kb_rp++; // перемещаем указатель чтения буфера клавиатуры на 1 позицию

EA = 1; // разрешаем прерывания от всех источников

return 1;

}

else {

*symbol = 0; // ничего не считано

EA = 1; // разрешаем прерывания от всех источников

return 0;

}

}

/*

Функция: запись в буфер клавиатуры

Входные параметры: symbol - указатель на читаемый символ

Выходные параметры: нет

*/

void writeKeyBuffer(unsigned char symbol) {

EA = 0; // запрещаем прерывания от всех источников

if ((((kb_wp / BUFFER_SIZE) - (kb_rp / BUFFER_SIZE)) != 0) &&

((kb_wp % BUFFER_SIZE) == (kb_rp % BUFFER_SIZE))) return;

kbBuffer[kb_wp % BUFFER_SIZE] = symbol; // пишем в буфер клавиатуры

kb_wp++; // перемещаем указатель записи буфера клавиатуры на 1 позицию

EA = 1; // разрешаем прерывания от всех источников

}

/*

Функция: обработчик прерывания от таймера (обработчик нажатия на клавишу)

Входные параметры: нет

Выходные параметры: нет

*/

void cleanStopWatch(void)

{

unsigned char i;

for (i=1;i<6;i++)

{

if (i==3)

{

GotoXY(i,1);

PrintChar(0x3A );

}

else

{

GotoXY (i,1);

PrintChar (0x30);

}

}

}

unsigned char stop=0;

int value=0;

void timerHandler() interrupt 1 {

int i;

TH0 = 0xDC; // устанавливаем таймер 0 на отсчет 10 мс

TL0 = 0x32;

keyPress = keyboardScan(&key); // сканируем клавиатуру

// (keyPress = 1 -> клавиша нажата)

// (keyPress = 0 -> клавиша не нажата)

if (key != previousKey) delay = 0; // если клавиша не повторяется, то задержка

// (счетчик задержки) между повторами = 0

if (delay == 0) { // если счетчик задержки = 0, то

if (keyPress) { // если клавиша нажата, то

firstPress = 0; // сбрасываем флаг первого нажатия

previousKey = key; // запоминаем текущую нажатую кнопку

if (drebezgWait) drebezgWait = 0; // если установлен флаг наличия дребезга,

// то сбрасываем его

else { // если флаг дребезга не установлен, то

if (firstRepeat) { // если первый повтор клавиши (напр. АА), то

Соседние файлы в папке будильник