Опрос модуля времени с использованием таймера

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Не могу реализовать опрос модуля времени DS1307 (библиотека DS1307RTC.h) раз в секунду, для того чтобы не мешала работе шим (на таймере OCR1A) и основной работе программы.

Так как при обычной работе прошивки мк во время опроса подвисает на несколько миллисекунд из за чего падает вольтаж на шим и прекращается управление портами (мерцает).

В таймерах не разбираюсь толком, но хотелось бы понять. После прочтения этой темы

Опрос модуля происходит так (DS1307RTC.cpp):

// Aquire data from the RTC chip in BCD format
bool DS1307RTC::read(tmElements_t &tm)
{
  uint8_t sec;
  Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100  
  Wire.write((uint8_t)0x00); 
#else
  Wire.send(0x00);
#endif  
  if (Wire.endTransmission() != 0) {
    exists = false;
    return false;
  }
  exists = true;

  // request the 7 data fields   (secs, min, hr, dow, date, mth, yr)
  Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);
  if (Wire.available() < tmNbrFields) return false;
#if ARDUINO >= 100
  sec = Wire.read();
  tm.Second = bcd2dec(sec & 0x7f);   
  tm.Minute = bcd2dec(Wire.read() );
  tm.Hour =   bcd2dec(Wire.read() & 0x3f);  // mask assumes 24hr clock
  tm.Wday = bcd2dec(Wire.read() );
  tm.Day = bcd2dec(Wire.read() );
  tm.Month = bcd2dec(Wire.read() );
  tm.Year = y2kYearToTm((bcd2dec(Wire.read())));
#else
  sec = Wire.receive();
  tm.Second = bcd2dec(sec & 0x7f);   
  tm.Minute = bcd2dec(Wire.receive() );
  tm.Hour =   bcd2dec(Wire.receive() & 0x3f);  // mask assumes 24hr clock
  tm.Wday = bcd2dec(Wire.receive() );
  tm.Day = bcd2dec(Wire.receive() );
  tm.Month = bcd2dec(Wire.receive() );
  tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
#endif
  if (sec & 0x80) return false; // clock is halted
  return true;
}

это происходит слишком медленно и мешает, прошу помочь реализовать это на таймере.

Будет ли работать цикл while и останавливать работу основного кода программы функция, вызванная таймером?

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

мк atmega328p, кварц на 8Mhz

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

NickSan пишет:

прошу помочь реализовать это на таймере.

Это не нужно реализовывать на таймере по нескольким причинам

1.
Таймер будет щелкать когда попало, например посередине секунды (с точки зрения часов) и потому изменения Вашего времени будет не точно когда в часах секунда сменилась, а когда у Вас таймер щёлкнул - то бишь подход сам по себе лоховский.

2.
Зачем занимать таймер? Их не так много, он для чего-нибудь более дельного пригодится.

Это делается гораздо проще.

DS1307 умеет выдавать на пин SQW signal  с частотой 1Гц. Вот им и надо воспользоваться. Сигнал завести на любую ногу контроллера, которая умеет выдавать прерывание, и по этому прерыванию спокойно спрашивать время. И время будет точно на переходе секунды обновляться и таймер не будет занят.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Спасибо за ответ, Евгений.

Не вариант, так как будет не красиво смотреться торчащий провод через всю плату печатную...

Есть ли еще способ по другому это реализовать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Какой торчащий провод? А что, дорожкой его провести не судьба?

Другие варианты - "по уму нет", а колхоз - да хоть через таймер, хоть через millis, но погрешность в среднем в полсекунды Вы получите стопудово, т.к. никак Вы не синхронизуетесь с переходом секунды в часах.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

В будущей плате на смд элементах проведу что захочу, а сейчас нет возможности.

Как реализовать Ваш вариант в коде?

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Есть вариант повесить таймер на функцию изменения режимов портов (что должно происходить по логике раз в 1мс и происходит, работает через millis) и проверки вольтажа ШИМ (выполняется сразу после вывода данных), timer0 и timer2 свободны.

Думаю на время опроса модуля выводить текущие значения времени, пока не обновит. (мерцаний не должно быть при таком варианте)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

NickSan пишет:

Как реализовать Ваш вариант в коде?

Какой вариант? Тут уже три обсуждалось

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

ЕвгенийП пишет:
Это делается гораздо проще.

DS1307 умеет выдавать на пин SQW signal  с частотой 1Гц. Вот им и надо воспользоваться. Сигнал завести на любую ногу контроллера, которая умеет выдавать прерывание, и по этому прерыванию спокойно спрашивать время. И время будет точно на переходе секунды обновляться и таймер не будет занят.

Этот вариант

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так всё ж написано.

Береёт пин, который умеете принимать прерывания. Конфигурируете его как INPUT_PULLUP и настраиваете на него прерывание на FALLING.

Соединяете его с пином SQW часов.

