Отправка СМС с данными сенсора
- Войдите на сайт для отправки комментариев
Вс, 17/01/2016 - 12:47
Здравствуйте!
Прошу помощи в указании на ошибки в реализации тривиальной задачи отправки смс с данными сенсора DS18b20 с использованием TinySine Shield GSM на Arduino Uno. В программировании не силён, но есть желание разобраться и реализовать этот проект для дачи.
На данный момент: На LCD I2C экран выводится сообщение с температурой -127, что говорит о том, что контроллер не видит датчик. Сам дачтик подключён через беспаечную плату к 4 выходу.
На телефон присылается только сообщение с первоначальной строкой: "Starting ok". Данные датчика не отправляются.
Используемый код:
#include <SIM900.h>
#include <sms.h>
#include <OneWire.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#define ONE_WIRE_BUS 4 // DS18S20 wired to digital pin 4, same bus for all sensors
LiquidCrystal_I2C lcd(0x27,20,4); // Liquide crystal is a 4x20 LCD with I2C support
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress bathroom = { 0x10, 0x5E, 0xE8, 0x33, 0x02, 0x08, 0x00, 0xDB }; //Sensor 1
unsigned int swt = 0; // flip for alternate the display btw temp and humidity
SMSGSM sms;
char number[]="+7912ХХХХХХХ"; // Destination number
char message[180];
char pos;
char *p;
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight(); // Backlight ON
lcd.setCursor(0, 1);
lcd.print(" Ardui'Home ");
lcd.setCursor(0, 2);
lcd.print(" Loading... ");
sensors.begin();
sensors.setResolution(bathroom, 10);
Serial.begin(9600);
if (gsm.begin(2400))
Serial.println("\nstatus=READY");
else
Serial.println("\nstatus=IDLE");
(sms.SendSMS(number, "Starting ok !")); //sending sms when he starting up
pinMode(7, OUTPUT); // Pin 7 for bliking running led
}
void loop()
{
temps(); // calculate and displaying temps from DS18 and DHT sensor's
runingled(); //loop to displaying a running LED
}
void temps()
{
sensors.requestTemperatures();
float tbathroom = sensors.getTempC(bathroom); // Bathroom sensor
swt++; // Alternate displaying betwen DS18 and DHT sensors
if ((swt % 15) > 5 )
{
//////////////DS18B20 Sensors/////////////////
lcd.setCursor(0, 0);
lcd.print("Sdb ");
lcd.print(tbathroom);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print(" ");
}
}
/////////// Blink a Led to check if the code run correctly ///////////
void runingled()
{
digitalWrite(7, HIGH);
delay(80);
digitalWrite(7, LOW);
delay(1000);
}
Буду благодарен за любую помощь и совет.
На телефон присылается только сообщение с первоначальной строкой: "Starting ok". Данные датчика не отправляются.
А должны? Покажите в какой строке.
Пока я вижу во всём скетче единственную отправку смс в строке 48. Она, по Вашим словам, работает нормально. Никаких других отправок смс я в тексте программы не нашёл.
Теперь увидел, Вы правы.
Нужно добавить в блок loop аналогичную функцию, заменив выражение на данные сенсора?
(sms.SendSMS(number,"Starting ok !"));И вопрос по самому датчику, почему он может не читаться на дисплее? Не в этой строке дело?
16DeviceAddress bathroom = { 0x10, 0x5E, 0xE8, 0x33, 0x02, 0x08, 0x00, 0xDB };//Sensor 1И вопрос по самому датчику, почему он может не читаться на дисплее? Не в этой строке дело?
16DeviceAddress bathroom = { 0x10, 0x5E, 0xE8, 0x33, 0x02, 0x08, 0x00, 0xDB };//Sensor 1Датчик не имеет никакого отношения к дисплею. Дело датчика выдать Вам цифирь, а дело дисплея эту цифирь показать. Т.е. ещё раз в строке 61 Вы получаете самое обыкновенное число типа float. На этом работа датчика закончилась. дальше Вы это число показываете на дисплее. Дисплею всё равно где Вы взяли это число - с датчика или руками вбили. Понимаете. что оно не могут быть ни совместимы, ни несовместимы друг с другом. Они друг другу фиолетово.
Теперь про эту строку. Это адрес датчика. Где Вы его взяли? Из какого-нибудь примера или прочитали со своего датчика? Если первое, то выбрасывайте - у каждого экземпляра датчика уникальный адрес.
И ещё. судя по коду Вы программируете свосем недавно. Тогда послушайте: я программирую почти сорок лет (с 1979 года) и я бы не взялся сразу писать Ваш скетч - это слишком сложно делать сразу. Я бы сначала отладил бы работу с датчиком. Для этого написал бы скетч БЕЗ экрана и БЕЗ смс - только датчик и вывод температуры в сериал. Потом бы я написал скеч для экрана БЕЗ датчика и БЕЗ смс - только вывод числа на экран. Число бы руками вбивал. Наконец, я бы написал скетч для смс БЕЗ датчика и БЕЗ экрана - отправлял бы вбитое руками число. И только когда все три куска у меня надёжно бы работали - я бы объединил их вместе.
Сейчас, если у Вас что-то не работает - Вы просто не знаете за что хвататься. т.к. Вы свалили всё в кучу и не работать можно может всё, что угодно. Отделите мух от котлет. Отладьте по отдельности работу со всеми тремя устройствами. Будет намного легче.
Евгений, благодарю за помощь, но просьба понять правильно. Я не программирую на С. Я знаю HTML5, частично PHP и JS, но профессионально я занят совсем в другом направлении, я занимаюсь логистикой уже 15 лет и у меня нет в ближайшем будущем цели программировать для Ардуино. У меня есть конкретная цель запустить этот проект и всё. Я перерыл весь интернет в поисках подходящего скетча но ни один не подошёл, поэтому вынужден был взять за основу близкий пример и вручную его дорабатывать.
Благодаря Вашим подсказкам мне уже удалось разобраться с выводом показания датчика на экран и регулярной отправкой СМС в цикле Loop. Но сейчас остался последний затык - не очень понимаю как указать вместо текстового сообщения именно значение температуры.
Если не затруднит, намекните пожалуйста.
#include <SIM900.h> #include <sms.h> #include <OneWire.h> #include <Wire.h> #include <SoftwareSerial.h> #include <DallasTemperature.h> #include <LiquidCrystal_I2C.h> #define ONE_WIRE_BUS 4 // DS18S20 wired to digital pin 4, same bus for all sensors LiquidCrystal_I2C lcd(0x27,20,4); // Liquide crystal is a 4x20 LCD with I2C support OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress bathroom = { 0x28, 0xFF, 0x32, 0x3D, 0x90, 0x15, 0x04, 0xC0 }; //Sensor 1 unsigned int swt = 0; // flip for alternate the display btw temp and humidity SMSGSM sms; char number[]="+7912ХХХХХХХ"; // Destination number char message[180]; char pos; char *p; char buffer1[] = "sensors"; void setup() { lcd.init(); // initialize the lcd lcd.backlight(); // Backlight ON lcd.setCursor(0, 1); lcd.print(" Ardui'Home "); lcd.setCursor(0, 2); lcd.print(" Loading... "); sensors.begin(); sensors.setResolution(bathroom, 10); Serial.begin(9600); if (gsm.begin(2400)) Serial.println("\nstatus=READY"); else Serial.println("\nstatus=IDLE"); (sms.SendSMS(number, "Starting ok !")); //sending sms when he starting up pinMode(7, OUTPUT); // Pin 7 for bliking running led } void loop() { temps(); // calculate and displaying temps from DS18 and DHT sensor's runingled(); //loop to displaying a running LED } void temps() { sensors.requestTemperatures(); float tbathroom = sensors.getTempC(bathroom); // Bathroom sensor if (sms.SendSMS(number, buffer1)) Serial.println("\nSMS sent OK"); delay(10000); swt++; // Alternate displaying betwen DS18 and DHT sensors if ((swt % 15) > 5 ) { //////////////DS18B20 Sensors///////////////// lcd.setCursor(0, 0); lcd.print("Sdb "); lcd.print(tbathroom); lcd.print(" C"); lcd.setCursor(0, 1); lcd.print(" "); } } /////////// Blink a Led to check if the code run correctly /////////// void runingled() { digitalWrite(7, HIGH); delay(80); digitalWrite(7, LOW); delay(1000); }Я ек понял, вопроса. Разве в 67 строке у Вас не выводится температура?
Иил Вы про сообщение в строке 57? Оно что, всё время слово "sensors" шлёт?
Так вставьте перед ней (строкой 57) запись Вашей температуры в buffer1. Как-то примерно так:
Да, я про 57 строку, отправляло всё время слово "sensors".
Супер, помогло. Спасибо огромное за помощь!
Всем доброго дня!
Вот ещё какой вопрос появился. Код доработал, передавая данные от 4 датчиков по событиям. Всё работает. Но, как только подключаю в коде вывод данных на lcd монитор (сейчас он в коде закомментирован), то при сработке события происходит перезагрузка и сообщения не приходят. Без монитора всё ок. Помогите понять логику.
#include "SIM900.h" #include <SoftwareSerial.h> #include "sms.h" #include <Wire.h> #include <DallasTemperature.h> //#include <LiquidCrystal_I2C.h> #include "DHT.h" #include <OneWire.h> DHT sensor; SMSGSM sms; String smsText = "Motion detected"; String smsText1 = "GAZ - ALARM!"; String smsText2 = "Podval - Low temp!"; String smsText3 = "Room - Low temp!"; boolean started=false; char sms_text[160]; char sms_text1[160]; char sms_text2[160]; char sms_text3[160]; char* smsNumbers[] = {"+7912ХХХХХХХ", "+7908ХХХХХХХ"}; // номера на которые необходимо отсылать аварийные сообщения int ledPin = 13; int pirPin = 7; int val = 0; int komnata; #define analogInPin A0 // Датчик Газа к А0 #define ONE_WIRE_BUS 4 // DS18S20 подключаем к 4 пину DeviceAddress podval = { 0x28, 0xFF, 0x32, 0x3D, 0x90, 0x15, 0x04, 0xC0 }; // Датчик в подвале //LiquidCrystal_I2C lcd(0x27,20,4); // Liquide crystal is a 4x20 LCD with I2C support OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); void setup() { Wire.begin(); pinMode (ledPin,OUTPUT); pinMode (pirPin, INPUT); pinMode(analogInPin, INPUT); //определить выходной контакт для датчика газа sensors.begin(); sensors.setResolution(podval, 10); Serial.begin(9600); if (gsm.begin(9600)) { Serial.println("\nstatus=READY"); started=true; } else Serial.println("\nstatus=IDLE"); //lcd.init(); // initialize the lcd //lcd.backlight(); // Backlight ON //lcd.setCursor(0, 0); //lcd.print("Home"); //lcd.setCursor(0, 1); //lcd.print("Loading..."); } void loop () { val = digitalRead(pirPin); digitalWrite(ledPin,val); if (val == 1) { smsText = smsText; smsText.toCharArray(sms_text,160); sms.SendSMS(smsNumbers,sms_text); String smsText = "Motion detected"; delay(6000); } int sensorValue = analogRead(analogInPin); if (sensorValue >= 400) { smsText1 = smsText1; smsText1.toCharArray(sms_text1,160); sms.SendSMS(smsNumbers,sms_text1); String smsText1 = "GAZ - ALARM!"; delay(6000); } sensors.requestTemperatures(); float tpodval = sensors.getTempC(podval); // Датчик температуры в подвале if (tpodval > 27) { smsText2 = smsText2; smsText2.toCharArray(sms_text2,160); sms.SendSMS(smsNumbers,sms_text2); String smsText2 = "Podval - Low temp!"; delay(6000); } komnata = sensor.read(5); // нужно указать № вывода для DHT (сейчас 5pin) if (sensor.tem > 27) { smsText3 = smsText3; smsText3.toCharArray(sms_text3,160); sms.SendSMS(smsNumbers,sms_text3); String smsText3 = "Room - Low temp!"; delay(6000); } //lcd.setCursor(0, 0); //lcd.print("T1 "); //lcd.print(tpodval); //lcd.setCursor(7, 0); //lcd.print("G "); //lcd.print(sensorValue); //lcd.setCursor(0, 1); //lcd.print((String)"T2 "+sensor.hum+"% "+sensor.tem+"C"); }А что там говорит про память после компиляции (ну. если раскомментировать использование экрана)?
С закомментированным экраном - Скетч использует 16 372 байт (50%) памяти устройства. Всего доступно 32 256 байт. Глобальные переменные используют 1 746 байт (85%) динамической памяти, оставляя 302 байт для локальных переменных. Максимум: 2 048 байт. Недостаточно памяти, программа может работать нестабильно.
После добавления экрана значения меняются на 63% и 88% соответствено. Но первый вариант работает, даже с учётом такого.
В этом всё дело? как можно оптимизировать использование памяти?
Ой, с памятью у Вас полный кошмар. Вот только первое, что бросается в глаза при беглом взгляде.
Учёл Ваши замечания, убрал задвоения, уменьшил память до
Выложите текущий скетч, я завтра посмотрю.
#include "SIM900.h" #include <SoftwareSerial.h> #include "sms.h" #include <Wire.h> #include <DallasTemperature.h> #include <LiquidCrystal_I2C.h> #include "DHT.h" #include <OneWire.h> DHT sensor; SMSGSM sms; boolean started=false; char smsNumber[] = "+7912ХХХХХХХ"; // номер на который необходимо отсылать аварийные сообщения int ledPin = 13; int pirPin = 7; int val = 0; int komnata; #define analogInPin A0 // Датчик Газа к А0 #define ONE_WIRE_BUS 4 // DS18S20 подключаем к 4 пину DeviceAddress podval = { 0x28, 0xFF, 0x32, 0x3D, 0x90, 0x15, 0x04, 0xC0 }; // Датчик в подвале LiquidCrystal_I2C lcd(0x27,20,4); // Liquide crystal is a 4x20 LCD with I2C support OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); void setup() { Wire.begin(); pinMode (ledPin,OUTPUT); pinMode (pirPin, INPUT); pinMode(analogInPin, INPUT); //определить выходной контакт для датчика газа sensors.begin(); sensors.setResolution(podval, 10); Serial.begin(9600); if (gsm.begin(9600)) { Serial.println("\nstatus=READY"); started=true; } else Serial.println("\nstatus=IDLE"); lcd.init(); // initialize the lcd lcd.backlight(); // Backlight ON lcd.setCursor(0, 0); lcd.print("Home"); lcd.setCursor(0, 1); lcd.print("Loading..."); } void loop () { val = digitalRead(pirPin); digitalWrite(ledPin,val); if (val == 1) { char sms_text[160]; String smsText = "Motion detected"; smsText = smsText; smsText.toCharArray(sms_text,160); sms.SendSMS(smsNumber,sms_text); delay(6000); } int sensorValue = analogRead(analogInPin); if (sensorValue >= 400) { char sms_text1[160]; String smsText1 = "GAZ - ALARM!"; smsText1 = smsText1; smsText1.toCharArray(sms_text1,160); sms.SendSMS(smsNumber,sms_text1); delay(6000); } sensors.requestTemperatures(); float tpodval = sensors.getTempC(podval); // Датчик температуры в подвале if (tpodval > 27) { char sms_text2[160]; String smsText2 = "Podval - Low temp!"; smsText2 = smsText2; smsText2.toCharArray(sms_text2,160); sms.SendSMS(smsNumber,sms_text2); delay(6000); } komnata = sensor.read(5); // нужно указать № вывода для DHT (сейчас 5pin) if (sensor.tem > 27) { char sms_text3[160]; String smsText3 = "Room - Low temp!"; smsText3 = smsText3; smsText3.toCharArray(sms_text3,160); sms.SendSMS(smsNumber,sms_text3); delay(6000); } lcd.setCursor(0, 0); lcd.print("T1 "); lcd.print(tpodval); lcd.setCursor(7, 0); lcd.print(" G "); lcd.print(sensorValue); lcd.setCursor(0, 1); lcd.print((String)"T2 "+sensor.hum+"% "+sensor.tem+"C"); delay(1000); }#include "SIM900.h" #include <SoftwareSerial.h> #include "sms.h" #include <Wire.h> #include <DallasTemperature.h> #include <LiquidCrystal_I2C.h> #include <OneWire.h> SMSGSM sms; boolean started=false; char smsNumber[] = "+7912ХХХХХХХ"; // номер на который необходимо отсылать аварийные сообщения int ledPin = 13; // Диод int pirPin = 7; // Подключаем датчик движения к 7 пину int val = 0; // Обнуляем датчик движения #define analogInPin A0 // Датчик Газа к А0 #define ONE_WIRE_BUS 4 // DS18S20 подключаем к 4 пину DeviceAddress kotel = { 0x28, 0xFF, 0x32, 0x3D, 0x90, 0x15, 0x04, 0xC0 }; // Датчик котла LiquidCrystal_I2C lcd(0x27,20,4); // Подключаем монитор OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); void setup() { Wire.begin(); pinMode (ledPin,OUTPUT); pinMode (pirPin, INPUT); pinMode(analogInPin, INPUT); //определить выходной контакт для датчика газа sensors.begin(); sensors.setResolution(kotel, 10); Serial.begin(9600); gsm.begin(9600); lcd.init(); // Включаем lcd lcd.backlight(); // Backlight ON lcd.setCursor(0, 0); lcd.print("Home"); lcd.setCursor(0, 1); lcd.print("Loading..."); } void loop () { val = digitalRead(pirPin); digitalWrite(ledPin,val); int sensorValue = analogRead(analogInPin); sensors.requestTemperatures(); float tkotel = sensors.getTempC(kotel); // Датчик температуры в подвале if (val == 1) { char sms_text[160]; String smsText = "Motion detected"; smsText = smsText; smsText.toCharArray(sms_text,160); sms.SendSMS(smsNumber,sms_text); delay(6000); } else if (sensorValue >= 400) { char sms_text1[160]; String smsText1 = "GAZ - ALARM!"; smsText1 = smsText1; smsText1.toCharArray(sms_text1,160); sms.SendSMS(smsNumber,sms_text1); delay(6000); } else if (tkotel > 27) { char sms_text2[160]; String smsText2 = "Kotel - Low temp!"; smsText2 = smsText2; smsText2.toCharArray(sms_text2,160); sms.SendSMS(smsNumber,sms_text2); delay(6000); } else { lcd.setCursor(0, 0); lcd.print("Temp Kotel: "); lcd.print(tkotel); lcd.setCursor(0, 1); lcd.print("Gaz level: "); lcd.print(sensorValue); delay(1000); } }Евгений, благодарю Вас ещё раз за помощь!
Изменил немного логику работы программы, теперь всё работает в целом как нужно.
Код рабочий, если кому будет нужен.
Остался один момент - это delay - позже сам разберусь как его корректно на millis заменить, чтобы экран не замирал на время отправки СМС и чтобы СМС не сыпались при этом каждую секунду.
Да чего там разбираться :
1. В начале скетча заведите некую переменную, например, unsigned long lastSendSMSmillis;
Также можно обозначить значение (в миллисекундах) минимального промежутка времени между отправками SMS, например #define SMSInterlapse 60000 // пусть будет минута
2. Перед каждым вызовом sms.SendSMS() вставьте строку lastSendSMSmillis = millis();
3. К каждому if, управляющему вызовом sms.SendSMS(), добавьте ещё одно условие && (millis() - lastSendSMSmillis > SMSInterlapse)
4. Все строки delay(6000); смело вычищайте.
UPD: Можно усложнить, сделав разную частоту отправок для разных событий.
Простите, я вчера замотался и не посмотрел, а сегодня только включил, чтобы посмотреть, а тут Вы уже сами разобрались. Ну, так оно и лучше.
Про delay, там несложно.
Да чего там разбираться
UPD: Можно усложнить, сделав разную частоту отправок для разных событий.
Спасибо огромное за подсказку! Теперь всё хорошо. Отличный форум и люди отзывчивые)
Под разбирательством я подразумеваю понимание логики работы, т.к. привык понимать что и зачем я делаю, а функция для меня новая, в общем как и весь язык С++ пока, но вникаю вроде постепенно.
частота отправок вроде бы не требуется разная, но подумаю.
Евгений, согласен, так действительно лучше, но Вы правда сильно помогли мне
а, никто не отправлял длинные значения в смс???
точнее все в одну строку - некрасиво выходит, а как делать в отправляемой смс перенс строки:
TEMP1: +38 TEMP2: +40 TEMP3: +10
или
TEMP1: +38С
TEMP2: +40С
TEMP3: +10С
и т.д.. так ведь намного лучше читается, и на экране телефона помещается
А что - \r\n уже отменили?