суббота, 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 и выведем время на него

16 комментариев:

  1. Спасибо большое за материал!!! Очень помогло разобраться, вник буквально за 10 минут.

    ОтветитьУдалить
  2. Как всегда очень объяснительно! :) А "добавка" будет? :) С кнопками?!

    ОтветитьУдалить
  3. при загрузке любого вашего скетча вылазит это stk500v2_ReceiveMessage(): timeout
    Не подскажете в чем проблема ? Ардуиномега+ds1307+lcdshied

    ОтветитьУдалить
    Ответы
    1. Простите, но я сомневаюсь что проблема это происходит при загрузке именно любого МОЕГО скетча. Есть подозрение что это происходит при загрузке ЛЮБОГО скетча.
      Судя по ошибке, это именно проблема заливки. А заливка и сам скетч - ортогональны.
      Причин же проблем с заливкой может быть море: слетел бутлоадер, не хватает питания, неправильно выбранная плата в меню tools, проблемы с драйверами, не качественный USB кабель, неверный boards.txt, неверное подключение (что-то привесили на D0,D1 случайно)
      В любом случае эта ошибка, грубо говоря, означает "ардуина не отвечает когда мы посылаем ей новую прошивку". Но сам факт того что "ее попытались послать" уже говорит о том, что скетч скомпилировался и проблема не в нем.
      Выкапывать пробелемы начинайте именно, как я в посте писал с "правильного подхода". Раз есть проблема, значит начинать пытаться что-то залить нужно не с "ардуино+ds1307+lcdshield", а с "ардуино". Как в статье "отложите в сторону...". Все. Залейте блинк обычный, если все норм, то подключаем что-то, скажем ds1307... и опять все тот же блинк. Если норм, то уже потом вливаем скетчи из поста. Если норм, то уже потом подключаем lcd... и т.п. Пошагово. Игра перелет/недолет. Ищем состояния когда "все норм", и "уже не норм". Выясняем "кто же пакостит".

      Удалить
    2. прежде всего спасибо что ответили
      блин:) один коммент не напечатался.....
      Вообщем без часов(ds1307) все работает. То есть Arduino+LCDshield+DHT11+влажность почвы - и мой скетч для всего этого добра заливается и работает.
      Ну я купил ds1307 в Китае , он без ножек пришел, я кое как их припаял (на это тоже грешу что не работает). И подключил их.
      Теперь как чего:
      Подключаю Дуню по юсб к компу.
      Она вкл и загружает мой скетч , все робит
      Заливаю ваш самый первый, простой . Компилит , но начинает заливать и выскакивает ошибка.
      Переподключаю Дуню, залииваю свой скетч , опять все работает.
      Вот такая фигня(

      Удалить
    3. Оставил только Ардуину, подключил , стал заливать ваш скетч, тоже ошибка.
      RX TX помигали и все, потом мигают когда ошибку пишет.
      Мой скетч нормально загружается.
      Скетч из примера библиотеки тоже заливается. Но правда не работают. Тот где время в сериал выводи писал время 165 тратата....
      Второй тоже на команды в порт не отвечал.

      Удалить
    4. Промахнулся с ответом: смотрите коментарии ниже

      Удалить
  4. >Она вкл и загружает мой скетч , все робит
    А если, поэтому этого... ничего не меняя, опять взять и залить ваш скетч? Не мой. Без переподключений?
    Два, три раза подряд, ваш скетч заливается?

    И, уже в третий раз советую: начните искать причину последовательно:
    - В "голую" ардуину все нормально вливается?
    - В "arduino+ds1307" нормально вливается? (без DHT, без LCD)

    Я же в прошлом ответе написал "подключайте постепенно". По одной внешней железке, а вы, вместо этого добавили в зоопарк еще и DHT11

    А ножки паять - желательно научится. Очень многие шилды идут именно так (меньше шансов повредить). Проще всего найти кого-то "кто-бы показал". У меня тоже была с этим трабла, но как только товарищ показал, то... все стало очень просто.
    В двух словах: покупаем припой типа "проволочка, а внутри нее флюс". Берем жало скошенное с одной стороны (многие новички пытаются брать жала поменьше, иглоки - это не нужно). Далее, греем ножку паяльником с одного бока (плоской стороной), а с другого прикладываем проволочку. Ее кончик "расплавится" и обхватит ножку и пад. Когда мы так делаем, а не "припой на паяльник, а потом на ногу", то мы имеем гарантию что припой начнет плавится когда нога уже достаточно прогрета. А не "намазали припой на холодную ногу".
    Ну и .... самого припоя меньше расходуется. Аккуратней пайка выходит.
    Если есть сомнения как припаяли - берите лупу и смотрите. Тестером прозвоните что нигде не замкнули соседние. Ну и просто можете еще раз пройтись паяльником, уже без припоя, "прогреть" сомнительные контакты.
    Можно предварительно смазав их флусом.
    Вообще говорят, что, при самой пайке, достаточно того который "в проволочке", но я, все-таки вначале ноги, все-таки в любом случае обливаю флюсом.
    Флюсом удобно "обливать", с помощью обычного шприца небольшого.

    ОтветитьУдалить
  5. Эмц.. а попробуйте еще такую "магию": вот в впервом скетче.
    Строка
    Serial.println("Error!!!! RTC Module not found");

    Замените ее на
    Serial.println("Error: RTC Module not found");

    (вообщем уберите восклицательные знаки).

    ОтветитьУдалить
  6. за способ паяния отдельный респект, буду учиться.
    Я вроде писал выше что даже на пустую Дуню не заливается. Все другие льются без проблем.
    Получил я время ... Ножки еще с другой стороны РТС припаял и к ним подключился. Я то думал пофиг к каким :) Вообщем скетч пример вроде заработал.
    Сейчас буду с вашими скетчами колдовать, он мне вроде больше всего понравился.

    ОтветитьУдалить
    Ответы
    1. Без !!! все работает !!!!! Ура:)

      Удалить
    2. Значит причина в том что у вас очень древний (имеющий баг) бутлоадер в меге.
      Способы борьбы:
      Нужно следить за тем что-бы в скетчах нигде не попадались три (или больше) восклицательных знака подряд. Неважно где.

      Или... обновить бутлоадер. Бага вообщем-то "древняя", не могу гарантировать, но практический уверен что ее фикс уже вошел в свежие релизы ArduinoIDE.
      Обновить - конечно лучше. Тогда можно восклицать сколько хочешь :)
      Но для этого понадобиться программатор (или другая ардуина в качестве программатора).

      Удалить
    3. Походу так и есть , ну китайцы :)
      Ардуино ИДЕ вроде последнее качал....Заказал еще пару Ардуин , как приедут буду прошивать

      Удалить
  7. >Я вроде писал выше что даже на пустую Дуню не заливается.
    Вы написали это пока я набирал пост. Поэтому я увидел это уже после того как нажал "отправить".

    >Сейчас буду с вашими скетчами колдовать,
    В первую очередь попробуйте, как я написал выше, убрать восклицательные знаки.

    Есть сильное подозрение что дело в них.

    ОтветитьУдалить
  8. Я так понял что до установки времени кнопками с шилда и хранении данных в памяти вы еще не дошли ? Или стало не интересно? Или спецом не стали выкладывать чтоб такие как я хоть немного подумали ?:)

    ОтветитьУдалить
  9. Можно пример скетча дя регулировки времени кнопками?

    ОтветитьУдалить