Go Down

Topic: Help needed (Read 1 time) previous topic - next topic

LanceRoberts

One more quick thing, if we get to a boiler which is large enough to need a blower delays 4 or less seconds we'll definitely be using more than 8 blowers, so there won't be a situation where blower 1 will still be blowing when the last blower has started.

wildbill

Try this:
Code: [Select]

#include <UTFT.h>
#include <Keypad.h>

// TFT
UTFT myGLCD(CTE32HR, 38, 39, 40, 41);
extern uint8_t BigFont[];
extern uint8_t Grotesk32x64[];

// Keypad
const byte ROWS = 4; // Four rows
const byte COLS = 4; // Four columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// Serial Number, change for each new unit
int serialNum = 0001;

const byte Machine1 = A0; // I/O pin connected by the first relay
const byte Machine2 = A1;
const byte Machine3 = A2;
const byte Machine4 = A3;
const byte Machine5 = A4;
const byte Machine6 = A5;
const byte Machine7 = A6;
const byte Machine8 = A7;

typedef struct
{
byte Pin;
unsigned long StartedTime;
} Blower;

Blower Blowers[]={
                  { Machine1,0 },
                  { Machine2,0 },
                  { Machine3,0 },
                  { Machine4,0 },
                  { Machine5,0 },
                  { Machine6,0 },
                  { Machine7,0 },
                  { Machine8,0 },
                 };
byte BlowerCount=(sizeof Blowers)/(sizeof Blowers[0]);
unsigned long BlowerStartTime;
byte CurrentBlower = 0;
int onTime = 1 ; // seconds on
int offTime = 30 ; // seconds off
unsigned long blows = 0;
unsigned long activeDays = 0;
unsigned long activeHours = 0;
unsigned long powderUsed = 0;
int GetNumber1();
int GetNumber2();
enum DisplayMode { TitleMode,SetOffTimeMode,SetOnTimeMode};
DisplayMode CurrentMode=TitleMode;
int InputNumber;

void setup()
{
for (int i = 0; i < BlowerCount;i++)
  {
  pinMode(Blowers[i].Pin, OUTPUT);
  }

Serial.begin(9600);
keypad.addEventListener(keypadEvent);
keypad.setDebounceTime(100);

// Intro screen
myGLCD.InitLCD();
myGLCD.setFont(Grotesk32x64);
myGLCD.clrScr();
myGLCD.setColor(VGA_BLUE);
myGLCD.print((char*)"CHINCO FIRESIDE", CENTER, 100);
myGLCD.print((char*)"TREATMENT", CENTER, 164);
delay (3000);
myGLCD.clrScr();
Splash();
}

void Splash() {
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"'Press 'A' - Statistics'", 1, 100);
  myGLCD.print((char*)"'Press 'B' - Delay Setup'", 1, 116);
  myGLCD.print((char*)"'Press 'C' - Blow Setup'", 1, 132);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"Serial #", 270, 286);
  myGLCD.printNumI(serialNum, 398, 286);
}

void title() {
  myGLCD.clrScr();
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"Delay Between Blows :", 2, 48); // Delay time
  myGLCD.printNumI(offTime, 337, 48);
  myGLCD.print((char*)"s", 403, 48);
  myGLCD.print((char*)"Duration of Each Blow :", 2, 64); // Blow time
  myGLCD.printNumI(onTime, 368, 64);
  myGLCD.print((char*)"s", 402, 64);
  myGLCD.print((char*)"System Active For :", 2, 80); //Active Days
  myGLCD.printNumI(activeDays, 305, 80);
  myGLCD.print((char*)"Days", 355, 80);
  myGLCD.print((char*)"System Active For :", 2, 96); //Active Hours
  myGLCD.printNumI(activeHours, 305, 96);
  myGLCD.print((char*)"Hours", 355, 96);
  myGLCD.print((char*)"Number of Blows :", 2, 112); //Blows
  myGLCD.printNumI(blows, 274 , 112);
  myGLCD.print((char*)"KGs powder used :", 2, 128); //KGs used
  myGLCD.printNumF(powderUsed, 3, 274, 128);
  myGLCD.setColor(VGA_RED);
  myGLCD.print((char*)"'Press 'A' - Update Stats'", 1, 150);
  myGLCD.print((char*)"'Press 'B' - Delay Setup'", 1, 166);
  myGLCD.print((char*)"'Press 'C' - Blow Setup'", 1, 182);
  myGLCD.setColor(VGA_GRAY);
  myGLCD.print((char*)"Serial #", 270, 286);
  myGLCD.printNumI(serialNum, 398, 286);
}

