Keresés

Új hozzászólás Aktív témák

  • schawo

    titán

    válasz tvamos #41 üzenetére

    PWM jelentése impulzusszélesség moduláció, önmagában bármilyen kapcsolófrekvenciát jelenthet. Az én értelmezésemben legalábbis.

    metro.h
    Ha jól emlékszem a hőmérővel a soros kommunikációhoz van rá szükség.

  • schawo

    titán

    válasz tvamos #38 üzenetére

    Itt egy kód. Nem a végleges, mert azt most valamiért nem találom (asszem notin fejeztem be, az meg most nincs velem), de a lényeg megvan itt is.

    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <LiquidCrystal.h>
    #include <Metro.h>
    #include <PID_v1.h>
    #include <PID_AutoTune_v0.h>


    #define ONE_WIRE_BUS_PIN 0

    #define TIME_INTERVAL 100
    #define INITIAL_INTERVAL 800
    #define REPEAT_INTERVAL 100

    Metro keyboardTimer(100); // keyboard timer intervals
    Metro cookingTimer(1000); // confirm timer
    Metro powerTimer(100);

    OneWire oneWire(ONE_WIRE_BUS_PIN);
    DallasTemperature sensors(&oneWire);

    DeviceAddress Probe01 = { 0x28, 0x2C, 0xBA, 0xE6, 0x03, 0x00, 0x00, 0x83 };
    DeviceAddress Probe02 = { 0x28, 0xEA, 0xD8, 0xE6, 0x03, 0x00, 0x00, 0x3C };
    DeviceAddress Probe03 = { 0x28, 0xE6, 0xD7, 0xE6, 0x03, 0x00, 0x00, 0x2E };
    DeviceAddress Probe04 = { 0x28, 0xEB, 0xBD, 0xE6, 0x03, 0x00, 0x00, 0xC8 };

    LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // setup LCD

    #define keyboardAnalogInput 0 // keyboard analog pin
    // #define MAX_STRING_LEN = 32;
    // #define MAX_WORDS = 10;
    // lang definitions
    const char* TEXT_WELCOME_L1 = "Sous Viduino";
    const char* TEXT_WELCOME_L2 = "Udvozollek!";
    const char* TEXT_TEMP_LONG = "Homerseklet";
    const char* TEXT_TEMP = "H";
    const char* TEXT_DEG = "C";
    const char* TEXT_TIME_LONG = "Fozesi ido";
    const char* TEXT_TIME = "I";
    const char* TEXT_MINUTE = "perc";
    const char* TEXT_CURRENT_TEMP_L1 = "Pillanatnyi";
    const char* TEXT_CURRENT_TEMP_L2 = "homerseklet";
    const char* TEXT_TIME_REMAINING = "Hatralevo ido";
    const char* TEXT_ARE_YOU_SURE = "Egeszen biztos?";
    const char* TEXT_YES = "IGEN";
    const char* TEXT_NO = "NEM";
    const char* TEXT_BACK = "Vissza";
    const char* TEXT_START_COOKING = "Fozes inditasa";
    const char* TEXT_PREHEATING = "Elomelegites";
    const char* TEXT_COOKING = "Fozes";
    const char* TEXT_TURN_OFF = "Kikapcsolas";
    const char* TEXT_BYE_L1 = "Sous Viduino";
    const char* TEXT_BYE_L2 = "Viszlat!";
    const char* TEXT_ERROR = "Hijnye, baj van.";
    const char* TEXT_SENSOR_FAIL = "Homero hiba.";


    // keyboard button definitions
    #define btnRIGHT 0
    #define btnUP 1
    #define btnDOWN 2
    #define btnLEFT 3
    #define btnENTER 4
    #define confNONE 5

    #define confNO 0
    #define confYES 1

    int keyIn = 0; // keyboard analog value
    int buttonPressed; // keyboard digital value
    int i = 0;
    int prevButton = confNONE; // stores previous digital value
    int counter = 0; // for keyoard repeats
    int Temp = 50;
    int Time = 240;
    int menuItem = 1;
    int menuSize = 3;
    int confValue = confNO;
    int Confirm = 0;
    int Cooking = 0;
    int Error = 0;
    int tempError = 0;
    const char* Status = TEXT_PREHEATING;
    float temp1;
    float temp2;
    float temp3;
    float temp4;
    float tempAvg;
    unsigned int timeRemaining = 0;
    int tempSetting = 0;


    //////////////////////

    byte ATuneModeRemember = 2;
    double input = 40, output = 1000, setpoint = 30;
    double kp = 1000, ki = 0.0, kd = 0.0;

    double kpmodel = 1.5, taup = 100, theta[50];
    double outputStart = 5;
    double aTuneStep = 50, aTuneNoise = 1, aTuneStartValue = 400;
    unsigned int aTuneLookBack = 20;

    boolean tuning = false;
    unsigned long modelTime, serialTime;

    PID myPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
    PID_ATune aTune(&input, &output);

    //set to false to connect to the real world
    boolean useSimulation = false;

    ///////////////////////

    void setup()
    {
    sensors.begin();
    sensors.setResolution(Probe01, 12);
    sensors.setResolution(Probe02, 12);
    sensors.setResolution(Probe03, 12);
    sensors.setResolution(Probe04, 12);

    delay(500);

    lcd.begin(16, 2); // init LCD
    lcd.print(TEXT_WELCOME_L1);
    lcd.setCursor(0, 1);
    lcd.print(TEXT_WELCOME_L2);
    delay(3000);
    lcd.clear();
    lcd.print(TEXT_TEMP_LONG);
    lcd.setCursor(0, 1);
    lcd.print("50 C");

    ////////////////////////
    myPID.SetOutputLimits(0, 1000);
    if(useSimulation) {
    for(byte i = 0; i < 50; i++) {
    theta[i] = outputStart;
    }
    modelTime = 0;
    }
    //Setup the pid
    myPID.SetMode(AUTOMATIC);

    if(tuning) {
    tuning = false;
    changeAutoTune();
    tuning = true;
    }
    //////////////////////
    }


    void loop()
    {
    if (keyboardTimer.check() == 1 && !Error) {
    lcd.setCursor(0, 1);
    buttonPressed = readKeyboard(); // read digital value
    if (buttonPressed == confNONE) counter = 0; // if button released, reset counter
    if (prevButton == buttonPressed) { // if button kept pressed
    ++counter;
    if (counter < (INITIAL_INTERVAL / TIME_INTERVAL) || counter % (REPEAT_INTERVAL / TIME_INTERVAL)) buttonPressed = confNONE; // if repeat timer not active, drop keyboard value
    } else if (buttonPressed == confNONE) prevButton = buttonPressed;
    if (buttonPressed != confNONE) // if new key or repeat active
    {
    switch(buttonPressed) {
    int result;
    case btnUP:
    if(menuItem > 3) break; // draw only for main menu
    menuItem = (menuItem == 1) ? menuSize : menuItem - 1; // move in the main menu
    showMenu(menuItem);
    break;
    case btnDOWN:
    if(menuItem > 3) break; // draw only for main menu
    menuItem = (menuItem == menuSize) ? 1 : menuItem + 1; // move in main menu
    showMenu(menuItem);
    break;
    case btnRIGHT:
    switch(menuItem) {
    case 1:
    showValue(++Temp, TEXT_DEG); // increase temp
    break;
    case 2:
    if(Time < 999) showValue(++Time, TEXT_MINUTE); // increase time
    break;
    case 4:
    showConfirm(confValue = ((confValue == confYES) ? confNO : confYES)); // select reply
    break;
    }
    break;
    case btnLEFT:
    if (menuItem == 1 && Temp > 0) showValue(--Temp, TEXT_DEG); // decrease temp, stay above zero
    if (menuItem == 2 && Time > 0) showValue(--Time, TEXT_MINUTE); // decrease time, stay above zero
    if (menuItem == 4) showConfirm(confValue = ((confValue == confYES) ? confNO : confYES)); // select reply

    break;
    case btnENTER:
    switch(menuItem) {
    case 3: // show confirm menu
    Confirm = 1;
    confValue = confNO;
    showConfirm(confValue);
    menuItem = 4;
    break;
    case 4:
    Confirm = 0;
    if(confValue == confYES) { // start cooking
    Cooking = 1;
    menuItem = 5;
    timeRemaining = Time * 60;
    tempSetting = Temp;
    setpoint = tempSetting;
    lcd.clear();
    }
    else {
    menuItem = 1; // return to main menu
    showMenu(menuItem);
    }
    }
    break;
    }
    prevButton = buttonPressed; // store
    }
    }

    if (cookingTimer.check() == 1 && Cooking && !Error) {
    // showStatus(Status);
    if (Status == TEXT_COOKING) timeRemaining--;
    sensors.requestTemperatures();
    temp1 = sensors.getTempC(Probe01);
    temp2 = sensors.getTempC(Probe02);
    temp3 = sensors.getTempC(Probe03);
    temp4 = sensors.getTempC(Probe04);
    if (temp1 > 0 && temp1 < 110 && temp2 > 0 && temp2 < 110 && temp3 > 0 && temp3 < 110 && temp4 > 0 && temp4 < 110) {
    tempError = 0;
    tempAvg = (temp1 + temp2 + temp3 + temp4) / 4;
    /* lcd.setCursor(0, 1);
    lcd.print(TEXT_TEMP);
    lcd.print(":");
    lcd.print(tempAvg);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(TEXT_TIME);
    lcd.print(":");
    lcd.print(timeRemaining / 60);
    lcd.print(":");
    if (timeRemaining % 60 < 10) lcd.print("0");
    lcd.print(timeRemaining % 60); */

    /////////////////////////
    if(!useSimulation) input = tempAvg;
    if(tuning) {
    byte val = (aTune.Runtime());
    if (val != 0) {
    tuning = false;
    }
    if(!tuning) { //we're done, set the tuning parameters
    kp = aTune.GetKp();
    ki = aTune.GetKi();
    kd = aTune.GetKd();
    myPID.SetTunings(kp, ki, kd);
    AutoTuneHelper(false);
    }
    }
    else myPID.Compute();

    if(useSimulation) {
    theta[30] = output;
    DoModel();
    }
    //// else analogWrite(0,output);
    //send-receive with processing if it's time
    SerialSend();

    //////////////////
    } else {
    if (++tempError > 10) {
    lcd.clear();
    lcd.print(TEXT_ERROR);
    lcd.setCursor(0, 1);
    lcd.print(TEXT_SENSOR_FAIL);
    Error = 1;
    }
    }
    }
    }

    int showStatus(const char* currStatus) {
    lcd.setCursor(0, 0);
    lcd.print(currStatus);
    }

    int readKeyboard()
    {
    keyIn = analogRead(keyboardAnalogInput);
    // read the value from the sensor
    // buttons when read are centered at these values: 0, 144, 329, 504, 741
    // add approx 70 to those values and check to see if we are close
    if (keyIn > 1000) return confNONE;
    if (keyIn < 70) return btnLEFT;
    if (keyIn < 215) return btnUP;
    if (keyIn < 400) return btnDOWN;
    if (keyIn < 575) return btnRIGHT;
    if (keyIn < 810) return btnENTER;
    return confNONE; // when all others fail, return this...
    }

    void showValue(int Value, const char* Unit) {
    lcd.setCursor(0, 1);
    lcd.print(Value);
    lcd.print(" ");
    lcd.print(Unit);
    lcd.print(" "); // to clear
    }

    void showMenu(int Menu) {
    lcd.clear();
    switch(Menu) {
    case 1:
    lcd.print(TEXT_TEMP_LONG); // temp
    showValue(Temp, TEXT_DEG);
    break;
    case 2:
    lcd.print(TEXT_TIME_LONG); // time
    showValue(Time, TEXT_MINUTE);
    break;
    case 3:
    lcd.print(TEXT_START_COOKING);
    break;
    // default:
    // lcd.print(TEXT_ERROR);
    }
    }

    void showConfirm(int Value)
    {
    if (Confirm == 1) {
    lcd.clear(); // reset screen for first use only
    lcd.print(TEXT_ARE_YOU_SURE);
    Confirm++;
    }
    lcd.setCursor(0, 1); // draw selection
    if (Value == confYES) lcd.print("#"); else lcd.print(" ");
    lcd.print(TEXT_YES);
    if (Value == confYES) lcd.print("#"); else lcd.print(" ");
    if (Value == confNO) lcd.print("#"); else lcd.print(" ");;
    lcd.print(TEXT_NO);
    if (Value == confNO) lcd.print("#"); else lcd.print(" ");;
    }

    void printTemperature(DeviceAddress deviceAddress, byte pos)
    {
    float tempC = sensors.getTempC(deviceAddress);
    switch(pos) {
    case 1:
    lcd.setCursor(0, 0);
    break;
    case 2:
    lcd.setCursor(8, 0);
    break;
    case 3:
    lcd.setCursor(0, 1);
    break;
    case 4:
    lcd.setCursor(8, 1);
    break;
    }
    if (tempC == -127.00) lcd.print("Error"); else lcd.print(tempC);
    }


    /////////////////////////////

    void changeAutoTune()
    {
    if(!tuning)
    {
    //Set the output to the desired starting frequency.
    output = aTuneStartValue;
    aTune.SetNoiseBand(aTuneNoise);
    aTune.SetOutputStep(aTuneStep);
    aTune.SetLookbackSec((int)aTuneLookBack);
    AutoTuneHelper(true);
    tuning = true;
    }
    else
    { //cancel autotune
    aTune.Cancel();
    tuning = false;
    AutoTuneHelper(false);
    }
    }

    void AutoTuneHelper(boolean start)
    {
    if(start)
    ATuneModeRemember = myPID.GetMode();
    else
    myPID.SetMode(ATuneModeRemember);
    }


    void SerialSend()
    {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("i"); lcd.print(input); lcd.print(" ");
    lcd.print("o"); lcd.print(output); // lcd.print(" ");
    lcd.setCursor(0, 1);
    // if(tuning){
    // lcd.print("tuning mode");
    // } else {
    lcd.print("p"); lcd.print(myPID.GetKp()); // lcd.print(" ");
    lcd.print("i"); lcd.print(myPID.GetKi()); // lcd.print(" ");
    lcd.print("d"); lcd.print(myPID.GetKd());
    // }
    }

    void DoModel()
    {
    //cycle the dead time
    for(byte i=0;i<49;i++)
    {
    theta[i] = theta[i+1];
    }
    //compute the input
    input = (kpmodel / taup) *(theta[0]-outputStart) + input*(1-1/taup) + ((float)random(-10,10))/100;

    }

  • schawo

    titán

    válasz tvamos #38 üzenetére

    Nyugodtan lehet 2% alá is vinni a teljesítményt, ha a PWM ciklus elég nagy :)

Új hozzászólás Aktív témák