标题:
STM8L驱动LCD1602液晶屏
[打印本页]
作者:
51hei小山
时间:
2016-11-1 00:29
标题:
STM8L驱动LCD1602液晶屏
由于上次诺基亚5110的液晶屏接触不良,所以没办法用在我要做的自平衡小车上面.我主要是想用液晶屏显示PID参数,用两个按键设置PID,方便平衡小车的调试.
我手中只剩下LCD1602这款液晶屏了,虽然一直很嫌弃它(驱动IO多,显示字符少)但也没办法.
本文使用四线驱动LCD1602的方法,主要是八线驱动太占用IO口.关于四线驱动,网上有很多例程可以参考,我也是参考网上的程序写的.但在编写LCD1602驱动程序时,还是经历了很多困难,时序问题就不提了.网上的很多程序都是没有判断忙标志位的,直接通过延时来实现.这样,延时时间多少合适成为一个问题,我改了好多次延时,但发现延时时间都比较长,写入一次数据的时间很长.这样的液晶屏用着很闹心,刷新一次时间那么,我的程序还有很多对时间要求比较苛刻的任务要执行呢,这样的速度可不行.
关于四线驱动如何去判断忙标志位,我也不懂,只好去网上搜,很少有这方面的例程,但最后还是找到了一个,照着写,总算解决了.
上图是单片机与LCD1602的接线图,DB0~DB7为8条并行数据线.VL是调节液晶屏的对比度的,外接一个电位器到地,如果显示不清晰,可以通过此电位器调节值最佳对比度.BLK,BLA接液晶背光.
除了8个数据线,和显示控制有关的还有RS,RW,E三个端口,上图是他们对应的功能.
通过向LCD1602写入命令和数据来控制显示.读状态是为了判断LCD1602此时是否处于忙的状态,如果忙,就只能等待不忙的时候再进行写操作.通过读状态时序,读到一个八位数据,最高位是忙标志位,此位为1说明此时忙,为了表示空闲.
大概没什么要讲的了,LCD1602的一些设置指令比较重要,手上也没找到详细的配置说明.
下图是LCD1602驱动芯片的显存,向对应的显存地址写入数据,就可以控制显示字符.由于LCD1602自带了一个ASCII码字库,所以一些常用的字符都可以直接显示,不需要自己去用软件生成字库了.
四线驱动时,写入的是0x28,八线驱动是写入的是0x38,如上图.
四线驱动的写命令写数据时序可以参考下面的例程.
本例程,使用STM8L的PB口驱动LCD1602,正好用完PB口的八个IO.高四位是数据接口,写入一字节数据时,先写高四位,再写第四位.
/*硬件连接*/
// PB0 --> RS
// PB1 --> RW
// PB2 --> E
// PB3 --> A(背光正极)
// PB4 --> D4
// PB5 --> D5
// PB6 --> D6
// PB7 --> D7
// PD6 --> 按键+
// PD7 --> 按键-
#define RS_H PB_ODR_ODR0=1
#define RS_L PB_ODR_ODR0=0
#define RW_H PB_ODR_ODR1=1
#define RW_L PB_ODR_ODR1=0
#define EN_H PB_ODR_ODR2=1
#define EN_L PB_ODR_ODR2=0
/****************************************************************************************
*开发环境:IAR for stm8 v6.5.3
*硬件平台:STM8L-DISCOVERY
*功能说明:LCD1602四线驱动控制,检测忙标志位 第一行显示一串字符,第二行显示一个可以用按键改变大小的三位数字
*作 者:茗风
****************************************************************************************/
#include"iostm8l152c6.h"
#include"stdbool.h"
#include"stdint.h"
const uint8_t Num_to_Char[10]="0123456789";
/******************************************************************************************************
* 名 称:void delay_100us(uint8_t x_us)
* 功 能:延时100us
* 入口参数:无
* 出口参数:无
* 说 明:
* 范 例:无
******************************************************************************************************/
void delay_100us(uint16_t x_us)
{
uint8_t j;
while(x_us--)
{
for(j=0;j<33;j++);//2*40个指令周期
}
//delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期
//*2*40+2*x_ms=80us+
//16M/8/2=1M 一个指令周期为1us
}
///******************************************************************** **********************************
//* 功 能 :LCD1602端口初始化函数
//* 入口参数 :无
//* 出口参数 :无
//* 说 明 :对LCD1602用的IO端口进行初始化
//* 范 例 :无
//******************************************************************************************************/
void LCD1602_GPIO_Init(void)
{
PB_DDR =0xFF;//PB设置为输出
PB_CR1 =0xFF;//PB设置为推挽输出
PB_CR2 =0xFF;//PB的IO输出速率为10MHz
PB_ODR =0x00;//PB输出高电平
PB_ODR |=0x08;
}
///******************************************************************************************************
//* 功 能 :LCD1602忙检测,若不忙则退出,忙则等待
//* 入口参数 :无
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
void LCD1602_Busy_Check(void)
{
PB_CR1 &=0x7F;//浮空输入
PB_CR2 &=0x7F;//无中断能力
PB_DDR &=0x7F;
PB_ODR |=0x80;
RS_L;
RW_H;
EN_H;
while(PB_IDR&0x80);
PB_DDR |=0x80;//PB设置为输出
PB_CR1 |=0x80;//PB设置为推挽输出
PB_CR2 |=0x80;//PB的IO输出速率为10MHz
EN_L;
}
///******************************************************************************************************
//* 功 能 :LCD1602写命令函数
//* 入口参数 :d 写入的一字节命令
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
void LCD1602_Write_One_Byte_Cmd(uint8_t d)
{
LCD1602_Busy_Check();
RW_L;//写
RS_L;//命令
PB_ODR &=0x0F;//清高四位
PB_ODR |=(d&0xF0);
EN_H;//
asm("nop");//200ns延时
EN_L;
asm("nop");//200ns延时
d<<=4; //低四位移到到高四位
PB_ODR &=0x0F;//清高四位
PB_ODR |=(d&0xF0);
EN_H;
asm("nop");//200ns延时
EN_L;
asm("nop");//200ns延时
}
///******************************************************************************************************
//* 功 能 :LCD1602写数据函数
//* 入口参数 :d 写入的一字节数据
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
void LCD1602_Write_One_Byte_Data(char d)
{
LCD1602_Busy_Check();
RS_H;//数据
RW_L;//写
PB_ODR &=0x0F;//清高四位
PB_ODR |=(d&0xF0);
EN_H;
asm("nop");
EN_L;
// asm("nop");
// delay_100us(1500);
d<<=4; //低四位移到到高四位
PB_ODR &=0x0F;//清高四位
PB_ODR |=(d&0xF0);
EN_H;
asm("nop");
EN_L;
asm("nop");
// delay_100us(1500);
}
///******************************************************************************************************
//* 功 能 :LCD1602一串字符函数
//* 入口参数 :x x轴坐标,取值范围(0~15)
//* y y轴坐标,取值范围(0~1),一共两行
//* *s 一串字符
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
uint8_t LCD1602_Display_String(uint8_t x,uint8_t y,uint8_t *s)
{
if(y==1)
{
LCD1602_Write_One_Byte_Cmd(0xC0+x);//设置写入字符开始坐标
}
else
{
LCD1602_Write_One_Byte_Cmd(0x80+x);//设置写入字符开始坐标
}
while(*s != '\0')
{
LCD1602_Write_One_Byte_Data(*s++);
}
return 0;
}
///******************************************************************************************************
//* 功 能 :LCD1602显示两位数字
//* 入口参数 :x x轴坐标,取值范围(0~15)
//* y y轴坐标,取值范围(0~1),一共两行
//* *s 一串字符
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月22日
//* 作 者 :茗风
//******************************************************************************************************/
void LCD1602_Display_Number(uint8_t x,uint8_t y,uint8_t number)
{
if(y==1)
{
LCD1602_Write_One_Byte_Cmd(0xC0+x);//设置写入字符开始坐标
}
else
{
LCD1602_Write_One_Byte_Cmd(0x80+x);//设置写入字符开始坐标
}
if(number<10)
{
LCD1602_Write_One_Byte_Data(' ');
LCD1602_Write_One_Byte_Data(' ');
LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
}
else if(number<100)
{
LCD1602_Write_One_Byte_Data(' ');
LCD1602_Write_One_Byte_Data(Num_to_Char[number/10]);
LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
}
else
{
LCD1602_Write_One_Byte_Data(Num_to_Char[number/100]);
LCD1602_Write_One_Byte_Data(Num_to_Char[number%100/10]);
LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);
}
}
///******************************************************************************************************
//* 功 能 :LCD1602初始化配置
//* 入口参数 :无
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
void LCD1602_init(void)
{
LCD1602_GPIO_Init();
LCD1602_Write_One_Byte_Cmd(0x28);//四线驱动
LCD1602_Write_One_Byte_Cmd(0x01);//清屏
LCD1602_Write_One_Byte_Cmd(0x06);//这个是上面指令码是 000001NS的设
LCD1602_Write_One_Byte_Cmd(0x0C);//显示开及光标设置
}
///******************************************************************************************************
//* 功 能 :按键GPIO初始化配置
//* 入口参数 :无
//* 出口参数 :无
//* 说 明 :
//* 编写日期 :2016年10月21日
//* 作 者 :茗风
//******************************************************************************************************/
void GPIO_Config(void)
{
//PE7 LED控制引脚
PE_DDR_DDR7 =1;//输出
PE_CR1_C17 =1;//推挽输出
PE_CR2_C27 =1;//输出速率10M
//配置阀门到位检测引脚PD6,PD7
PD_DDR_DDR6 =0;
PD_CR1_C16 =1;//带上拉电阻输入
PD_CR2_C26 =1;//使能外部中断
PD_DDR_DDR7 =0;
PD_CR1_C17 =1;//带上拉电阻输入
PD_CR2_C27 =1;//使能外部中断
EXTI_CR3_PDIS =2;//PD口上升沿中断
/*00: Falling edge and low level
01: Rising edge only
10: Falling edge only
11: Rising and falling edge*/
EXTI_CONF_PDHIS =1;//PD[7:4] are used for EXTID interrupt generation
//设置中断
//CPU_CCR |=MASK_CPU_CCR_I1+MASK_CPU_CCR_I0;//启用硬件优先级,禁用软件优先级
}
uint8_t num=30;
void main(void)
{
GPIO_Config();
LCD1602_init();
LCD1602_Display_String(0,0,"nannan wo ai ni!");
LCD1602_Display_String(0,1,"NUM:");
asm("rim"); //enable interrupts
while(1)
{
LCD1602_Display_Number(4,1,num);
PE_ODR ^=0x80;
asm("wfi");
//delay_100us(10000);
}
}
#pragma vector=EXTID_vector
__interrupt void EXTID_ISR(void)
{
delay_100us(100);//10ms延时,暂时这么做
if(PD_IDR_IDR6==0)//加
{
if(num>256)
num=255;
else
num++;
}
else if(PD_IDR_IDR7==0)//减
{
if(num==0)
num=0;
else
num--;
}
EXTI_SR2_PDF =1;//They are cleared by writing a ‘1’ by software
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1