отчеты по лабораторным работам / будильник / lab4
.docСанкт-Петербургский государственный университет
информационных технологий, механики и оптики
(СПбГУ ИТМО)
Кафедра вычислительной техники
Лабораторная работа № 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) { // если первый повтор клавиши (напр. АА), то