Hello everybody.
In my project I want to input a value y using a rotary encoder and then print the value of y along with some text onto a lc-display.
Although this challange seems simple enough I ran into some problems that have me stumped. When I use the code without the part that is used to print the text on the display it works just fine and increasing and decreasing y is no problem. As soon as I try to print the text onto the display increasing the value of y becomes impossible. I have tried putting the part that is used to print the text into a seperate function, but it didnt change anything.
The board I am using is a Elegoo Mega2560 r3 wich is simmular to the Arduino Mega 2560 rev3.
The rotary encoder I am using is the KY-040 rotary encoder module by az - delivery.
For communication with the LCD I am using the LiquidCrystal_I2C library.
Although I would consider myself decent at coding I am by no means an expert and I have little expierience with both rotary encoders and LCDs.
Here is the code I have made:
#include <Wire.h> //include library "Wire.h
#include <LiquidCrystal_I2C.h> //include library "LiquidCrystal_I2C"
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 20 chars and 4 line display
int DT = 6; //Digital pin 6 is connected to the DT pin of the encoder module
int CLK = 5; //Digital pin 5 is connected to the CLK pin of the encoder module
int SW = 7; //This pin is used for the pushbutton on the encoder module and will not be used
int y = 0; //input value
int Letzte_y = LOW; //varaible for storing the value of q
int q = LOW; //variable for storing the state of CLK
int Taster = LOW; //Variable for storing the value of SW. This will not be used
int Letzte_Taster = LOW; // -||-
void setup() {
Serial.begin (9600);
//Setup of the pins that are connected to the encoder module
pinMode (CLK, INPUT_PULLUP);
pinMode (DT, INPUT_PULLUP);
pinMode (SW, INPUT_PULLUP);
//Printing the text onto the display the first time.
//this does not interfere with the counting process
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zieltemp.:");
lcd.setCursor(11, 0);
lcd.print(y);
lcd.setCursor(13, 0);
lcd.print("*C");
}
void loop() {
//This next part is used to inv´crese and decrease the value of y.
//Perhaps there is a better way to do this
q = digitalRead(CLK);
Taster = !digitalRead(SW);
if ((Letzte_y == LOW) && (q == HIGH)) {
if (digitalRead(DT) == LOW) {
y++;
} else {
y--;
}
Serial.println(y);
}
Letzte_y = q;
//this next part of the code seems to be the cause of the problems:
lcd.setCursor(0, 0);
lcd.print("Zieltemp.:");
lcd.setCursor(11, 0);
lcd.print(y);
lcd.setCursor(13, 0);
lcd.print("*C");
}
I hope you can help me and I am looking forward to your replies
If you post a schematic, it would help us a lot trying to figure out your problem. It appears to be a hardware problem. The schematic should show all power, grounds, power supplies, interconnections etc, not a frizzy thing. Note lcd printing takes time and nothing else can occur during that process. The serial.print() is interrupt driven.
While I frequently critical of the unwise use of interrupts, the problem here is as gilshultz suggests, the amount of time it takes to execute the display update, especially since you are performing unnecessary updates in any case.
It may therefore be necessary to use interrupts to service the rotary encoder, however a first step would be to swap to the much more efficient "HD44780" library installed along with its documentation from the IDE Library Manager.
Your rotary encoder code is not right - you are only looking for changes to one output - you should not consider the quadrature signals as "clock" and "data"; they are both of equal status.
You need to go and read the forum instructions so that you can go back and modify your original post (not re-post it) - using the "More -> Modify" option below the right hand corner of your post - to mark up your code as such using the "</>" icon in the posting window. Just highlight each section of code (or output if you need to post that) from the IDE and click the icon.
In fact, the IDE itself has a "copy for forum" link to put these markings on a highlighted block for you so you then just paste it here in a posting window. But even before doing that, don't forget to use the "Auto-Format" (Ctrl-T) option first to make it easy to read. If you do not post it as "code" it can often be quite garbled and is generally more difficult to read due to the font.
Also tidy up your blank space. Do use blank lines, but only single blanks between complete functional blocks.
Update:
I swaped out the "LiquidCrystal_I2C" with the "HD44780" library. In addition I prevented the display from performing the unnessesary updates and the code works fine now. Thank you for your help and sorry for the bad formatting of the original Post.
controllernoob:
Update:
I swaped out the "LiquidCrystal_I2C" with the "HD44780" library. In addition I prevented the display from performing the unnessesary updates and the code works fine now. Thank you for your help and sorry for the bad formatting of the original Post.
That should speed things up quite a bit.
One thing that you need to be aware of and may need to fix/work around is the printing of the Temperature value.
In the previous code you had:
An issue you may run into is that when you use print(y) it will print the temperature but the field width (number of digits) can vary.
If the temperature changes from 2 digits to 1 or to 3 digits the width of the field will change which can upset your other text in the display or in the case of the previous code leave "trash" on the screen (an extra "C") if you go to a fewer number of digits like from 3 to 2 or from 2 to 1.
There are several ways to work around it.
Here are two options:
ensure that the temp number field is always 3 digits/characters (use either leading spaces or leading zeros)
print a couple of spaces after the "C" (would have to be done every time you printed the temerature)
BTW, You can use custom characters to create a "degree" symbol or you can even create a custom character that combines the degree and the "C" into a single character.
You can see the data encodings for these in the "LCDCustomChars" sketch that comes with the hd44780 library.
You can see what they look like if you run the sketch.
That is actually why I asked for the "improved" code.
Since the line printing "Zieltemp.:" is already in setup(), it is not necessary at all This was arguably the longest delay. He has not made the mistake of clearing the LCD in loop(), so that is not a problem. Printing the two extra characters after the actual temperature is not a great penalty and if the temperature never goes to 100, a single extra space would suffice.
Note that a character code of 0xB0 (o) or 0xDF (°), depending on the make of the HD44780, will give a plausible "degree" symbol.
I have read your additional replies and made some further ajustements to the code. I dont plan on inputing temperatures that are lower than 20°C or higher than 40°C. I used a custom character to get a "°" Symbol.
This is the latest version of the code:
#include <Wire.h>
#include <hd44780.h> // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip
const int LCD_COLS = 20;
const int LCD_ROWS = 4;
int customcharRow = 0;
uint8_t degreeSymbol[8] = {0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00};
int DT = 6; //Digital pin 6 is connected to the DT pin of the encoder module
int CLK = 5; //Digital pin 5 is connected to the CLK pin of the encoder module
int SW = 7; //This pin is used for the pushbutton on the encoder module and will not be used
int y = 20; //input value
int Letzte_q = LOW; //varaible for storing the value of q
int letzte_y; //Variable for storing the last value of y
int q = LOW; //variable for storing the state of CLK
int Taster = LOW; //Variable for storing the value of SW. This will not be used
int Letzte_Taster = LOW; // -||-
void setup() {
int status;
status = lcd.begin(LCD_COLS, LCD_ROWS);
if (status) // non zero status means it was unsuccesful
{
hd44780::fatalError(status);
}
//Setup of the pins that are connected to the encoder module
pinMode (CLK, INPUT_PULLUP);
pinMode (DT, INPUT_PULLUP);
pinMode (SW, INPUT_PULLUP);
//Printing the text onto the display the first time.
lcd.createChar(1, degreeSymbol);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zieltemp.:");
lcd.setCursor(11, 0);
lcd.print(y);
lcd.setCursor(13, 0);
lcd.print('\1');
lcd.setCursor(14, 0);
lcd.print("C");
}
void loop() {
//This next part is used to inv´crese and decrease the value of y.
//Perhaps there is a better way to do this
q = digitalRead(CLK);
Taster = !digitalRead(SW);
if ((Letzte_q == LOW) && (q == HIGH)) {
if (digitalRead(DT) == LOW) {
y++;
if (y > 40) {
y = 40;
}
} else {
y--;
if (y < 20) {
y = 20;
}
}
}
Letzte_q = q;
//If the value of y has changed, update the display
if (letzte_y != y) {
lcd.setCursor(11, 0);
lcd.print(y);
letzte_y = y;
}
}
Your suggestions were very helpful. After the additional improvements the code is running much smoother now.