We are going to interface LCD 4 bit mode with stm8s103f3 microcontroller. The code will be equally applicable for similar line STM8 microcontroller. The language we are going to use is C and the compiler we used is COSMIC C compiler for STM8. The IDE that we used for writing our code is STVD from ST Microelectronics. Which is a free development tool-set for STM8 based micro controllers. We used same IDE for writing our STM8 Assembly code in our previous post.
Create a new project
First Lets open STVD and open or create a new work space for your projects. In that work-space create a new folder and name anything for the project you want and then click on create new project or ADD New Project and then create a new project with name of your choice and click next. Next you need to select the microcontroller. Which in our case is STM8S103F3P So I chooses this microcontroller. Main file will be automatically created for me so All I have to do is to add the main header file for the definitions of all registers in STM8S based micro-controllers. I chooses this generic header file naming “iostm8s.h”. If you want to be more specific you may also choose the header file of “iostm8s103.h”. But for our code of lcd former header file will work just fine.
STM8 GPIO as Output
Now we need to configure our GPIO pins as an Output mode. In STM8 if we want to use any GPIO as an Output mode we have two options, either we can configure this pin as PUSH PULL or we can select OPEN DRAIN mode. These settings are done with CR1 registers of respective port. To choose either Input or Output we need to write proper bit high or low into the DDR register which will select the direction of that port. Finally to actually write data to output we need to use ODR register. So to sum up we need these registers for now
- PD_DDR
- PD_CR1
- PD_ODR
- PC_DDR
- PC_CR1
- PC_DDR
You may see these definitions like this in the code
#define LCD_DATA_DDR PC_DDR #define LCD_CNT_DDR PD_DDR #define LCD_DATA_CR1 PC_CR1 #define LCD_CNT_CR1 PD_CR1 #define LCD_DATA_PORT PC_ODR
Next we need to define the control pins which are RS, RW and EN stands for Register Select (RS) , Read/Write (RW) and Enable (EN). We can define bit accesable variable in cosmic like this.
Note: “Remember this is cosmic specific, You need to check your compiler’s reference manual if you are using other compiler than cosmic.”
_Bool RS @PD_ODR:1; _Bool RW @PD_ODR:2; _Bool EN @PD_ODR:3;
Required Functions
So Now you have Your pins and port definitions which you may use into the initialization procedure. Here are four functions that we are going to use in our code.
void lcd_cmd(unsigned char); void lcd_data(unsigned char); void lcd4bit_init(void); void delay_ms(unsigned int);
LED Blinking Code in STM8
delay_ms function should be approximately equal to mili seconds which make very important role in our code so we used a on board LED blink code to test and validate our delay. LED blinking was also to make sure that our delay is not too long or too short for the LCD. Here is on board LED blinking code which is connected to PB5 pin in my board and in Common anode manner. Which means that If I provide 0 onto the LED pin the LED will light up, and if I place a 1 or logic HIGH on that pin the LED Will Turn OFF.
main() { CLK_CKDIVR = 0x00; //CPUDIV=1,HSDIV=1,Int_clock= 16MHz PB_DDR |= (1<<5); PB_CR1 |= (1<<5); PB_ODR |= (1<<5); while (1){ PB_ODR ^= (1<<5); delay_ms(500); } }
Final Code
Here is complete code used for interfacing LCD with STM8S microcontroller
/* MAIN.C file * * Copyright (c) 2002-2005 STMicroelectronics */ #include "iostm8s.h" #define CLR_BIT(p,n) ((p) &= ~((1) << (n))) #define SET_BIT(p,n) ((p) |= (1 << (n))) #define FLIP_BIT(p,n) ((p) ^= ((1)<<(n))) #define READ_BIT(p,n) (!!((p)&((1)<<(n)))) #define LCD_DATA_DDR PC_DDR #define LCD_CNT_DDR PD_DDR #define LCD_DATA_CR1 PC_CR1 #define LCD_CNT_CR1 PD_CR1 #define LCD_DATA_PORT PC_ODR _Bool RS @PD_ODR:1; _Bool RW @PD_ODR:2; _Bool EN @PD_ODR:3; void lcd_cmd(unsigned char); void lcd_data(unsigned char); void lcd4bit_init(void); void delay_ms(unsigned int); main() { CLK_CKDIVR = 0x00; //CPUDIV=1,HSDIV=1,Int_clock= 16MHz PB_DDR |= (1<<5); PB_CR1 |= (1<<5); PB_ODR |= (1<<5); lcd4bit_init(); lcd_data('h'); lcd_data('e'); lcd_data('l'); lcd_data('l'); lcd_data('o'); while (1){ PB_ODR ^= (1<<5); delay_ms(500); } } void delay_ms(unsigned int nCount) { /* Decrement nCount value */ unsigned int i =0; while (nCount != 0) { for(i=0;i<0x3FF;i++); nCount--; } } void lcd_cmd(unsigned char cmd){ RS=0;RW=0; LCD_DATA_PORT =(cmd & 0xF0); //Send higher nibble EN=1; delay_ms(5); EN=0; LCD_DATA_PORT =((cmd<<4) & 0xF0); EN=1; delay_ms(5); EN=0; } void lcd_data(unsigned char data){ RS=1;RW=0; LCD_DATA_PORT =data; EN=1; delay_ms(5); EN=0; LCD_DATA_PORT=((data<<4)&0xF0); EN=1; delay_ms(5); EN=0; } void lcd4bit_init(){ //--------- PORT INIT ----------- LCD_DATA_DDR |= 0xF0; LCD_CNT_DDR |= 0x0F; LCD_DATA_CR1 |= 0xF0; LCD_CNT_CR1 |= 0x0F; //------------------------------ RW=0; //RW will remain 0 all the time //------------------------------ delay_ms(20); RS=0;RW=0; LCD_DATA_PORT =0x20; EN=1; delay_ms(5); EN=0; //lcd_cmd (0x02); lcd_cmd(0x28); // 4-bit mode - 2 line - 5x7 font. lcd_cmd(0x0C); // Display no cursor - no blink. lcd_cmd(0x06); // Automatic Increment - No Display shift. lcd_cmd(0x01); lcd_cmd(0x80); // Address DDRAM with 0 offset 80h. }