Показаны сообщения с ярлыком clock. Показать все сообщения
Показаны сообщения с ярлыком clock. Показать все сообщения

суббота, 10 августа 2013 г.

Еще одни часы на Ардуине. Часть 1. Запускаем часы


Для следующего проекта, попались мне в руки два таких шилда:

Arduino LCD KeyPad Shield (SKU: DFR0009) - Robot Wiki
Текстовый экран 16x2 плюс четыре кнопки с помощью делителя напряжения заведенные на пин A0
И шилд часов реального времени: Real Time Clock Module (DS1307) V1.1 (SKU:DFR0151) - Robot Wiki


Тут могла быть ваша реклама вашего магазина шилдов :)

Руки зачесались...
Понятно, что это 1001 проект  "часы на ардуине" и можно просто взять что-то готовое. Но у меня две цели: поиграться с модулями и показать как "вырастает проект". Правильный, с моей точки зрения, процесс. В противовес тому, как многие новички пытаются "накупить железо", составить 1000 "хотелок" и запустить все это сразу.

Итак, раз мы будем идти мелкими шагами - откладываем пока наш экран в сторону. Для начала освоимся с часами.

Железная составляющая


Подключаем их в соотвествии с wiki-производителя:
Линию DS - можно, пока, не подключать (пунктирная линия). С ней будем разбиратся позже.

Но у меня плата - Arduino Mega. У нее шина I2C (по ней передает данные модуль часов) расположены не на A4,A5, а на D20,D21
Поэтому я подключал SDA->D20 ,  SLC->D21

Если у вас другая плата - можете сверится с этой табличкой:
ПлатаI2C / TWI pins
Uno, EthernetA4 (SDA), A5 (SCL)
Mega256020 (SDA), 21 (SCL)
Leonardo2 (SDA), 3 (SCL)
Due20 (SDA), 21 (SCL)

Щупаем програмно

Что-бы комфортно работать с часами, на закапываясь в даташиты нам потребуется скачать и установить библиотеку для DS1307. Производитель модуля - предоставляет ее, но мне больше понравилась альтернативная. Вот эта: ds1307new - DS1307 RTC Library with NV-RAM support - Google Project Hosting
Скачиваем ее, распаковываем, забрасываем в папку libraries и пишем первый наш код, проверяющий видит ли ардуина наши часы:
   // Библиотеки необходимые для работы модуля часов
#include <Wire.h>
#include <DS1307new.h>

void setup(){
  Serial.begin(9600);
  if(RTC.isPresent()){ // обнаружен ли модуль?
    Serial.println("RTC Ready"); // все хорошо
  } else {
    Serial.println("Error!!!! RTC Module not found"); // сообщаем о проблеме
    while(1); // и останавливаем скетч
  }
}

void loop(){
}

Заливаем, открываем Serial монитор и надпись:


Для перепроверки, отсединяем, скажем, линю SLC. Закрываем, открываем монитор (перезапускаем скетч) и видим что надпись у нас сменилась на "Error!!!! RTC Module not found".
Возвращаем проводок на место и опять видим "RTC Ready". Наш "детектор проблем" - работает.

А который час?

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

Ну что-же давай попробуем вывести время. Что-бы сразу привыкать к "хорошим манерам", не будем сильно захламлять loop(), вынесем вывод времени в отдельную функцию и назовем ее printTimeToSerial()  и будем ее вызвать из loop()

void loop(){
  RTC.getTime();// получить время от модуля
  printTimeToSerial(); // выводим полученное время
}
 
void printTimeToSerial(){
  Serial.print(RTC.hour); // часы
  
  Serial.print(":"); // разделитель
  Serial.print(RTC.minute);
  
  Serial.print(":"); 
  Serial.println(RTC.second);
}
В логе (сериал мониторе видим) что-то типа:
17:53:35
17:53:35
17:53:35
17:53:35
17:53:35

Много, много раз...
C одной стороны - хорошо. Модуль посылает нам время и мы научились отправлять его в Serial. С другой... он старается делать это как можно чаще. Насколько хватает пропускной способности Serial. А нам - это не нужно :) Столько дублирования. Поэтому давайте отправлять время в Serial только если, скажем секунды, изменились с прошлого вызова функции.
// Выводит текущие время в Serial
void printTimeToSerial(){

  byte static prevSecond=0; // тут будем хранить, сколько секунд было при прошлом отчете
  
  if(RTC.second!=prevSecond){ // что-то делаем только если секунды поменялись
    Serial.print(RTC.hour); // часы
  
    Serial.print(":"); // разделитель
    Serial.print(RTC.minute);
  
    Serial.print(":"); 
    Serial.println(RTC.second);
    
    prevSecond=RTC.second; // запомнили когда мы "отчитались"
  }
}