void offTimeChange() {
  myGLCD.clrScr();
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"CHANGE BLOW DELAY TIME", CENTER, 50);
  myGLCD.print((char*)"ENTER VALUE", CENTER, 66);
  myGLCD.print((char*)"PRESS # TO SAVE", CENTER, 100);
  myGLCD.setColor(VGA_RED);
  myGLCD.print((char*)"'Press 'A' - Statistics'", 1, 146);
  myGLCD.print((char*)"'Press 'C' - Blow Setup'", 1, 162);
  myGLCD.setColor(VGA_GRAY);
  myGLCD.print((char*)"Serial #", 270, 286);
  myGLCD.printNumI(serialNum, 398, 286);
}

void onTimeChange() {
  myGLCD.clrScr();
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"CHANGE LENGTH OF BLOW TIME", CENTER, 50);
  myGLCD.print((char*)"ENTER VALUE", CENTER, 66);
  myGLCD.print((char*)"PRESS # TO SAVE", CENTER, 102);
  myGLCD.print((char*)"PRESS * TO CENCEL", CENTER, 118);
  myGLCD.setColor(VGA_RED);
  myGLCD.print((char*)"'Press 'A' - Statistics'", 1, 146);
  myGLCD.print((char*)"'Press 'B' - Delay Setup'", 1, 162);
  myGLCD.setColor(VGA_GRAY);
  myGLCD.print((char*)"Serial #", 270, 286);
  myGLCD.printNumI(serialNum, 398, 286);
}

void offTimeSaved() {
  myGLCD.clrScr();
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"LENGTH OF DELAY TIME SAVED", CENTER, 50);
  myGLCD.print((char*)"DELAY TIME NOW", CENTER, 66);
  myGLCD.setColor(VGA_RED);
  myGLCD.printNumI(offTime, CENTER, 82);
  delay (3000);
  title();
}

void reset() {
  myGLCD.clrScr();
  myGLCD.setColor(VGA_BLUE);
  myGLCD.drawRect(0, 0, 479, 305);
  myGLCD.setFont(BigFont);
  myGLCD.print((char*)"CHINCO FIRESIDE TREATMENT", CENTER, 2);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"NO CHANGES HAVE BEEN SAVED", CENTER, 50);
  delay (3000);
  Splash();

}

void loop()
{
  ManageBlowers();
  int activeDs = millis() / 864000000UL;
  int activeHrs = millis() / 3600000UL;
  activeDays = activeDs;
  activeHours = activeHrs;
  int powderUse = (blows * 50) / 1000;
  powderUsed = powderUse;
}

void ManageBlowers()
{
if (millis() - BlowerStartTime > offTime * 1000UL)
    {
    StartBlower(CurrentBlower);
    CurrentBlower++;
    if (CurrentBlower >= BlowerCount)
      CurrentBlower=0;
    }
 
for (int i = 0; i < BlowerCount;i++)
  {
  if(millis()-Blowers[i].StartedTime > onTime)
    {
    StopBlower(i);  // Note that this will call StopBlower excessively. No harm done unless you put LCD code in that routine
    }
  }
}

void StopBlower(int BlowerIndex)
{
digitalWrite(Blowers[BlowerIndex].Pin, LOW);
}

void StartBlower(int BlowerIndex)
{
  digitalWrite(Blowers[BlowerIndex].Pin, HIGH);
  blows ++;
  BlowerStartTime=Blowers[BlowerIndex].StartedTime = millis();
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"LAST APPLICATOR TO BLOW", CENTER, 216);
  myGLCD.setColor(VGA_RED);
  myGLCD.printNumI(BlowerIndex + 1, CENTER, 234);
}

void IncreaseNewTime(char key)
{
if (CurrentMode != TitleMode)
  {
  InputNumber=InputNumber*10+key-'0';
  }
}

void SaveNewTime()
{
if(CurrentMode==SetOffTimeMode)
  {
  offTime=InputNumber;
  offTimeSaved();
  }
if(CurrentMode==SetOnTimeMode)
  {
  onTime=InputNumber;
  //onTimeSaved()
  }
}

void keypadEvent (KeypadEvent key)
{
if (keypad.getState()==PRESSED)
  {
  switch(key)
    {
    case 'A':
      CurrentMode=TitleMode;
      title();
      InputNumber=0;
      break;
    case 'B':
      CurrentMode=SetOffTimeMode;
      offTimeChange();
      InputNumber=0;
      break;
    case 'C':
      CurrentMode=SetOnTimeMode;
      onTimeChange();
      InputNumber=0;
      break;
    case '0' ... '9':
      IncreaseNewTime(key); 
      break;
    case '*':
      InputNumber=0;
      break;
    case '#':
      SaveNewTime();
      InputNumber=0;
      break; 
    }
  }
}

Compiled, not tested.

As previously discussed, the intent is that it starts a blower every offtime seconds and stops that blower after ontime seconds.

wildbill

oops. The final comma in this section should not be there:
Code: [Select]

