PDA

Просмотр полной версии : подскажите по ардуинке



tuner68
25.02.2017, 23:47
Доброго всем времени суток! Прошу подсказки в программировании ардуино. Тех задача - менять угол поворота серво в зависимости от температуры ( автоподсос на карбюратор). Почему серво поворачивается 5 шагов, возвращается назад и так по кругу. Если можно, сильно тапками не кидать - это мой первый опыт программирования. Скетч:
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <Servo.h>


Servo myservo;


int dspin = 10;
int val;
OneWire ds(10); // Подключаем датчик к 10 цифровому пину


LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Подключаем LCD




void setup(void)
{
myservo.attach(9);
lcd.begin(16, 2); //16 знаков, 2 строки
lcd.print("Temp:"); //Печатаем верхнюю строку LCD
lcd.setCursor(9, 0);

}


void loop(void)
{
byte i;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;

// Ищем алрес датчика
if ( !ds.search(addr))
{


ds.reset_search();
delay(250);
return;
}


// Проверяем не было ли помех при передаче
if (OneWire::crc8(addr, 7) != addr[7])
{

return;
}


// Определяем серию датчика
switch (addr[0])
{
case 0x10:

type_s = 1;
break;
case 0x28:
;
type_s = 0;
break;
case 0x22:

type_s = 0;
break;
default:

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;





lcd.setCursor(0, 1); //Пишем в LCD на 2 строке
lcd.print("C:");
lcd.setCursor(2, 1);
lcd.print(celsius); //Цельсии
lcd.setCursor(8, 1);


val = (float)raw / 16.0;
if (val == 25);
{
myservo.write(5);
delay(500);
}
if (val == 30);
delay(500);
{
myservo.write(10);
delay(500);
}
if (val == 35);
{
myservo.write(15);
delay(500);
}
if (val == 40);
{
myservo.write(20);
delay(500);
}
if (val == 45);
{
myservo.write(25);
delay(500);
}
if (val == 50);
{
myservo.write(30);
delay(500);
}



}

errno
26.02.2017, 00:31
!!! Почав редагувати код і побачив ";" після if (val == 25) - це взагалі робить умову беззмістовною. Див. код нижче.

Я не зовсім зрозумів симптоми, але в вашому коді є промлема з порівнянням 'val'. Змінна 'val' містить температуру як число з плаваючою комою (float). A значить там може бути 23.5, або 56.8 і тд. Тобто імовірність спрацювання умови val == 30 "прямує до нуля" :) Для того щоб порівнюувати діапазони треба зробити якось так:
val = (float)raw / 16.0;
if (val <= 25){
myservo.write(5);
delay(500);
}
if (val <= 30) {
myservo.write(10);
delay(500);
}
if (val <= 35) {
myservo.write(15);
delay(500);
}
if (val <= 40) {
myservo.write(20);
delay(500);
}
if (val <= 45) {
myservo.write(25);
delay(500);
}
if (val <= 50)
{
myservo.write(30);
delay(500);
}

Але перетворення у вас "лінійне", і не зрозуміло навіщо ступінчате, газ же можна регулювати плавно правда? Тому пробуємо так:
float throttle; // винесіть нагору до решти оголошень
throttle = val - 20;
if (throttle < 5) throttle = 5; // обмеження "знизу"
if (throttle > 30 ) throttle = 30; // обмеження "зверху"
myservo.write(throttle);
delay(500);

Якось так.

tuner68
26.02.2017, 12:35
Дякую велике! Спробую так. Буду вчитись далi, може зрозумiю, як його програмувати:drag:

tuner68
27.02.2017, 18:37
Попробовал оба варианта - плавный поворот заработал, а со ступенчатым никаких изменений и на температуру никакой реакции, где проблема, так и не понял.