Теперь наш лог, примет такой вид:

RTC Ready
18:0:26
18:0:27
18:0:28
18:0:29

Каждая надпись - появляется раз в секунду. Можно дествительно смотреть как "часы идут".

 Кстати, возможно вы заметили что время выглядит "не очень красиво", вмето привычных 18:00:26, у нас получилось 18:0:26. Но так как работа с Serial у нас "вспомогательная", мы не будет отвлекатся на решение этой проблемы. Но вернемся к ней и будем "наводить красоту", когда время будет показываться уже на LCD экране.


А точнее?

Получать время - это хорошо. Но его же нужно еще уметь устанавливать. В конечном итоге - будем делать это с помощью кнопок, но пока... сделаем временное решение. Самое простейшие: забъем нужное нам время прямо в скетч. И будем его посылать модулю, если из Serial нам пришел символ 's'

Функция установки времени:

void setSomeTime(){
    RTC.stopClock();// останавливаем часы
    RTC.fillByHMs(19,15,0); // "подкручиваем стрелки на 19:15:00
    RTC.setTime();// отправляем "подкрученное время" самому модулю
    RTC.startClock(); // и опять запускаем часы
}

Функция которая слушает команды из Serial

 void doSerialCommands(){
  if(Serial.available()){ // что-нибудь пришло?
    char ch=Serial.read(); // читаем что пришло
    
    switch(ch){
      case 's': // команда устновки времени
           setSomeTime(); // устанавливаем
           break;
           
       // тут, в будущем, мы можем добавлять дополнительные команды
      default:;
           // на неизвестну команду - ничего не делаем
    };
  }
} 

Все. Нам осталось только вставить вызов doSerialCommand() в loop()  для регулярного опроса команда из Serial. После чего наш скетч принимает вид:

// Author: alxarduino@gmail.com
// Sample Clock App for http://alxarduino.blogspot.com

// Библиотеки необходимые для работы модуля часов
#include "Wire.h"
#include "DS1307new.h"

void setup(){
  Serial.begin(9600);
  if(RTC.isPresent()){ // обнаружен ли модуль?
    Serial.println("RTC Ready"); // все хорошо
  } else {
    Serial.println("Error!!!! RTC Module not found"); // сообщаем о проблеме
    while(1); // и останавливаем скетч
  }
}

void loop(){
  RTC.getTime();// получить время от модуля
  printTimeToSerial(); // выводим полученное время
  doSerialCommands(); // слушаем и выполняем команды из Serial
}

// Выводит текущие время в Serial
void printTimeToSerial(){

  byte static prevSecond=0; // тут будем хранить, сколько секунд было при прошлом отчете
  
  if(RTC.second!=prevSecond){ // что-то делаем только если секунды поменялись
    Serial.print(RTC.hour); // часы
  
    Serial.print(":"); // разделитель
    Serial.print(RTC.minute);
  
    Serial.print(":"); 
    Serial.println(RTC.second);
    
    prevSecond=RTC.second; // запомнили когда мы "отчитались"
  }
}

// устанавливает часы модуля на какое-то заранее определенное время
void setSomeTime(){
  RTC.stopClock();// останавливаем часы
  RTC.fillByHMS(19,15,0); // "подкручиваем стрелки на 19:15:00
  RTC.setTime();// отправляем "подкрученное время" самому модулю
  RTC.startClock(); // и опять запускаем часы
}

// слушает из Serial команды и выполняет их. Каждая команда - один символ.
// доступны команды:
//  s - установить время указанное в функции setSomeTime()
void doSerialCommands(){
  if(Serial.available()){ // что-нибудь пришло?
    char ch=Serial.read(); // читаем что пришло
    
    switch(ch){
      case 's': // команда установки времени
           setSomeTime(); // устанавливаем
           break;
           
       // тут, в будущем, мы можем добавлять дополнительные команды
      default:;
           // на неизвестную команду - ничего не делаем
    };
  }
}


Заливаем.Открываем Serial Монитор. Набираем s (в нижнем регистре) и нажимает "отправить"

Итого:

  • Мы подключили модуль часов DS1307. 
  • Убедились что Ардуина "его видит" (и сообщает нам если не видит). 
  • Научились получать от модуля время и отправлять его в Serial.
  • Научились устанавливать время модуля по команде из Serial

В следующей части: мы подключим уже LCD и выведем время на него