热度 21
2012-11-6 00:15
1168 次阅读|
0 个评论
接上次的话茬,在并行的驱动方式下,我们的编程的确是很省事,不过最大的不足就是,如果你的单片机能够给你使用的端口没有那么多,特别是那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;i8;i++) { if((dat0x80)==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); }