Кто сможет объяснить доходчиво алгоритм часов?

Обсуждаем контроллеры компании Atmel.
Ответить
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Доброго времени суток, друзья! =)))

Короче... год уже прошел, а я все никак часы доделать не могу... Обычные часики. На АТТини2313 и часах реального времени с протоколом I2C. В свое время досконально разобрался с этим протоколом и даже написал всю программулину на ассемблере, чтобы с часами обмениваться данными. Итого, у меня получилось. По каждому прерыванию один раз в секунду микроконтроллер прибавляет значение секунд. Часы реального времени используются только как источник стабильных импульсов каждую секунду... Хотя, до этого они и устанавливаются в программе в нулевое значение и запускаются.
Организовал вывод значения часов и минут на 7сигментные индикаторы, динамическая индикация. Все показывает и даже считает время с 00:00 прибавляя по минуте.

Встал ступор у меня на том, что надо как-то организовать изначальную установку часов... Как это программно сделать не знаю. Ну и будильника тоже и чтобы потом этот будильник звонил еще...
И еще один момент... Экспериментировал с сенсорными кнопками туда же.... Что-то получилось, что-то нет. Сенсоры простые, которые измеряют время заряда конденсатора при увеличении емкости при прикосновении. Не могу сделать точные измерения, т.е. чтобы часы сами калибровались при включении.

Если что не понятно, спрашивайте. ДОбавлю информации.
Станислав
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6339
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

Ну во-первых, I2C тут вроде как не при делах, поскольку исползуется только 1-секундный импульс. В этом случае RTC можно безболезненно заменить любым кварцованным генератором на 1 Гц. Соль RTC -- в хранении текущего времени за счет автономного питания при выключенном питании самих часов - не используется. Так что для начала нужно организовать действительный обмен по I2C с RTC, чтобы подхватывать с него время при включении питания часов . Когда это выполнится, с коррекцией совсем просто : кнопками настроить на индикаторе время и по сигналу точного времении отправить в RTC, обновить ему хранимое время. Проектов таких в сети -- думаю, вагон. Сам лет 15 тому назад делал хранение точного времени для солидного промышленного устройства, проблем не возникало особых.
PS RTC -- real time clock, если кого озадачила аббревиатура.
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Jack_A писал(а):Так что для начала нужно организовать действительный обмен по I2C с RTC
Конечно! )))) И это тоже нужно. У меня не укладывается в голове, как это все один МК сможет прожевать.... И чтобы при этом не прегрузить его функциями, чтобы продолжал считать время дальше. А сохранение времени обязательно надо, зачем же тогда батарейку ставил???!!! )))
Станислав
Друг Кота
Аватара пользователя
Сообщения: 7377
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

А в чем проблема? Нарисуйте простенькие программки, которые для начала отображают время, затем, которая умеет обрабатывать кнопки, а потом можно и всё остальное. Часики - это хороший тренировочный полигон, чтобы поучиться программировать. Вот только недавно закончил писать фирмварь для часиков на панаплексном дисплее.
Спойлер

Код: Выделить всё

void show_humantime() {
  unsigned int i, dst_en, dst = 0;
  char  timezone;
  unsigned char keyb, last_second = 99, current_brightness;
  
  while(1) {
   if (flag.sec_event == 1) {
      flag.sec_event = 0;
      current_time.seconds = read_ds1302(0x81);
      if (current_time.seconds != last_second) {
        last_second = current_time.seconds;
        current_time.seconds = read_ds1302(0x81);
        current_time.minutes = read_ds1302(0x83);
        current_time.hours   = read_ds1302(0x85);
        current_time.date    = read_ds1302(0x87);
        current_time.month   = read_ds1302(0x89);
        current_time.weekday = read_ds1302(0x8b);
        if (current_time.weekday == 7) current_time.weekday = 0;
        current_time.year    = read_ds1302(0x8d);

        videobuffer[0] = charset[(current_time.seconds & 0x0f)];
        videobuffer[1] = charset[(current_time.seconds & 0xf0)>>4];
        
        videobuffer[2] = charset[(current_time.minutes & 0x0f)] | seg_h;
        videobuffer[3] = charset[(current_time.minutes & 0xf0)>>4];
        
        videobuffer[4] = charset[(current_time.hours & 0x0f)] | seg_h;
        videobuffer[5] = charset[(current_time.hours & 0xf0)>>4];
        
        
        i = (current_time.weekday) << 2;
        
        videobuffer[9] = dow[i++];
        videobuffer[8] = dow[i++];
        videobuffer[7] = dow[i++];
        
        videobuffer[6] = let_;
        videobuffer[10] = let_;
      }
      if (keyb = kbdread()) {
        if (keyb == KEY_LEFT) {
          current_brightness = read_ds1302(0xC5) & 0x07;
          if (current_brightness > 0) {
            --current_brightness;
            write_ds1302(0x8e, 0x00);   // disable write protection
            write_ds1302(0xC4, current_brightness);
            write_ds1302(0x8e, 0x80);   // enable write protection
          }
          for (i=0; i<12 ;++i) videobright[i] = current_brightness;
        }
        if (keyb == KEY_RIGHT) {
          current_brightness = (read_ds1302(0xC5) & 0x07);
          if (current_brightness < 7) {
            ++current_brightness;
            write_ds1302(0x8e, 0x00);   // disable write protection
            write_ds1302(0xC4, current_brightness);
            write_ds1302(0x8e, 0x80);   // enable write protection
          }
          for (i=0; i<12 ;++i) videobright[i] = current_brightness;
        }
        if (keyb == KEY_BOTH) return;
      }
    }
  }
}
Вот пример просто отображения времени. флаг sec_event выставляется каждые 16мс и проверяется, сменилась секунда или нет. У меня применена микросхема, которая, к сожалению, не даёт секундные импульсы. И если секунда изменилась - обновляется информация на индикаторе. Ну и, разумеется, опрашиваются клавиши, которые изменяют яркость индикатора или переключают другой режим отображения.