Blower Blowers[]={
                  { Machine1,0 },
                  { Machine2,0 },
                  { Machine3,0 },
                  { Machine4,0 },
                  { Machine5,0 },
                  { Machine6,0 },
                  { Machine7,0 },
                  { Machine8,0 },
                 };

LanceRoberts

#48
Jan 21, 2017, 03:26 pm Last Edit: Jan 21, 2017, 03:38 pm by LanceRoberts
oops. The final comma in this section should not be there:
Code: [Select]

Blower Blowers[]={
                  { Machine1,0 },
                  { Machine2,0 },
                  { Machine3,0 },
                  { Machine4,0 },
                  { Machine5,0 },
                  { Machine6,0 },
                  { Machine7,0 },
                  { Machine8,0 },
                 };

It seems to be working great now!
I had to add the * 1000UL in 'if(millis()-Blowers.StartedTime > onTime * 1000UL)"

One issue I am having is theres a funny symbol instead of "BLOW" when it prints the line,
myGLCD.print((char*)"LAST APPLICATOR TO BLOW", CENTER, 239);
This message also comes up from the start, whereas the original code only showed the line when the first blower activated, this is not an issue as long as I can get rid of the funny symbol.

Also on the line "myGLCD.printNumI(BlowerIndex + 1, CENTER, 255);", it prints a 55 when the unit starts up and then shows the correct number as soon as the first blower activates.

The code is now,
Code: [Select]

void ManageBlowers()
{
if (millis() - BlowerStartTime > offTime * 1000UL)
    {
    StartBlower(CurrentBlower);
    CurrentBlower++;
    if (CurrentBlower >= BlowerCount)
      CurrentBlower=0;
    }
 
for (int i = 0; i < BlowerCount;i++)
  {
  if(millis()-Blowers[i].StartedTime > onTime * 1000UL)
    {
    StopBlower(i);  // Note that this will call StopBlower excessively. No harm done unless you put LCD code in that routine
    }
  }
}

void StopBlower(int BlowerIndex)
{
digitalWrite(Blowers[BlowerIndex].Pin, LOW);

}

void StartBlower(int BlowerIndex)
{
  digitalWrite(Blowers[BlowerIndex].Pin, HIGH);
  blows ++;
  BlowerStartTime=Blowers[BlowerIndex].StartedTime = millis();
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print((char*)"LAST APPLICATOR TO BLOW", CENTER, 239);
  myGLCD.setFont(Grotesk32x64);
  myGLCD.setColor(VGA_RED);
  myGLCD.print((char*)"'", 192, 255);
  myGLCD.print((char*)"'", 256, 255);
  myGLCD.printNumI(BlowerIndex + 1, CENTER, 255);
  myGLCD.setFont(BigFont);
}



wildbill

Hard to speculate without seeing all the code.

Off-topic a little, you may want to think about all those delays you've got in the display sections. They have the potential to throw off the blower sequence.

LanceRoberts

Hard to speculate without seeing all the code.

Off-topic a little, you may want to think about all those delays you've got in the display sections. They have the potential to throw off the blower sequence.
Thanks a lot Bill,

The delays are there for testing, I'll make them a lot shorter, or even take them out before the unit goes to the client.

I copied your code into my original to test and that's the only time the strange symbol and 55 comes up, it doesn't come up in your code. Let me check it out a bit and I'll get back to you.

Thanks again for all your help!!

cedarlakeinstruments

Sorry if I'm confusing everyone, didn't think this was going to become such a complicated application.
That's what experience gets you: the ability to see that something apparently simple will become complex if the complexity isn't managed from the beginning.

I believe that in my PM to you I stated that what you were asking for was not difficult: I stand by that assertion. It's not difficult, but taking the wrong approach will make it so. My initial estimate was about 4-6 hours for what you initially asked for, including testing. Out of curiosity: how much time have you spent on it so far?
Electronics and firmware/software design and assistance. No project too small

LanceRoberts

That's what experience gets you: the ability to see that something apparently simple will become complex if the complexity isn't managed from the beginning.

I believe that in my PM to you I stated that what you were asking for was not difficult: I stand by that assertion. It's not difficult, but taking the wrong approach will make it so. My initial estimate was about 4-6 hours for what you initially asked for, including testing. Out of curiosity: how much time have you spent on it so far?
It took me a lot longer than 4-6 hours but at least I learned a lot about how it works.

LanceRoberts

This should take care of it:
Code: [Select]

    case '#':
      if(InputNumber>0)
        {
        SaveNewTime();
        InputNumber=0;
        }
      break; 

Hi WildBill,
The unit is working great now, sorry for not getting back to you sooner.

In the quoted reply that you gave me regarding disabling the # and * keys... How would I disable all the numeric keys when the unit is not in the change menus? As the code is now it will except numeric keys in any of the menus.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy