Keyboard
Пример клавиатуры в системе на базе микроконтроллера семейства MCS-51
Микросхема кодера SAA3010 (код RC-5)
Довольно часто разработчик микроконтроллерной системы сталкивается с проблемой создания клавиатуры с количеством кнопок более десятка. При этом совсем не хочется увеличивать стоимость системы за счет введения схем обработки клавиатуры или нагружать микроконтроллер задачами по обслуживанию последней.
В таких ситуациях может быть полезна идея использовать широко распространенный кодер SAA3010 фирмы PHILIPS, использующей код для передачи сформированных кодов кнопок под названием RC-5.
Эта микросхема была спроектирована для систем дистанционного управления аудио-видео аппаратурой и используется в пультах дистанционного управления. Однако этот кодер можно с успехом использовать в системах на базе микроконтроллера в качестве контроллера клавиатуры. Подробное описание этой микросхемы я не буду приводить здесь, так как достаточно литературы, ее описывающей, и мест в Интернете, где она подробно рассмотрена.
Остановлюсь на конкретном примере использования этого кодера в системе на базе микроконтроллера семейства MCS-51.
В моем, реально работающем, приборе, SAA3010 подключена к микроконтроллеру T89C51RD2.
SAA3010 в тактируется извне (однако, это может быть и керамический резонатор на частоту 450 КГц, как это описано в документации на микросхему) частотой равной частоте кварцевого резонатора микроконтроллера деленной на 32 (деление происходит в программируемой логической интегральной схеме).
Частота кварцевого резонатора микроконтроллера равна 11.059200 МГц. После деления получаем частоту равную 345600 КГц.
Выход кодера подключен к входу внешнего прерывания микроконтроллера INT0.
Используемые ресурсы микроконтроллера: внешнее прерывание INT0 (старт анализа посылки) и TIMER1 (для сэмплирования битов посылки).
Вот собственно и все аппаратные подключения.
Формат посылки кодера SAA3010 с комментариями приведены на рисунке.

Текст программы на языке Си приведен ниже.
Содержание файла main.h.
#define false
0
#define true
1
#define HighB(value)
(value >>
8)
#define LowB(value)
(value)
#define
RELOAD1
0xf600
#define
RELOAD
0xf800
#define
KEYBOARD P3_2
Содержание файла main.с.
///////////////////////////////////////////////////
// Проект
Keyboard //
//
Кодер SAA3010 //
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// Design
SoftWare:
//
// Keil
Software, Inc.
//
// C compiler
V7.10
//
// Assembler
V7.09
//
// Linker/Locator
LX51 V3.63 //
//////////////////////////////////////////////////
//
Заголовочные файлы
#include
<89c51rd2.h>
#include "main.h"
// Битовые переменные
bit sound;
bit startBit, toggleBit;
bit key;
// Глобальные переменные
unsigned char data addressCode, commandCode;
unsigned char data qPulses;
unsigned char data delay0, delay1;
// Обработка прерывания от кодера SAA3010
void Keyboard(void)
interrupt
0
{
// Запретить
прерывание до анализа кода кнопки
EX0 =
0;
//
Засинхронизироваться на середину первого стартового бита
while(!KEYBOARD);
// Загрузить таймер
1
TH1 = HighB(RELOAD1);
TL1 = LowB(RELOAD1);
// Запустить таймер
1
TR1 =
1;
// Инициализировать
счетчик битов на ноль
qPulses =
0;
addressCode = 0;
commandCode
=
0;
}
// Системный тайминг
void Timer0(void)
interrupt 1
{
// Перезагрузка
таймера 0 для интервала 2 мс. при частоте кварца 11.059200 МГц
TH0 =
0xf8;
TL0
=
0xcd;
// Сформировать длительность звукового импульса
длительностью 100 мс.
if(sound)
{
// Включить зуммер
P1_0 =
0;
delay0--;
if(!delay0)
{
delay0 =
50;
// Выключить зуммер
P1_0 =
1;
sound = false;
}
}
// Определение отпускания кнопки
if(key)
{
if(KEYBOARD)
{
delay1--;
if(!delay1)
{
EX0 =
1;
delay1 =
50;
key = false;
}
}
else delay1 =
50;
}
}
// Анализ битов посылки кодера
SAA3010
void Timer1(void)
interrupt 3
{
bit bLevel;
// Определение состояния выхода кодера
SAA3010
bLevel = KEYBOARD;
//
Перезагрузка таймера 1 для анализа следующего бита
TH1 = HighB(RELOAD);
TL1 = LowB(RELOAD);
switch(qPulses)
{
case
0:
// Определение стартового бита 2
startBit = false;
if(bLevel) startBit = true;
break;
case
1:
// Определение toggle бита
toggleBit = false;
if(bLevel) toggleBit = true;
break;
case
2:
case
3:
case
4:
case
5:
case
6:
// Определение 5, 4, 3, 2 и 1-го бита адреса
if(bLevel) addressCode |=
0x01;
else addressCode &=
0xfe;
if(qPulses !=
6)
addressCode = addressCode <<
1;
break;
case
7:
case
8:
case
9:
case
10:
case
11:
case
12:
// Определение 6, 5, 4, 3, 2 и 1-го бита команды
if(bLevel) commandCode |=
0x01;
else commandCode &=
0xfe;
if(qPulses !=
12)
{
commandCode = commandCode << 1;
break;
}
// Все тринадцать анализов битов сделаны
// Теперь определение действий по коду commandCode
TR1 =
0;
key = true;
// Для предотвращения сбоев, определение действий по коду commandCode
// делается только при наличии второго стартового бита и, например, при addressCode равном нулю
if(startBit && !addressCode)
{
switch(commandCode)
{
case :
.
.
.
break;
.
.
.
}
break;
}
//
Следующий бит
qPulses++;
}
// Основной цикл программы
void main(void)
{
CKCON =
0x7f;
AUXR = 0x2d;
delay0 =
50;
delay1 =
50;
// Режимы прерываний:
// внешнее прерывание 1 (клавиатура) - по уровню
IT0 =
0;
// Приоритеты прерываний:
// 1 - клавиатура
// 2 - таймер 0 (системный тайминг)
PX0 = 1;
PT0 =
1;
// Режимы таймеров:
//
// таймер 0 (тайминг) - 1
// таймер 1 (декодер клавиатуры) - 1
TMOD = 0x11;
// Константа перезагрузки
таймера 0, для получения времени 2 мс.
TH0 =
0xf8;
TL0 =
0xcd;
// Разрешить прерывания от клавиатуры
EX0 =
1;
// Разрешить прерывания от таймера 0
ET0 =
1;
// Разрешить прерывания
от таймера 1
ET1 =
1;
// Глобальное разрешение прерываний
EA =
1;
// Запустить системный тайминг
TR0 =
1;
// Сгенерировать звуковой сигнал
sound = true;
// Бесконечный цикл
while(true);
}