Помогите в допиливании кода
- Войдите на сайт для отправки комментариев
Вс, 27/04/2014 - 10:46
Собственно, написал код для считывания с DS18x20 температуры, и вывод на LCD, в комнате все выводится нормально, но стоит температуре понизится, до однозначного числа, как сразу на LCD отображается не один знак после запятой, а 2, как это исправить. Конструктивная критика по коду приветствуется, комментраии в наличии
#include <LiquidCrystal.h> //Библиотека для работы с LCD
#include <OneWire.h> //Библиотека для работы по 1wire
byte letterP[8] =
{
B11111,
B10001,
B10001,
B10001,
B10001,
B10001,
B10001,
B00000,
}; //Добавляем букву "П"
byte letterU[8] =
{
B10001,
B10001,
B10001,
B01110,
B00100,
B01000,
B10000,
B00000,
}; //Добавляем букву "У"
byte letterC[8] =
{
B10001,
B10001,
B10001,
B10001,
B10001,
B11110,
B00001,
B00000,
}; //Добавляем букву "Ц"
byte letterF[8] =
{
B00100,
B01110,
B10101,
B10101,
B10101,
B01110,
B00100,
B00000,
}; //Добавляем букву "Ф"
OneWire ds(8); // Подключаем датчик к 8 цифровому пину
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD
void setup(void)
{
Serial.begin(9600);// Связь с ПК
lcd.createChar(1, letterP);
lcd.createChar(2, letterU);
lcd.createChar(3, letterC);
lcd.createChar(4, letterF);
lcd.begin(16, 2); //16 знаков, 2 строки
lcd.setCursor(2, 0); //Отступ на 2 знака, на 3 пишем
lcd.print("TEM""\1""EPAT""\2""PA:"); //Печатаем верхнюю строку LCD, слово "TEMПЕРАТУРА"
}
void loop(void)
{
byte i;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit; //Создаем паременные под Цельсии и Фаренгейты
// Ищем алрес датчика
if ( !ds.search(addr))
{
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
// Проверяем не было ли помех при передаче
if (OneWire::crc8(addr, 7) != addr[7])
{
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// Определяем серию датчика
switch (addr[0])
{
case 0x10:
Serial.println(" Chip = DS18S20");
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr); // Выбираем адрес
ds.write(0x44, 1); // Производим замер, в режиме паразитного питания
delay(1000);
ds.reset();
ds.select(addr);
ds.write(0xBE); // Считываем оперативную память датчика
for ( i = 0; i < 9; i++)
{
data[i] = ds.read(); // Заполняем массив считанными данными
} // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число
int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту
if (type_s)
{
raw = raw << 3;
}
if (data[7] == 0x10)
{
raw = (raw & 0xFFF0) + 12 - data[6];
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00)
raw = raw << 3;
else if (cfg == 0x20)
raw = raw << 2;
else if (cfg == 0x40) \
raw = raw << 1;
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print("Temp = "); //Пишем в ПК информацию (на всякий случай)
Serial.print(celsius);
Serial.print(" C, ");
Serial.print(fahrenheit);
Serial.println(" F");
lcd.setCursor(0, 1); //Пишем в LCD на 2 строке
lcd.print("\3"":"); //Буква "Ц"
lcd.setCursor(2, 1); //Отступ
lcd.print(celsius, 1); //Цельсии, один знак после запятой
lcd.setCursor(10, 1); //Отступ
lcd.print("\4"":"); //Буква "Ф"
lcd.setCursor(12, 1); //Отступ
lcd.print(fahrenheit, 1); //Фаренгейты, один знак после запятой
}
arssev1, в код не смотрел, скорее всего у вас типовуха - lcd не стирает экран без особой на то команды. Когда у вас меняются данные, они просто перезаписываются в те-же позиции. Используйте lcd.clear(), или если будет рябить, то нужно что-то придумывать, тема в принципе избитая, посмотрите кто как решает. Вот например обсуждали: http://arduino.ru/forum/programmirovanie/problema-s-vyvodom-znacheniya-p...
замени строки 154-161 на
lcd.setCursor(0, 1); //Пишем в LCD в ячейку с координатами x,y (отсчет с 0) lcd.print("\3"":"); //Буква "Ц" lcd.setCursor(2, 1); //Пишем в LCD в 3-ю позицию на 2-й строке lcd.print(" "); //Убираем предыдущие показания (5 пробелов) if (celsius > 0) lcd.print("+"); // чтобы положительные и отрицательные показания смотрелись одинаково lcd.setCursor(2, 1); //Снова пишем в LCD в 3-ю позицию на 2-й строке lcd.print(celsius, 1); //Цельсии, один знак после запятой lcd.setCursor(10, 1); //Пишем в LCD в 11-ю позицию на 2-й строке lcd.print("\4"":"); //Буква "Ф" lcd.setCursor(13, 1); //Пишем в LCD в 14-ю позицию на 2-й строке lcd.print(" "); //Убираем предыдущие показания (5 пробелов) if (fahrenheit > 0) lcd.print("+"); // плюсик для красоты lcd.setCursor(13, 1); //Снова пишем в LCD в 14-ю позицию на 2-й строке lcd.print(fahrenheit, 1); //Фаренгейты, один знак после запятойЗахотел сделать так, чтобы по нажатию кнопки менялось с Цельсиев на Фаренгейты и обратно, но что-то не выходит. При загрузке кода отображается на нижней строке температура в цельсиях, только число
#include <LiquidCrystal.h> //Библиотека для работы с LCD #include <OneWire.h> //Библиотека для работы по 1wire byte letterP[8] = { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B00000, }; //Добавляем букву "П" byte letterU[8] = { B10001, B10001, B10001, B01110, B00100, B01000, B10000, B00000, }; //Добавляем букву "У" byte letterC[8] = { B10001, B10001, B10001, B10001, B10001, B11110, B00001, B00000, }; //Добавляем букву "Ц" byte letterF[8] = { B00100, B01110, B10101, B10101, B10101, B01110, B00100, B00000, }; //Добавляем букву "Ф" OneWire ds(8); // Подключаем датчик к 8 цифровому пину LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD const int buttonPin = 9; float celsius, fahrenheit; //Создаем паременные под Цельсии и Фаренгейты int val = 0; void setup(void) { Serial.begin(9600);// Связь с ПК lcd.createChar(1, letterP); lcd.createChar(2, letterU); lcd.createChar(3, letterC); lcd.createChar(4, letterF); lcd.begin(16, 2); //16 знаков, 2 строки lcd.setCursor(2, 0); //Отступ на 2 знака, на 3 пишем lcd.print("TEM""\1""EPAT""\2""PA:"); //Печатаем верхнюю строку LCD, слово "TEMПЕРАТУРА" } void loop(void) { byte i; byte type_s; byte data[12]; byte addr[8]; // Ищем алрес датчика if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } // Проверяем не было ли помех при передаче if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // Определяем серию датчика switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); // Выбираем адрес ds.write(0x44, 1); // Производим замер, в режиме паразитного питания delay(1000); ds.reset(); ds.select(addr); ds.write(0xBE); // Считываем оперативную память датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); // Заполняем массив считанными данными } // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту if (type_s) { raw = raw << 3; } if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; else if (cfg == 0x20) raw = raw << 2; else if (cfg == 0x40) \ raw = raw << 1; } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print("Temp = "); //Пишем в ПК информацию (на всякий случай) Serial.print(celsius); Serial.print(" C, "); Serial.print(fahrenheit); Serial.println(" F"); if (digitalRead(buttonPin) == HIGH) { val = (val + 1); delay(500); } if(val == 2) { val = 0; } if(val == 0) { displayC(); } if(val == 1) { displayF(); } } void displayF() { lcd.setCursor(0,1); lcd.print(" "); label: lcd.setCursor(0,4); lcd.print("\4"":"); lcd.setCursor(0,6); lcd.print(fahrenheit, 1); delay(100); goto label; } void displayC() { lcd.setCursor(0,1); lcd.print(" "); label: lcd.setCursor(0,4); lcd.print("\3"":"); lcd.setCursor(0,6); lcd.print(celsius, 1); delay(100); goto label; }зачем так сложно?
Тем более goto = флажок чайника :)
#include <LiquidCrystal.h> //Библиотека для работы с LCD #include <OneWire.h> //Библиотека для работы по 1wire #define PIN_ONEWIRE 8 // пин для датчиков температуры #define PIN_BUTTON 9 // пин для кнопки boolean displayCelsius = true; // логическая переменная, если false, то отображаем по Фаренгейту byte letterP[8] = { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B00000, }; //Добавляем букву "П" byte letterU[8] = { B10001, B10001, B10001, B01110, B00100, B01000, B10000, B00000, }; //Добавляем букву "У" byte letterC[8] = { B10001, B10001, B10001, B10001, B10001, B11110, B00001, B00000, }; //Добавляем букву "Ц" byte letterF[8] = { B00100, B01110, B10101, B10101, B10101, B01110, B00100, B00000, }; //Добавляем букву "Ф" byte gradus[8] = { 0xc,0x12,0x12,0xc,0x0,0x0,0x0,0x0 }; //Добавляем символ градуса OneWire ds(PIN_ONEWIRE); // Подключаем датчик к 8 цифровому пину LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD float celsius, fahrenheit; //Создаем паременные под Цельсии и Фаренгейты void setup(void) { Serial.begin(9600);// Связь с ПК lcd.createChar(1, letterP); lcd.createChar(2, letterU); lcd.createChar(3, letterC); lcd.createChar(4, letterF); lcd.createChar(5, gradus); lcd.begin(16, 2); //16 знаков, 2 строки lcd.setCursor(2, 0); //Отступ на 2 знака, на 3 пишем lcd.print("TEM""\1""EPAT""\2""PA:"); //Печатаем верхнюю строку LCD, слово "TEMПЕРАТУРА" } void loop() { readSensor(); checkButton(); displayTemperature(); } void checkButton() { if (digitalRead(PIN_BUTTON) == HIGH) // если нажата кнопка, { displayCelsius = !displayCelsius; // то инвертируем логическую переменную delay(500); // защита от дребезга } } void readSensor() { byte i; byte type_s; byte data[12]; byte addr[8]; // Ищем алрес датчика if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } // Проверяем не было ли помех при передаче if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // Определяем серию датчика switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); // Выбираем адрес ds.write(0x44, 1); // Производим замер, в режиме паразитного питания delay(1000); ds.reset(); ds.select(addr); ds.write(0xBE); // Считываем оперативную память датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); // Заполняем массив считанными данными } // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту if (type_s) { raw = raw << 3; } if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; else if (cfg == 0x20) raw = raw << 2; else if (cfg == 0x40) \ raw = raw << 1; } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print("Temp = "); //Пишем в ПК информацию (на всякий случай) Serial.print(celsius); Serial.print(" C, "); Serial.print(fahrenheit); Serial.println(" F"); } void displayTemperature() { lcd.setCursor(0,0); lcd.print(" "); lcd.setCursor(0,4); // если переменная displayCelsius сейчас true, то выводим по Цельсию if (displayCelsius) {lcd.print("\4"":");} else {lcd.print("\3"":");} lcd.setCursor(0,6); if ((celsius > 0) || (fahrenheit > 0)) lcd.print("+"); lcd.print(displayCelsius?celsius:fahrenheit, 1); // равноценно выражению: // if (displayCelsius == true) lcd.print(celsius, 1); // else lcd.print(fahrenheit, 1); lcd.print("\5"); //значок градуса lcd.print(displayCelsius?"C":"F"); delay(1000); // меньше нет смысла, т.к. датчик выдает показания не чаще раз в 750 мс }Ваш код работает следующим образом:
1.На верхней строке LCD по центру отображается надпись "ТЕМПЕРАТУРА:" (все ок)
2.Надпись стирается, на нижней строке в самом начале появляется значение температуры в Цельсиях (такого не должно по идее быть, то есть перед этим должна появится буква "Ц:"
3.при удержании кнопки отображаются фаренгейты тоже без буквы впереди тоже в начале строки
мне саечку: кроме теории надо тестировать на железе :) У тебя же дисплей 16х2, а я по привычке пишу для своего.
void displayTemperature() { lcd.setCursor(0,2); lcd.print(" "); lcd.setCursor(0,2); // если переменная displayCelsius сейчас true, то выводим по Цельсию if (displayCelsius) {lcd.print("\3"":");} else {lcd.print("\4"":");} lcd.setCursor(2,2); if ((celsius > 0) || (fahrenheit > 0)) lcd.print("+"); lcd.print(displayCelsius?celsius:fahrenheit, 1); // равноценно выражению: // if (displayCelsius == true) lcd.print(celsius, 1); // else lcd.print(fahrenheit, 1); lcd.print("\5"); //значок градуса lcd.print(displayCelsius?"C":"F"); delay(100); }Кстати, в данной реализации кода чтения датчика температуры случайно выявлена фишка: если датчиков температуры подключено несколько, то их показания выводятся последовательно, безо всякого дополнительного кода. :) Надо это применить в своем проекте.
За что выражаю свое спасибо.
Я кажись понял в чем дело - подсчет lcd.setCursor работает немного иначе т.е максимальное значение в скобочках может быть (15,1) т.к. Подсчет с нуля
кроме теории надо тестировать на железе :)
После тестов обработал напильником (мб будет интересно):
#include <LiquidCrystal.h> //Библиотека для работы с LCD #include <OneWire.h> //Библиотека для работы по 1wire #define PIN_ONEWIRE 8 // пин для датчиков температуры #define PIN_BUTTON 9 // пин для кнопки boolean displayCelsius = true; // логическая переменная, если false, то отображаем по Фаренгейту byte letterP[8] = { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B00000, }; //Добавляем букву "П" byte letterU[8] = { B10001, B10001, B10001, B01110, B00100, B01000, B10000, B00000, }; //Добавляем букву "У" byte gradus[8] = { 0xc,0x12,0x12,0xc,0x0,0x0,0x0,0x0 }; //Добавляем символ градуса OneWire ds(PIN_ONEWIRE); // Подключаем датчик к 8 цифровому пину LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD float celsius, fahrenheit; //Создаем паременные под Цельсии и Фаренгейты void setup(void) { Serial.begin(9600);// Связь с ПК lcd.createChar(1, letterP); lcd.createChar(2, letterU); lcd.createChar(3, gradus); lcd.begin(16, 2); //16 знаков, 2 строки lcd.setCursor(2, 0); //Отступ на 2 знака, на 3 пишем lcd.print("TEM""\1""EPAT""\2""PA:"); //Печатаем верхнюю строку LCD, слово "TEMПЕРАТУРА" } void loop() { readSensor(); checkButton(); displayTemperature(); } void checkButton() { if (digitalRead(PIN_BUTTON) == HIGH) // если нажата кнопка, { displayCelsius = !displayCelsius; // то инвертируем логическую переменную delay(100); // защита от дребезга } } void readSensor() { byte i; byte type_s; byte data[12]; byte addr[8]; // Ищем алрес датчика if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } // Проверяем не было ли помех при передаче if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // Определяем серию датчика switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); // Выбираем адрес ds.write(0x44, 1); // Производим замер, в режиме паразитного питания delay(1000); ds.reset(); ds.select(addr); ds.write(0xBE); // Считываем оперативную память датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); // Заполняем массив считанными данными } // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту if (type_s) { raw = raw << 3; } if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; else if (cfg == 0x20) raw = raw << 2; else if (cfg == 0x40) \ raw = raw << 1; } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print("Temp = "); //Пишем в ПК информацию (на всякий случай) Serial.print(celsius); Serial.print(" C, "); Serial.print(fahrenheit); Serial.println(" F"); } void displayTemperature() { lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(4,1); if ((celsius > 0) || (fahrenheit > 0)) lcd.print("+"); lcd.print(displayCelsius?celsius:fahrenheit, 1); // равноценно выражению: // if (displayCelsius == true) lcd.print(celsius, 1); // else lcd.print(fahrenheit, 1); lcd.print("\3"); //значок градуса lcd.print(displayCelsius?"C":"F"); delay(750); }А именно:
1.Вырезал буквы "Ц" и "Ф" ибо нафиг не нужны, т.к. в конце и так C или F
2.Понизил delay при чтении с кнопки
3.Исправил отображение на LCD (при условии того, что у меня 16x2)
4.Понизил delay в displayTemperature
Что обнаружил:
Появился противное мерцание экрана, немножко раздражает, пытался бороться с ним при помощи goto, программа зациклилась и не работала кнопка.
Как сделать так, чтобы 16 пробелов рисовались при смене с фаренгейтов на цельсии и наоборот, а не постоянно?
Строки 163-164 перенести на 70-ю строку.
Спасибо. А как с 2 датчиков читать?
Этот код и так читает со всех датчиков (подключать параллельно существующему), просто показания выводятся поочередно.
Согласно коду есть 2 переменные - 1 считается из показаний датчика (Цельсии), а вторая (Фаренгейты) считается из цельсиев по формуле. Куда будет записыватся температура из второго датчика если и в 1 и во второй переменной хранятся данные первого датчика?
P.S. Можешь дать какие-либо контакты, чтоб форум не засорять, что угодно (Skype, почту и т.д.) Буду признателен
В одну и ту же переменную пишутся. При первом проходе loop читается первый датчик и значения зано ятся в эти переменные. При втором прогоне цикла читается следующий датчик и в эту же переменную записываются его показания. Т.е. одновременно у тебя есть показания только одного из датчиков.
Чтобы использовать датчики одновременно, надо применять библиотеку DallasTemperature, там в примерах много чего есть, в том числе обращение по конкретному номеру или адресу датчика.
Какая жуткая реализация -_-
А как реализовать 2 датчика через DallasTemperature?
Это просто ваш код чтения датчика неклассический :)
Все, финиш, написал финальный код, все работает как надо, читает 2 датчика, кнопка работает, LCD не тупит, не мерцает
#include <LiquidCrystal.h> //Библиотека для работы с LCD #include <OneWire.h> //Библиотека для работы по 1wire #include <DallasTemperature.h> #define ONE_WIRE_BUS 8 #define PIN_BUTTON 9 // пин для кнопки boolean displayCelsius = true; // логическая переменная, если false, то отображаем по Фаренгейту byte gradus[8] = { 0xc,0x12,0x12,0xc,0x0,0x0,0x0,0x0 }; //Добавляем символ градуса OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD float celsius0, fahrenheit0, celsius1, fahrenheit1; //Создаем паременные под Цельсии и Фаренгейты void setup(void) { sensors.begin(); lcd.createChar(1, gradus); lcd.begin(16, 2); //16 знаков, 2 строки lcd.print("Inside Outside"); //Печатаем верхнюю строку LCD, слово "TEMПЕРАТУРА" } void loop() { readSensor(); checkButton(); displayTemperature(); } void checkButton() { if (digitalRead(PIN_BUTTON) == HIGH) // если нажата кнопка, { lcd.setCursor(0,1); lcd.print(" "); displayCelsius = !displayCelsius; // то инвертируем логическую переменную delay(100); // защита от дребезга } } void readSensor() { sensors.requestTemperatures(); celsius0 = sensors.getTempCByIndex(0); celsius1 = sensors.getTempCByIndex(1); fahrenheit0 = celsius0 * 1.8 + 32.0; fahrenheit1 = celsius1 * 1.8 + 32.0; } void displayTemperature() { lcd.setCursor(0,1); lcd.print(displayCelsius?celsius0:fahrenheit0, 1); lcd.print("\1"); //значок градуса lcd.print(displayCelsius?"C":"F"); lcd.setCursor(10,1); lcd.print(displayCelsius?celsius1:fahrenheit1, 1); lcd.print("\1"); //значок градуса lcd.print(displayCelsius?"C":"F"); delay(750); }Кажись не набыдлокодил нигде