Introduction
The SN74HC595N outputs can control any devices such relays, LED, or even a HD44780-based character LCD. Using a single SN74HC595N shift registers a master MCU can control a character LCD using the LCD 4-bit data transfer mode.
![]() |
| Information Screen |
I made my own serial character LCD using a SN74HC595N chip, a TC1604-01 16x4 HD44780 LCD, some passive components, and a DIY PCB.
![]() |
| DIY SN74HC595N 16x4 Serial LCD using TC1604-01 HD44780 |
However using its 4-bit data transfer mode, we need to care about the LCD RS and Enable Pin since the nibbles have to transfer twice.
dsPIC30F2010 LCD Programming in MikroC
I need to write my own LCD driver routine for this example. However the source code is difficult than using the direct 4-bit LCD interface.
We can wire your own SPI LCD using the schematic below.
Schematic:
![]() |
| Schematic Diagram |
However the 16x2 and the 16x4 LCD pin outs are the same. We can use one of these.
In this example, the dsPIC30F2010 show some texts on this serial LCD module.
MikroC Source Code:
- /*TWI LCD Driver*/
- #define RS 1
- #define RW 2
- #define EN 3
- #define BL 0
- // Chip Select Pin
- sbit Chip_Select at LATE3_bit;
- sbit Chip_Select_Direction at TRISE3_bit;
- char backLight=0;
- void lcd_delay(unsigned int counts){
- unsigned int i=0;
- for (i=0;i<counts;i++);
- }
- void spi_lcd_command(char command){
- char _data;
- _data=command&0xF0;
- SPI1_Write(_data|(backLight<<BL)|(1<<EN));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(_data|(backLight<<BL));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- _data=command<<4;
- SPI1_Write(_data|(backLight<<BL)|(1<<EN));
- Chip_Select = 0; // Select SPI chip
- lcd_delay(10);
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(_data|(backLight<<BL));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- }
- void spi_lcd___data(char command){
- char __data;
- __data=command&0xF0;
- SPI1_Write(__data|(backLight<<BL)|(1<<EN)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(__data|(backLight<<BL)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- lcd_delay(50);
- __data=command<<4;
- SPI1_Write(__data|(backLight<<BL)|(1<<EN)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(__data|(backLight<<BL)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- }
- void spi_lcd_xy(char x, char y){
- //16x2
- //char addr[]={0x80,0xC0};
- //16x4
- char addr[]={0x80,0xC0,0x90,0xD0};
- spi_lcd_command(addr[y-1]+x-1);
- }
- void spi_lcd_line_1(void){
- spi_lcd_command(0x80);
- }
- void spi_lcd_line_2(void){
- spi_lcd_command(0xC0);
- }
- void spi_lcd_line_3(void){
- spi_lcd_command(0x90);
- }
- void spi_lcd_line_4(void){
- spi_lcd_command(0xD0);
- }
- void spi_lcd_cursor_off(void){
- spi_lcd_command(0x0C);
- }
- void spi_lcd_text(char *txt){
- while(*txt) spi_lcd___data(*txt++);
- }
- void i2c_lcdClear(void){
- spi_lcd_command(0x01);
- Delay_ms(10);
- }
- void spi_lcd_init(void){
- SPI1_Write(0);
- lcd_delay(500);
- spi_lcd_command(0x33);
- lcd_delay(10);
- spi_lcd_command(0x32);
- lcd_delay(10);
- spi_lcd_command(0x28);
- lcd_delay(10);
- spi_lcd_command(0x0F);
- lcd_delay(10);
- spi_lcd_command(0x01);
- Delay_ms(20);
- spi_lcd_command(0x06);
- lcd_delay(50);
- }
- void main() {
- Chip_Select = 1;
- Chip_Select_Direction = 0; // Set CS# pin as Output
- SPI1_Init(); // Initialize SPI module
- spi_lcd_init();
- Chip_Select = 1;
- spi_lcd_line_1();
- spi_lcd_text("dsPIC30F2010 SPI");
- spi_lcd_line_2();
- spi_lcd_text("SN74HC595N LCD");
- spi_lcd_line_3();
- spi_lcd_text("Programming with");
- spi_lcd_line_4();
- spi_lcd_text("MikroC for dsPIC");
- while(1){
- }
- }
I tested this program on my DIY dsPIC30F1010 Prototype Board. It works fine.
![]() |
| DIY dsPIC30F1010 Prototype Board |
dsPIC30F2010 Simple DVM Serial LCD
There are one on-board POT. So we can make a simple 5VDC serial display digital voltmeter. The variable DC input voltage is connect to RB4(AN4) pin via a POT. Its maximum measurement is 5VDC since the supply and ADC reference voltage is 5VDC.
![]() |
| dsPIC30F2010 and SN74HC595N 16x4 Character LCD |
MikroC Source Code:
- /*TWI LCD Driver*/
- #define RS 1
- #define RW 2
- #define EN 3
- #define BL 0
- // Chip Select Pin
- sbit Chip_Select at LATE3_bit;
- sbit Chip_Select_Direction at TRISE3_bit;
- char backLight=0;
- void lcd_delay(unsigned int counts){
- unsigned int i=0;
- for (i=0;i<counts;i++);
- }
- void spi_lcd_command(char command){
- char _data;
- _data=command&0xF0;
- SPI1_Write(_data|(backLight<<BL)|(1<<EN));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(_data|(backLight<<BL));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- _data=command<<4;
- SPI1_Write(_data|(backLight<<BL)|(1<<EN));
- Chip_Select = 0; // Select SPI chip
- lcd_delay(10);
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(_data|(backLight<<BL));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- }
- void spi_lcd___data(char command){
- char __data;
- __data=command&0xF0;
- SPI1_Write(__data|(backLight<<BL)|(1<<EN)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(__data|(backLight<<BL)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- lcd_delay(50);
- __data=command<<4;
- SPI1_Write(__data|(backLight<<BL)|(1<<EN)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- SPI1_Write(__data|(backLight<<BL)|(1<<RS));
- Chip_Select = 0; // Select SPI chip
- Chip_Select = 1; // Deselect SPI chip
- }
- void spi_lcd_xy(char x, char y){
- //16x2
- //char addr[]={0x80,0xC0};
- //16x4
- char addr[]={0x80,0xC0,0x90,0xD0};
- spi_lcd_command(addr[y-1]+x-1);
- }
- void spi_lcd_line_1(void){
- spi_lcd_command(0x80);
- }
- void spi_lcd_line_2(void){
- spi_lcd_command(0xC0);
- }
- void spi_lcd_line_3(void){
- spi_lcd_command(0x90);
- }
- void spi_lcd_line_4(void){
- spi_lcd_command(0xD0);
- }
- void spi_lcd_cursor_off(void){
- spi_lcd_command(0x0C);
- }
- void spi_lcd_text(char *txt){
- while(*txt) spi_lcd___data(*txt++);
- }
- void i2c_lcdClear(void){
- spi_lcd_command(0x01);
- Delay_ms(10);
- }
- void spi_lcd_init(void){
- SPI1_Write(0);
- lcd_delay(500);
- spi_lcd_command(0x33);
- lcd_delay(10);
- spi_lcd_command(0x32);
- lcd_delay(10);
- spi_lcd_command(0x28);
- lcd_delay(10);
- spi_lcd_command(0x0C);
- lcd_delay(10);
- spi_lcd_command(0x01);
- Delay_ms(20);
- //spi_lcd_command(0x06);
- lcd_delay(50);
- }
- void main() {
- unsigned int temp_res;
- float voltage=0;
- char text[16];
- TRISB = 0xFFFF; // PORTB is input
- ADC1_Init(); // Enable ADC module
- Delay_ms(10);
- Chip_Select = 1;
- Chip_Select_Direction = 0; // Set CS# pin as Output
- SPI1_Init(); // Initialize SPI module
- spi_lcd_init();
- Chip_Select = 1;
- spi_lcd_line_1();
- spi_lcd_text("dsPIC30F2010 ADC");
- spi_lcd_line_2();
- spi_lcd_text("SN74HC595N SPI");
- spi_lcd_line_3();
- spi_lcd_text("LCD Voltmeter");
- spi_lcd_line_4();
- spi_lcd_text("MikroC for dsPIC");
- Delay_ms(5000);
- spi_lcd_command(0x01);
- Delay_ms(20);
- while(1){
- // Get 10-bit results of AD conversion
- temp_res = ADC1_Read(4);
- voltage = (5.0 * temp_res)/1023;
- spi_lcd_line_1();
- spi_lcd_text(" AN4 ADC:");
- spi_lcd_line_2();
- sprintf(text," %4d Decimal",temp_res);
- spi_lcd_text(text);
- spi_lcd_line_3();
- spi_lcd_text(" Voltage:");
- spi_lcd_line_4();
- sprintf(text," %0.4f Volts",voltage);
- spi_lcd_text(text);
- Delay_ms(500);
- }
- }
DIY dsPIC30F2010 Prototype Board:
![]() |
| ADC Voltage Reading |
![]() |
| ADC Voltage Reading |
![]() |
| ADC Voltage Reading |
![]() |
| Information Screen |









No comments:
Post a Comment