Страница 1 из 1
Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 09:14:30
Jman
Доброго времени суток. Собираю часы на Attiny 13 + DS1307, которые должны слать набор байт по usart на другой МК к которому прикручен дисплей и прочая переферия. Я написал следующий код:
Библиотека для работы с I2C взята из проекта
https://radiokot.ru/circuit/digital/home/239/:
Спойлер
Код: Выделить всё
#define SCL 3
#define SDA 4
#define ACK 1
#define NACK 0
#define SCL_HIGH DDRB&=~(1<<SCL)
#define SCL_LOW DDRB|=(1<<SCL)
#define SDA_HIGH DDRB&=~(1<<SDA)
#define SDA_LOW DDRB|=(1<<SDA)
#include <avr/io.h>
#include "TWI.h"
unsigned char k = 0;
void i2c_start (void)
{
SCL_HIGH;
SDA_HIGH;
SDA_LOW;
SCL_LOW;
}
void i2c_stop (void)
{
SDA_LOW;
SCL_HIGH;
SDA_HIGH;
}
void i2c_send_byte (unsigned char data)
{
SCL_LOW;
for(k=8;k>0;k--)
{
if(data&(1<<(k-1))) SDA_HIGH;
else SDA_LOW;
SCL_HIGH;
SCL_LOW;
}
SCL_HIGH;
SCL_LOW;
}
unsigned char i2c_receive_byte (unsigned char ACK_NACK)
{
unsigned char out_data=0;
SCL_LOW;
for(k=8;k>0;k--)
{
SCL_HIGH;
if(PINB&(1<<SDA)) out_data|=(1<<(k-1));
else out_data&=~(1<<(k-1));
SCL_LOW;
}
if(ACK_NACK) SDA_LOW;
else SDA_HIGH;
SCL_HIGH;
SCL_LOW;
SDA_HIGH;
return out_data;
}
Основная программа:
Спойлер
Код: Выделить всё
#ifndef F_CPU
# define F_CPU 1200000UL // 1.2 MHz
#endif /* !F_CPU */
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "uart.h"
#include "DS1307.h"
#include "TWI.h"
int main(void)
{
char* time;
char s;
DDRB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (0<<PINB2) | (0<<PINB1) | (0<<PINB0);
PORTB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (1<<PINB2) | (0<<PINB1) | (0<<PINB0);
GIMSK=(1<<PCIE); // кнопка
PCMSK=(1<<PCINT3);
while (1)
{
i2c_start();
i2c_send_byte(0xD0); //отправить адрес устройства с 0 = запись
i2c_send_byte(1); //отправить № байта, с которого начнём работать
i2c_start();
i2c_send_byte(0xD1); //отправить адрес устройства с 1 = чтение
time[0] = i2c_receive_byte(1); //считать минуты
time[1] = i2c_receive_byte(0); //считать секунды
i2c_stop();
uart_putc(time[1]);
_delay_ms(1000);
}
}
Библиотеку для работы с программным USART -> взял
https://github.com/lpodkalicki/attiny13 ... ibraryЛиба вроде рабочая, пробовал передавать и строку и символы в Proteus, в терминал все приходит корректно.
Но если выводить буфер часов минуты или секунды, функция uart_putc в Proteus постоянно выводит в HEX что-то не понятное. Если в uart_putc вставить любой символ -> то HEX код символа передается в терминал верно. Видимо где-то не правильно читаю часики? В чем может быть проблема? по идее мне надо прочитать часы, минуты и каждый элемент массива отправить через
uart_putc(аргумент); через определенный квант времени? В либе USART еще есть функция
uart_puts(аргумент) которая выводит строку. Какой алгоритм лучше использовать?
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 09:24:12
ARV
во-первых, почему считывается в НУЛЕВОЙ элемент массива ПЕРВЫЙ байт памяти часов, а в ПЕРВЫЙ элемент - НУЛЕВОЙ байт? ну в чем смысл? тут самое то начинать с нулевого байта памяти часов и последовательно, т.е. без указания номера следующего, считывать сколько надо следующих. но это придирки, конечно
во-вторых, вам нужно время именно в BCD-формате или в "человеческом"? считываете вы BCD, а для человека надо символы, т.е. надо преобразовывать полученное число в строку хотя бы при помощи itoa, а уж потом выводить строку.
в-третьих, если у вас нет каких-то хитрых целей, вычитывать время из часов непрерывно в цикле нет никакой нужды. я всегда использую режим часов, когда они на своем выходе формируют меандр с частотой 1 Гц - опрашивая (или по прерываниям) этот пин можно точно знать, что прошла секунда и надо обновить время - это логично.
не знаю, помогут ли мои советы решить вашу проблему... но я бы советовал к ним прислушаться.
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 09:48:22
Jman
[uquote="ARV",url="/forum/viewtopic.php?p=4203474#p4203474"]не знаю, помогут ли мои советы решить вашу проблему... но я бы советовал к ним прислушаться.[/uquote]
Благодарю! Да, советы действительно полезные!
во-вторых, вам нужно время именно в BCD-формате или в "человеческом"? считываете вы BCD, а для человека надо символы, т.е. надо преобразовывать полученное число в строку хотя бы при помощи itoa, а уж потом выводить строку.
Я вообще думаю, перевести из BCD сформировать строку и отправлять по UART.
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 13:43:28
GoldenAndy
ARV, а смысл считать время вручную?
Код чтения времени из часов уже есть. Он нужен для стартового чтения.
Зачем еще придумывать код своих часов? А если с календарем, то еще и счёт календаря?
Неужто чтение раз в секунду времени из МС часов так сильно изнашивает их?
В 99% домашних поделок МК не загружен настолько сильно, что бы не уделить несколько миллисекунд для чтения данных по и2ц...
На скорости 100 кГц чтение байта по и2ц - порядка 100 мкс. 10 байт - миллисекунда.... На 400 кГц - еще быстрее...
Зачем дулбировать программно уже реализованный в железе функционал?
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 14:10:06
ARV
GoldenAndy писал(а):а смысл считать время вручную?
то ли я сказал непонятно, то ли вы о своём думаете...
GoldenAndy писал(а):На скорости 100 кГц чтение байта по и2ц - порядка 100 мкс. 10 байт - миллисекунда.... На 400 кГц - еще быстрее...
по-вашему разумным выходит делать примерно 1000 чтений абсолютно одинакового результата в секунду, чем спокойно дождаться, когда значение обновится и считать 1 раз новое?
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 14:44:10
GoldenAndy
ARV, зачем 1000????
Или по 1 сек с вашего вывда 1 гц - это если есть желание заводить этот 1 гц в мк.
Или по своим внутренним алгоритмам, тоже раз в секунду...
Основная программа ж крутится в каком то цикле... И этот цикл, теоретически, привязан ко времени выполнения. Вот там, раз в секунду читать время.
А если это тупо первичные часы, у которых никакой другой работы нет, кроме как читать время - то тут пофиг.
Или ждать импульс 1 Гц на каком то входе, или тупо в цикле читать данные из часов, запомнив показания секунд из прошлого чтения.
Как только секунды поменялись - выплюнуть в УАРТ.
Тут же еще фишка - для программного счета времени нужно стабильное тактирование. Т.е. еще и кварц лепить.
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 14:47:29
ARV
GoldenAndy писал(а):Вот там, раз в секунду читать время.
прошу прощения: а нафига тогда внешний RTC? если программно считать секунды, то и внешний RTC не нужен. как правило, главный цикл, если его специально не тормозить, прокручивается за миллисекунды даже при большой нагрузке... 1 секунда - слишком много даже для дохленького AVR. поэтому, раз уж тормозить, почему бы не тормозить по сигналу от часов? часы сказали "у меня есть новое время!" - отреагировать на это, часы молчат - делать свои темные дела... ну, или, если делать нечего - спать или ждать...
Re: Часы на Attiny 13 + DS1307
Добавлено: Пт мар 25, 2022 15:24:43
GoldenAndy
Всё зависит от задачи. Если это батарейка - то да - проснуться от RTC, прочитать время, віплюнуть его и спать дальше.
Если питание нормальное - то тут пофиг, ждать 1 Гц, отсчитівать 1000мс delay-ами или постоянно опрашивать RTC.
Это пофиг.
А вот в дополнение к RTC считать своё время и календарь средствами МК, как на форуме некоторые советуют - лишнее.
ЗЫ. Я не совсем внимательно прочел вашу фразу про использование прерывания и почему то подумал, что вы предлагаете по этим 1 Гц считать время средствами МК. Сорри.
Re: Часы на Attiny 13 + DS1307
Добавлено: Пн мар 28, 2022 16:24:06
Jman
Так как нет свободных ног, решил примерно раз в 5 сек опрашивать часы и передавать в UART.
Код: Выделить всё
#ifndef F_CPU
# define F_CPU 1200000UL // 1.2 MHz
#endif /* !F_CPU */
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "uart.h"
#include "DS1307.h"
#include "TWI.h"
const uint8_t WORK_TIME = 25; // 1200000/1024/256=3.8 (0.026 сек) 12/0.26=46,15 = 10 сек, для 1 секунды = 4-5
volatile uint8_t tick = 0;
volatile unsigned char hour, minute, second;
volatile unsigned char* time;
volatile unsigned char* buffer;
ISR(TIM0_OVF_vect)
{
tick++;
if(tick >= WORK_TIME){
time = rtc_read();
second = (((time[0] & 0xF0) >> 4)*10)+(time[0] & 0x0F);
minute = (((time[1] & 0xF0) >> 4)*10)+(time[1] & 0x0F);
itoa(minute, buffer, 10); // ???? хз....
uart_puts(buffer);
tick = 0;
}
}
int main(void)
{
DDRB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (0<<PINB2) | (0<<PINB1) | (0<<PINB0);
PORTB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (1<<PINB2) | (0<<PINB1) | (0<<PINB0);
GIMSK=(1<<PCIE); //Захват кнопки
PCMSK=(1<<PCINT3); //по прерыванию
TCCR0B |= (1<<CS02) | (1<<CS00); // предделитель на 1024 (CLK=1200000Hz/1024/256=4Hz, 0.25s)
TIMSK0 |= (1<<TOIE0); // переполнение по таймеру
sei();
while (1){
}
}
Гоняю в протеусе, железа нет. Прерывание отрабатывает, читаются часики, но как понять, визуально в терминале Protes понять, правильное ли время. Сейчас выводиться какая-то дичь...
Вот код чтения:
Код: Выделить всё
#define ACK 1
#define NACK 0
volatile char time[2];
char* rtc_read (void){
i2c_start();
i2c_send_byte(0xD0); //отправить адрес устройства с 0 = запись
i2c_send_byte(1); //отправить № байта, с которого начнём работать
i2c_start();
i2c_send_byte(0xD1); //отправить адрес устройства с 1 = чтение
time[0] = i2c_receive_byte(ACK); //считать минуты
time[1] = i2c_receive_byte(NACK); //считать часы
i2c_stop();
return time;
}
Re: Часы на Attiny 13 + DS1307
Добавлено: Пн мар 28, 2022 16:44:01
ARV
у вас beffer - это указатель, а где память, на которую он указывает? объявите так char buffer[7]; хотя бы...
Добавлено after 1 minute 34 seconds:
ну и вообще: из обработчика прерываний вызывать "долгоиграющие" функции - не комильфо... ставьте в обработчике прерываний флаг, а в главном цикле читайте часы, выводите и сбрасывайте флаг... собственно, флагом может быть прямо флаг запроса прерывания, тогда обработчик вообще не нужен...
Re: Часы на Attiny 13 + DS1307
Добавлено: Пн мар 28, 2022 17:11:14
Jman
А само чтение часов же вроде верно организовано?
Re: Часы на Attiny 13 + DS1307
Добавлено: Вт мар 29, 2022 15:47:49
Jman
Сделал так. Передает часы и минуты в уарт. Готов получить порцию рациональной критики:
Код: Выделить всё
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "uart.h"
#include "DS1307.h"
#include "TWI.h"
#define TIME_SIZE 2
#define BUFFER_SIZE 7
#define TRUE 1
#define FALSE 0
const uint8_t WORK_TIME = 25; // 1200000/1024/256=3.8 (0.026 сек) 12/0.26=46,15 = 10 сек, для 1 секунды = 4-5
volatile uint8_t tick = 0;
volatile unsigned char hour, minute, second;
unsigned char data[TIME_SIZE];
volatile unsigned char buffer[BUFFER_SIZE];
volatile uint8_t isRead = FALSE;
void mcu_int(void);
int main(void);
ISR(TIM0_OVF_vect)
{
tick++;
if(tick >= WORK_TIME){
isRead = TRUE;
tick = 0;
}
}
int main(void)
{
mcu_int();
while (1){
if(isRead){
cli();
rtc_read(&data);
second = (((data[1] & 0xF0) >> 4)*10)+(data[1] & 0x0F);
minute = (((data[0] & 0xF0) >> 4)*10)+(data[0] & 0x0F);
itoa(second, buffer, 10);
uart_puts(buffer);
itoa(minute, buffer, 10);
uart_puts(buffer);
isRead = FALSE;
sei();
}
}
}
void mcu_int(void){
DDRB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (0<<PINB2) | (0<<PINB1) | (0<<PINB0);
PORTB = (0<<PINB5) | (0<<PINB4) | (0<<PINB3) | (1<<PINB2) | (0<<PINB1) | (0<<PINB0);
GIMSK=(1<<PCIE); //Захват кнопки
PCMSK=(1<<PCINT3); //по прерыванию
TCCR0B |= (1<<CS02) | (1<<CS00); // предделитель на 1024 (CLK=1200000Hz/1024/256=4Hz, 0.25s)
TIMSK0 |= (1<<TOIE0); // переполнение по таймеру
sei();
}
Re: Часы на Attiny 13 + DS1307
Добавлено: Вт мар 29, 2022 15:52:40
ARV
sei() один раз перед главным циклом, а cli() вообще не нужно. а в остальном - работает? ну и чудно! видно, что кое-что у вас уже по полочкам улеглось.
Re: Часы на Attiny 13 + DS1307
Добавлено: Вт мар 29, 2022 16:00:37
Jman
[uquote="ARV",url="/forum/viewtopic.php?p=4206022#p4206022"]sei() один раз перед главным циклом, а cli() вообще не нужно.[/uquote]
Да, но почему-то в Протеусе без запрета глобальных прерываний не фурычит. Уже в железе буду проверять.
Re: Часы на Attiny 13 + DS1307
Добавлено: Ср мар 30, 2022 17:19:29
Карбофос
rtc_read(&data); - data и так есть указатель на область данных, ошибка?
Re: Часы на Attiny 13 + DS1307
Добавлено: Ср мар 30, 2022 17:59:53
Dimon456
Jman писал(а):Да, но почему-то в Протеусе без запрета глобальных прерываний не фурычит.
Но если вы вот это используете[uquote="Jman",url="/forum/viewtopic.php?p=4203469#p4203469"]Библиотека для работы с I2C взята из проекта
https://radiokot.ru/circuit/digital/home/239/:
Код: Выделить всё
#define SCL 3
#define SDA 4
#define ACK 1
#define NACK 0
#define SCL_HIGH DDRB&=~(1<<SCL)
#define SCL_LOW DDRB|=(1<<SCL)
#define SDA_HIGH DDRB&=~(1<<SDA)
#define SDA_LOW DDRB|=(1<<SDA)
#include <avr/io.h>
#include "TWI.h"
void i2c_start (void)
{
SCL_HIGH;
SDA_HIGH;
SDA_LOW;
SCL_LOW;
}
[/uquote]то ни чего удивительного.
Re: Часы на Attiny 13 + DS1307
Добавлено: Ср мар 30, 2022 18:39:39
Карбофос
Мне кажется, ничего страшного в этом фрагменте кода нет.
Возможно, передавая неправильную ссылку, что-то в SREG или хз куда пишется.
Re: Часы на Attiny 13 + DS1307
Добавлено: Ср мар 30, 2022 19:01:34
Dimon456
Не стал полностью код цитировать, но раз в Attiny13 нет аппаратного i2c, значит используется "ногодрыг", которому прерывание и как раз мешает. Лучше бы Attiny25 поставил.
Re: Часы на Attiny 13 + DS1307
Добавлено: Ср мар 30, 2022 20:23:57
Карбофос
[uquote="Jman",url="/forum/viewtopic.php?p=4205527#p4205527"]Так как нет свободных ног[/uquote]
Вы ведь ничего по уарту не получаете? Вот и нога свободная появилась.
Код: Выделить всё
#define DS3231_REG_CONTROL 0x0E // Control register
I2C_write(DS3231_REG_CONTROL);
I2C_write(0); // SQUARE-WAVE OUTPUT FREQUENCY 1 Hz
Записываем в Control Register (0Eh) 0, получаем 1 Гц на ножке 32kHz, по заднему фронту считываем текущее время.