Всё отображение и опрос клавиш, организованы в прерываниях (не привожу, так как кристалл не AVR) и выполняется в фоне.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 6339
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

СКАЗОЧНИК писал(а): И чтобы при этом не прегрузить его функциями, чтобы продолжал считать время дальше.
Да какая там перегрузка - кроме часов, там ничего нет :) Успеет, позевывая и не торопясь.
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Я вообще думал туда пихать что-нибудь типа РТОС урезанную, но с диспетчером... )))) А кто-нибудь с сенсорами разбирался? Как правильнее сделать на ассемблере подсчет времени заряда конденсатора?
Я пока что-то типа того намутил....

Код: Выделить всё

;			---------- определяем порог для пустого сенсора -----------------------------

			clr temp
			clr temp1
			ldi Counter, 0x04
			
		
			clr RTCaddr
			clr SensorL
			clr SensorR
			
		ForCounter:

			dec Counter				; Уменьшаем количество циклов на 1
		
			ldi temp, 0b01000001	; Изначально порт настроен на выход, дергаем сенсор вниз, чтобы разрядить конденсатор 
			out PORTD, temp

			ldi temp, 0b01001111	; Переключаем порт на вход для сеноров, остальные - выход
			out DDRD, temp		

				SENS4: 	inc RTCaddr	; Начинаем отсчет времени заряда пустого сенсора
				
						sbis PIND, 4	; Пропускаем следующую команду, если пин 4 в регистре Д стал равен единице
						rjmp SENS4		; Иначе, проверяем снова

			ldi temp, 0b01111111	; Переключаем порт на выход
			out DDRD, temp	

			ldi temp, 0b01000001	; Дергаем сенсор вниз, чтобы разрядить конденсатор 
			out PORTD, temp

			ldi temp, 0b01001111	; Переключаем порт на вход для сеноров, остальные - выход
			out DDRD, temp	
				
				SENS5: 	inc temp1	; Начинаем отсчет времени заряда пустого сенсора
				
						sbis PIND, 5	; Пропускаем следующую команду, если пин 5 в регистре Д стал равен единице
						rjmp SENS5		; Иначе, проверяем снова

;				--------------------------------------------------
			
			cp SensorL, RTCaddr			; Сравниваем два значения, если первое больше
			brsh OTHER				; или равно, то выходим на проверку следующих

				mov SensorL, RTCaddr	; Иначе, пихаем в первый большее значение

	OTHER:	cp SensorR, temp1
			brsh NEXTFOR

				mov SensorR, temp1

	NEXTFOR:	cpi Counter, 0x00		; Проверяем, не стал ли счетчик равен 0?
				brne ForCounter


Станислав
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7377
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

Использовать, например, аппаратный таймер. В АВРах они, ведь, есть? В некоторых кристаллах, есть даже возможность использовать гейт разрешающий/запрещающий работать счетчику. В 18-х пиках есть даже специальный блок измерения коротких интервалов (для измерения емкости от сенсорных кнопок). Вариантов - море.

Тупой метод, вроде инкремента переменной в цикле, не предлагаю, так как точность измерения может оказаться не достаточной.
Друг Кота
Аватара пользователя
Сообщения: 6296
Зарегистрирован: Пн ноя 22, 2010 00:57:15
Откуда: Ukraine

Сообщение FreshMan »

СКАЗОЧНИК писал(а):Доброго времени суток, друзья! =)))

По каждому прерыванию один раз в секунду микроконтроллер прибавляет значение секунд.
правельнее было бы сделать чтобы мк по каждому прерыванию читал время с DS1307
Tell Me The Truth
Друг Кота
Аватара пользователя
Сообщения: 6339
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

FreshMan писал(а): правильнее было бы сделать чтобы мк по каждому прерыванию читал время с DS1307
А смысл ? При включении питания часов "схлопнули" из RTC сохраненное время, и при каждом импульсе время будет синхронно прибавляться и в часах, и в RTC. Главное -- не пропустить и зафиксировать провал питания , чтобы знать, что нужно повторно синхронизуться.
Друг Кота
Аватара пользователя
Сообщения: 15752
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Или при подаче питания однократное чтение RTC с запуском внутреннего набора регистров (самостоятельные часики) - приращение по прерываниям слишком роскошно для простейшей конструкции. 8)
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Зато оно точнее. )))))) мне так кажется.
Станислав
Друг Кота
Аватара пользователя
Сообщения: 15752
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

На практике для бытовых нужд и автоматики практически неотличимо. 8)
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Что же мне теперь РТС выкидывать???? :shock:
Станислав
Друг Кота
Аватара пользователя
Сообщения: 15752
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

А оно (RTC) для того и существует, чтоб продолжать отсчет при отключенном питании и чтоб каждый раз после включения устройства кнопкодавством не заниматься. Плюс энергонезависимое ОЗУ для собственных параметров каких-нить величин.
8)
Опытный кот
Сообщения: 758
Зарегистрирован: Вс фев 10, 2013 15:26:00

Сообщение nirq »

... при отключенном питании от питания более экономичного.

По основной проблеме: не надо пытаться съесть сразу вообще слона.
А надо сначала выбрать какую-то такую часть слона, которая поместилась бы в тарелку. Потом эту часть от слона отрезать, положить в тарелку и съесть. И только потом вспоминать про существование остального слона.
Ответить

Вернуться в «AVR»