[PIC单片机] 吴坚鸿单片机程序风格赏析【2】
- 格式:doc
- 大小:424.00 KB
- 文档页数:95
(一)按键行列扫描与蜂鸣器(1)技术体会:在行列式扫描结构的薄膜按键里,干扰很大,按键扫描程序非常讲究,尤其是去抖动的处理。
(2)功能需求:每按一个按键,蜂鸣器就响一次。
(3)硬件原理:(a)用4个IO来做2X2按键行列扫描,其中作为输入的2个IO口必须接上拉电阻20K左右。
(b)用1个IO经过8050三极管来驱动有源蜂鸣器,有源蜂鸣器通电就一直响,断电就停止。
而无源蜂鸣器是要靠断断续续的开关信号来驱动才能响,就是要频率来驱动。
(4)源码适合的单片机:PIC18F4620,晶振为22.1184MHz(5)源代码讲解如下:#include<pic18.h> //包含芯片相关头文件//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr#define beep_dr LATA1 //蜂鸣器输出#define key_dr1 LATB3 //2X2按键行输出#define key_dr2 LATB4 //2X2按键行输出#define key_sr1 RB6 //2X2按键行输入#define key_sr2 RB7 //2X2按键行输入//补充说明:吴坚鸿程序风格是这样的,凡是做延时计数阀值的常量//前缀都用cnt_表示。
#define cnt_delay_cnt1 25 //按键去抖动延时阀值#define cnt_delay_cnt2 5 //按键行输出信号稳定的小延时阀值#define cnt_voice_time 60 //蜂鸣器响的声音长短的延时阀值void delay1(unsigned int de) ;//小延时程序,时间不宜太长,因为内部没有喂看门狗//补充说明:吴坚鸿程序风格是这样的,凡是按键扫描函数都放在定时中//断里,凡是按键服务程序都是放在main函数循环里。
有人说不应该把子程序//放在中断里,别听他们,信鸿哥无坎坷。
第一节:吴坚鸿谈初学单片机的误区。
(1)很难记住繁杂的寄存器?寄存器不用死记硬背,鸿哥我行走江湖多年,连一个寄存器都记不住。
需要配置寄存器的时候,直接在网上或者书本上参考别人现成的配置程序是上策,查找芯片数据手册是中策,死记硬背寄存器是最最下策。
(2)很难记住繁杂的汇编语言指令?除非是在校学生要应付考试或者少数工作中绕不开汇编,否则学汇编就是浪费时间。
鸿哥我行走江湖多年,从来就没有用汇编帮客户做过一个项目。
(3)C语言很难学?你不用学指针,你不用学带形参的函数,你不用学结构体,你不用学宏定义,你不用学文件操作,你也不用死记繁琐的数据类型。
你只要会:5条指令语句switch语句,if else语句,while语句,for语句,=赋值语句。
7个运算符+,-,*,/,|,&,!。
4个逻辑关系符||,&&,!=,==.3个数据类型unsigned char, unsigned int, unsigned long。
3个进制相互转化,二进制,十六进制,十进制。
1个void函数。
1个一维数组code(或const) unsigned char array[]。
那么世界上任何一种逻辑功能的单片机软件你都能做出来。
鸿哥我当年刚毕业出来工作的时候才知道可以用C语言开发单片机,一开始只用if 语句就把项目做出来了,没有用指针,没有用带形参的函数等复杂的功能。
再到后来才慢慢开始用C语言其他的高级功能,但是我发现C语言其他的高级功能,本质上都是用我前面列举出来的最基本功能集合而成,只是书写更加简单方便了一点,编译后的机器码都大同小异。
所以不会指针等高级功能你不用自卑,恰恰相反,当你会最简单的几个语句,就把这些高级功能的程序都做出来了,你才发现你对底层了解得更加透切,再学那些高级功能轻而易举。
当你裸机跑的程序都能够协调得很好的时候,你才发现所谓高深的操作系统也不过如此,只要给你时间和金钱你也可以写个操作系统来玩玩。
一文读懂PIC单片机的技术特性和优势对于电子工程师而言,PIC单片机是非常重要的一个产品。
PIC单片机是一种用来开发的去控制外围设备的集成电路,一种具有分散作用(多任务)功能的CPU,与人类相比,大脑就是CPU,PIC共享的部分相当于人的神经系统。
PIC单片机的特点PIC 单片机是一个小的计算机,PIC单片机有计算功能和记忆内存像CPU并由软件控制运行。
然而,处理能力—般,存储器容量也很有限,这取决于PIC的类型。
但是它们的最高操作频率大约都在20MHz 左右,存储器容量用做写程序的大约1K—4K字节。
时钟频率与扫描程序的时间和执行程序指令的时间有关系。
但不能仅以时钟频率来判断程序处理能力,它还随处理装置的体系结构改变。
如果是同样的体系结构,时钟频率较高的处理能力会较强。
因为PIC单片机可以把计算部分、内存、输入和输出等都做在一个芯片内。
所以它工作起来效率很高、功能也自由定义还可以灵活的适应不同的控制要求,而不必去更换不同的IC。
这样电路才有可能做的很小巧。
PIC单片机的优势PIC最大的特点是不搞单纯的功能堆积,而是从实际出发,重视产品的性能与价格比,靠发展多种型号来满足不同层次的应用要求。
就实际而言,不同的应用对单片机功能和资源的需求也是不同的。
比如一个摩托车的点火器需要一个I/O较少、RAM及程序存储空间不大、可靠性较高的小型单片机,若采用40脚且功能强大的单片机,投资大不说,使用起来也不方便。
PIC系列从低到高有几十个型号,可以满足各种需要。
其中,PIC12C508单片机仅有8个引脚,是世界上最小的单片机。
该型号有512字节ROM、25字节RAM、一个8位定时器、一根输入线、5根I/O线,市面售价在3-6元人人民币。
这样一款单片机在象摩托车点火器这样的应用无疑是非常适合。
PIC的高档型号,如PIC16C74(尚不是最高档型号)有40个引脚,其内部资源为ROM共4K、192字节RAM、8路A/D、3个8位定时器、2个CCP模块、三个串行口、1个并行口、11个中断源、33个I/O脚。
#in elude "REG52.H"#defi ne con st_se nd_size #defi ne con st_key_time1#defi ne con st_voice_short 40〃蜂鸣器短叫的持续时间void in itial_myself(void);void in itial_ perip heral(void);void delay_short (un sig ned int uiDelayshort);void delay_ long(un sig ned int uiDelay Ion g);void eusart_se nd(u nsig ned char ucSe ndData); //发送一个字节,内部自带每个字节之间的延时 void TO_time(void); // 定时中断函数 void usart_receive(void); // 串口接收中断函数void key_service(); //按键服务的应用程序void key_sca n(); //按键扫描函数 放在定时中断里sbit led_dr=卩1人5; //Led 的驱动 IO 口sbit beep_dr=卩2人5; //蜂鸣器的驱动IO 口sbit key_sr1=卩3人2; //对应朱兆祺学习板的 S1键 sbit key_gnd_dr= POM; //模拟独立按键的地 GND ,因此必须一直输出低电平 unsigned charucSendregBuf[const_send_size]; // 接收串口中断数据的缓冲区数组un sig ned int uiVoiceC nt=O;//蜂鸣器鸣叫的持续时间计数器 un sig ned char ucVoiceLock=0; 〃蜂鸣器鸣叫的原子锁un sig ned char ucKeySec=0;// 被触发的按键编号 unsigned int uiKeyTimeCnt1=O; //按键去抖动延时计数器 unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志 void mai n(){in itial_myself();delay_lo ng(100);in itial_ perip heral();while(1){key_service(); II 按键服务的应用程序} void eusart_se nd(un sig ned char ucSe ndData) {10 //串口发送数据的缓冲区数组大小20 〃按键去抖动延时的时间ES = 0; //关串口中断TI = 0; II 清零串口发送完成中断请求标志SBUF =ucSendData; II 发送一个字节I*注释一:*根据我个人的经验, 在发送一串数据中,每个字节之间必须添加一个延时, 用来等待串 口发送完成。
高手讲解PIC单片机:从管脚到指令,一看就懂展开全文这个8条腿的小螃蟹就是我们的第一顿饭,只要把它吃下去,以后的大餐就好办了。
第1、8条腿接电源 +5V 和地线。
头两条腿是螃蟹钳子,好吃的很。
现在剩下了 6 条腿第2、3条腿使用时外接一个晶振的东西我们接一个 4 MHz的。
第4条腿是复位脚,是一个信号输入脚。
单片机正常运行时接高电平。
当有一个低电平脉冲输入到这个脚时单片机就复位。
所谓复位就是单片机内部所有的工作部件统统回到规定的状态,程序也复位到头一句上开始逐条运行。
例如,你设计的一个报警锁定的LED红灯亮后,当需要解除报警时,用一个按钮给这个脚瞬时接地一下,相当于给它一个夫脉冲,系统就复位了,led灯就熄灭了,程序从头开始。
以上5个脚,几乎所有单片机都有,包括世界上最复杂的,和世界比较简单的单片机-----PIC12CE519轮到第几条腿啦?奥,是第5条腿,这条叫单片机的 I/O 脚。
就是输入输出脚。
你可通过程序动态地控制它作为输入或输出,作为输出时可以程序控制它的输出电平为高1或低0。
所以,他的工作状态有四种:输入0,输入1,输出0,输出1,剩下的两条腿和第5脚功能一个样。
上边我们已经把8条腿消化掉了,其实我们要弄明白的也就3只腿,我们再简单一些,先整明白两条腿,即GP0,GP1.这两条腿低级一点的用法,可以控制继电器,LED灯,高级一些的用法可以进行I2C总线,RS232总线的通信,作为扩展输入可以模拟出来A/D转换器(6--7bit),可以测量一个电阻的粗略值。
作为输出也可以直接推动扬声器奏出音乐。
这是后话暂且不提。
现在要控制使用这两只腿,我这个三脚猫功夫的说书的不得不讲一下软件了,要想讲明白软件又不得不涉及到单片机的内部结构。
那位说啦,你可别提这软件和结构了,以前俺就是让它们打败的,现在听到这个心里就打鼓。
嘿嘿,不要紧,果真如你所说,那你就不妨跟着我再失败一次,反正吗多一次失败又不纳税,嘿嘿。
《谈学单片机有前途还是嵌入式系统有前途》一文吴坚鸿回复整理(1)六月初吴坚鸿发表了《吴坚鸿谈学单片机有前途还是嵌入式系统有前途》一文,后被andy1989转发至博客中,在发烧友中引起了很大的反响。
对于论坛上很多发烧友的评论,吴坚鸿一一作了答复,吴先生对于每个发烧友的评论都很认真的回复了,因此小编整理出来,供更多的发烧友们学习!稍稍啰嗦一下,吴坚鸿的回复可以解决很多单片机学者的疑问,如果有耐心看完的话,对大家会有极大的帮助的!谢谢版主的关注,没想到有那么多朋友关注,让我的虚荣心一下子得到极大的满足。
我决心对每个贴都回复。
无论有多忙,每天坚持抽一点时间来跟各位朋友交流。
(这是对于大家反映这么热烈的回复)好文章!很受启发——这个就是我分享心得的动力源泉。
嵌入式貌似学校没有怎么教——学校是学基础的地方,C语言,单片机,电子技术,数字技术,模拟技术,高等数学这些才是最重要的。
学校没教嵌入式,我认为是对的。
引用侯俊杰老师的一句话“勿在沙丘筑高台。
是啊脚踏实地最重要好高骛远到了最后一切都是浮云啊——共勉。
很感谢!—— 如果真要感谢我的话,就先感谢电子技术论坛的版主。
其中这句话我很赞同“我觉得单片机开发是艺术,我做的每一个作品都让我充满成就感。
”我比较偏爱自己独立开发自己喜欢的东西,这不为赚钱,只是自己个人对电子的爱好、热情!不过在工作中,个人的力量是有限的,团队合作也很重要!“英文阅读能力要好”这点很重要,不管是看参考资料还是软件开发寻求帮助对英语阅读能力都有很高的要求。
“掌握常用的不同厂家单片机,要掌握各种常用外围芯片,常用数字电路,模拟电路。
第三十六节:EPROM篇--利用单片机内部自带EPROM存储数据开场白:这一节最有价值的可能不是我下面写的源代码讲解,而是我现在正在讲的开场白。
单片机内部自带EPROM存储数据,曾经是我去年一个挥之不去的噩梦。
去年我接了一个小项目,本来预计一个月内搞完的,结果因为小小的EPROM害得我阴沟里翻了船,拖了半年才验收通过。
事情是这样的,这个系统是工作在3.3V,利用单片机内部自带EPROM存储数据,我花了三个星期就交付给客户了,客户做了十几套样板在测试,发现数据偶尔会丢失,逼得我不得不想尽各种办法,比如备份数据等多种方法双管齐下,最终花了半年时间才弄好。
至于我是怎么弄好的我也不想多分享,因为这个系统有特殊性,我仅仅也是巧妙地利用它自身的特殊性才解决,这种解决问题的方法没有复制的价值。
不过从此之后我总结出了以下3条个人教训。
(a)凡是在低于5V电压工作的系统中,千万不要用单片机内部自带EPROM,宁可多花几毛钱也要用外挂的EPROM。
否则凶多吉少。
(b)在5V电压工作的系统中,如果要用单片机内部自带EPROM,那么这款单片机必须自带上电延时和掉电复位功能,同时烧录配置位时必须把这两项功能都打开。
因为单片机自带EPROM最容易丢失数据的时刻就是发生在掉电和上电那段“权力真空”的时间里。
(c)不管是工作在5V还是工作在低于5V的系统中,最保险的方法还是尽量选用外挂的EPROM。
因为去年那个项目给我留下了“成年阴影”,宁可错杀一千也不放过一个。
注:上电延时在PIC的烧录配置位是指power up timer掉电复位在PIC的烧录配置位是指brown out reset那个项目是去年年初开始弄,半年后才验收通过。
之后跟那个老总就几乎没什么联系了,到了年底的时候,突然有一天我接到了他的电话,他问我周末有没有空,他说想专门请我去酒楼吃海鲜,就我和他两个人。
我很开心地答应了,因为我想他肯定有什么大项目要跟我合作了。
第十一节:鸿哥单色液晶屏三大类定律(KS0107驱动12864屏)(1)开场白:我曾经做过一年的液晶屏工程师,“出家”做自由职业者之后我又在很多项目上应用液晶屏。
深圳很多液晶模块公司都是用我帮他们做的测试程序。
不管什么品种的单色屏我都能玩得转。
谦虚一点说就是,在单色液晶驱动程序这方面,吴坚鸿在全国绝对排名在前三名之内(如果不谦虚地说我就号称第一了,呵呵)。
接下来我要介绍一下我的新发现,单色屏驱动程序的三大类定律。
市面上有各种各样的单色屏,什么点阵,段码等等,但是都逃不出我总结的三大类定律。
读者只要学会了鸿哥的三大类定律,以后任何单色屏对于你们来说都是浮云。
想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。
在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。
第一大类定律:纵向显示八个点的类型。
这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。
而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
第二大类定律:横向显示八个点的类型。
这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
第三大类定律:任意位置显示一个点的类型。
这类液晶屏在任意位置上以一个点为基本单位,因此X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
下面,我以驱动芯片为KS0107的12864液晶屏为例子,来介绍一下第一大类定律:纵向显示八个点的类型。
12864液晶屏实际上是由左右两块6464液晶屏合并在一起的,然后通过两根IO口来片选不同的6464液晶屏。
因此,我们只要弄懂了一块6464液晶屏的显示方法就够了。
6464屏在横向上是64个点,纵向上是64个点,也就是一个正方形的屏。
因为它属于第一大类的屏,所以X轴坐标数值的最大范围是64-1=63,而纵向坐标数值的最大范围是(64/8)-1=7.正常的操作思路是这样的,先发送X轴与Y轴的位置数据,确定位置后,就发送一个字节(八个点)的显示数据。
这类屏还有一个特征,连续发送显示数据时,在横向(X轴上)的位置数据会自动加一,因此如果在不换行的情况下,只要设定一次位置,就可以从左到右连续发送显示的数据。
当换行显示数据时,必须重新设定一下坐标位置。
字节正序与倒序的概念解释:当我们一次在纵向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从上到下的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。
12864这个屏是属于倒序的屏。
取模软件是必须的,读者可以在网上自己下载,资料很多。
(2)功能需求:在12864屏上显示8X16的字符,16X16的汉字,24X24的汉字。
(3)硬件原理:液晶屏的VEE接20K可调电阻的左边端口,VO接可调电阻的中间端口,VSS接可调电阻的右边端口,此可调电阻在这里用来调节液晶屏的对比度。
模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。
这个大家都懂。
(4)源码适合的单片机:PIC18f4520,晶振为11.0592MHz。
(5)源代码讲解如下:#include<pic18.h> //包含芯片相关头文件#define Disp_On 0x3f //液晶模块的寄存器初始化的参数,抄网上的,我也从来没有#define Disp_Off 0x3e //研究过它是什么含义,因为根本没必要知道,直接用就行#define Col_Add 0x40#define Page_Add 0xb8#define Start_Line 0xc0//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus#define Lcd_bus PORTB //液晶的数据总线#define Bf_sr RB7 //芯片忙检查#define Mcs_dr LATD6 //左右6464屏的片选#define Scs_dr LATD7 //左右6464屏的片选#define Enable_dr LATD5 //类似时钟的数据线#define Di_dr RC7 //数据与指令的选择线#define RW_dr RD4 //读与写的选择线void delay(unsigned int t); //时序延时函数声明void chk_busy () ; //忙检测,液晶驱动时序的一部分void write_com(unsigned char cmdcode); //往液晶模块写入指令void write_data(unsigned char Di_drspdata); //往液晶模块写入数据void screen_clear(); //清空屏的内容void zf_display816(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示8X16的字符函数,本节的核心内容void hz_display1616(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示16X16的汉字函数,本节的核心内容void hz_display2424(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示24X24的汉字函数,本节的核心内容void init_lcd(); //初始化液晶模块//补充说明:吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用zf,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。
如果有重复的,则多加一个序列号标////识。
如果是汉字,则前缀用hz,其它的一样。
const unsigned char zf816_v[]=//从取模软件中复制的字库,纵向取模,字节倒序{/*-- 文字: V --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, };const unsigned char zf816_5[]={/*-- 文字: 5 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, };const unsigned char hz1616_hong[]={/*-- 文字: 鸿--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x10,0x61,0x86,0x60,0x08,0xF8,0x08,0x00,0xFC,0x0E,0x35,0x04,0x44,0x7C,0x00,0x00, 0x04,0x7C,0x03,0x04,0x04,0x03,0x0A,0x08,0x09,0x09,0x09,0x09,0x49,0x81,0x7F,0x00, };const unsigned char hz1616_ge[]={/*-- 文字: 哥--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x02,0x02,0x7A,0x2A,0x2A,0x2A,0x2A,0x7A,0x02,0x02,0x7E,0x02,0x82,0x00,0x00, 0x01,0x01,0x01,0x3D,0x15,0x15,0x15,0x15,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00, };const unsigned char hz2424_hong[]={/*-- 文字: 鸿--*//*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/0x00,0x80,0x00,0x04,0x18,0x90,0x40,0x40,0x40,0xC0,0x40,0x60,0x40,0xE0,0x20,0x30,0xAC,0x24,0x20,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x03,0x06,0xF8,0x07,0x00,0x00, 0x80,0xFF,0x80,0x40,0x00,0x7F,0x40,0x40,0x41,0x49,0x58,0x4F,0xC0,0xE0,0x00,0x00,0x00,0x00,0x01,0x7F,0x60,0x00,0x01,0x01,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x24,0x22,0x62,0x64,0x3F,0x03,0x00,0x00,};const unsigned char hz2424_ge[]={/*-- 文字: 哥--*//*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/0x00,0x00,0x00,0x08,0x08,0x08,0xE8,0x48,0x48,0x48,0x48,0x48,0xE8,0x08,0x08,0x08, 0x08,0xF8,0x08,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xD0,0xD3,0x52, 0x52,0x52,0x52,0x52,0xD3,0x10,0x10,0x10,0x10,0xF7,0x10,0x10,0x08,0x08,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x04,0x04,0x04,0x04,0x04,0x0F,0x00,0x20,0x20, 0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,};//主程序main(){ADCON0=0x00;ADCON1=0x0f;ADCON2=0x00;TRISA=0x02;TRISE=0x00;TRISC=0x7f;TRISD=0x0f;TRISB=0x00;RBPU=0;SSPEN=0; //决定RA5作为IOTRISE2=1;//补充说明,以上的内容为寄存器配置,每种不同的单片机会有点差异,//大家不用过度关注以上寄存器的配置,只要知道有这么一回事即可init_lcd(); //初始化液晶屏screen_clear ();//清空整屏显示内容Mcs_dr=1;Scs_dr =0; //左6464屏,正显,16X16的汉字,“鸿哥V5”hz_display1616(0, 0,hz1616_hong,0);hz_display1616(16, 0,hz1616_ge,0);zf_display816(32, 0,zf816_V,0);zf_display816(40, 0,zf816_5,0);Mcs_dr =0;Scs_dr =1; //右6464屏,反显,24X24的汉字,“鸿哥V5”hz_display2424(0, 0,hz2424_hong,1);hz_display2424(24, 0,hz2424_ge,1);zf_display816(48, 0,zf816_V,1);zf_display816(56, 0,zf816_5,1);while(1){CLRWDT(); //喂看门狗,大家不用过度关注此行}}//------------------时序延时子程序-----------------------------void delay(unsigned int t){unsigned int i,j;for(i=0;i<t;i++)for(j=0;j<10;j++)CLRWDT();}//------------------忙闲检查,驱动液晶程序的一部分------------------------------void chk_busy (){TRISB=0xff;Lcd_bus=0xff;Di_dr=0;RW_dr=1;delay(0);Enable_dr=1;while(Bf_sr==1);Enable_dr=0;TRISB=0x00;}//------------------写命令到LCD,,驱动液晶程序的一部分------------------------------ void write_com(unsigned char cmdcode){chk_busy ();Di_dr=0;RW_dr=0;Lcd_bus=cmdcode;delay(0);Enable_dr=1;delay(0);Enable_dr=0;}//-------------------写数据到LCD,,驱动液晶程序的一部分----------------------------void write_data(unsigned char Di_drspdata){chk_busy ();Di_dr=1;RW_dr=0;Lcd_bus=Di_drspdata;delay(0);Enable_dr=1;delay(0);Enable_dr=0;}//*------------------清空屏幕的内容,本节的核心内容---------------*/void screen_clear (){unsigned char j,i;Mcs_dr=1;Scs_dr=0; //选择左屏6464for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.{write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63{write_data(0x00); //都显示空内容,达到清空的目的}}Mcs_dr=0;Scs_dr=1; //选择右屏6464for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.{write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63{write_data(0x00); //都显示空内容,达到清空的目的}}}//显示8X16的字符函数,本节的核心内容。