uouSTM8是一种性价比很高的单片机,LCD1602是很常用的电子制作零件,当这两者组合的时候,会发现LCD1602把STM8S103的GPIO基本都占掉了。
标准模式下LCD1602需要8个数据线(DB0-DB7)3个辅助信号线(RW RS E),这就11个GPIO的需求量,而20脚的STM8被占了11个IO之后就基本不能干啥了
好在LCD1602还有4线驱动模式,如果把检测忙和读LCD1602内部寄存器的功能省略掉,那就只需要6跟线(DB4 - DB7 RS E)
此时就木有读LCD1602的操作了,等待LCD忙完的功能由一个延时函数代替
写LCD1602时,首先等待会儿LCD忙完,然后如果是写指令那么RS=0,写数据RS=1。4线写数据的时候,先写高4位,再写低4位,每次写完之后需要在E上产生一个上升沿信号。
LCD1602在使用之前需要先初始化,根据LCD1602的PDF,先发3个0x03(DB4-DB7=0x03)再发1个0x02,最后发0x28,然后这样就进入4线模式了,之后的使用方法和8线的差不多了
0x01清屏
0x80和0xC0分别是两行的开始地址,将字符的序号加上行的地址作为命令发送给LCD1602会让下一个字符输出在指定的位置
下面是LCD1602.C
<code class="lang-cpp">#include "main.h"
void LCD_Init(void){
GPIO_PinInit(RS_PORT ,RS_PIN ,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_PinInit(E_PORT,E_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_PinInit(DB7_PORT,DB7_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_PinInit(DB6_PORT,DB6_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_PinInit(DB5_PORT,DB5_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_PinInit(DB4_PORT,DB4_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);
Util_DelayUs(1000);
LCD_Write(0,0x33);
LCD_Write(0,0x32);
LCD_Write(0,0x28);
LCD_Write(0,0x0c);
LCD_Write(0,0x01);
LCD_Write(0,0x80);
}
void LCD_Write(unsigned char isData,unsigned char cmd){
Util_DelayUs(2000); //Hardcoding delay, keep waiting while the LCD is busy
GPIO_Pin(RS_PORT, RS_PIN, isData);
GPIO_PinClr(E_PORT, E_PIN);
GPIO_Pin(DB7_PORT, DB7_PIN, BitGet(cmd, 7));
GPIO_Pin(DB6_PORT, DB6_PIN, BitGet(cmd, 6));
GPIO_Pin(DB5_PORT, DB5_PIN, BitGet(cmd, 5));
GPIO_Pin(DB4_PORT, DB4_PIN, BitGet(cmd, 4));
nop();
nop();
GPIO_PinSet(E_PORT, E_PIN); //E = 1
nop();
nop();
GPIO_PinClr(E_PORT, E_PIN); //E = 0
GPIO_Pin(DB7_PORT, DB7_PIN, BitGet(cmd, 3));
GPIO_Pin(DB6_PORT, DB6_PIN, BitGet(cmd, 2));
GPIO_Pin(DB5_PORT, DB5_PIN, BitGet(cmd, 1));
GPIO_Pin(DB4_PORT, DB4_PIN, BitGet(cmd, 0));
nop();
nop();
GPIO_PinSet(E_PORT, E_PIN); //E = 1
nop();
nop();
GPIO_PinClr(E_PORT, E_PIN); //E = 0
}
void LCD_Locate(unsigned char x,unsigned char y){
LCD_Write(0, x + (y?0xc0:0x80));
}
void LCD_PrintString(char* c){
while(*c){
LCD_Write(1,*c);
c++;
}
}</code>
main.h中定义了一些宏:
这些是函数包装好的声名,直接用就好,用之前先初始化
这个main.h还包含一些通用函数,比如#define版本的GPIO操作,省得跳转到库函数去了,能提高点效率(有待考证)
<code class="lang-cpp">#ifndef __MAIN_H__
#define __MAIN_H__
#include "stm8s.h"
#include "GPIODef.h"
//Util Macros
#define NULL 0
#define Pin(p) (1<<p) #define bitget(bit, i) ((bit>>i)&1)
#define GPIO_PinSet(GPIOx, pin) SetBit(GPIOx->ODR, pin)
#define GPIO_PinClr(GPIOx, pin) ClrBit(GPIOx->ODR, pin)
#define GPIO_PinGet(GPIOx, pin) BitGet(GPIOx->IDR, pin)
#define GPIO_Pin(GPIOx, pin, v) if(v){SetBit(GPIOx->ODR, pin);}else{ClrBit(GPIOx->ODR, pin);}
#define GPIO_PinInit(GPIOx, pin, mode) GPIO_Init(GPIOx, 1<<pin, mode) lcd1602 #define lcd_clear() lcd_write(0,0x01) void lcd_init(void); lcd_write(unsigned char isdata,unsigned cmd); lcd_locate(unsigned x,unsigned y); lcd_printstring(char* c); util functions util_delay(unsigned int a); #endif< code></pin,></p)></code>
延时函数:
<code class="lang-cpp">void Util_Delay(unsigned int a){
while(a--);
}</code>
延时函数是在CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);情况下的,如果CPU的时钟配置不一样,延时的时间也不一样
LCD1602等待忙那里宁可多等也不能少等,等少了根本不能用,如果觉得等待浪费效率的话,那就接上RW线做Busy检测吧,代码不贴了,因为懒没做
另外在单片机上点之后也不要立刻就开始初始化屏幕,需要等电压稳定下再来
以上程序完全原创,开发环境STVD+COSMIC,使用ST官方库函数
LCD1602是能打出日文假名的,比如
<code class="lang-cpp">LCD_Write(1,0xC1);
LCD_Write(1,0xD9);
LCD_Write(1,0xC9);</code>
就会打出琪露诺的日文名
特殊符号比如欧姆,mu等也能打出来,具体参见PDF
LCD1602.pdf
842.43KB
PDF
198次下载
预览
200字以内,仅用于支线交流,主线讨论请采用回复功能。