Часы конфигурируете, чтобы они туда раз в секунду выдавали низкий уровень (в даташите написано как это делать).

Ну и всё. Случилось прерывание - запрашиваете время и, если надо, обновляете на экране.

b707
Offline
Зарегистрирован: 26.05.2017

NickSan пишет:

Не вариант, так как будет не красиво смотреться торчащий провод через всю плату печатную...

а что, печатная плата будет без корпуса?

Каких только бредовых обьяснений не встретишь на форуме...

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

ЕвгенийП пишет:
Часы конфигурируете, чтобы они туда раз в секунду выдавали низкий уровень (в даташите написано как это делать).

Спасибо.

Хотелось еще задать вопрос по поводу таймеров, так как сколько не лазаю не могу понять что мне нужно и как это реализовать.

Помимо ШИМ, который подает ток, у меня есть функция, которая переключает режимы портов раз в 1мс, хочу завести таймер для выполнения этой самой функции на фоне основого цикла программы, без управления другими пинами.

Читал этот пост, работает, но не пойми что творится.  (То дросель свистит, то вообще вольтаж перестаёт генерироваться на шим)

NickSan пишет:
мк atmega328p, кварц на 8Mhz

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

b707 пишет:
Каких только бредовых обьяснений не встретишь на форуме...

С корпусом, еще сертификацию проходить. А так как объем маленький, то заказывать новые печатные платы влетит в копеечку.

GarryC
Offline
Зарегистрирован: 08.08.2016

Вообще то пост с самого начала меня озадачил - как может что либо вообще влиять на ШИМ ?

Единственное разумное объяснение - у вас таймер в однократном режиме - сделайте режим у перезапуском и будет у Вас чистый ШИМ без всякого влияния.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

GarryC пишет:

Вообще то пост с самого начала меня озадачил - как может что либо вообще влиять на ШИМ ?

Единственное разумное объяснение - у вас таймер в однократном режиме - сделайте режим у перезапуском и будет у Вас чистый ШИМ без всякого влияния.

Как раз таки так не нужно, необходимо в зависимости от выставленных настроек менять требуемый вольтаж постоянного тока от 150 до 210 вольт, плюс вольтаж может проседать при смене портов.

Это всё работает. (мосфет не греется, дросель не свистит)

GarryC
Offline
Зарегистрирован: 08.08.2016

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

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Я меняю только период в зависимости от вольтажа (ICR1)

Вопрос про таймер в силе.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

http://playground.arduino.cc/Code/Timer1

void OutputDisplay(){ //Управление портами и вольтажом
}
void setup(){
//Set the Timer 1 IRQ frequency
Timer1.initialize(1000);      //Set the timer period in uS (this function will attempt to match using the available prescaller settings
            
//Set the timer 1 IRQ fucntion to be called
Timer1.attachInterrupt(OutputDisplay); // attach the service routine here

Timer1.start();
}

void loop{
getRTCtime(); // ds1307
}
void loop() {
  Timer1.restart();
}

 

Я всё правильно делаю?

Мне кажется нужно правильно рассчитать период для Timer1.initialize, только не вижу как это сделать...

Плюс не обрабатываются кнопки из основного цикла программы (void loop)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

NickSan пишет:

С корпусом, еще сертификацию проходить. А так как объем маленький, то заказывать новые печатные платы влетит в копеечку.

Вообще-то это хоббийный форум. Какая сертификация? Какой объём? Если у Вас коммерческая разработка, так наймите специалиста, чего задарма-то решения спрашивать?

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Нет не коммерческий, но хотелось бы, мечтать нельзя что ли?.. Возможно, что вообще я это делаю для себя или в подарок кому нибудь и свет не увидит...

Просто это причина, почему я не хочу кидать провод через всю плату или печатать новую, у меня тут и так трэш... не хочу усугублять.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Timer1.initialize(50);   - цикл программы не выполняется

Timer1.initialize(1000);   - цикл программы не выполняется

Timer1.initialize(10000); - выполняется цикл программы, генерируется вольтаж, таймер не выполняется или частота выполнения достаточно редкая...

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

NickSan пишет:

мк atmega328p, кварц на 8Mhz

неужели нельзя запустить таймер OCR0A без управления пинами на бесконечное выполнение раз в 1мс?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

NickSan пишет:

неужели нельзя запустить таймер OCR0A без управления пинами на бесконечное выполнение раз в 1мс?

можно

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017
void TTimerList::Init()
{
	byte oldSREG = SREG;
	cli();

	TCCR0A = TCCR0A & 0b11111100;
	OCR0A = TIMER0_ONE_MS;             // 245
	TIMSK0 |= 0x3;
	TIFR0 = TIFR0 | 0x2;

	SREG = oldSREG;

}

ISR(TIMER0_COMPA_vect)
{

	TCNT0 = 0xFF;   // это чтоб миллис и делай работали дальше
	TimerList.Step();
}

поизучай. там всё

https://github.com/DetSimen/Arduino-