#include <SoftwareSerial.h>
SoftwareSerial megaSerial(2,3); //rx,tx
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // select the pins used on the LCD panel
// define some values used by the panel and buttons
int buttonPress = 0;
int adc_key_in = 0;
int buttonPressPrev = 0;
byte megaVal = 0;
byte megaValPrev=0;
int keyInPrev = 0;
unsigned long serialMillis;
unsigned long currentMillis;
unsigned long pressTime;
unsigned long debounceTime = 30;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int menu = 1;
int subMenu = 1;
int subMenuPrev = 0;
int menuPrev = 0;
int read_LCD_buttons()
{
adc_key_in = analogRead(0);
if (adc_key_in != keyInPrev)
{
delay(20);
adc_key_in=analogRead(0);
keyInPrev=adc_key_in;
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this.
}
}
void setup() {
lcd.begin(16, 2); // start the library
Serial.begin(9600);
megaSerial.begin(9600);
}
void loop()
{
if (megaSerial.available())
{
megaVal=megaSerial.read();
}
currentMillis = millis();
buttonPress = read_LCD_buttons(); // read the b
ButtonAction();
if (subMenu != subMenuPrev || menu != menuPrev||megaVal!=megaValPrev)
{
updateLCD();
menuPrev = menu;
subMenuPrev = subMenu;
megaValPrev=megaVal;
}
}
void ButtonAction()
{
if (buttonPress != buttonPressPrev)
{
if (currentMillis - pressTime >= debounceTime)
{
pressTime = currentMillis;
buttonPressPrev = buttonPress;
switch (buttonPress)
{
case btnRIGHT: menu++; subMenu = 1; break;
case btnLEFT: menu--; subMenu = 1; break;
case btnUP: subMenu--; break;
case btnDOWN: subMenu++; break;
case btnSELECT: SelectAction(); break;
case btnNONE: break;
default: break;
}
if (menu > 5)
{
menu = 1;
}
if (menu < 1)
{
menu = 5;
}
}
}
}
void SelectAction()
{
}
void updateLCD()
{
switch (menu)
{
case 0: menu = 5; break;
case 1: MenuOne(); break;
case 2: MenuTwo(); break;
case 3: MenuThree(); break;
case 4: MenuFour(); break;
case 5: MenuFive(); break;
default: menu = 1;
}
}
void MenuOne()
{
if (subMenu < 1)
{
subMenu = 5;
}
if (subMenu > 5)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("co2"); break;
case 2: Show("dayCO2Low"); break;
case 3: Show("dayCO2High"); break;
case 4: Show("nightCO2Low"); break;
case 5: Show("nightCO2High"); break;
default: subMenu = 1;
}
}
void MenuTwo()
{
if (subMenu < 1)
{
subMenu = 7;
}
if (subMenu > 7)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("Temperature"); break;
case 2: Show("dayTempLow"); break;
case 3: Show("dayTempHigh"); break;
case 4: Show("mornTempLow"); break;
case 5: Show("mornTempHigh"); break;
case 6: Show("nightTempLow"); break;
case 7: Show("nightTempHigh"); break;
default: subMenu = 1;
}
}
void MenuThree()
{
if (subMenu < 1)
{
subMenu = 2;
}
if (subMenu > 2)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("RH"); break;
case 2: Show("rhSetpoint"); break;
default: subMenu = 1;
}
}
void MenuFour()
{
if (subMenu < 1)
{
subMenu = 5;
}
if (subMenu > 5)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("photoperiod"); break;
case 2: Show("hoursOn1"); break;
case 3: Show("hoursOff1"); break;
case 4: Show("hoursOn2"); break;
case 5: Show("hoursOff2"); break;
default: subMenu = 1;
}
}
void MenuFive()
{
if (subMenu < 1)
{
subMenu = 6;
}
if (subMenu > 6)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("dayCount"); break;
case 2: Show("uvSecs"); break;
case 3: Show("vegDays"); break;
case 4: Show("mornHours"); break;
case 5: Show("fanMins"); break;
case 6: Show("pumpSecs"); break;
default: subMenu = 1;
}
menuPrev = menu;
subMenuPrev = subMenu;
}
void Show(char *label)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(label);
lcd.setCursor(0, 1);
lcd.print(megaVal);
}
I have a dfrobot 1602 lcd keypad shield plugged into the uno, with wires soldered onto digital pins 2 and 3 for serial connection, and wires soldered onto 5v and ground to power the uno.
the mega has a jumper from pin 50 to pin 3 of the uno
and pin 51 to pin 2 of the uno
I also have 5v to 5v and gnd to gnd mega to uno
the mega is plugged into the computer via usb
the uno turns on and the menu is navigatable but megaVal stays zero.
Your Mega program is sending a number as text with
Serial.print(megaVal);
but your Uno program is only reading a single character with
megaVal=megaSerial.read();
Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.
The simplest option is to change your Mega program a little - to this
Serial.println(megaVal);
and use the second example in my link to receive the data.
However the whole thing would be more robust if you use the technique in my 3rd example.
thank you sir, haven't looked at your link yet, but I will also need to send intergers back and forth, if that is not covered in your examples, could you point me in the right direction for that, sending two bytes rather than one.
this all seems to deal with ascii characters, what if I just want to send and receive a value between 0 and 255 then store that value and use it in the code? What I am wanting to do is have the uno send a number between 0 and 25. then the mega recvs that number and uses that number to decide what info to send the uno. the information sent to the uno will more often than not be a number greater than 255. the uno then stores that number and prints it on the lcd screen.
I have the arduino cookbook and it deals in charecters too. is there a good write up on how to send and receive basic numbers?
I used serial.parseint and it definitely does what I want it to do. It just does it in a blocking sort of way. It's not a big deal right now, but I do want to learn to do it smoother. in order to do it smoother, do I need to convert an interger value to single ascii characters transmit them and then convert them back to an integer value?
#include <SoftwareSerial.h>
SoftwareSerial megaSerial(2,3); //rx,tx
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // select the pins used on the LCD panel
// define some values used by the panel and buttons
int buttonPress = 0;
int adc_key_in = 0;
int buttonPressPrev = 0;
byte megaVal = 0;
byte megaValPrev=0;
int keyInPrev = 0;
unsigned long serialMillis;
unsigned long currentMillis;
unsigned long pressTime;
unsigned long debounceTime = 30;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int menu = 1;
int subMenu = 1;
int subMenuPrev = 0;
int menuPrev = 0;
int read_LCD_buttons()
{
adc_key_in = analogRead(0);
if (adc_key_in != keyInPrev)
{
delay(20);
adc_key_in=analogRead(0);
keyInPrev=adc_key_in;
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this.
}
}
void setup() {
lcd.begin(16, 2); // start the library
Serial.begin(9600);
megaSerial.begin(9600);
}
void loop()
{
if (megaSerial.available())
{
megaVal=megaSerial.parseInt();
}
currentMillis = millis();
buttonPress = read_LCD_buttons(); // read the b
ButtonAction();
if (subMenu != subMenuPrev || menu != menuPrev||megaVal!=megaValPrev)
{
updateLCD();
menuPrev = menu;
subMenuPrev = subMenu;
megaValPrev=megaVal;
}
}
void ButtonAction()
{
if (buttonPress != buttonPressPrev)
{
if (currentMillis - pressTime >= debounceTime)
{
pressTime = currentMillis;
buttonPressPrev = buttonPress;
switch (buttonPress)
{
case btnRIGHT: menu++; subMenu = 1; break;
case btnLEFT: menu--; subMenu = 1; break;
case btnUP: subMenu--; break;
case btnDOWN: subMenu++; break;
case btnSELECT: SelectAction(); break;
case btnNONE: break;
default: break;
}
if (menu > 5)
{
menu = 1;
}
if (menu < 1)
{
menu = 5;
}
}
}
}
void SelectAction()
{
}
void updateLCD()
{
switch (menu)
{
case 0: menu = 5; break;
case 1: MenuOne(); break;
case 2: MenuTwo(); break;
case 3: MenuThree(); break;
case 4: MenuFour(); break;
case 5: MenuFive(); break;
default: menu = 1;
}
}
void MenuOne()
{
if (subMenu < 1)
{
subMenu = 5;
}
if (subMenu > 5)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("co2"); break;
case 2: Show("dayCO2Low"); break;
case 3: Show("dayCO2High"); break;
case 4: Show("nightCO2Low"); break;
case 5: Show("nightCO2High"); break;
default: subMenu = 1;
}
}
void MenuTwo()
{
if (subMenu < 1)
{
subMenu = 7;
}
if (subMenu > 7)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("Temperature"); break;
case 2: Show("dayTempLow"); break;
case 3: Show("dayTempHigh"); break;
case 4: Show("mornTempLow"); break;
case 5: Show("mornTempHigh"); break;
case 6: Show("nightTempLow"); break;
case 7: Show("nightTempHigh"); break;
default: subMenu = 1;
}
}
void MenuThree()
{
if (subMenu < 1)
{
subMenu = 2;
}
if (subMenu > 2)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("RH"); break;
case 2: Show("rhSetpoint"); break;
default: subMenu = 1;
}
}
void MenuFour()
{
if (subMenu < 1)
{
subMenu = 5;
}
if (subMenu > 5)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("photoperiod"); break;
case 2: Show("hoursOn1"); break;
case 3: Show("hoursOff1"); break;
case 4: Show("hoursOn2"); break;
case 5: Show("hoursOff2"); break;
default: subMenu = 1;
}
}
void MenuFive()
{
if (subMenu < 1)
{
subMenu = 6;
}
if (subMenu > 6)
{
subMenu = 1;
}
switch (subMenu)
{
case 1: Show("dayCount"); break;
case 2: Show("uvSecs"); break;
case 3: Show("vegDays"); break;
case 4: Show("mornHours"); break;
case 5: Show("fanMins"); break;
case 6: Show("pumpSecs"); break;
default: subMenu = 1;
}
menuPrev = menu;
subMenuPrev = subMenu;
}
void Show(char *label)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(label);
lcd.setCursor(0, 1);
lcd.print(megaVal);
}
that's what I have now
void loop()
{
if (megaSerial.available())
{
megaVal=megaSerial.parseInt();
}
there is a close up of what I changed.
the buttons are not as responsive as I'd like. sometimes it takes a bit for the menu to change. like it only reads button pushes intermittently. do I need to send a terminating character?
roosterqmoney:
the buttons are not as responsive as I'd like. sometimes it takes a bit for the menu to change. like it only reads button pushes intermittently.
Then don't use parseInt but use the principles described in Robin2's Serial Input Basics thread.
Sending a line ending will speed up the parseInt if data is being received; it will not speed it up if there is no data.
And please explain why you use Software Serial on a Mega that has 4 hardware serial ports?
Reply#1 by Robin2 and Reply#13 by Robin2 already anticipated your objections and answered your questions. Read the linked article. Study it if necessary. It will help.
i used software serial because i had never used it before, is there a reason why i should use the hardware serial if available?
int value;
void loop()
{
if (Serial.available())
{
char ch=Serial.read();
if isDigit(ch))
{
value=(value*10)+(ch-0);
}
else if (ch==10)
{
blinkRate=value;
serial.println(blinkRate);
value=0;
}
}
blink();
)
So I found this in arduino cookbook, and I think I understand it.
the way I understand it is that Serial.print(1024) sends a 1 then a 0 then a 2 then a 4 all as ascii charecters.
that bit of code reads each character separately and turns it into the number 1024 with the line
value=value*10+ch-0
I understand the ch-0 as the book gives a good explanation. Is it a zero or the letter o? pretty sure its a zero but can't hurt to ask.
I don't fully understand else if (ch==10).
I believe that is what you send it to tell it this is the end of the data. so I would send the character with an ascii value of 58 at the end of each send.
problem is the book never really tells you how to send data to this sketch.
I believe that using Serial.println(1024) automatically adds the 58 on the end.
if I have it wrong, what line of code will send data to that sketch that will cause blinkrate to be equal to 1024 and not block. also how does doing it that way and using parseInt make the code behave differently.
HardwareSerial performs much much better than SoftwareSerial. ALWAYS use HardwareSerial if you have the option.
the way I understand it is that Serial.print(1024) sends a 1 then a 0 then a 2 then a 4 all as ascii charecters.
Yes.
You should also send a linefeed character with Serial.println(); at the end of your message so the receiving Arduino knows that it is the end of the message.
that bit of code reads each character separately and turns it into the number 1024 with the line
value=value*10+ch-0
Why not just use the atoi() function like in my example? atoi is short for ascii-to-integer
"Why not just use the atoi() function like in my example? atoi is short for ascii-to-integer "
I don't know. This is all super new to me.
how does hardware serial work much much better? Is it faster? Is it possible to have errors using software?
"Why not just use the atoi() function like in my example? atoi is short for ascii-to-integer "
when reading up on atoi() it started talking about strings and arrays and it did not fully make sense. the example from arduino cookbook makes sense to me.
can you give me an example how I would send the value 1024 to an arduino that uses the code from the cookbook. that is the piece I am missing to fully understand that method of serial communication.
I don't fully understand this statement
"You should also send a linefeed character with Serial.println(); at the end of your message so the receiving Arduino knows that it is the end of the message."
what is a linefeed character? should it be sent as a separate Serial.print()? An example line of code would help.