Мне нужно было сделать часы на основе микросхемы, имеющей I2C интерфейс. Микросхема RTC, т.н. «часы реального времени» PCF8583.
Внутри микросхемы расположены: часы, будильник, таймер, календарь (кривой), и 240 байт оперативной памяти, куда можно записывать любую информацию, которую лишь вздумается. Оперативная память это очень полезная штука, в отличии от флеш-памяти, оперативная память не имеет ограничений по количеству циклов перезаписи, и в неё можно сохранять какие-то данные, настройки, сколь угодно часто.
Но была одна проблемка — писАть код жутко не хотелось, и я решил найти готовый код в интернете. Как позже выяснилось, найти «на свою голову». Скачал пример работы с I2C, подправил, прошил микроконтроллер. Не заработало. Стал ковырять код, искать причину неработоспособности… и ужаснулся!! Запись в некоторых случаях велась во весь порт сразу, а не в конкретные биты. Таким образом, если на порт повесить ещё что-то, например, дисплей, то скорее всего, оно работать не будет. Также неправильно было реализовано чтение данных по шине (без генераций условия окончания приёма, или просто без NACK). Но это пол-беды. Основная проблема в другом. Зачастую автор кода выставлял в порт логическую «1», а как мы знаем, шина I2C управляется «притягиванием» выводов SDA и SCL к общему проводу. А логическая «1» на шине, в свою очередь, формируется за счёт подтяжки к плюсу питания резисторами на 4,7 килоом. Таким образом, если на выходе микроконтроллера выставить логическую «1», а ведомое устройство «притянет» этот выход к общему проводу, то получится «ба-бах» короткое замыкание. Мне это очень не понравилось, и я решил изобрести свой велосипед написать свою библиотеку, а вернее даже 2 библиотеки: одна для работы с шиной I2C, а другая непосредственно для работы с часами реального времени PCF8583. Да, кстати, код написан в AVR Studio 6.
Для того, чтобы подключить библиотеку I2C к проекту, нужно прописать её через include, как на картинке, а также скопировать библиотеку в папку с проектом.
После чего, необходимо открыть файл «i2c.h», и указать ножки микроконтроллера, которые будут выступать в роли шины I2C. По умолчанию шина настроена на ножки PC0 (SCL) и PC1 (SDA). А настройка делается вот тут:
Всё, библиотеку I2C мы подключили, ножки настроили, библиотека готова к работе. Пример использования:
i2c_init (); // Инициализация шины I2C
i2c_start_cond(); // старт шины
i2c_send_byte (0xA0); // адрес устройства, которое висит на шине
i2c_send_byte (0x10); // байт данных, который записываем в устройство
i2c_send_byte (0x10); // ещё один байт данных, который записываем в устройство
i2c_stop_cond(); // стоп шины
После стоп-условия, мы можем проверить, всё ли у нас в порядке с шиной I2C. Для этого нужно прочитать переменную «i2c_frame_error». Если всё нормально, то в ней будет 0. Если один из выводов шины не «подтянулся» к питанию, и логическая «1» не установилась на шине, то библиотека генерирует ошибку, и записвает в переменную «i2c_frame_error» циферку 1. Читать переменную «i2c_frame_error» нужно после стоп-условия. На рисунке ниже продемонстрирую как работает контроль ошибки:
Теперь займёмся подключением библиотеки часов реального времени PCF8583. Для этого нужно проделать те же самые действия. Скопируем в папку с проектом файл «PCF8583.h», и пропишем его в include, как на фото:
Готово. Библиотека часов реального времени PCF8583 подключена. Она не требует каких-либо настроек, поэтому можно сразу приступать к чтению времени и даты с микросхемы. Обращаю внимание, что библиотека PCF8583 работает при помощи библиотеки I2C, поэтому если хотим работать с PCF8583, то нужно подключить обе библиотеки!
Пример использования библиотеки (запись и чтение времени и даты):
// Инициализация шины I2C
i2c_init ();
// Подготавливаем время и дату для записи в микросхему PCF8583
PCF_hour=23; // 23 часа
PCF_min=59; // 59 минут
PCF_day=31; // 31 число
PCF_month=12; // 12 месяц — декабрь
PCF_year=0; // год (0 — не високосный)
PCF_weekday=6; // 6 день недели (воскресенье)
// Записываем время и дату в микросхему PCF8583
PCF_write_hh_mm_ss();
// Считываем время и дату из микросхемы PCF8583
PCF_read_hh_mm_ss();
Пример работы с оперативной памятью (запись и чтение):
// Подготавливаем 5 байт для записи в микросхему PCF8583
PCF_data_ram_1=255; // байт 1
PCF_data_ram_2=255; // байт 2
PCF_data_ram_3=255; // байт 3
PCF_data_ram_4=255; // байт 4
PCF_data_ram_5=255; // байт 5
// Записываем 5 байт в микросхему PCF8583
PCF_write_ram();
// Считываем 5 байт из микросхемы PCF8583
PCF_read_ram();
Чтение из микросхемы ещё проще – достаточно вызвать функцию PCF_read_hh_mm_ss() после чего, время и дата появятся в переменных, откуда их лишь забирай. Для чтения оперативной памяти соответственно используем функцию PCF_read_ram() после чего данные забираем в переменных PCF_data_ram_N
Вот список переменных, где и что хранится:
// время и дата
PCF_hour=0; // время, часы (от 0 до 23, защита от переполнения при записи и чтении)
PCF_min=0; // время, минуты (от 0 до 59, защита от переполнения при записи и чтении)
PCF_sec=0; // время, секунды (лишь для чтения, при записи сбрасываются в 00)
PCF_day=0; // день (от 1 до 31, защита от переполнения при записи и чтении)
PCF_weekday=0 // день недели (0-понедельник; 6-воскресенье, защита от переполнения при записи и чтении)
PCF_month=0; // месяц (от 1 до 12, защита от переполнения при записи и чтении)
PCF_year=0; // год (0-високосный; 1,2,3-невисокосные, защита от переполнения при записи и чтении)
// оперативная память
PCF_data_ram_1; // Данные (ОЗУ PCF8583), байт 1
PCF_data_ram_2; // Данные (ОЗУ PCF8583), байт 2
PCF_data_ram_3; // Данные (ОЗУ PCF8583), байт 3
PCF_data_ram_4; // Данные (ОЗУ PCF8583), байт 4
PCF_data_ram_5; // Данные (ОЗУ PCF8583), байт 5
Теперь расскажу про защиту от переполнения. Допустим, мы забыли подключить микросхему. Прочитаем данные с микросхемы, и… прочитается байт 11111111, или число 255. Всё дело в том, что в основе шины I2C лежат 2 подтягивающих резистора, вот они то и выдают нам логические «единички» если микросхема не подключена. Для защиты от подобных случаев, в библиотеке PCF8583 я сделал защиту от переполнений, которая следит за тем, чтобы часики не показывали вам 62 часа 81 минуту… Наличие переполнения можно проследить, прочитав переменную «PCF_overflow». Если в ней 0, значит ошибок переполнения не было. Если в ней 1 или более, значит ошибки переполнения имеются. Читать переменную «PCF_overflow» нужно после функции чтения даты и времени PCF_read_hh_mm_ss()
Для наглядности, проект AVR Studio 6 под ATmega32 прилагается. Перекомпилировать можно под любой AVR. В проекте я также подключил дисплей для визуального контроля. При подаче питания, микроконтроллер устанавливает 23 часа 59 минут, 31 декабря, Воскресенье. И через минуту становится 00 часов 00 минут, 1 января, Понедельник.
Теперь расскажу, почему я говорил про «кривой» календарь этой микросхемы. Всё дело в том, что микросхема не умеет хранить текущий календарный год, а хранит лишь флаг високосного года. Короче говоря:
0 – високосный год
1 – не високосный год
2 – не високосный год
3 – не високосный год
И так по циклу 0-1-2-3-0-1-2-3-0…
В общем чтобы сделать нормальный календарь, нужно реализовывать программный расчёт и сохранение года, например, в ту же оперативную память PCF8583, но это не удобно. А главное, что при обесточенной схеме память, увы, никто не перезапишет…
Также прилагаю в конце статьи небольшой видеоотчёт. В программировании я можно сказать новичок, хоть и программирую уже 3 года (понемногу), за код строго не судите, если есть какие-либо дополнения и замечания, пишите, будем исправлять. Всем удачных самоделок!
Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот
МК AVR 8-битATmega321
Часы реального времени (RTC)PCF85831
LCD-дисплейWH16021
Резистор4.7 кОм2
Кварц32768 Гц1
Добавить все
Скачать список элементов (PDF)
Прикрепленные файлы: