Category Archives: Arduino

Hitachi HD44780 LCD Character Display

I finally got round to writing my own ‘Hello World!’ for an LCD connected to an Arduino Nano. So what! I hear you all cry. Well, I wanted to do it without the Arduino LCD library. Why? Well, it’s a challenge isn’t it!

First off, the following PDFs are invaluable in understanding the controller on the majority of the LCD on the market utilising the ubiquitous Hitachi HD44780 controller.

LCD Controller part 1
LCD Controller part 2

Oh, in 4-bit mode only!

#define LCD_ENABLE (0x00 << 2)
#define LCD_CLEAR (0x01 << 2)
#define LCD_HOME (0x02 << 2)
#define LCD_DISP_ON_UNDERLINE_BLINK (0x0f <>2)
#define LCD_8BITMODE (0x30 >>2)
#define LCD_RESET 0x38

#define LCD_RS_COMMAND_MODE 0x00
#define LCD_RS_DATA_MODE 0x01

int RS=A0;
int RW=A1;
int ENABLE=A2;

void setup()
{
delay(100); // power on delay
DDRD=B11111100; // set bits on D2-D7 as outputs
PORTD=0;

pinMode (ENABLE,OUTPUT);
pinMode (RW,OUTPUT);
pinMode (RS,OUTPUT);
digitalWrite (RW,LOW);

}

wire D2 to LCD D4
wire D3 to LCD D5
wire D4 to LCD D6
wire D5 to LCD D7
wire A2 to LCD Enable pin
wire A1 to LCD R/W pin
wire A0 to LCD RS pin

The basic sequence of operation is as follows:
Once the LCD had powered on the init sequence should be:

  • set the read/write line permanently low to write as we won’t be reading from the display – or tie to 0V
  • set command mode (RS pin) (logic 0)
  • set 8 bit mode X 3
  • set the data lines;
  • pulse the enable line (high to low transition and back to low again

#define LCD_ENABLE (0x00 << 2)
#define LCD_CLEAR  (0x01 << 2)
#define LCD_HOME   (0x02 << 2)
#define LCD_DISP_ON_UNDERLINE_BLINK (0x0f <>2)
#define LCD_8BITMODE (0x30 >>2)
#define LCD_RESET 0x38
#define LCD_RS_COMMAND_MODE 0x00
#define LCD_RS_DATA_MODE 0x01
int RS=A0;
int RW=A1;
int ENABLE=A2;
void setup()
{
 delay(100); // power on delay
 DDRD=B11111100; // set bits on D2-D7 as outputs
 PORTD=0;
 pinMode (ENABLE,OUTPUT);
 pinMode (RW,OUTPUT);
 pinMode (RS,OUTPUT);
 digitalWrite (RW,LOW);
}

wire D2 to LCD D4
wire D3 to LCD D5
wire D4 to LCD D6
wire D5 to LCD D7
wire A2 to LCD Enable pin
wire A1 to LCD R/W pin
wire A0 to LCD RS pin
The basic sequence of operation is as follows:
Once the LCD had powered on the init sequence should be:
set the read/write line permanently low to write as we won't be reading from the display - or tie to 0V
set command mode (RS pin) (logic 0)
set 8 bit mode X 3
set the data lines;
pulse the enable line (high to low transition and back to low again

void hd44780_init() // it's recommended that the 8-bit mode be sent 3 times to ensure full initialisation of the LCD controller
{
  for (int poweron=0; poweron<3; poweron++)
   {
    digitalWrite(RS,LCD_RS_COMMAND_MODE); // switch LCD into COMMAND_MODE
    PORTD=LCD_8BITMODE;
    pulse(); 
    }
}
void init_4bitmode()
{
  delay(5);
  digitalWrite(RS,LCD_RS_COMMAND_MODE);
  PORTD=LCD_4BITMODE;
  delay(5);
  pulse();
}
void lcd_clear()
{
  digitalWrite(RS,LCD_RS_COMMAND_MODE);
  PORTD=(0 <<2);
  pulse();
  PORTD=(1 <<2);
  pulse();
  delay(200);
}
void lcd_2linemode()
{
  digitalWrite(RS,LCD_RS_COMMAND_MODE);
  PORTD=(2 <<2);
  pulse();
  PORTD=(8 <<2);
  pulse();
}
void lcd_displayon() // also cursor underline and blink
{
  digitalWrite(RS,LCD_RS_COMMAND_MODE);
  PORTD=(0 <<2);
  pulse();
  PORTD=(0xf <<2);
  pulse();
}
void pulse()
{
  digitalWrite(ENABLE,HIGH);
  delayMicroseconds(40);
  digitalWrite(ENABLE,LOW);
  delayMicroseconds(40);
}
void lcd_print_char(char *nextchar)
{
digitalWrite(RS,LCD_RS_DATA_MODE);
  while (*nextchar !='\0')
   {
    char lower=(*nextchar & 0x0f);
    char upper=(*nextchar >> 4) &0x0f;
    char shiftup=(upper << 2);
    char shiftlow=(lower << 2);
    PORTD=shiftup;
    delay(5);
    pulse();
    PORTD=shiftlow;
    delay(5);
    pulse();
    nextchar++;
   }
}
void loop()
{
hd44780_init();  // post power-on-reset send 8 bit mode three times to ensure reset
init_4bitmode(); // now switch to 4-bit mode
lcd_clear();     // clear the display and set cursor position to home
lcd_2linemode(); // set two line mode for the 2X16 HD44780 DEM controller
lcd_displayon(); // finally, turn the LCD's display on so we can see this!!!!
lcd_print_char("Hello World!");
while (1==1)
 {
 }
}

Arduino RF communications using the nRF24L01+

The nRF24L01+ is a great little device to allow RF data exchange between two or more arduino devices. They are very inexpensive and you can purchase 4 units from ebay for under £5. There isn’t a library for the module within the core ardino libraries and the best library I found is written by a guy called manicbug and you can find information on how to download and install the library on his website . The rest of this post implies you’ve installed the library to your ardunio’s library directory.

I learnt a lot thanks to manicbug’s blog and various other posts which I will note at the end of this post if you want further background reading.

Regrettably, I could not get any of the examples working correctly despite checking and rechecking the connections, configuration. As the code was a little hard to understand ( I hate classes,pointers and anything OOP) I found I could not penetrate the code successfully. This is a limitation on my part and isn’t a slight against the library’s author.

So, I went on a search on the arduino forum and towards the end of the discussion there are mentions of powering up and down the radio device to ensure successful transmission. I then implemented the example provided on shanes.net with the mods provided by mlc and the packet exchange was then flawless. My modified code is shown below – This is the transmitter.

#include <SPI.h>;
#include <nRF24L01.h>;
#include <RF24.h>;
#include <RF24_config.h>;
/*
This sketch sends a string to a corresponding Arduino
with nrf24 attached. It appends a specific value
(2 in this case) to the end to signify the end of the
message.
*/
int success,fail;
char msg[1];
int i=77; // Lowercase 'a'
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
 
void setup(void)
{
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);
}
 
void loop(void){
radio.powerUp();
delay(1);
// int messageSize = theMessage.length();
// for (int i = 0; i &lt; messageSize; i++) {
// int charToSend[1];
// charToSend[0] = theMessage.charAt(i);
// radio.write(charToSend,1);
// }
//send the 'terminate string' value...
msg[0] = 'H';
bool h=radio.write(msg,1);
if (h==false)
{
Serial.println("Failed to tx HIGH ");
fail++;
Serial.print("failed to send ");
Serial.print(fail);
Serial.println(" packets");
 
}
else
Serial.println("Sent HIGH OK");
radio.powerDown();
delay(500);
 
/*delay sending for a short period of time. radio.powerDown()/radio.powerupp
//with a delay in between have worked well for this purpose(just using delay seems to
//interrupt the transmission start). However, this method could still be improved
as I still get the first character 'cut-off' sometimes. I have a 'checksum' function
on the receiver to verify the message was successfully sent.
*/
 
radio.powerUp();
delay(1);
msg[0] = 'L';
bool l=radio.write(msg,1);
if (l==false)
{
Serial.println("Failed to tx LOW ");
fail++;
Serial.print("failed to send ");
Serial.print(fail);
Serial.println(" packets");
}
else
Serial.println("Sent LOW OK");
delay(500);
 
radio.powerDown();

 msg[0]=i;
 radio.powerUp();
 
delay(1);
bool shite=radio.write(msg,1);
i++; // incremenet counter to next alphanumeric character

if (i>122) i=77; // 122='z' reset to 'a'



if (shite==false)
{
Serial.println("Failed to tx random char ");
fail++;
Serial.print("failed to send ");
Serial.print(fail);
Serial.println(" packets");
}
else
Serial.println("Sent random char OK");
}

Receiver Code.

#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
 
/*
This sketch receives strings from sending unit via nrf24 
and prints them out via serial.  The sketch waits until
it receives a specific value (2 in this case), then it 
prints the complete message and clears the message buffer.
*/
 
int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
// int lastmsg = 1;
// String theMessage = "";=
void setup(void){
  Serial.begin(9600);
  pinMode(8,OUTPUT);
  digitalWrite(8,LOW);
  radio.begin();
  radio.openReadingPipe(1,pipe);
  radio.startListening();
}
void loop(void){
  if (radio.available()){
    bool done = false;  
      done = radio.read(msg, sizeof(msg)); //1); 
   //   char theChar = msg[0]
      
      if (msg[0]==76) // got character 'L'
      {
        digitalWrite(8,LOW);
        Serial.print("rx = ");
        Serial.print(msg[0]);
        Serial.println("");
      }
      else if (msg[0]==72)  // got character 'H'
      {
        digitalWrite(8,HIGH);
        Serial.print("rx = ");
        Serial.print(msg[0]);
        Serial.println("");
      }
      
      else // a character was received, but it's one we weren't expecting !!!
      {
      Serial.print("Received invalid data ");
      Serial.print(msg[0]);
      char ewwor=msg[0];
      Serial.print(" which is the character ");
      Serial.println(ewwor);
      }
   }

}

There ya go! Happy new year 🙂

Interfacing medium-power loads with an arduino

One of my ‘to-do’ projects is an automated plant/garden watering system for those times when we’re away from the house on holiday for a week or longer. Previously, I’ve placed my chilli plants and bonsai tree in the bath with an inch of water to allow the plants to soak up the water. This isn’t be best way to do this and can cause the roots of the plants to become saturated which is worse for them than a brief cycle of under-watering. OK, enough background; let’s move on.

This article won’t design the entire system; this article is to provide information and the knowledge required to interface to inductive loads – relays, pumps, solenoids etc.. As I’ve previously posted, an arduino cannot sink the current requirements of an inductive load so an interface is required to switch the current through the load.

First steps:

Find out how much current your load requires. This can be easily found from the data sheet by reading it! If you don’t have the datasheet, then you’ll need to power the load with a PSU and measure the current flowing through it with a multimeter to understand the loads requirements. I’ll show you how I did this with a relay and a water pump.

Connecting a multimeter set to amps in series with the positive end of the power supply and positive end of the pump with a clamp diode to reduce the effects of induced current when the power is switched off the meter showed the pump drawing 0.35A,  350mA of current while pumping the water. Great. Knowing the load current is much higher than the 20mA the arduino can sink from one of the digital outputs I know I need an transistor that can handle at least 350mA of collector current. Having a look through the data sheets on the transistors I have in my component box I discounted my ZTX108s, 2N2222, BC109,2N3415 and had a choice of BFY51, BC639 and TIP142L.

I (initially) decided to use the BFY51 as it can cope with the demands. It didn’t quite work out in practice as it told me in would in theory! Keep reading 🙂

No collector resistor is required as the pump’s inductor puts up a DC resistance. So referring to our base resistor calculator we know that to ensure the transistor is saturated Rb=((Vswitch-Vbe)/Ic)*hfe(min) for the BFY51 this gives 368.57Ω so use 330Ω  as the nearest preferred value. I wired the circuit and it worked, but not quite as expected the transistor was getting really quite hot after a few seconds – I checked the wiring again it was all fine so what was going on? measuring the collector emitter voltage it was showing nearly 6V! in saturation it should be about 0.2V. This is where all the heat was coming from the transitor was on,working in its liner mode but not saturated. I tried another BFY51 as they were manufactured in 1982 and have been reused in various projects. Same effect – weird.  Next step I checked the input circuit and there was the problem. I was using a 6V battery and it was on its way out – under load it was reading 3.2v so the base current was enough to turn the transistor on but not enough to force it towards saturation. Once the battery was replaced all was perfect – a nice cool transistor and a fully operational pump! Placing the meter in  series with the supply and pump  0.35A flowing! Perfect! stage one complete.

 

Min/Max detection

This routine will be useful where you need to take readings from any sensor and use the previous reading as a comparison for an action to be taken. Nothing special about this.

I use an LDR connected in a voltage divider configuration to pin A0.

/*
This application will read the light level from the LDR
on power-up and will use that initial value as the first reference
for the min/max light levels.
It will then continually compare that initial stored value
with the next reading and update the min/max levels accordingly
*/

int ldr=A0;
int tempmin,tempmax;
int initreading;

void setup()
{
Serial.begin(9600);
pinMode(ldr,INPUT);
delay(200);
initreading=analogRead(ldr); // take an initial reading
tempmin=initreading; // assign the initial reading to the min
tempmax=initreading; // and the max readings
Serial.print(&quot;Initial light level: &quot;);
Serial.println(initreading);
Serial.println(&quot;This is lux(min) and lux(max)&quot;);
}

void loop()
{
int reading=analogRead(ldr);
delay(1000);

if (reading&lt;tempmin)
{
tempmin=reading;

Serial.print(&quot;New minimum of: &quot;);
Serial.print(reading);
Serial.println(&quot; read from the sensor&quot;);
}
if (reading&gt;tempmax)
{
tempmax=reading;
Serial.print(&quot;New maximum of: &quot;);
Serial.print(reading);
Serial.println(&quot; read from the sensor&quot;);
}
else
{
Serial.print(&quot;Current mimimum is: &quot;);
Serial.print(tempmin);
Serial.print(&quot; and the maximum is: &quot;);
Serial.print(tempmax);
Serial.print(&quot; with a current lux of: &quot;);
Serial.println(reading);
}
}