Обозначение пункта на индикаторе
|
Расшифровка
|
ЗВН 01
|
ЗВН 02
|
Переход в режим ввода звонка 2
|
…
|
…
|
ЗВН N*
|
Переход в режим ввода звонка N
|
ВЫХОД
|
Выход в меню настройки звонков
|
Рис. 6. Пример отображения на LED-индикаторе пункта меню
времени звонков
После нажатия кнопки ВВОД на одном из пунктов, пользователь
последовательно вводит час и минуту звонка, аналогично тому, как это
производится в режиме ввода времени, и автоматически возвращается в меню
времени звонков.
Список литературы
1. Яценков
В.С. Микроконтроллеры Microchip с аппаратной поддержкой USB. - М.: Горячая
линия-Телеком, 2008. - 400 с.
Приложение
1
Схема
устройства принципиальная
Приложение 2
микроконтроллер автомат звонок часы
Листинг текста программы
/*
Курсовой проект по дисциплине «Цифровые устройства и
микроконтроллеры»
// заголовочный файл
#include <pic18.h>
// конфигурация контроллера
__CONFIG (1, CPUDIV1 & INTIO);
__CONFIG (2, PWRTDIS & BORDIS & WDTDIS);
__CONFIG (3, PBDIGITAL & MCLREN);
__CONFIG (4, LVPDIS);
__CONFIG (5, UNPROTECT);
__CONFIG (6, UNPROTECT);
__CONFIG (7, UNPROTECT);
// -
// глобальные переменныеchar i=0, j, l; // вспомогательные
счетные переменныеchar d, month, day, year; // вспомогательные вычислительные
переменныеunsigned char CallDuration=5; // длительность звонка в секундахchar
CallCount=0; // для временного хранения числа звонков (максимум 30)char
Zvonok=0; // для хранения номера звонка, время которого изменяется в настоящий
моментchar WDAY_Month; // переменнная для считывания текущего дня недели и
месяца из часовchar Minutes; // переменнная для считывания текущего значения
минут из часовchar Hours; // переменнная для считывания текущего значения
часаchar Seconds; // переменнная для считывания текущего значения секундchar
LedWork=0; // логическая переменная (режим настройки вкл/выкл) *дисплей
работает только в режиме настройкиchar SymPlace=0x00; // 6 младших битов этой
переменной определяют,
// на какие позиции дисплея необходимо выводить символыchar
DotPlace=0x00; // на какие позиции ставаить точкиchar Symbols[12]; // массив
символов, которые в данный момент должны выводиться на экран
// (каждый символ использует два байта для описания своей
конфигурации на дисплее)char Mode; // определяет, в каком режиме находится
система настройки
// 1 - главное меню
// 2 - режим установки времени и даты
// 3 - режим ввода года
// 4 - режим ввода месяца
// 5 - режим ввода числа
// 6 - режим ввода дня недели
// 7 - режим ввода часа
// 8 - режим ввода минуты
// 9 - меню настройки звонков
// 10 - настройка количесва звонков (до 30)
// 11 - выбор номера звонка для настройки времени
срабатывания
// 12 - режим ввода часа выбранного звонка
// 13 - режим ввода минуты выбранного звонка
// 14 - режим ввода длительности звонков (в секундах)char m;
// определяет номер текущей позиции внутри данного режима
// изображение чисел 0 1 2 3 4 5 6 7 8 9unsigned char
DigitL[10]={0xFF, 0x30, 0xEE, 0xFC, 0x31, 0xDD, 0xDF, 0xF0, 0xFF, 0xFD}; //
младший байт
const unsigned char DigitH[10]={0x00, 0x00, 0x11,
0x11, 0x11, 0x11, 0x11, 0x00, 0x11, 0x11}; // старший байт
// изображение букв K(0) A(1) Г(2) О(3) Д(4) М(5) Е(6) С(7)
Н(8) Ч(9) И(10) Ь(11) |(12) Х(13) У(14) Т(15) З(16) В(17) /(18) Р(19) Я(20)
Л(21)
const unsigned char LetterL[22]={0x03, 0x30,
0xC3, 0xFF, 0x3C, 0x33, 0xCF, 0xCF, 0x33, 0x31, 0x33, 0x1F, 0x03, 0x00, 0x3D,
0xC0, 0xCC, 0xCF, 0x00, 0xE3, 0xF1, 0x30};unsigned char LetterH[22]={0x29,
0x32, 0x00, 0x00, 0x22, 0xA0, 0x11, 0x00, 0x11, 0x11, 0x22, 0x11, 0x00, 0xAA,
0x11, 0x44, 0x29, 0x29, 0x22, 0x11, 0x13, 0x22};
// массив позиций 0 1 2 3 4 5unsigned char Pos[6]={0x7C, 0xBC,
0xDC, 0xEC, 0xF4, 0xF8};
unsigned short int k=0; // переменная для задержки
// -
// вывод на LED-дисплей символа на позицию PosSymbOut
(char SymbolL, char SymbolH, char Pos, char Dot)
{(Dot) Pos+=(1<<1);=0;(i=0; i<8; i++) // передаем
младший байт изображения символа на регистр сдвига
{=(((1<<i)&(SymbolL))>>i);=1;=0;
}=1;=0; (i=0; i<8; i++) //
старший байт изображения
{=(((1<<i)&(SymbolH))>>i);=1;=0;
}=1;=0;(i=0; i<8; i++) // байт позиции
{=(((1<<i)&(Pos))>>i);=1;=0;
}=1;=0;=1;
}
// -
// вывод на LED-дисплей всех необходимых в данный момент
символов на соответствующие позиции
void LedOutput(void)
{(j=0; j<7; j++) ((1<<j)&SymPlace)((1<<j)&DotPlace)
SymbOut (Symbols[j], Symbols [j+6], Pos[j], 1);SymbOut (Symbols[j], Symbols
[j+6], Pos[j], 0);
}
// -
// записываем в SymPlace, DotPlace и массив Symbols[12]
данные, соответствующие текущему режиму настройки
{(Mode)
{1: // режим главного меню(m)
{1: // находимся на позиции «установка даты»
SymPlace=0x3F;=0x09;[0]=LetterL[15];[6]=LetterH[15];[1]=LetterL[1];[7]=LetterH[1]; [2]=LetterL[4];[8]=LetterH[4];[3]=LetterL[15];[9]=LetterH[15];[4]=LetterL[7];[10]=LetterH[7];[5]=LetterL[14];[11]=LetterH[14]; ;
case 2: // находимся на позиции «установка времени звонков»
SymPlace=0x3F;=0x09;[0]=LetterL[8];[6]=LetterH[8];[1]=LetterL[17];[7]=LetterH[17];
Symbols[2]=LetterL[16];[8]=LetterH[16];[3]=LetterL[15];[9]=LetterH[15];[4]=LetterL[7];[10]=LetterH[7];[5]=LetterL[14];[11]=LetterH[14];
break;
case 3: // находимся на позиции «выход»
SymPlace=0x3F;=0x00;[0]=LetterL[4];[6]=LetterH[4];[1]=LetterL[3];[7]=LetterH[3]; [2]=LetterL[13];[8]=LetterH[13];[3]=LetterL[12];[9]=LetterH[12];[4]=LetterL[11];[10]=LetterH[11];[5]=LetterL[17];[11]=LetterH[17];;
};2: // режим установки времени и даты(m)
{1: // находимся на позиции «год»
SymPlace=0x38;=0x00;[3]=LetterL[4];[9]=LetterH[4];[4]=LetterL[3];[10]=LetterH[3];[5]=LetterL[2];[11]=LetterH[2];;
case 2: // находимся на позиции «месяц»
SymPlace=0x38;=0x00;[3]=LetterL[7];[9]=LetterH[7];[4]=LetterL[6];[10]=LetterH[6];[5]=LetterL[5];[11]=LetterH[5];;
case 3: // находимся на позиции «число»
SymPlace=0x38;=0x00;[3]=LetterL[7];[9]=LetterH[7];[4]=LetterL[10];[10]=LetterH[10];[5]=LetterL[9];[11]=LetterH[9];;
case 4: // находимся на позиции «день недели»
SymPlace=0x38;=0x00;[3]=LetterL[8];[9]=LetterH[8];[4]=LetterL[18];[10]=LetterH[18];[5]=LetterL[4];[11]=LetterH[4];;
case 5: // находимся на позиции «час»
SymPlace=0x38;=0x00;[3]=LetterL[7];[9]=LetterH[7];[4]=LetterL[1];[10]=LetterH[1];[5]=LetterL[9];[11]=LetterH[9];;
case 6: // находимся на позиции «минута»
SymPlace=0x38;=0x00;[3]=LetterL[8];[9]=LetterH[8];[4]=LetterL[10];[10]=LetterH[10];[5]=LetterL[5];[11]=LetterH[5];;
case 7: // находимся на позиции «выход»
SymPlace=0x3F;=0x00;[0]=LetterL[4];[6]=LetterH[4];[1]=LetterL[3];[7]=LetterH[3]; [2]=LetterL[13];[8]=LetterH[13];[3]=LetterL[12];[9]=LetterH[12];[4]=LetterL[11];[10]=LetterH[11];[5]=LetterL[17];[11]=LetterH[17];;
};
// режимы ввода:3: // года4: // месяца
case 5: // числа6: // дня недели7: // часов8: // минут10: //
количества звонков=0x3B;
DotPlace=0x00;=m/10;[0]=DigitL
[m-d*10];[6]=DigitH [m-d*10]; [1]=DigitL[d];[7]=DigitH[d];;9: // режим установки звонков(m)
{1: // находимся
на позиции «количество звонков»
SymPlace=0x38;=0x00;[3]=LetterL[21];[9]=LetterH[21];[4]=LetterL[3];[10]=LetterH[3];[5]=LetterL[0];[11]=LetterH[0];;
case 2: //
находимся на позиции «время звонков»
SymPlace=0x1F;=0x00;[0]=LetterL[20];[6]=LetterH[20];[1]=LetterL[5];[7]=LetterH[5]; [2]=LetterL[6];[8]=LetterH[6];[3]=LetterL[19];[9]=LetterH[19];[4]=LetterL[17];[10]=LetterH[17];;3: // находимся на позиции «длительность
звонков»
SymPlace=0x38;=0x00;[3]=LetterL[15];[9]=LetterH[15];[4]=LetterL[21];[10]=LetterH[21];[5]=LetterL[4];[11]=LetterH[4];;
case 4: //
находимся на позиции «выход»
SymPlace=0x3F;=0x00;[0]=LetterL[4];[6]=LetterH[4];[1]=LetterL[3];[7]=LetterH[3]; [2]=LetterL[13];[8]=LetterH[13];[3]=LetterL[12];[9]=LetterH[12];[4]=LetterL[11];[10]=LetterH[11];[5]=LetterL[17];[11]=LetterH[17];;
};11:
// режим выбора звонка(m<CallCount+1)
{=0x3B;=0x00;=m/10;[0]=DigitL
[m-d*10];[6]=DigitH [m-d*10]; [1]=DigitL[d];[7]=DigitH[d];[3]=LetterL[8];[9]=LetterH[8];[4]=LetterL[17];[10]=LetterH[17];[5]=LetterL[16];[11]=LetterH[16];
}
{=0x3F;=0x00;[0]=LetterL[4];[6]=LetterH[4];[1]=LetterL[3];[7]=LetterH[3]; [2]=LetterL[13];[8]=LetterH[13];[3]=LetterL[12];[9]=LetterH[12];[4]=LetterL[11];[10]=LetterH[11];[5]=LetterL[17];[11]=LetterH[17];
};12: // режим
ввода часа выбранного звонка
SymPlace=0x3B;=0x00;=m/10;[0]=DigitL
[m-d*10];[6]=DigitH [m-d*10]; [1]=DigitL[d];[7]=DigitH[d];[3]=LetterL[7];[9]=LetterH[7];[4]=LetterL[1];[10]=LetterH[1];[5]=LetterL[9];[11]=LetterH[9];
break;13: //
режим ввода минуты выбранного звонка
SymPlace=0x3B;=0x00;=m/10;[0]=DigitL
[m-d*10];[6]=DigitH [m-d*10]; [1]=DigitL[d];[7]=DigitH[d];[3]=LetterL[8];[9]=LetterH[8];[4]=LetterL[10];[10]=LetterH[10];[5]=LetterL[5];[11]=LetterH[5];
break;14: //
режим установки длительности звонков
SymPlace=0x3B;=0x00;=m/10;[0]=DigitL
[m-d*10];[6]=DigitH [m-d*10]; [1]=DigitL[d];[7]=DigitH[d];[3]=LetterL[15];[9]=LetterH[15];[4]=LetterL[21];[10]=LetterH[21];[5]=LetterL[4];[11]=LetterH[4];
break;
}
}
// -
// работа с
передачей данных между часами PCF8583 и микроконтроллером
const
char WRITE=0b10100000; // адрес PCF8583 + бит записиchar READ= 0b10100001; // адрес PCF8583 + бит чтения
void start() //
начало передачи данных по интерфейсу I2C
{&=~(1<<7);&=~(1<<6);
// состояние линий SDA и SCL определяет ведущий (мк)=1;=1;=0;=0;
}stop() //
окончание передачи данных по интерфейсу I2C
{&=~(1<<7);&=~(1<<6);
// состояние линий SDA и SCL определяет ведущий (мк)=0;=0;=1;=1;
}WriteByte (char
c) // передача байта c по интерфейсу I2C
{&=~(1<<7);&=~(1<<6);
// состояние линий SDA и SCL определяет ведущий (мк)
for
(i=8; i>=1; i-) // посылаем 8 байтов данных
{=((c&(1<<(i-1)))>>(i-1));
RB7=1;=0;
}&=~(1<<7);|=(1<<6);
// здесь уровень на SDA поределяет ведомый (часы)=1;=0;&=~(1<<7);&=~(1<<6);
}ReadByte() //
прием байта по интерфейсу I2C
{out=0x00;&=~(1<<7);|=(1<<6);
// линию SDA определяет ведомый, a SCL - ведущий
for
(i=8; i>=1; i-)
{=1;+=(RB6<<(i-1));
RB7=0;
}&=~(1<<7);&=~(1<<6);
// состояние линий SDA и SCL определяет ведущий (мк)
RB6=1;=1;=0;out;
}Write
(char Adress, char Data) // записываем данные
Data в ячейку часов с адресом
Adress
}Read (char
Adress) // считываем данные из ячейки часов с адресом Adress
{output; //
переменная для вывода(); // начинаем передачу по I2C(WRITE); // передаем адрес
часов + бит записи(Adress); // передаем адрес нужной ячейки(); // рестарт
протокола I2C(READ); // передаем адрес часов + бит чтения=ReadByte(); //
считываем ячейку(); // завершаем прием данных по I2Coutput;
}
// полная копия
функции Write, но для обработчика прерываний
// пришлось сделать
такую копию, так как в ином случае возникает необъяснимая ошибка
// которая не
происходит, если эту функцию использовать под разными именами в main() и
interrupt()W (char Adress, char Data) // записываем данные Data в ячейку часов
с адресом Adress
{(); // начинаем
передачу по I2C(WRITE); // передаем адрес часов + бит записи(Adress); //
передаем адрес часов + бит записи(Data); // записывем нужные данные(); //
завершаем прием данных по I2C
}
// -
// обработчик
прерыванийinterrupt ISR()
{
// - Прерывания
от кнопок управления -
// Нажатие кнопки
«ВНИЗ»(INT0IF)
{(LedWork) //
Находимся в режиме настройки
{(Mode) //
Смотрим, какой режим активен
{1: // Режим
главного меню(m<3) m++; else m=1;;2: // Режим установки времени и даты
if
(m<7) m++; else m=1;;
case 3: // Режим
ввода года(m>0) m-; else m=3;
break;4:
// Режим ввода месяца(m>1) m-; else m=12;;
case 5: // Режим
ввода числа=((Read(0x06)&0x10)>>4)*10+(Read(0x06)&0x0F); //
считываем записанный в часы месяц=((0xC0&Read(0x05))>>6);(month) // в
зависимости от месяца и високосности года изменяем предел установки дня
{1:
case 3: case 5: case 7: case 8: case 10: case 12:=31; break;4: case 6:
case 9: case 11:=30; break;2:(year) day=28; else day=29; break;
}(m>1)
m-; else m=day;
break;6: // Режим
ввода дня недели
if
(m>0) m-; else m=6;;
case 7: // Режим
ввода часа(m>0) m-; else m=23;
break;8:
// Режим ввода минут(m>0) m-; else m=59;;9: // Режим меню звонков(m<4)
m++; else m=1;
break;10: //
Режим ввода количества звонков
if
(m>0) m-; else m=30;;
case 11: // Режим
выбора звонка для редактирования времени
if
(m>1) m-; else m=Read(16)+1;
break;12: //
Режим ввода часа выбранного звонка
if
(m>0) m-; else m=23;;
case 13: // Режим
ввода минуты выбранного звонка
if
(m>0) m-; else m=59;;
case 14: // Режим
ввода длительности звонков(m>0) m-; else m=59;
break;
}();
}IF=0;
}