вторник, 14 сентября 2010 г.

Пример прошивки для ATMega8

#include <mega8.h>
#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
// };

Комментариев нет:

Отправить комментарий