I was working on my personal project – an audio amplifier and needed the LCD display functions, I had already described in my experiments the way to do so, but there were some flaws, so here we are again. What do we need?
- Display any info on LCD.
- Display the time.
- Display the temperature.

Let me tell the story: Initially, I’d bought a display produced by sunlike sc1602, and wasted tons of my time of debugging this piece of silicon. I think I tried all known init procedures I was able to find on the web and still did not see any sign of the life. After that I just bought another LCD from Winstar, and, surprise surprise it initialized immediately by the standard procedure, I was using in my first experiment about LCD.
The display is connected, but the old code has some flaws, that is how I changed lcd.h:
#include <htc.h> #ifndef _LCD_H_ #define _LCD_H_ #ifndef _XTAL_FREQ // Unless specified elsewhere, 4MHz system frequency is assumed #define _XTAL_FREQ 4000000 #endif #define LCD_RS RD2 #define LCD_EN RD3 #define lcd4b RD4 #define lcd5b RD5 #define lcd6b RD6 #define lcd7b RD7 #define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80) #define LCD_STROBE() ((LCD_EN = 1),(LCD_EN=0)) #define testbit(data,bitno) ((data>>bitno)&0x01) extern void lcd_write(unsigned char c); extern void lcd_clear(void); extern void lcd_puts(const char * s); extern void lcd_putch(char c); extern void lcd_goto(unsigned char pos); extern void lcd_init(); #endif
The main difference in this file – I did not use the whole port for the data as it was done in the previous experiment, only 4 lines were used so only pins are changing their state. So we also need to change two functions: lcd_write and lcd_init.
lcd.c
#include "lcd.h"
void
lcd_write(unsigned char c)
{
__delay_us(40);
if (testbit(c,4)) lcd4b = 1; else lcd4b = 0;
if (testbit(c,5)) lcd5b = 1; else lcd5b = 0;
if (testbit(c,6)) lcd6b = 1; else lcd6b = 0;
if (testbit(c,7)) lcd7b = 1; else lcd7b = 0;
LCD_STROBE();
if (testbit(c,0)) lcd4b = 1; else lcd4b = 0;
if (testbit(c,1)) lcd5b = 1; else lcd5b = 0;
if (testbit(c,2)) lcd6b = 1; else lcd6b = 0;
if (testbit(c,3)) lcd7b = 1; else lcd7b = 0;
LCD_STROBE();
}
void
lcd_clear(void)
{
LCD_RS = 0;
lcd_write(0x1);
__delay_ms(2);
}
void
lcd_puts(const char * s)
{
LCD_RS = 1; // write characters
while(*s)
lcd_write(*s++);
}
void
lcd_putch(char c)
{
LCD_RS = 1; // write characters
lcd_write( c );
}
void
lcd_goto(unsigned char pos)
{
LCD_RS = 0;
lcd_write(0x80+pos);
}
void
lcd_init()
{
LCD_RS = 0;
LCD_EN = 0;
__delay_ms(15); // wait 15mSec after power applied,
lcd4b = 1;
lcd5b = 1;
lcd6b = 0;
lcd7b = 0;
LCD_STROBE();
__delay_ms(5);
LCD_STROBE();
__delay_us(200);
LCD_STROBE();
__delay_us(200);
lcd4b = 0;
lcd5b = 1;
lcd6b = 0;
lcd7b = 0; // Four bit mode
LCD_STROBE();
lcd_write(0x28); // Set interface length
lcd_write(0xF); // Display On, Cursor On, Cursor Blink
lcd_clear(); // Clear screen
lcd_write(0x6); // Set entry Mode
}Use the next code to check how if it works:
TRISD = 0x00;
lcd_init();
lcd_goto(0x00);
lcd_puts("LCD 16x2 test");
lcd_goto(0x40);
lcd_puts("Diymicro.ru");That how the success looks like 🙂 :

The time for bullets 2 and 3 has come.
At the moment I wasn’t aware that LCD can be treated like uart interface, by ASCII table, and if you want to send the number you can simply add 0x30 to your number. Instead I made it by predefined arrays here – if you wish to send the data using the minimum possible memory, so far I need just numbers:
const unsigned char digits[10] = {
0b00110000, //0
0b00110001, //1
0b00110010, //2
0b00110011, //3
0b00110100, //4
0b00110101, //5
0b00110110, //6
0b00110111, //7
0b00111000, //8
0b00111001, //9
};Now, we are ready to write functions for periodic refreshing of the display:
void display_tt() { //дежурная функция отображения информации на LCD
unsigned char d;
get_temp(); //берем значение температуры
LCD_RS = 0;
lcd_write(0b00001100); //выключаем курсор
__delay_us(100);
lcd_clear();
d = ReadHour();
lcd_goto(0x05);
lcd_putch(digits[d/10]); //выводим значение часов
d = d - ((d/10)*10);
lcd_putch(digits[d]);
d = 0b00111010;
lcd_putch(d);
d = ReadMin();
lcd_putch(digits[d/10]); //выводим значение минут
d = d - ((d/10)*10);
lcd_putch(digits[d]);
lcd_goto(0x44);
if (!sign) lcd_putch(0b00101011); else lcd_putch(0b10110000); //знак температуры
d=temperature/10;
lcd_putch(digits[d]); //целое значение температуры
d=temperature-((temperature/10)*10);
lcd_putch(digits[d]);
d = 0b00101110;
lcd_putch(d); //точка
lcd_putch(digits[temp_drob]); //вывод дробного значения
d = 0b11011111;
lcd_putch(d); //градус
d = 0b01000011;
lcd_putch(d); //С
}in the middle of the debug process…

The next thing is to set up the refreshing rate, I used interrupts and TMR2, since I suspected that I might need other timers for different purposes in a future project. We don’t need to do this quite frequently, so I used all maximum values and even added an extra variable to obtain the refreshing rate of about 32s:
interrupt isr() {
if (TMR2IF) {
update++;
if (update == 255) {
flag++;
update = 0;
}
TMR2 = 0x01;
T2CKPS0 = 1; T2CKPS1 = 1; //1 делитель не делит входную частоту
TOUTPS2 = 1; TOUTPS1 = 1; TOUTPS3 = 1; TOUTPS0 = 1; //2 делитель делит на 5
TMR2IF = 0; //сброс флага
}
}Don’t forget that for variables used inside of the interrupt routine the volatile word should be added in the declaration section.
Pingback: Humidity control for the bathroom | diymicro.org