Sketch works great on Uno, but not so well on NodeMCU
Posted: Wed Mar 29, 2017 1:02 pm
So, I have successfully created a sketch, albeit most likely hacked together when compared to someone who actually knows what they're doing, for Arduino. I have this NodeMCU and uploaded the sketch successfully to it, but for some reason the serial monitor is not recognizing my response as expected. Would anyone have any insight into why the serial monitor is not correctly deciphering my Serial.readString entry from the "start1:" position in the void loop() of my sketch?
Code: Select all
/**
Midea AC IR driver
driving a IR LED at 38 KHz
This sketch controls a Midea Heat Pump using Arduino.
*/
#define Duty_Cycle 56 //in percent (10->50), usually 33 or 50
//TIP for true 50% use a value of 56, because of rounding errors
//TIP for true 40% use a value of 48, because of rounding errors
//TIP for true 33% use a value of 40, because of rounding errors
#define Carrier_Frequency 38000 //usually one of 38000, 40000, 36000, 56000, 33000, 30000
#define PERIOD (1000000+Carrier_Frequency/2)/Carrier_Frequency
#define HIGHTIME PERIOD*Duty_Cycle/100
#define LOWTIME PERIOD - HIGHTIME
#define txPinIR 4 //IR carrier output
int mode; //integer for mode value
int fanSpeed; //integer for fan speed value
int temp; //integer for temperature value after conversion from input_3
const int temperaturePin = 0;
String input_1; //string for mode value input by user in void loop
String input_2; //string for fan speed value input by user in void loop
int input_3; //integer for temperature value input by user in void loop
void setup() {
Serial.begin(19200);
pinMode(txPinIR, OUTPUT);
}
void mark(unsigned long mLen) {
if (mLen==0) return;
unsigned long now = micros();
while ((micros() - now) < mLen) {
digitalWrite(txPinIR, HIGH);
delayMicroseconds(HIGHTIME-6);
digitalWrite(txPinIR, LOW);
delayMicroseconds(LOWTIME-7);
}
}
void space(unsigned long sLen) {
if (sLen==0) return;
while (sLen>16383) {
delayMicroseconds(16383);
sLen -= 16383;
}
delayMicroseconds(sLen);
}
/* The following function int emit_midea.start sets the 38 kHz pulse width modulation and sends the frame start markers.*/
void emit_midea_start() {
mark(4200);
space(4500);
}
/*The following function "command_midea_ac) compiles the start markers, the 6 Byte payload, and the end markers into a single task to configure the selected mode, fan speed, and temperature.*/
void command_midea_ac(byte b1, byte b2) {
emit_midea_start(); //runs start function for IR command
emit_midea_byte(178);
emit_midea_byte(b1);
emit_midea_byte(b2);
emit_midea_end(); //runs end function for IR command
/* the IR command is sent twice */
emit_midea_start();
emit_midea_byte(178);
emit_midea_byte(b1);
emit_midea_byte(b2);
emit_midea_end(); //runs end function for IR command
}
/*The following function "command_midea_ac_follow_me" compiles the start markers, the 6 Byte payload, and the end markers into a single task to configure the AC to use the thermistor temperature sensor in the remote for setpoint management.
The Follow Me translation from snooping the voltage signal from the remote to the heat pump is as follows: 10111010(byte1=value of 186)01000101(byte1 inverse)01011010(byte2=value of 90)10100101(byte2 inverse)01010010(byte3=value of 82)10101101(byte3 inverse) */
void command_midea_ac_follow_me() {
emit_midea_start(); //runs start function for IR command
emit_midea_byte(186);
emit_midea_byte(90);
emit_midea_byte(82);
emit_midea_end(); //runs end function for IR command
/* the IR command is sent twice */
emit_midea_start(); //runs start function for IR command
emit_midea_byte(186);
emit_midea_byte(90);
emit_midea_byte(82);
emit_midea_end(); //runs end function for IR command
}
/* The following function int emit_midea_end sends the frame end markers essentially ending the command_midea_ac function. Mark is IR LED on and Space is IR LED off.*/
void emit_midea_end() {
mark(550);
space(4500);
}
/*The following function is used by the command_midea_ac function to selectively broadcast 0s or 1s for each bit in each byte
that is held in the "byte b" variable. It works by first converting the variables to binary, then using a mask at each bit
location in the variable byte to test it for a particular condition. This is done with an if statement. The first thing that
happens is the IR LED is turned on for 450 mlliseconds (i.e. irsend.mark(450)). Then the bits are examined.....for example,
if you have a variable byte of 1001, with a mask byte of 1000, you would typically compare the left most bit in the variable
byte with the left most bit in the mask byte. Since the "&" operator is used in the code below (i.e. cur "&" mask), the two
bits are compared to see if they are both 1 and if so, then according to the code, the first condition of the if statement
is satisfied and the IR LED is turned off for 1700 milliseconds (i.e. irsend.space(1700) representing a 1. After the first
loop through, the 1 in the mask is advanced one space to the right (i.e. the mask is now 0100 instead of 1000) as indicated
by the "mask >>=1" portion of the code and the if statement is ran again. Again, the IR LED is turned on for 450 milliseconds
and then next two bits are compared to each other (i.e. 1"0"01 is compared to 0"1"00). Since they are not both 1, the first
condition of the if statement is not met and the else condition is used which turns off the IR LED for 600 milliseconds
representing a 0. This process continues until the test (i.e. i<8) is satisfied and this particular byte payload is sent.
In this particular communication method, each byte is first sent "as is" and then its compliment is sent. The tilde symbol
"~" is used to change every bit in the variable byte to its opposite (e.g. 1001 becomes 0110) and the same process as
described above is ran again.*/
void emit_midea_byte(byte b) {
int i;
byte cur = b;
byte mask = 0x80;
for (i = 0;i < 8;i++) {
mark(450);
if (cur & mask)
space(1700);
else
space(600);
mask >>= 1;
}
cur = ~b;
mask = 0x80;
for (i = 0;i < 8;i++) {
mark(450);
if (cur & mask)
space(1700);
else
space(600);
mask >>= 1;
}
}
void loop() {
start:
Serial.println("Which AC mode (case sensitive)?"); //prompt user for specific mode they wish the AC to operate in
Serial.println("cool, heat, auto, dry, or off?"); //prompt user for specific mode they wish the AC to operate in
Serial.println(""); //enters a blank line
Serial.println("You may also choose 1 for cool/auto/72, or 2 for cool/auto/84."); //gives the user a quick config option
Serial.println(""); //enters a blank line
start1:
while (Serial.available() == 0) { }; //wait for user input
input_1 = Serial.readString(); //this will fill the string value for "input_1"
if (input_1 == "cool") { //checks to see if the user input matches "cool"
mode = 0; //if "cool" is entered, the mode integer value is set to 0
}
else if (input_1 == "heat") { //checks to see if the user input matches "heat"
mode = 12; //if "heat" is entered, the mode integer value is set to 12
}
else if (input_1 == "auto") { //checks to see if the user input matches "auto"
mode = 8; //if "auto" is entered, the mode integer value is set to 8
fanSpeed = 1; //in "auto" moode, the fan speed can't be selected, this value has to be entered
Serial.println("You can't choose a fan speed for the auto mode."); //instructs user that they can't choose a fan speed for "auto"
Serial.println(""); //enters a blank line
goto start3;
}
else if (input_1 == "dry") { //checks to see if the user input matches "dry"
mode = 4; //if "dry" is entered, the mode integer value is set to 4
fanSpeed = 1; //in "dry" moode, the fan speed can't be selected, this value has to be entered
Serial.println("You can't choose a fan speed for the dry mode."); //instructs user that they can't choose a fan speed for "dry"
Serial.println(""); //enters a blank line
goto start3;
}
else if (input_1 == "off") { //checks to see if the user input matches "off"
command_midea_ac(123, 224); //if "off" is entered, command_midea_ac is ran to turn AC off
Serial.println(""); //enters a blank line
Serial.println("The AC is now off."); //informs the user that the AC is now in the off mode
Serial.println(""); //enters a blank line
goto start; //after the command_midea_ac is ran, this returns the user to the mode prompt located directly after start:
}
else if (input_1 == "1"){
command_midea_ac(191,112);
delay (2000);
command_midea_ac_follow_me();
Serial.println("The AC is set to cool, with fan to auto, and temp is 72.");
Serial.println(""); //enters a blank line
goto start;
}
else if (input_1 == "2"){
command_midea_ac(191,128);
delay (2000);
command_midea_ac_follow_me();
Serial.println("The AC is set to cool, with fan to auto, and temp is 84.");
Serial.println(""); //enters a blank line
goto start;
}
else {
Serial.println("You either misspelled the mode, "); //if neither "cool", "heat", "auto", "dry", or "off" is entered, the user is given this instruction
Serial.println("used the incorrect case, "); //if neither "cool", "heat", "auto", "dry", or "off" is entered, the user is given this instruction
Serial.println("or entered an incorrect value."); //if neither "cool", "heat", "auto", "dry", or "off" is entered, the user is given this instruction
Serial.println(""); //enters a blank line
Serial.println("Try again:"); //prompts user to try again
Serial.println(""); //enters a blank line
goto start1; //this returns the user the the start1: position to try again
}
Serial.println("Which fan speed (case sensitive)?"); //prompt user for a specific fan speed
Serial.println("low, medium, high, or auto?"); //prompt user for a specific fan speed
Serial.println(""); //enters a blank line
start2:
while (Serial.available() == 0) { }; //wait for user input
input_2 = Serial.readString(); //this will fill the string value for "input_2"
if (input_2 == "low") { //checks to see if the user input matches "low"
fanSpeed = 9; //if "low" is entered, the fanSpeed integer value is set to 9
}
else if (input_2 == "medium") { //checks to see if the user input matches "medium"
fanSpeed = 5; //if "medium" is entered, the fanSpeed integer value is set to 5
}
else if (input_2 == "high") { ///checks to see if the user input matches "high"
fanSpeed = 3; //if "high" is entered, the fanSpeed integer value is set to 3
}
else if (input_2 == "auto") { ////checks to see if the user input matches "auto"
fanSpeed = 11; //if "auto" is entered, the fanSpeed integer value is set to 11
}
else {
Serial.println("You either misspelled the fan speed, "); //if neither "low", "medium", "high", or "auto" is entered, the user is given this instruction
Serial.println("used the incorrect case, "); //if neither "low", "medium", "high", or "auto" is entered, the user is given this instruction
Serial.println("or entered an incorrect value."); //if neither "low", "medium", "high", or "auto" is entered, the user is given this instruction
Serial.println(""); //enters a blank line
Serial.println("Try again:"); //prompts user to try again
Serial.println(""); //enters a blank line
goto start2; //this returns the user the the start2: position to try again
}
start3:
Serial.println("Enter an even temp between 62 & 86."); //prompt user for specific temperature value
Serial.println(""); //enters a blank line
while (Serial.available() == 0) { }; //wait for user to input something
input_3 = Serial.parseInt(); //this will fill the integer value for "input_3"
if ((input_3%2!=0)||(input_3<62||(input_3>86))) { //the condition of this if statment first tests to see if the value is even, then if it is in the allowed range
Serial.println("You either entered a temp that's not even "); //prompt user that they entered an odd temp or one that's out of the allowed range
Serial.println("or that's out of range."); //prompt user that they entered an odd temp or one that's out of the allowed range
Serial.println(""); //enters a blank line
Serial.println("Try again:"); //prompts user to try again
goto start3; //this returns the user the the start3: position to try again
}
else {
/*This is a lookup table for converting temperature entry from the "start 3" section directly above into a numerical value which corresponds to the Midea IR protocol. */
switch (input_3){
case 62: {temp=0;}
break;
case 64: {temp=1;}
break;
case 66: {temp=3;}
break;
case 68: {temp=2;}
break;
case 70: {temp=6;}
break;
case 72: {temp=7;}
break;
case 74: {temp=5;}
break;
case 76: {temp=4;}
break;
case 78: {temp=12;}
break;
case 80: {temp=13;}
break;
case 82: {temp=9;}
break;
case 84: {temp=8;}
break;
case 86: {temp=10;}
break;
}
}
Serial.print("You are currently in ");
Serial.print(input_1);
Serial.println(" mode");
Serial.print("with a fan speed set to ");
if (input_2 == "") {
Serial.print("auto");
}
else {
Serial.print(input_2);
}
Serial.println(" and ");
Serial.print("a temperature setpoint of ");
Serial.print(input_3);
Serial.println(".");
Serial.println("");
Serial.println("");
command_midea_ac(fanSpeed << 4 | 15, temp << 4 | mode);
delay (2000);
command_midea_ac_follow_me;
}