接上次的话茬,在并行的驱动方式下,我们的编程的确是很省事,不过最大的不足就是,如果你的单片机能够给你使用的端口没有那么多,特别是那8个数据管脚占有的那么多的数量,看着心疼啊,所以这里介绍另一种驱动的方法,那就是串行的驱动方法。
串行的方式有时就不说了,但是也有缺点,那就是速度的制约,你想,原来8根数据线一同传输的数据,这时要用2根数据线进行传输,速度肯定是变慢了,具体变慢了多少呢?这个你可以自己计算一下。
下面是在Arduino中的有关的管脚的定义:
可以明显的看出来,这里的使用的管脚少了很多其实主要就是烧得数据管脚部分,现在我们如果要发送数据,其实这就是主要的功能实现的方法,用发送数据的方法告诉LCD要显示啥,在哪里显示,以及以怎样的顺序来进行显示,怎样的方式。
所以这样看来,以前的发送数据的函数肯定是不能够使用了,所以这里我们需要去重新写一个函数,以其能够用两根线也能完成我们需要完成的事情,这件事情其实不是很难,主要是在这里,很多事情的铺垫已经做好了。
我们再一次回到时序图,在这里面,有所有我们需要的东西,有我们的函数的书写的指导,有我们需要拉高拉低的电平,有我们需要显示字符的位置,有我们能够做的任何一件事。
照之前的经验,这里重写写数据函数,当然,还有读数据函数。这里的写可以这么理解,就是分为8个阶段,8个脉冲,读也是这样子来完成,那么这样的8个脉冲之前必须还要加上一些标记性的东西才行,不然LCD凭什么就能知道他应该去把之后的8个脉冲之内的数据当成他需要读取的数据或者给出的数据?恩,这就在时序图中看出来了。
恩,之前的准备工作还是不可以少的,所以这里贴上,基本上和之前并行的时候差不多,只不过中间使用到的发送数据的函数做了一个改头换面,所以我们的调用形式还是不变,我觉得这个其实还是很重要的,在实际的开发过程中,底层的开发人员提供一些基本的函数,而在设计这些函数之前,必须考虑到今后的改动,以及在入口参数方面做一些详尽的考虑,这样使得以后的开发少一点纠结,这也是一个好的习惯,有些参数现在可能用不到,但是可能以后会用得到,所以有的时候需要做出一些权衡,也是为了上层的工作更好的开展。
好了,闲话少说,初始化:
// set the pin mode
pinMode(vcc_pin,OUTPUT);
pinMode(psb_pin,OUTPUT);
pinMode(reset_pin,OUTPUT);
pinMode(bla_pin,OUTPUT);
pinMode(blk_pin,OUTPUT);
pinMode(e_pin,OUTPUT);
pinMode(rs_pin,OUTPUT);
pinMode(rw_pin,OUTPUT);
pinMode(v0_pin,OUTPUT);
pinMode(reset_pin,OUTPUT);
// testing point
digitalWrite(vcc_pin,HIGH);
digitalWrite(bla_pin,HIGH);
digitalWrite(blk_pin,LOW);
digitalWrite(psb_pin,0); // set the mode to parallel
analogWrite(v0_pin,150);
digitalWrite(reset_pin,LOW);
digitalWrite(reset_pin,HIGH);
reset就是一个复位,不过这里是这样,其实不是很必须,不过复位了那就更多一点放心,而已。
之后是一个功能的实现。
LCD_Init();
delay(1000);
LCD_WriteStr(1,1,shuzu);
这个init的函数后面会讲,之前的初始化其实是对管脚的一轮的初始定义,而在软件代码上还需要一个初始化,这里的目的就是在屏上写一串字符,字符定义在一个数组中,是:char shuzu[]={"hello"};
好了,看看具体的实现。
我们将写的函数分为两部分,一个有概括的意味:
void LCD_write_byte(unsigned char RW, unsigned char RS, unsigned char W_data)
还有一个是一个像是在埋头苦干的小伙:
void serial_write_byte(unsigned char dat)
好了,下面是这两者的代码,不过稍等一会,给出时序图先。
这是读写的时序,是每一次写的时候的方式表达。
还有一张图:
这是传送一个完整的8位的字节数据所经历的过程,这样我们写函数的时候就能知道是不是对了,只需要对照这样的两张图进行书写,拉高拉低电平就可以了吗很多的期间其实在时序图上是很复杂的,远远比这个要复杂很多,所以这个时候需要编写者的耐心和细心,这两样是必不可少的,做电子的,其实都是需要这个的,你不知道你所写的代码将要运行在哪一个地方,不知道谁将来回去进行借鉴和参考,并且或者是直接的应用,如果这些代码做的事情和人们的生命安全有关系,和重大的工程项目有关系,那么,你可以想见,这样的细心和耐心是必要的。
这里控制的管脚的名字似乎是不认识了吧,没有关系,其实是换了一身马甲,你还是能够认出他们的。Sclk就是e这个管脚,就是允许管脚,然后剩下的应该很好判断吧,之后的代码中你能够轻易的看出来。
下面啥都不说了,贴代码,一切尽在代码中!
void serial_write_byte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
if((dat&0x80)==0){
clear_rw();
delay(2);
set_e();
delay(4);
clear_e();
delay(2);
clear_rw();
}
else{
set_rw();
delay(2);
set_e();
delay(4);
clear_e();
delay(2);
clear_rw();
}
dat = dat << 1;
}
}
void LCD_write_byte(unsigned char RW, unsigned char RS, unsigned char W_data)
{
unsigned int H_data,L_data,S_ID = 0xf8; //11111RWRS0
if(RW == 0) //RW=0,MCU写一个数据到液晶;
{
S_ID &=~ 0x04;
}
else //RW=1,从液晶读数据到MCU
{
S_ID |= 0X04;
}
if(RS == 0) //RS=1,写入的是数据
{
S_ID &=~ 0x02;
}
else //RS=0,写入的是指令;
{
S_ID |= 0X02;
}
H_data = W_data;
H_data &= 0xf0; //屏蔽低4位的数据
L_data = W_data; //xxxx0000格式
L_data &= 0x0f; //屏蔽高4位的数据
L_data <<= 4; //xxxx0000格式
set_rs();
serial_write_byte(S_ID); //发送S_ID
serial_write_byte(H_data); //发送H_data
serial_write_byte(L_data); //发送L_data
clear_rs();
}
void LCD_Init(void)
{
delay(2);
LCD_write_byte(0,0,0x30); //功能设置 8位数据,基本指令
delay(2);
LCD_write_byte(0,0,0x04); //点设定:显示字符/光标从左到右移位,DDRAM地址加1
delay(2);
LCD_write_byte(0,0,0x0C); //显示设定:开显示,显示光标,当前显示位反白闪动
delay(2);
LCD_write_byte(0,0,0x01); //写指令:清除显示, 清DDRAM
delay(2);
LCD_write_byte(0,0,0x02); //写指令:DDRAM地址归位
delay(2);
LCD_write_byte(0,0,0x80); //写指令:设置DDRAM地址,把显示地址设为0X80,即为第一行的首位
delay(2);
}
文章评论(0条评论)
登录后参与讨论