#include <stdio.h> // Standard Input/Output functions
#include <delay.h>
#include "tpalibs.h"
#include "modlibs.h"
#include "bits.h"
// Здесь устанавливается версия программы, которая потом будет отдаваться по MDB по команде CONFIG
#define cMajorVersion 0x01 // Мажор и минор версии этой программы
#define cMinorVersion 0x04 // Version = "cMajorVersion.cMinorVersion"
// Описание функций
byte MotorInit(void); // Инициализация замка
byte MotorControl(byte); // Управление мотором LOCKOPEN, LOCKCLOSE, LOCKBRAK, LOCKSTOP
#ifdef MDB_MODE
void MDBInit(void);
void MDBConfig(void);
void MDBDiagnostic(void);
void MDBPoll(void);
void MDBEvent(void);
#else
void ADCReadAndPrint(void);
#endif
// Описание внешних переменных
#ifdef MDB_MODE
byte LastEvent = 0;
#endif
// Начало программы
void main(void) {
byte status;
byte inbyte;
byte MotorMode; // Статус мотора
word W; // Значение АЦП
bit isCanOpenDoor = 1, isCanCloseDoor = 1; // 2 взаимосвязанных битовых флага регистра замка
bit isGerkonOpen = 1, isGerkonClose = 1; // 2 взаимосвязанных битовых флага регистра геркона двери
// bit ENABLEPRINTW; // Печатать ли ADC
#ifdef MDB_MODE
bit MDBBUSResetSignal = 0; // Сигнал на Reset контроллера
SelfAddress = cSelfAddress;
#endif
blinking();
#ifdef MDB_MODE
init_mega8(SERIAL9); // Инициализируем кристалл в 9-ти битным UART'ом
#else
init_mega8(SERIAL8); // Инициализируем кристалл в 8-ми битным UART'ом
#endif
blinking();
#ifndef MDB_MODE
printf("\n\rСтарт тестового ПО замка ИК барьера. Версия %u.%u(С). ", cMajorVersion, cMinorVersion);
printf("Параметры прошивки: 4.1 мс + 6 СК (Внутренни RC - 4 МГц)\n\r");
#else
ReturnFromCommand();
#endif
blinking();
#asm("sei") // Global enable interrupts
MotorInit();
while (1) {
if ((status=UCSRA) & RX_COMPLETE) { // Если что-то есть в порту
#ifdef MDB_MODE
recv_vmc(SelfAddress);
#else
inbyte = MDBPort;
switch (inbyte) {
case 0x31:
MOTORPHASE = 1; printf("PHASE = 1\r\n"); break;
case 0x32:
MOTORSLEEP = 1; printf("SLEEP = 1\r\n"); break;
case 0x33:
MOTORENABLE = 1; printf("ENABLE = 1\r\n"); break;
case 0x34:
MOTORPHASE = 0; printf("PHASE = 0\r\n"); break;
case 0x35:
MOTORSLEEP = 0; printf("SLEEP = 0\r\n"); break;
case 0x36:
MOTORENABLE = 0; printf("ENABLE = 0\r\n"); break;
case 0x7A: // 'z'
MotorInit(); break;
case 0x78: // 'x'
printf("Открываем замок\r\n"); MotorControl(LOCKOPEN); break;
case 0x63: // 'c'
printf("Закрываем замок\r\n"); MotorControl(LOCKCLOSE); break;
case 0x37: // Зажигаем на время светик на плате
ERRLAMP = 1; Timer0Counter = cTimer0Counter; break;
case 0x38: // Отключаем принудительно светик на плате
ERRLAMP = 0; break;
case 0x39: // Печатаем значение всех ADC
ADCReadAndPrint(); break;
default:
MotorControl(0);
printf("СТОП мотор! UDR = %x ", inbyte); break;
};
#endif
};
#ifdef MDB_MODE
if (ComandCompleted) { // Если прием от VMC завершился
// Если сейчас режим ожидания подтверждения от VMC
if (ConfirmFromVMC) confirm_vmc(); else {
switch (CommandFromVMC) {
case 0 :
MDBInit(); break;
case 1 :
MDBConfig(); break;
case 2 :
MDBDiagnostic(); break;
case 3 :
MDBPoll(); break;
case 4 :
MDBEvent(); break;
default :
ReturnFromCommand(); break;
};
};
};
/* Здесь определяем реакцию программы на ресет по шине MDB
Анализ ресета по шине длиной 522 мс при частоте 8 MHz
(Внимание! Если меняется частота, пересчитать константу cResetTimer) */
if (RXD_MDB) MDBBUSResetSignal = 0; else { // если на шине установлена логическая 1, то игнорируем дальнейший код
// Как только на шине выставился логический 0, то включаем подсчет времени
if (!MDBBUSResetSignal) { Timer2Counter = 0; MDBBUSResetSignal = 1; };
// Если кол-во срабатываний таймера превысило 16, то пора перегружаться
if (Timer2Counter >= TimeToRestart) {
#asm("RJMP __RESET");
};
};
#endif
// Проверяем значение датчиков на моторе замка
if (DATAKEY1) {
BLINKLAMP = 1; Timer1Counter = cTimer1Counter;
if (isCanOpenDoor) { // Здесь код для 1-го срабатывания
isCanOpenDoor = 0; isCanCloseDoor = 1;
MotorControl(LOCKSTOP); LastEvent = evLOCKCLOSE;
};
} else BLINKLAMP = 0;
if (DATAKEY2) {
ERRLAMP = 1; Timer1Counter = cTimer1Counter;
if (isCanCloseDoor) { // Здесь код для 2-го срабатывания
isCanCloseDoor = 0; isCanOpenDoor = 1;
MotorControl(LOCKSTOP); LastEvent = evLOCKOPEN;
};
} else ERRLAMP = 0;
// Если мотор сейчас крутится, то анализируем потребление тока
if (MOTORTURNONMODE) { // Анализируем статус мотора (если не 0, то начинаем анализ)
W = read_adc(cDC_Motor); // Измеряем 2-й канал, если мотор уже крутится
if (Timer0Counter == 0) { // Если уже можно мерять, то выполняем нижеследующую часть кода
// printf ("TimerCount = %d ", Timer1Counter);
if (W > cMinADCMotor) {
if (W > cMaxADCMotor) {
#ifdef MDBMODE
LastEvent = evDIAGFALSE;
#else
printf("Мотор перегружен, W = %d... Остановите его кто-нибудь! ", W);
#endif
MotorControl(LOCKSTOP);
};
} else {
// Мотор отключен или сломан. Подаем команду остановки на кристалл
#ifdef MDBMODE
LastEvent = evDIAGFALSE;
#else
printf("Мотор отключен или сломан. W = %d ", W);
#endif
// delay_ms(500);
};
};
};
// Проверяем геркон двери
if (GERKONMODE) {
if (isGerkonOpen) { LastEvent = evGERKONOPEN; isGerkonOpen = 0; isGerkonClose = 1; };
} else {
if (isGerkonClose) { LastEvent = evGERKONCLOSE; isGerkonOpen = 1; isGerkonClose = 0; };
};
};
}
#ifdef MDB_MODE
// INIT
void MDBInit(void) {
// Если контрольная сумма 0, то отсылаем ACK
if (~ControlSumError) send_vmc(cACK, 1); else send_vmc(cNAK, 1);
MotorInit(); // взводим мотор в исходное состояние
ReturnFromCommand(); // взводим в исходное состояние
};
// CONFIG
void MDBConfig(void) {
// Если ошибка в контрольной сумме - посылаем NACK
if (ControlSumError) { send_vmc(cNAK, 1); return; };
// Сначала посылаем мажор и минор версии этой программы (2 байта)
byte_vmc(cMajorVersion); byte_vmc(cMinorVersion);
// Отсылаем контрольную сумму
crc_vmc();
ConfirmFromVMC = 1; // Включаем ожидание от VMC
};
// DIAG
void MDBDiagnostic(void) {
// Если контрольная сумма 0, то отсылаем ACK
if (~ControlSumError) send_vmc(cACK, 1); else send_vmc(cNAK, 1);
ReturnFromCommand();
};
// POLL
void MDBPoll(void) {
// Если контрольная сумма 0, то отсылаем ACK
if (~ControlSumError) send_vmc(cACK, 1); else send_vmc(cNAK, 1);
ReturnFromCommand(); // взводим в исходное состояние
};
// EVENT
void MDBEvent(void) {
byte inbyte, mstatus;
// Анализируем событие во втором байте.
inbyte = FromVMC[1];
switch (inbyte) {
case 0x00: // Представляем значение ИК-барьера после обработки
byte_vmc(LastEvent); LastEvent = 0;
break;
case 0xA0:
mstatus = MotorControl(LOCKOPEN);
byte_vmc(mstatus);
break;
case 0xA8:
mstatus = MotorControl(LOCKCLOSE);
byte_vmc(mstatus);
break;
default:
Timer1Counter = cTimer1Counter; ERRLAMP = 1; // Зажигаем светик ошибки SETBIT(ERRPORT,ERRPIN);
byte_vmc(0);
break;
};
byte_vmc(SelfAddress);
crc_vmc();
ConfirmFromVMC = 1; // Включаем ожидание от VMC
};
#else
// Печать всех входов АЦП
void ADCReadAndPrint(void) {
byte i;
word ADCResult;
printf("Старт измерений по всем каналам\n\r");
for (i = 0; i < cADCChannels; i++) {
ADCResult = read_adc(i);
printf("Канал %u, значение %u\n\r", i, ADCResult);
delay_ms(50);
};
};
#endif
// Инициализация замка
byte MotorInit(void) {
#ifndef MDB_MODE
printf("Инициализация замка\r\n");
#endif
if ((!DATAKEY2) && (!DATAKEY1)) MotorControl(LOCKCLOSE);
if (DATAKEY2 && (!DATAKEY1)) return (0);
delay_ms(1000);
MotorControl(LOCKCLOSE);
#ifndef MDB_MODE
printf("Вторая попытка\r\n");
#endif
if (DATAKEY2 && (!DATAKEY1)) return (0);
delay_ms(1000);
MotorControl(LOCKCLOSE);
#ifndef MDB_MODE
printf("Не удалось\r\n");
#endif
return (0);
};
// Управление мотором LOCKOPEN, LOCKCLOSE, LOCKBRAK, LOCKSTOP
byte MotorControl(byte MotorComand) {
byte MotorMode; // Локальная переменная текущего состояния мотора
MotorMode = MOTORSTATUS; // Вычитываем 3 бита состояния
if (MotorMode == MotorComand) return (MotorMode); // Если мотор в этом же режиме, то сразу выходим
// printf(" Команда замку = %x ", MotorComand);
switch (MotorComand) {
case LOCKSTOP:
MOTORENABLE = 0; MOTORSLEEP = 0; MOTORPHASE = 0;
break;
case LOCKOPEN:
MOTORENABLE = 1; MOTORSLEEP = 1; MOTORPHASE = 0;
break;
case LOCKCLOSE:
MOTORENABLE = 1; MOTORSLEEP = 1; MOTORPHASE = 1;
break;
case LOCKBRAK:
MOTORENABLE = 0; MOTORSLEEP = 1; MotorMode = MotorControl(LOCKSTOP);
break;
default:
MotorMode = MotorControl(LOCKSTOP);
break;
};
Timer0Counter = cTimer0Counter;
return (MOTORSTATUS);
};
// Сработка KEY1
// interrupt [EXT_INT0] void ext_int0_isr(void) { // External Interrupt 0 service routine
// };
// Сработка KEY2
// interrupt [EXT_INT1] void ext_int1_isr(void) { // External Interrupt 0 service routine
// };
