由于上次诺基亚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
- }
|
0
|
|
|
|