软件综合
0
STM8系列单片机用4线LCD1602驱动程序(完整源码)
金坷居士 2016-4-29 00:32:04
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

#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++;
    }
}
main.h中定义了一些宏:

这些是函数包装好的声名,直接用就好,用之前先初始化
这个main.h还包含一些通用函数,比如#define版本的GPIO操作,省得跳转到库函数去了,能提高点效率(有待考证)
#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);
void LCD_Write(unsigned char isData,unsigned char cmd);
void LCD_Locate(unsigned char x,unsigned char y);
void LCD_PrintString(char* c);
  
//Util functions
void Util_Delay(unsigned int a);
#endif



延时函数:
void Util_Delay(unsigned int a){
    while(a--);
}


延时函数是在CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);情况下的,如果CPU的时钟配置不一样,延时的时间也不一样


LCD1602等待忙那里宁可多等也不能少等,等少了根本不能用,如果觉得等待浪费效率的话,那就接上RW线做Busy检测吧,代码不贴了,因为懒没做
另外在单片机上点之后也不要立刻就开始初始化屏幕,需要等电压稳定下再来
以上程序完全原创,开发环境STVD+COSMIC,使用ST官方库函数






LCD1602是能打出日文假名的,比如
LCD_Write(1,0xC1);
LCD_Write(1,0xD9); 
LCD_Write(1,0xC9);
就会打出琪露诺的日文名

特殊符号比如欧姆,mu等也能打出来,具体参见PDF
LCD1602.pdf843k9次
2016-4-29 01:25:12
1楼
0
标准的LCD1602似乎是日本字库,里面的"\"被"¥"代替
2楼
0
引用 我说要有光:
标准的LCD1602似乎是日本字库,里面的"\"被"¥"代替
[s::D]试了两块1602, 一块是通常的牛屎,另一块是Hitachi的HD44780,\都显示为¥
3楼
0
[s::dizzy:]前几天用STC12C2052AD&1602做了个温度计....就是用的6脚的驱动...
4楼
0
前些时间我用105k4做过,当时初始化化很烦。后来先用八位指令写一遍初始化,再用4bit指令写一遍初始化才弄出来。到时我也分享下263903
5楼
0
低IO数目的情况下可以试试IIC总线的屏,只占用两个IO。速度也不错,而且能比较容易地做多屏操作
6楼
0
引用 drzzm32:
低IO数目的情况下可以试试IIC总线的屏,只占用两个IO。速度也不错,而且能比较容易地做多屏操作
ST的I2C威名远扬……慎重使用,除非对存在的问题很了解并且愿意花时间绕过
金坷居士(作者)
7楼
0
引用 phpskycn:
ST的I2C威名远扬……慎重使用,除非对存在的问题很了解并且愿意花时间绕过
窝的I2C倒是能调的通、没有传说中辣么巨毒
2016-5-3 13:45:39
8楼
0
引用 金坷居士:
窝的I2C倒是能调的通、没有传说中辣么巨毒
试了下I2C和MPU6050通信,能工作但是有一定概率会卡住,重新上电又能解决
金坷居士(作者)
9楼
0
引用 phpskycn:
试了下I2C和MPU6050通信,能工作但是有一定概率会卡住,重新上电又能解决
窝那个是驱动24C02,没问题的,可能是ST的I2C兼容性不好
10楼
0
引用 金坷居士:
窝那个是驱动24C02,没问题的,可能是ST的I2C兼容性不好
我记得那个仅仅是stm32F1系列硬件iis不能开中断

想参与大家的讨论?现在就 登录 或者 注册

万流景仰
专栏收藏夹发私信
学术分 11科创币 16.42总主题 171 帖总回复 1711 楼拥有证书:会员 学者 机友 笔友
注册于 2011-09-23 14:21最后登录 2019-04-19 00:55

个人简介

怪哉!灵异的三极管电流流向! 这素一个在仿真的RCC电路,示波器上绿色的是集电极电流红色的是发射极电流。窝萌都知道发射姬电流素集电极电流和基极电流之和,所以讲道理发射极电流一定比集电极略大。可仿真结果刷了三观,Q1集电极电流一部分流经基极,然后流经Q2的C->E。

Github  https://github.com/kccd/nkc.git

科创研究院 (c)2001-2019

蜀ICP备11004945号-2 川公网安备51010802000058号