МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”

ЗВІТ
ДО ЛАБОРАТОРНОЇ РОБОТИ № 5
З КУРСУ “МІКРОПРОЦЕСОРНІ ПРИСТРОЇ”
«Побудова модуля управління системи контролю доступу на AVR – мікро контролерах. Робота з інтерфейсами 1 – Wire, IC, SPI»



Мета роботи: ознайомитись з принципами побудови модулів управління системи контролю доступу. Вивчити правила обміну інформацією через інтерфейси 1 – Wire, IC, SPI та ознайомитися з їх програмною реалізацією для AVR – мікроконтролерів на мові С в середовищі Code VISION AVR
Завдання :
1. Створити проект в Code VISION AVR, ввести свою програму, провести її компіляцію.
2. відкрити файл LR_5.dsn в програмі Proteus, внести у схему відповідно до свого індивідуального завдання, підключити до МК отриманий в Code VISION AVR hex – файл.
3. запустити режим симуляції схеми та перевірити правильність функціонування модуля управління СКД у всіх режимах роботи: очікування, пред’явлення зареєстрованого ключа, пред’явлення незареєстрованого ключа, натискання кнопки виходу.

Кількість запитів N
Кількість зареєстрованих ключів
Час відкриття дверей t, сек
Формат реєстраційного запису
Початкова дата та час

2
40
3
5
Номер ключа, число, година, тип події (вхід/вихід)
02.02.09
13:15:27


Текст програми у Code VISION AVR
// Блок управління системи контролю доступу на МК АТ90S2313 з iButton DS1990, I2C-RTC DS1307 та SPI-EEPROM 25LC256 (32Kx8)
// 20.05.2009 р.
// Тактова частота МК 7.3728 МГц
////////////////////////////////////////////////////////////////////////////////////
// Порт для підключення iButton DS1990
#asm
.equ __w1_port = 0x18
.equ __w1_bit = 5
#endasm
////////////////////////////////////////////////////////////////////////////////////
// Порт для підключення I2C-RTC DS1307
#asm
.equ __i2c_port = 0x18
.equ __scl_bit = 2
.equ __sda_bit = 1
#endasm
////////////////////////////////////////////////////////////////////////////////////
#include <90S2313.h>
#include <1wire.h>
#include <i2c.h>
#include <delay.h>
////////////////////////////////////////////////////////////////////////////////////
// Оголошення типу даних - байт
typedef unsigned char byte;
////////////////////////////////////////////////////////////////////////////////////
// Структура дати і часу
typedef struct
{
byte Second;
byte Minute;
byte Hour;
byte Day;
byte Date;
byte Month;
byte Year;
} DS1307_Data;
////////////////////////////////////////////////////////////////////////////////////
// Глобальні змінні
// Оголошення змінної для збереження поточного часу і дати
DS1307_Data DS1307_1;
// Оголошення змінної для збереження ідентифікаційного номера iButton DS1990A
byte ROM_Code[9];
////////////////////////////////////////////////////////////////////////////////////
//******************************************************************//
// Виводи SPI-EEPROM 25LC256
#define PORT_EEPROM PORTD
#define DDR_EEPROM DDRD
#define PIN_EEPROM PIND
#define CS 3
#define SCK 4
#define SI 5
#define SO 6
//******************************************************************//
// Виводи I2C-RTC DS1307
#define PORT_RTC PORTB
#define DDR_RTC DDRB
#define PIN_RTC PINB
#define SDA 1
#define SCL 2
//******************************************************************//
// Виводи iButton DS1990A
#define PORT_iButton PORTB
#define DDR_iButton DDRB
#define PIN_iButton PINB
#define Data_iButton 5
//******************************************************************//
// Виводи електронного замка
#define PORT_Switch PORTB
#define DDR_Switch DDRB
#define PIN_Switch PINB
#define Switch 7
//******************************************************************//
// Виводи світлодіоду
#define PORT_Led PORTB
#define DDR_Led DDRB
#define PIN_Led PINB
#define Led 6
//******************************************************************//
// Виводи кнопки виходу
#define PORT_Out_Key PORTD
#define DDR_Out_Key DDRD
#define PIN_Out_Key PIND
#define Out_Key 2
//******************************************************************//
// Коди команд EEPROM 25LC256
#define EEPROM_READ 0x03
#define EEPROM_WRITE 0x02
#define EEPROM_WRDI 0x04
#define EEPROM_WREN 0x06
#define EEPROM_RDSR 0x05
#define EEPROM_WRSR 0x01
//******************************************************************//
// Коди команд iButton DS1990
#define SEARCH_ROM 0xF0
//******************************************************************//
// Адреса сімейства iButton
#define DS1990_FAMILY_CODE 0x01
//******************************************************************//
// Кількість подій в системі
#define N_Record 55
//******************************************************************//
// Розмір одного запису в байтах
#define Record_Size 16
//******************************************************************//
// Адреса початку записів в EEPROM 25LC256
#define Record_Addr 0x40
//******************************************************************//
// Адреса лічильника записів в EEPROM
#define Record_Count_Addr 0x30
//******************************************************************//
// Час відкривання дверей в мілісекундах
#define T_msec 5000
//******************************************************************//
// Кількість зареєстрованих ключів
#define N_Key 3
//******************************************************************//
// Тип запису
#define Input_Record 0
#define Output_Record 1
//******************************************************************//
// E8C52A
// 3D2C90
/*----------------------------------------------------------------*/
// Підпрограма обслуговування зовнішнього переривання по виводу INT0
interrupt [2] void ext_interrupt0(void);
/*----------------------------------------------------------------*/
void Pin_Init(void);
// Функції нижнього рівня роботи з РКД
void DS1307_Init(void);
void DS1307_Read(DS1307_Data* arg1);
void DS1307_Write(DS1307_Data* arg1);
byte SPI_Send_Byte(byte data);
void SPI_Send_CMD1(byte cmd);
byte SPI_Read_SR(void);
byte SPI_Read_Data(int address, byte* buffer, byte n);
byte SPI_Write_Data(int address, byte* buffer, byte n);

