Библиотека AVR для работы с шиной I2C и с часами реального времени PCF8583

Мне нужно было сделать часы на основе микросхемы, имеющей 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)

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.