МІНІСТЕРСТВО ОСВІТИ УКРАЇНИ
ДЕРЖАВНИЙ УНІВЕРСИТЕТ «ЛЬВІВСЬКА ПОЛІТЕХНІКА»
Побудова модуля управління системи контролю доступу на
AVR-мікроконтролерах
Лабораторна робота № 5
З курсу «Мікропроцесорні пристрої»
Львів 2010
Мета роботи – ознайомитись з побудовою інфрачервоних детекторів руху і їх програмно апаратною реалізацією на AVR-мікроконтролерах.
ЗАВДАННЯ
Домашня підготовка до роботи
1.Вивчити теоретичний матеріал.
2.Вивчити основні властивості МК необхідні для виконання лабораторної роботи.
3.Підготувати програму функціонування охоронної системи
Виконати в лабораторії
1.Створити проект в CodeVision, ввести свою програму, провести її асемблювання.
2.В режимі покрокової відладки переконатися в правильності роботи програми.
3.Відкрити файл-схему у програмі Proteus, підключити до МК hex-файл.
4.Запустити режим симуляції схеми та перевірити правильність функціонування охоронної системи у всіх режимах роботи.
ТЕКСТ ПРОГРАМИ
#include <90S2313.h>
#include <delay.h>
// Підтримка 1-Wire інтерфейсу
#asm
.equ __w1_port=0x18 // Для підкл. iButton викор. PORTB
.equ __w1_bit=5 // Вивід 5 - РВ5
#endasm
#include <1wire.h>
// Підтримака І2С інтерфейсу
#asm
.equ __i2c_port=0x18 // Для інтерфейсу I2C використовується PORTB
.equ __sda_bit=1 // SDA = PB1
.equ __scl_bit=2 // SCL = PB2
#endasm
#include <i2c.h>
// SPI Settings
//#define SPI PORTD
#define NCS 3 //PD3
#define SCLK 4 //PD4
#define MOSI 5 //PD5
#define MISO 6 //PD6
// адреса масиву легальних ключів
#define REG_KEY_ADDR 16
// адрера початку журналу
#define EVENT_LIST 0x60
// максимальна кількість записів в журналі
#define MAX_EVENTS 95
// маска для вибору необхідних даних з ГРЧ
#define MASK 0b01110000
// час відкриття дверей (cек.)
#define OPEN_TIME 10
typedef unsigned char BYTE;
// структура одного запису реєстраційного журналу
struct RegRec
{
unsigned char ID[8]; // ідентифікатор користувача
BYTE date[3]; // 0 - дата, 1 - місяць, 2 - рік
unsigned char type; // 1 - вхід, 0 - вихід
} event;
//////////////////////////////////////////////////////////////////////////////////////
// передача одного байту через SPI
// повертає отриманий байт
BYTE SPI_SendByte(BYTE data)
{
BYTE temp, res = 0, mask = 0x80;
while(mask)
{
// зберігаємо біт що поступив на вхід
temp = PIND & (1<<MISO);
if(temp) res|=mask;
// формуємо вихідний біт
PORTD.MOSI = (data & mask) && 1;
#asm("nop");
delay_ms(10);
PORTD.SCLK = 1;
mask>>=1;
PORTD.SCLK = 0;
}
return res;
}
///////////////////////////////////////////////////////////////////////////////////
// запис блоку даних через SPI
void SPI_Write(const BYTE *buf, BYTE size, unsigned int addr)
{
if(!buf || !size || size>64) return ;
PORTD.SCLK = 0;
PORTD.NCS = 0;
SPI_SendByte(0b00000110); // дозволити запис в пам'ять
PORTD.NCS = 1; // завершити команду
#asm("nop");
PORTD.NCS = 0; // розпочати команду
SPI_SendByte(0b00000010); // код операції запису в пам'ять
SPI_SendByte(addr>>8); // старший байт адреси
SPI_SendByte((BYTE)addr); // молодший байт адреси
// запис самих даних
while(size)
SPI_SendByte(*buf++), --size;
PORTD.NCS = 1;
}
////////////////////////////////////////////////////////////////////////
// запис блоку даних через SPI
BYTE SPI_Read(BYTE *buf, BYTE size, unsigned int addr)
{
if(!buf || !size || size>64) return 1;
PORTD.SCLK = 0;
PORTD.NCS = 0; // розпочати команду
SPI_SendByte(0b00000011); // код операції читання з пам'яті
SPI_SendByte(addr>>8); // старший байт адреси
SPI_SendByte((BYTE)addr); // молодший байт адреси
// читання самих даних
while(size)
*buf++=SPI_SendByte(0), --size;
PORTD.NCS = 1;
return 0;
}
////////////////////////////////////////////////////////////////////////////
BYTE FindKey(const BYTE key[8])
{
BYTE key_count;
BYTE rKey[8],k;
int addr = REG_KEY_ADDR;
SPI_Read(&key_count, sizeof(key_count), REG_KEY_ADDR-1);
while(key_count--)
{
SPI_Read(rKey, sizeof(rKey), addr);
for(k=0;k<sizeof(rKey);k++) if(rKey[k]!=key[k]) break;
if(k==sizeof(rKey)) return 1;
addr+=sizeof(rKey);
}
return 0;
}
//////////////////////////////////////////////////////////
void RegisterEvent(BYTE key[8], BYTE type)
{
BYTE ev_count; // кількість записів в журналі
BYTE tmp, mask;
int addr = EVENT_LIST; // адреса нового запису
SPI_Read(&ev_count, sizeof(ev_count), EVENT_LIST - sizeof(ev_count));
if(ev_count==MAX_EVENTS) ev_count=0;
tmp = ev_count++;
// знаходимо адресу для нового запису
while(tmp--) addr+=sizeof(event);
// записуємо кількість записів
SPI_Write(&ev_count, sizeof(ev_count), EVENT_LIST-sizeof(ev_count));
// формуємо запис, копіюємо ключ
for (ev_count=0;ev_count<sizeof(key);ev_count++)
event.ID[ev_count]=key[ev_count];
// запитаємо рік, місяць і дату в ГРЧ
while(!i2c_start());
// звертаємося до годинника реального часу
while(!i2c_write(0b11010000));
while(!i2c_write(0)); // читаємо з 0 адреси
while(!i2c_start()); // repeat start
while(!i2c_write(0b11010001));
for(mask=1, ev_count=0; mask; mask<<=1)
{
tmp = i2c_read(1);
if(mask & MASK) // вибираємо тільки необхідні дані
event.date[ev_count++]=tmp;
}
i2c_stop();
// задаємо тип
event.type = type;
// записуємо дані в журнал
SPI_Write((BYTE*)&event, sizeof(event), addr);
}
///////////////////////////////////////////////
// Ініціалізація годинника реального часу
void InitRealTimeClock()
{
i2c_init(); // ініціалізація I2C інтерфейсу
// очікуємо на звільнення шини і формуємо умову початку передачі даних
while(!i2c_start());
// звертаємося до годинника реального часу
while(!i2c_write(0b11010000));
// починаємо запис з нульової комірки пам'яті
while(!i2c_write(0));
// необхідно записати дату/час 13.01.09 02:58:51
while(!i2c_write(0b01010001)); // секунди 51
while(!i2c_write(0b01011000)); // хвилини 58
while(!i2c_write(0b01000010)); // години 02/24
while(!i2c_write(0b01000011)); // день тижня
while(!i2c_write(0b00001001)); // дата 09
while(!i2c_write(0b00000001)); // місяць 01
while(!i2c_write(0b00001001)); // рік 09
while(!i2c_write(0)); // інші налаштування по замовчуванню
i2c_stop(); //закінчуємо обмін даними
}
//////////////////////////////////////////////////////
void main()
{
unsigned char item_key[9]; // ID поточного пристрою
BYTE out_h=1;
PORTD.NCS = 1;
DDRD.NCS = DDRD.SCLK = DDRD.MOSI = 1;
DDRB.6 = PORTB.6= 1; // вимикаємо світлодіод
InitRealTimeClock();
while(1)
{
// опитуємо кнопку виходу
if(!PIND.2 && out_h)
{
// оскільки при виході не стоїть зчитувач ключів
// ми не можемо ідентифікувати особу - обнуляємо ключ
for(out_h=0;out_h<sizeof(item_key);out_h++) item_key[out_h]=0;
out_h=0;
PORTB.6 = 0; // вмикаємо світлодіод
// реєструємо запис в журналі
RegisterEvent(item_key, 0);
delay_ms(OPEN_TIME*1000); // відкриваємо двері.
PORTB.6 = 1; // вимикаємо світлодіод
}
if(PIND.2) out_h=1;
// очікуємо на підключення пристрою 1-Wire
if(!w1_init()) continue;
// посилаємо команду зчитування ID
if(!w1_search(0xF0, item_key)) continue;
// шукаємо ключ в базі доступних ключів
if(!FindKey(item_key)) continue;
// користувач легальний, вмикаємо світлодіод
PORTB.6 = 0;
// Реєструємо його в журналі
RegisterEvent(item_key, 1);
delay_ms(OPEN_TIME*1000); // відкриваємо двер.
PORTB.6 = 1; // вимикаємо світлодіод
}
}
СХЕМА
ВИСНОВОК
На даній лаболаторній роботі я ознайомився з послідовністю створення та відладки програмно-апаратних засобів на основі мікроконтролерів сімейства AVR в програмах AVR Studio та Proteus 7.