void Save_Record(DS1307_Data* arg1, byte* code, byte type);
////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
byte temp, ii, jj, temp1;

byte iButton_Arrary[N_Key][8];
Pin_Init();
DS1307_1.Second = 0x27; //02-02-09 13:15:27
DS1307_1.Minute = 0x15;
DS1307_1.Hour = 0x13;
DS1307_1.Day = 0x01;
DS1307_1.Date = 0x02;
DS1307_1.Month = 0x02;
DS1307_1.Year = 0x09;
DS1307_Init();
DS1307_Write(&DS1307_1);
// Прочитати зареєстровані ключі з EEPROM-пам'ті
for(ii = 0; ii < N_Key; ii++)
temp = SPI_Read_Data(0x0000 + ii * 8, &iButton_Arrary[ii][0], 8);
// Налаштувати зовнішнє переривання INT0 від кнопки виходу
GIMSK = GIMSK | 0x40;
MCUCR = MCUCR | 0x02;
while(1)
{
#asm("cli")
temp = w1_search(SEARCH_ROM, &ROM_Code[0]);

if (temp == 0)
{
#asm("sei")
}
else
{
// Пошук
for(ii = 0; ii < N_Key; ++ii)
{
temp1 = 0;

for(jj = 0; jj < 8; ++jj)
{
if(ROM_Code[jj] != iButton_Arrary[ii][jj])
{
temp1 = 1;
break;
}
}

if(temp1 == 0)
break;
}

if(temp1 == 0)
{
DS1307_Read(&DS1307_1);
Save_Record(&DS1307_1, &ROM_Code[0], Input_Record);

PORT_Led.Led = 0;
PORT_Switch.Switch = 1;

delay_ms(T_msec);

PORT_Led.Led = 1;
PORT_Switch.Switch = 0;
}
else
#asm("sei");
}

delay_ms(1);
};
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void DS1307_Init(void)
{
// Ініціалізація І2С шини та режиму роботи годинника реального часу (RTC)
byte temp;
temp = i2c_start();
temp = i2c_write(0xd0);
temp = i2c_write(0x07);
temp = i2c_write(0b00000000);
i2c_stop();
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void DS1307_Read(DS1307_Data* arg1)
{
// Зчитування часу та дати з RTC
byte temp2;
temp2 = i2c_start();
temp2 = i2c_write(0xd0);
temp2 = i2c_write(0x00);
i2c_stop();
temp2 = i2c_start();
temp2 = i2c_write(0xd1);
arg1->Second = i2c_read(1) & 0x7F;
arg1->Minute = i2c_read(1) & 0x7F;
arg1->Hour = i2c_read(1) & 0x3F;
arg1->Day = i2c_read(1) & 0x07;
arg1->Date = i2c_read(1) & 0x3F;
arg1->Month = i2c_read(1) & 0x1F;
arg1->Year = i2c_read(0);
i2c_stop();
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void DS1307_Write(DS1307_Data* arg1)
{
// Запич часу та дати в RTC
byte temp2;
temp2 = i2c_start();
temp2 = i2c_write(0xd0);
temp2 = i2c_write(0x00);

temp2 = i2c_write(arg1->Second);
temp2 = i2c_write(arg1->Minute);
temp2 = i2c_write(arg1->Hour | 0b00000000);
temp2 = i2c_write(arg1->Day);
temp2 = i2c_write(arg1->Date);
temp2 = i2c_write(arg1->Month);
temp2 = i2c_write(arg1->Year);

i2c_stop();
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
byte SPI_Send_Byte(byte data)
{
byte ii, temp, result = 0, temp1 = 0x80;
for(ii = 0; ii < 8; ++ii)
{
temp = PIN_EEPROM;
temp = temp & (1<<SO);

if(temp != 0)
result = result | temp1;

PORT_EEPROM.SI = (data & temp1) && 1;
#asm("nop");

PORT_EEPROM.SCK = 1;

temp1 = temp1 >> 1;

PORT_EEPROM.SCK = 0;
}
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void Pin_Init(void)
{
PORT_EEPROM.CS = 1;
PORT_EEPROM.SCK = 0;
PORT_EEPROM.SI = 0;
PORT_EEPROM.SO = 0;
DDR_EEPROM.CS = 1;
DDR_EEPROM.SCK = 1;
DDR_EEPROM.SI = 1;
DDR_EEPROM.SO = 0;
PORT_Switch.Switch = 0;
DDR_Switch.Switch = 1;
PORT_Led.Led = 1;
DDR_Led.Led = 1;
PORT_Out_Key.Out_Key = 0;
DDR_Out_Key.Out_Key = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
byte SPI_Write_Data(int address, byte* buffer, byte n)
{
byte ii, result;
PORT_EEPROM.CS = 0;
SPI_Send_Byte(EEPROM_WRITE);
SPI_Send_Byte(address>>8);
SPI_Send_Byte(address);

for(ii = 0; ii < n; ++ii)
{
SPI_Send_Byte(buffer[ii]);
}
PORT_EEPROM.SI = 0;
PORT_EEPROM.CS = 1;
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
byte SPI_Read_Data(int address, byte* buffer, byte n)
{
byte ii, result;
PORT_EEPROM.CS = 0;

SPI_Send_Byte(EEPROM_READ);
SPI_Send_Byte(address>>8);
SPI_Send_Byte(address);

for(ii = 0; ii < n; ii++)
{
buffer[ii] = SPI_Send_Byte(0);
}

PORT_EEPROM.SI = 0;
PORT_EEPROM.CS = 1;
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void SPI_Send_CMD1(byte cmd)
{
PORT_EEPROM.CS = 0;

SPI_Send_Byte(cmd);

PORT_EEPROM.SI = 0;
PORT_EEPROM.CS = 1;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
byte SPI_Read_SR(void)
{
byte temp;
PORT_EEPROM.CS = 0;

temp = SPI_Send_Byte(EEPROM_RDSR);
temp = SPI_Send_Byte(0);

PORT_EEPROM.SI = 0;
PORT_EEPROM.CS = 1;

return temp;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
interrupt [2] void ext_interrupt0(void)
{
byte ii;
delay_ms(10);
if(PIN_Out_Key.Out_Key == 0)
{
DS1307_Read(&DS1307_1);

for(ii = 0; ii < 8; ++ii)
ROM_Code[ii] = 0;

Save_Record(&DS1307_1, &ROM_Code[0], Output_Record);

PORT_Led.Led = 0;
PORT_Switch.Switch = 1;

delay_ms(T_msec);

PORT_Led.Led = 1;
PORT_Switch.Switch = 0;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
void Save_Record(DS1307_Data* arg1, byte* code, byte type)
{
byte temp, temp1, temp2[2];
int start;
while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM
;

// Прочитати значення лічильника подій в змінну temp1
temp = SPI_Read_Data(Record_Count_Addr, &temp1, 1);
if(temp1 == N_Record) // Якщо досягнуто максимального значення
{
temp1 = 1; // Почати заново
start = Record_Addr;
}
else // Інакше обчислити адресу наступного запису
{
start = Record_Addr + Record_Size * (int)temp1;
temp1++; // Збільшити кількість записів на 1
}
SPI_Send_CMD1(EEPROM_WREN); // Дозволити запис в EEPROM
while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM
;
// Записати 8 байт ідентифікаційного номеру DS1990A
temp = SPI_Write_Data(start, code, 8);
while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM
;
SPI_Send_CMD1(EEPROM_WREN); // Дозволити запис в EEPROM


while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM
;
temp2[0] = arg1->Hour;
temp2[1] = arg1->Date;

temp = SPI_Write_Data(start + 8, temp2, 2);
while((temp = SPI_Read_SR()) & 0x01)
;
SPI_Send_CMD1(EEPROM_WREN);
while((temp = SPI_Read_SR()) & 0x01)
;
temp = SPI_Write_Data(start + 15, &type, 1);
while((temp = SPI_Read_SR()) & 0x01)
;
SPI_Send_CMD1(EEPROM_WREN);
while((temp = SPI_Read_SR()) & 0x01)
;
temp = SPI_Write_Data(Record_Count_Addr, &temp1, 1);
};
Схема симуляції у Proteus 7

Висновок на даній лабораторній роботі я ознайомилася з принципами побудови модулів управління систем контролю доступу , вивчила правила обміну інформацією через інтерфейси 1 – Wire, IC, SPI та ознайомилася з їх програмною реалізацією для AVR – мікроконтролерів на мові С в середовищі Code VISION AVR