Введите текст заголовка

Страница на этапе разработки

В данном уроке мы с Вами подключим часовую микросхему DS3231 к микроконтроллеру  Atmega328P:

Распиновка микросхемы DS3231:

Краткие параметры микросхемы DS3231:
• Точность ±2 ppm в диапазоне 0°..+40°C.
• Точность ±3.5 ppm в диапазоне -40°..+85°C.
• Выход цифрового датчика температуры с точностью ±3°C.
• Регистр учета старения (Aging Trim).
• Система входа/выхода для генерации сброса микроконтроллера с подавлением дребезга.
• Два программируемых по времени дня будильника (Time-of-Day Alarm).
• Последовательный интерфейс I2C. Скорость работы интерфейса до 400 кГц.
• Вход резервного питания для подключения батареи с очень низким потреблением энергии.
• Работа от уровня напряжения 3.3V.
• Рабочие диапазоны температуры 0°..+70°C для коммерческого и -40°..+85°C для индустриального исполнения.
Расположение данных по адресам регистров:

В данном уроке мы с Вами рассмотрим базовые возможности работы с данной микросхемой, более специфические функции мы будем рассматривать в других уроках по мере необходимости. 

В уроке №42 мы с Вами уже работали с шиной I2C, по этому не будем мы тут на нем останавливаться. Данные будем выводить через UART на монитор порта. Настройка UART аналогична настройке UART Atmega8 с урока №4, с очень маленьким отличием: так как в Atmeg328P, USART0 — то регистры имеют цифру ноль в своих названиях (UCSR0B).

Теперь напишем программный код:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUD 9600L // Скорость обмена данными
#define UBRRL_value (F_CPU/(BAUD*16))-1 //Согластно заданной скорости подсчитываем значение для регистра UBRR

#define DS3231_ADDRESS 0b11010000 //0x68
unsigned char sec,min,hour,day,date,month,year;

void I2C_init(void);// инициализация
void I2C_Start(void);//Старт
void I2C_Stop(void);//Стоп
void I2C_SendByte(unsigned char c);//отправка данных
void I2C_SendByteAdres(unsigned char c, unsigned char addr );// отправка данных по адресу
char I2C_ReadByte(void);// чтение байта
unsigned char I2C_ReadLastByte(void);

void init_USART();
void send_UART(char value);

unsigned char RTC_ConvertFromDec(unsigned char c); //перевод двоично-десятичного числа в десятичное
unsigned char RTC_ConvertFromBinDec(unsigned char c); //перевод десятичного числа в двоично-десятичное

int main(void)
{
init_USART();
I2C_init();// инициализация
// запись данных
I2C_Start(); // запуск i2c
I2C_SendByte(DS3231_ADDRESS); // передача адреса устройства,
I2C_SendByte(0x00); // передача адреса памяти
I2C_SendByte(RTC_ConvertFromBinDec(0)); //секунды
I2C_SendByte(RTC_ConvertFromBinDec(31)); //минуты
I2C_SendByte(RTC_ConvertFromBinDec(20)); //часы
I2C_SendByte(RTC_ConvertFromBinDec(5)); //день недели
I2C_SendByte(RTC_ConvertFromBinDec(29)); //дата
I2C_SendByte(RTC_ConvertFromBinDec(1)); //месяц
I2C_SendByte(RTC_ConvertFromBinDec(16)); //год
I2C_Stop(); // остановка i2c

while (1)
{
//Читаем время
I2C_SendByteAdres(0,0b11010000); //переходим на адрес 0
_delay_ms(300);
I2C_Start(); //Отправим условие START
I2C_SendByte(0b11010001); //отправим в устройство бит чтения
sec = I2C_ReadByte();
min = I2C_ReadByte();
hour = I2C_ReadByte();
day = I2C_ReadByte();
date = I2C_ReadByte();
month = I2C_ReadByte();
year = I2C_ReadLastByte();
I2C_Stop(); //Отправим условие STOP
sec = RTC_ConvertFromDec(sec); //Преобразуем в десятичный формат
min = RTC_ConvertFromDec(min); //Преобразуем в десятичный формат
hour = RTC_ConvertFromDec(hour); //Преобразуем в десятичный формат
day = RTC_ConvertFromDec(day); //Преобразуем в десятичный формат
year = RTC_ConvertFromDec(year); //Преобразуем в десятичный формат
month = RTC_ConvertFromDec(month); //Преобразуем в десятичный формат
date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат
send_UART(date/10+0x30);//Преобразуем число в код числа
send_UART(date%10+0x30);//Преобразуем число в код числа
send_UART(‘.’);
send_UART(month/10+0x30);//Преобразуем число в код числа
send_UART(month%10+0x30);//Преобразуем число в код числа
send_UART(‘.’);
send_UART(year/10+0x30);//Преобразуем число в код числа
send_UART(year%10+0x30);//Преобразуем число в код числа
send_UART(‘ ‘);
send_UART(‘-‘);
send_UART(day+0x30);//Преобразуем число в код числа
send_UART(‘-‘);
send_UART(‘ ‘);
send_UART(‘ ‘);
send_UART(hour/10+0x30);//Преобразуем число в код числа
send_UART(hour%10+0x30);//Преобразуем число в код числа
send_UART(‘:’);
send_UART(min/10+0x30);//Преобразуем число в код числа
send_UART(min%10+0x30);//Преобразуем число в код числа
send_UART(‘:’);
send_UART(sec/10+0x30);//Преобразуем число в код числа
send_UART(sec%10+0x30);//Преобразуем число в код числа
send_UART(0x0d);//переход в начало строки
send_UART(0x0a);//перевод каретки
}
}

void I2C_init(void){
TWSR=(0<<TWPS1)|(0<<TWPS0);// настройка делителя
TWBR=0x03; // настройка рабочей частоты шины
}

void I2C_Start(void){
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
}

void I2C_Stop(void){
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void I2C_SendByte(unsigned char c){
TWDR=c;
TWCR=(1<<TWINT)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
}

void I2C_SendByteAdres(unsigned char c, unsigned char addr )
{
I2C_Start();
I2C_SendByte(addr);
I2C_SendByte(c);
I2C_Stop();
}

char I2C_ReadByte(void){
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR&(1<<TWINT))){;}
return TWDR;
}

unsigned char I2C_ReadLastByte(void){
TWCR=(1<<TWINT)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
return TWDR;
}

unsigned char RTC_ConvertFromBinDec(unsigned char c){
unsigned char ch = ((c/10)<<4)|(c%10);
return ch;
}

unsigned char RTC_ConvertFromDec(unsigned char c){
unsigned char ch = ((c>>4)*10+(0b00001111&c));
return ch;
}

void init_USART() {
UBRR0L = UBRRL_value; //Младшие 8 бит UBRRL_value
UBRR0H = UBRRL_value >> 8; //Старшие 8 бит UBRRL_value
UCSR0B |=(1<<TXEN0); //Бит разрешения передачи
//UCSR0C |=(1<< URSEL|(1<< UCSZ0)|(1<< UCSZ1); //Устанавливем формат 8 бит данных
}

void send_UART(char value) {
while(!( UCSR0A & (1 << UDRE0))); // Ожидаем когда очистится буфер передачи
UDR0 = value; // Помещаем данные в буфер, начинаем передачу
}