ПОБУДОВА МОДУЛЯ УПРАВЛІННЯ СИСТЕМИ КОНТРОЛЮ ДОСТУПУ НА AVR-МІКРОКОНТРОЛЕРАХ. РОБОТА З ІНТЕРФЕЙСАМИ 1-WIRE, I2C, SPI

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
Не вказано
Кафедра:
Не вказано

Інформація про роботу

Рік:
2024
Тип роботи:
Лабораторна робота
Предмет:
Захист інформації

Частина тексту файла (без зображень, графіків і формул):

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”  ЛАБОРАТОРНА РОБОТА №5 з курсу “Мікропроцесори в системах технічного захисту інформації” ТЕМА: «ПОБУДОВА МОДУЛЯ УПРАВЛІННЯ СИСТЕМИ КОНТРОЛЮ ДОСТУПУ НА AVR-МІКРОКОНТРОЛЕРАХ. РОБОТА З ІНТЕРФЕЙСАМИ 1-WIRE, I2C, SPI» Мета роботи: ознайомитись з принципами побудови модулів управління систем контролю доступу. Вивчити правила обміну інформацією через інтерфейси 1-Wire, I C, SPI та набути навиків з їх програмної реалізації для AVR-мікроконтролерів на мові С в середовищі CodeVisionAVR. Завдання: Варіант №4 Дані для реєстрації: номер ключа, число, година, тип події(вхід/вихід), попередньо встановлена дата 04.04.09 06:09:38, кількість записів 30, кількість зареєстрованих ключів – 4, час відкриття дверей – 4 с. Виконання роботи: Лістинг програми // Блок управління СКД на МК АТ90S2313 з iButton DS1990А, ГРЧ DS1307 та EEPROM 25LC256 // Тактова частота МК 7.3728 МГц //////////////////////////////////////////////////////////////////////////////////// // Порт для підключення iButton DS1990 (PORTB, PB5) #asm .equ __w1_port = 0x18 .equ __w1_bit = 5 #endasm //////////////////////////////////////////////////////////////////////////////////// // Порт для підключення I2C-RTC DS1307 (PORTB, PB2, PB1) #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> #include <stdio.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 30 //******************************************************************// // Розмір одного запису в байтах #define Record_Size 16 //******************************************************************// // Адреса початку записів в EEPROM 25LC256 #define Record_Addr 0x40 //******************************************************************// // Адреса лічильника записів в EEPROM #define Record_Count_Addr 0x30 //******************************************************************// // Час відкривання дверей в мілісекундах #define T_msec 4000 //******************************************************************// // Кількість зареєстрованих ключів #define N_Key 4 //******************************************************************// // Тип запису #define Input_Record 0 #define Output_Record 1 //******************************************************************// /*----------------------------------------------------------------*/ // Підпрограма обслуговування зовнішнього переривання по виводу INT0 // Викликається при натисканні кнопки виходу interrupt [2] void ext_interrupt0(void); /*----------------------------------------------------------------*/ // Ініціалізація виводів void Pin_Init(void); /*----------------------------------------------------------------*/ // Функції для роботи з ГРЧ // Ініціалізація ГРЧ DS1307 void DS1307_Init(void); // Читання даних з ГРЧ DS1307 void DS1307_Read(DS1307_Data* arg1); // Запис даних в ГРЧ DS1307 void DS1307_Write(DS1307_Data* arg1); /*----------------------------------------------------------------*/ // Функції для роботи з SPI EEPROM-пам'ттю 25LC256 // Обмін одним байтом через інтерфейс SPI byte SPI_Send_Byte(byte data); // Відправка однобайтової команди через інтерфейс SPI void SPI_Send_CMD1(byte cmd); // Читання регістра статусу EEPROM-пам'ті 25LC256 byte SPI_Read_SR(void); // Читання в масив buffer n байт з EEPROM-пам'ті, починаючи з адреси address void SPI_Read_Data(int address, byte* buffer, byte n); // Запис масиву buffer розміром n байт в EEPROM-пам'ть, починаючи з адреси address void SPI_Write_Data(int address, byte* buffer, byte n); // Функція для занесення реєстраційного запису в EEPROM-пам'ять void Save_Record(DS1307_Data* arg1, byte* code, byte type); ///////////////////////////////////////////////////////////////////////////////////// void main(void) { byte temp, ii, jj, temp1; // Масив в ОЗП для зберігання ID зареєстрованих в системі N_Key ключів iButton byte iButton_Arrary[N_Key][8]; // Налаштування виводів СКД Pin_Init(); // Ініціалізація заданими часом і датою: 04-04-09 06:09:38 DS1307_1.Second = 0x38; DS1307_1.Minute = 0x09; DS1307_1.Hour = 0x06; DS1307_1.Day = 0x04; DS1307_1.Date = 0x04; DS1307_1.Month = 0x047; DS1307_1.Year = 0x09; // Ініціалізація I2C інтерфейсу DS1307_Init(); // Запис дати і часу в ГРЧ DS1307_Write(&DS1307_1); // Прочитати зареєстровані ключі з EEPROM-пам'ті в ОЗП for(ii = 0; ii < N_Key; ii++) SPI_Read_Data(0x0000 + (ii << 3), &iButton_Arrary[ii][0], 8); // Налаштувати зовнішнє переривання INT0 від кнопки виходу GIMSK = GIMSK | 0x40; // Дозволити переривання INT0 MCUCR = MCUCR | 0x02; // Переривання по спадаючому фронту // Вічний цикл опитування зчитувачів iButton while(1) { #asm("cli") // Заборонити переривання temp = w1_search(SEARCH_ROM, &ROM_Code[0]); // Чи є торкання зчитувача ключом iButton if (temp == 0) // Якщо немає - дозволити переривання { #asm("sei") } else // Якщо виявлено DS1990A { // Пошук серед зареєстрованих в СКД ключів for(ii = 0; ii < N_Key; ii++) // Для кожного ключа { temp1 = 0; for(jj = 0; jj < 8; jj++) // Порівняти його 8-байтний ID з зареєстрованими ключами { if(ROM_Code[jj] != iButton_Arrary[ii][jj]) { temp1 = 1; // Якщо хоча б 1 байт неспівпадає break; // Перейти до перевірки наступного ключа } } if(temp1 == 0) // Якщо ключ знайдено - вийти з циклу break; } if(temp1 == 0) // Якщо ключ знайдено { DS1307_Read(&DS1307_1); // Прочитати поточні час і дату Save_Record(&DS1307_1, &ROM_Code[0], Input_Record); // Сформувати реєстраційний запис і записати в EEPROM-пам'ять 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(10); // Через 10 мс знову повернутися до опитування зчитувачів }; }; /////////////////////////////////////////////////////////////////////////////////////// // Ініціалізація І2С шини та режиму роботи годинника реального часу DS1307 void DS1307_Init(void) { i2c_start(); // Сформувати умову START на шині І2С i2c_write(0xd0); // Задати адресу DS1307 та операцію запису (R/W=0) i2c_write(0x07); // Задати внутрішню адресу з якої почнеться запис-регістр Control i2c_write(0b00000000); // Вихід SQW/OUT - неактивний, з логічним 0 i2c_stop(); // Сформувати умову STОР на шині І2С }; /////////////////////////////////////////////////////////////////////////////////////// // Функція зчитування з ГРЧ DS1307 часу і дати // Вхідні параметри: // arg1 - структура, в яку записуються поточні час і дата. void DS1307_Read(DS1307_Data* arg1) { i2c_start(); // Сформувати умову START на шині І2С i2c_write(0xd0); // Задати адресу DS1307 та операцію запису (R/W=0) i2c_write(0x00); // Записати внутрішню адресу DS1307 з якої почнеться читання i2c_stop(); // Сформувати умову STОР на шині І2С i2c_start(); // Сформувати умову START на шині І2С i2c_write(0xd1); // Задати адресу DS1307 та операцію читання (R/W=1) arg1->Second = i2c_read(1) & 0x7F; // Прочитати регістр секунд, сформувати біт ACK arg1->Minute = i2c_read(1) & 0x7F; // Прочитати регістр хвилин, сформувати біт ACK arg1->Hour = i2c_read(1) & 0x3F; // Прочитати регістр годин, сформувати біт ACK arg1->Day = i2c_read(1) & 0x07; // Прочитати регістр днів, сформувати біт ACK arg1->Date = i2c_read(1) & 0x3F; // Прочитати регістр числа, сформувати біт ACK arg1->Month = i2c_read(1) & 0x1F; // Прочитати регістр місяця, сформувати біт ACK arg1->Year = i2c_read(0); // Прочитати регістр року, сформувати біт NACK i2c_stop(); // Сформувати умову STОР на шині І2С }; ///////////////////////////////////////////////////////////////////////////////////// // Функція запису в ГРЧ DS1307 часу і дати // Вхідні параметри: // arg1 - структура, яка містить задані час і дату void DS1307_Write(DS1307_Data* arg1) { i2c_start(); // Сформувати умову START на шині І2С i2c_write(0xd0); // Задати адресу DS1307 та операцію запису (R/W=0) i2c_write(0x00); // Задати внутрішню адресу DS1307 з якої почнеться запис i2c_write(arg1->Second); // Записати в регістр секунд і запустити відлік часу i2c_write(arg1->Minute); // Записати в регістр хвилин i2c_write(arg1->Hour); // Записати в регістр годин i2c_write(arg1->Day); // Записати в регістр дня i2c_write(arg1->Date); // Записати в регістр числа i2c_write(arg1->Month); // Записати в регістр місяця i2c_write(arg1->Year); // Записати в регістр року i2c_stop(); // Сформувати умову STОР на шині І2С }; //////////////////////////////////////////////////////////////////////////////////// // Функція обміну байтом через інтерфейс SPI // Вхідні параметри: // data - байт для передачі через SPI. // Вихідні параметри: // Прийнятий байт через SPI. byte SPI_Send_Byte(byte data) { byte ii, temp, result = 0, mask = 0x80; for(ii = 0; ii < 8; ++ii) // Цикл для передачі і прийому 8 біт через SPI { temp = PIN_EEPROM & (1<<SO); // Прочитати стан сигналу на лінії SO if(temp != 0) // Якщо SO=1, занести 1 у черговий біт результату result = result | mask; PORT_EEPROM.SI = (data & mask) && 1; // Виставити на лінію SI черговий біт #asm("nop"); PORT_EEPROM.SCK = 1; // Сформувати тактовий імпульс mask = mask >> 1; // Зсунути маску на 1 розряд PORT_EEPROM.SCK = 0; // Зняти тактовий імпульс } return result; // Повернути прийнятий байт }; ////////////////////////////////////////////////////////////////////////////////////// // Функція здійснює налаштування виводів МК відповідно до схеми СКД // Виводи підключені до зчитувача iButton та ГРЧ DS1307 ініціалізуються компілятором void Pin_Init(void) { // Виводи підключені до мікросхеми EEPROM-пам'яті 25LC256 PORT_EEPROM.CS = 1; // На лінії лог. 1 - мікросхема EEPROM-пам'яті 25LC256 неактивна PORT_EEPROM.SCK = 0; // На лінії логічний 0 PORT_EEPROM.SI = 0; // На лінії логічний 0 PORT_EEPROM.SO = 0; // Внутрішній підтягуючий резистор відключений DDR_EEPROM.CS = 1; // Вихід сигналу #SS інтерфейсу SPI DDR_EEPROM.SCK = 1; // Вихід сигналу SCLK інтерфейсу SPI DDR_EEPROM.SI = 1; // Вихід сигналу MОSІ інтерфейсу SPI DDR_EEPROM.SO = 0; // Вхід сигналу MISO інтерфейсу SPI // Вивід підключений до електронного замка PORT_Switch.Switch = 0; // На лінії логічний 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; // Внутрішній підтягуючий резистор відключений }; ////////////////////////////////////////////////////////////////////////////////////// // Функція здійснює запис масиву байт в EEPROM-пам'ять 25LC256 // Вхідні параметри: // address - адреса в EEPROM-пам'яті з якої почнеться запис; // buffer - масив з даними для запису; // n - кількість байт для запису. void SPI_Write_Data(int address, byte* buffer, byte n) { byte ii; PORT_EEPROM.CS = 0; // Активізувати мікросхему EEPROM-пам'яті SPI_Send_Byte(EEPROM_WRITE); // Відправти в EEPROM команду запису SPI_Send_Byte(address>>8); // Відправити в EEPROM ст. байт адреси початку запису SPI_Send_Byte(address); // Відправити в EEPROM мол. байт адреси початку запису for(ii = 0; ii < n; ii++) // Цикл запису n байт в EEPROM-пам'ять SPI_Send_Byte(buffer[ii]); PORT_EEPROM.SI = 0; // Перевести лінію SI в неактивний стан PORT_EEPROM.CS = 1; // Відключити мікросхему EEPROM-пам'яті }; /////////////////////////////////////////////////////////////////////////////////////// // Функція здійснює читання масиву байт з EEPROM-пам'яті 25LC256 // Вхідні параметри: // address - адреса в EEPROM-пам'яті з якої почнеться читання; // buffer - масив для зберігання прочитаних даних; // n - кількість байт для читання. void SPI_Read_Data(int address, byte* buffer, byte n) { byte ii; PORT_EEPROM.CS = 0; // Активізувати мікросхему EEPROM-пам'яті SPI_Send_Byte(EEPROM_READ); // Відправти в EEPROM-пам'ять команду читання SPI_Send_Byte(address>>8); // Відправити в EEPROM ст. байт адреси початку читання SPI_Send_Byte(address); // Відправити в EEPROM мол. байт адреси початку читання for(ii = 0; ii < n; ii++) // Цикл читання n байт з EEPROM-пам'яті buffer[ii] = SPI_Send_Byte(0); PORT_EEPROM.SI = 0; // Перевести лінію SI в неактивний стан PORT_EEPROM.CS = 1; // Відключити мікросхему EEPROM-пам'яті }; /////////////////////////////////////////////////////////////////////////////////////// // Функція відсилає однобайтову команду в EEPROM-пам'ять 25LC256 // Вхідні параметри: // cmd - код команди. void SPI_Send_CMD1(byte cmd) { PORT_EEPROM.CS = 0; // Активізувати мікросхему EEPROM-пам'яті SPI_Send_Byte(cmd); // Відправти в EEPROM-пам'ять код команди PORT_EEPROM.SI = 0; // Перевести лінію SI в неактивний стан PORT_EEPROM.CS = 1; // Відключити мікросхему EEPROM-пам'яті }; /////////////////////////////////////////////////////////////////////////////////////// // Функція читає регістр статусу EEPROM-пам'яті 25LC256 та повертає його значення // Вихідні параметри: // Вміст регістра статусу. byte SPI_Read_SR(void) { byte temp; PORT_EEPROM.CS = 0; // Активізувати мікросхему EEPROM-пам'яті SPI_Send_Byte(EEPROM_RDSR); // Відправти в EEPROM команду читання регістра статусу temp = SPI_Send_Byte(0); // Прочитати регістр статусу PORT_EEPROM.SI = 0; // Перевести лінію SI в неактивний стан PORT_EEPROM.CS = 1; // Відключити мікросхему EEPROM-пам'яті return temp; // Повернути вміст регістру статусу }; /////////////////////////////////////////////////////////////////////////////////////// // Функція обслуговування зовнішнього переривання INT0 з виводу PD2 // Переривання викликається при натисканні кнопки виходу всередині приміщення interrupt [2] void ext_interrupt0(void) { byte ii; delay_ms(10); // Затримка 10 мс для захисту від тремтіння контактів кнопки виходу if(PIN_Out_Key.Out_Key == 0) // Якщо кнопка дійсно натиснута { DS1307_Read(&DS1307_1); // Прочитати поточні час і дату for(ii = 0; ii < 8; ii++) // Обнулити код ID ROM_Code[ii] = 0; // Сформувати реєстраційний запис і занести його в EEPROM-пам'ять 25LC256 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; // Виключити електронний замок - двері закриті } }; ////////////////////////////////////////////////////////////////////////////////////// // Функція формування і занесення в EEPROM-пам'ять реєстраційного запису // Вхідні параметри: // arg1 - структура, яка містить поточні час і дату; // code - масив, який містить 8-байтний ID код ключа iButton; // type - тип події: 0 - вхід, 1 - вихід. void Save_Record(DS1307_Data* arg1, byte* code, byte type) { byte temp, temp1, temp2[5]; int start; // Очікувати готовності EEPROM до запису while((temp = SPI_Read_SR()) & 0x01) {}; // Прочитати значення лічильника подій в змінну temp1 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 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 {}; // Записати 5 байт часу і дати temp2[0] = arg1->Minute; temp2[1] = arg1->Hour; temp2[2] = arg1->Date; temp2[3] = arg1->Month; temp2[4] = arg1->Year; SPI_Write_Data(start + 8, temp2, 5); while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM {}; SPI_Send_CMD1(EEPROM_WREN); // Дозволити запис в EEPROM while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM {}; SPI_Write_Data(start + 13, &type, 1); // Записати тип події while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM {}; SPI_Send_CMD1(EEPROM_WREN); // Дозволити запис в EEPROM while((temp = SPI_Read_SR()) & 0x01) // Очікувати готовності EEPROM {}; // Записати нове значення лічильника реєстраційних записів SPI_Write_Data(Record_Count_Addr, &temp1, 1); }; ///////////////////////////////////////////////////////////////////////////////////// Схема симуляції в Proteuz  Висновок: на даній лабораторній роботі було реалізовано схему СКД з мікроконтролерним керуванням, а також відлагоджено програму для вищезгаданого мікроконтролера під заданий варіант завдання. Результат було отримано при симуляції в програмі ISIS, пакета Proteus. Симуляція показала правильне функціонування сигналізації вцілому.
Антиботан аватар за замовчуванням

25.03.2013 23:03-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!