1602LCD显示的秒表 C语言程序(优选.)
- 格式:doc
- 大小:34.00 KB
- 文档页数:9
//液晶显示温度#include "AT89X52.H"#define Ddata P0sbit RS=P2^7; //命令数据控制端sbit RW=P2^6; //读写选择端sbit LCDE=P2^5; //液晶使能端sbit DQ=P2^0; //ds18b20与单片机连接口#define uchar unsigned char#define uint unsigned intunsigned char hour=0,min=0,sec=0; //定义初值unsigned int count=0;unsigned char line1[16]={" temp: "}; //16个字符unsigned char line2[16]={" time: 00:00:00"}; //16个字符unsigned char tab[]={'0','1','2','3','4','5','6','7','8','9'}; //数组uchar data disdata[5];uint tvalue; //温度值uchar tflag; //温度正负标志void time();/*************************lcd1602程序**************************/ void delay1ms(unsigned int ms)//延时1毫秒(不够精确的){unsigned int i,j;for(i=0;i<ms;i++)for(j=0;j<110;j++);}void delay5ms()//延时5毫秒(不够精确的){unsigned int i;for (i=0;i<1000;i++);}void delay50us(){register int i;for (i=0;i<20;i++);}void delay(){unsigned char m,n;for(m=255;m>0;m--)for(n=255;n>0;n--);}void wr_com(unsigned char comm) //********写控制字符程序E=1 RS=0RW=0 **********//{LCDE=0; //使能端RS=0; //********RS寄存器选择输入端,当RS=0;当进行写模块操作,指向指令寄存器。
目录1 概述 01.1 1602LCD研究的历史背景和意义 01.2 1602LCD研究的发展和现状 02 课题方案设计 02.1系统设计目的 02.2系统结构模块论证 (1)2.2.1 显示部分 (1)3 系统硬件设计 (1)3.1 总体设计 (1)3.2 单片机运行的最小系统 (2)3.2.1 电源电路 (2)3.2.2晶振电路 (2)3.2.3复位电路 (3)3.3 显示电路 (4)3.3.1引脚说明: (4)3.4 单片机STC89C52 (5)3.4.1主要特性 (5)3.4.2功能特性概述 (6)3.4.3主要引脚及芯片基本工作条件说明 (6)4 系统软件设计 (7)4.1 总流程图 (7)4.2 最小系统检测电路程序 (8)4.3 编程调试界面 (9)4.4 Proteus仿真结果 (9)5软硬件联调及调试结果 (10)5.1 实物图 (10)5.2 调试结果 (11)结束语 (12)参考文献 (12)附录2 1602LCD设计的秒表PCB图 (14)附录3 1602LCD设计的秒表Proteus仿真图 (15)附录4 1602LCD设计的秒表C语言程序清单 (15)附录5 基于单片机的1602LCD设计的秒表元器件目录表 (21)1 概述1.1 1602LCD研究的历史背景和意义LCD1602是16字乘以2行的字符型液晶模板。
其特点是:(1)位数多,可显示32位。
(2)显示内容丰富,可显示所有数字、字母、符号等192种ASCII码对应的字符。
(3)程序简单1.2 1602LCD研究的发展和现状液晶显示模块具有体积小、功耗低、显示内容丰富、超薄轻巧等优点,在袖珍式仪表和低功耗应用系统中得到广泛的应用。
目前字符型液晶显示模块已经是单片机应用设计中最常用的信息显示器件。
LCD1602液晶显示模块,它可以显示两行,每行16个字符,采用单+SV电源供电,外围电路配置简单,价格便宜,具有很高的性价比。
源程序代码://名称:用1602LCD设计的秒表//说明:首先按下K1键时开始计时,自此按下时暂停,第三次按下时继续累积计时,再次按下时停止计时,K2键用于清零秒表。
//#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define delayNOP ( ) ﹛_nop_( ); _nop_( ); _nop_( ); _nop_( );﹜//LCD控制函数void LCD_Initialize( );void LCD_Set_POS(uchar);void LCD_Write_Date(uchar);void Display_String(uchar﹡,uchar);sbit K1 = P1^0;sbit K2 = P1^1;sbit BEEP = P3^0;sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;uchar KeyCount = 0;uchar code msg1[] = ﹛〞Second Watch 0 〞﹜;uchar code msg2[] = ﹛〞>>>> 0 〞﹜;uchar code Prompts[] [16] ={﹛〞:: 1- - - - > 〞﹜,﹛〞:: 1- - - - > ::2 〞﹜,﹛〞:: 1 - >2 ::3- - > 〞﹜,﹛〞:: 1 - >2 ::3- - >4 〞﹜};// 计时缓冲与显示缓冲uchar Time_Buffer[] ={0,0,0,0};uchar LCD_Display_Buffer[]={〞00: 00: 00:00〞}; //// 蜂鸣器//void Beep ()﹛uchar i,j = 70;for (i = 0;i< 180;i++ )﹛while(--j);BEEP = ~BEEP;﹜BEEP = 0;﹜//// 延时//void DelayX(uint ms){uchar i;while(ms--) for (i= 0;i< 120;i++);﹜//// 显示计时//void Show_Second( ){uchar i;LCD_Set_POS(0x45); //设置LCD显示起点for(i = 3;i != 0xff ;i--);{//将两位整数的1/100s,秒,分,时转换为8位数字字符LCD_Display_Buffer[2﹡i+1] = Time_Buffer[i] / 10 + ˊ0 ˊ;LCD_Display_Buffer[2﹡i] = Time_Buffer[i] % 10 + ˊ0 ˊ;//在 = 3,2,1,0时分别显示时,分,秒,1/100sLCD_Writer_Date(LCD_Display_Buffer[2﹡i+1])LCD_Writer_Date(LCD_Display_Buffer[2﹡i])LCD_Writer_Date(ˊ: ˊ)}}//// Time0中断//Void Time0( ) interrupt 1 using 0{THO = -10000 / 256;TLO = -10000 % 256;Time_Buffer[0] ++if(Time_Buffer[0] == 100){Time_Buffer[0] = 0; Time_Buffer[1]++;}if(Time_Buffer[1] == 60) //秒{Time_Buffer[1] = 0; Time_Buffer[2]++;}if(Time_Buffer[2] == 60) //分{Time_Buffer[2] = 0; Time_Buffer[3]++;}if(Time_Buffer[3] == 24) //时Time_Buffer[3] = 0;}////主函数//void main( ){uchar i;IE = 0x82;TMOD = 0x01;THO = -10000 / 256;TLO = -10000 % 256;LCD_Initialize( );Display_String(msg1,0x00);Display_String(msg2,0x40);While(1){if(k1 == 0){DelayX(100);i = ++KeyCount;switch (i){case 1:case 3: TRO = 1;Display_String(Prompts[i-1],0);Break;case 2:case 4: TRO = 0;Display_String(Prompts[i-1],0);break;default:TRO = 0;break;}While (K1 == 0); // 等待释放K1键Beep( );}elseif(K2 == 0){TRO = 0;KeyCount = 0;for(i = 0;i < 4; i++)Time_Buffer [i] = 0; // 清零计数缓冲Display_String(msg1,0);Beep( );DelayX(100);while (K2 == 0); // 等待释放K2键}Show_Second( );}}//// 1602LCD显示驱动函数//#include 〈reg51.h〉#include 〈intrins.h〉#define uchar unsigned char#define uint unsigned int#define DellayNOP( )﹛_nop_( ); _nop_( ); _nop_( ); _nop_( );﹜sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;bit LCD_Busy_Check( );void LCD_Initialize( );void LCD_Set_POS(uchar);void LCD_Write_Command(uchar);void LCD_Write_ Date(uchar);//// 延时//void DelayMS(uint ms){uchar t;while(ms--) for (t =0;t < 120;t++);}//// LCD忙检查//bit LCD_Busy_Check( );{bit Rsult;LCD_RS = 0; LCD_RW = 1; LCD_EN = 1;DelayNOP( );Result = (bit)(p0 ﹠ 0x80);LCD_EN = 0return Result;}//// 向LCD写指令//void LCD_Write_Command(uchar cmd);{while(LCD_Busy_Check() );LCD_RS = 0; LCD_RW = 0; LCD_EN = 0;_nop_( ); _nop_( );pO = cmd; DelayNOP( );LCD_EN = 1;DelayNOP( );LCD_EN = 0;}//// 向LCD写数据//void LCD_Write_Date(uchar str);{while(LCD_Busy_Check() );LCD_RS = 1; LCD_RW = 0; LCD_EN = 0;pO = str; DelayNOP( ); LCD_EN = 1;DelayNOP( );LCD_EN = 0;}//// 初始化LCD//void LCD_Initialize( );{DelayMS(5); LCD_Write_Command(0x38);DelayMS(5); LCD_Write_Command(0x0c);DelayMS(5); LCD_Write_Command(0x06);DelayMS(5); LCD_Write_Command(0x01);DelayMS(5);}//// 设置显示位置//void LCD_Set_POS(uchar Poition){LCD_Write_Command(Position ︱ 0x80);}////显示函数,在LCD指定行上显示字符串//void Display_String(uchar﹡str,uchar LineNO) {uchar k;LCD_Set_POS(LineNO);for (k = 0;k < 16;k++) LCD_Write_Date(str[k]) }。
目录1概述 (1)1.1课题的研究意义和目的 (1)2方案论证 (1)2.1 STC89C52主要功能特性 (1)2.2系统分析 (3)3硬件系统的设计 (3)3.1硬件介绍 (3)3.2部分硬件原理图 (4)3.3最小单片机系统 (5)4系统的软件设计 (5)5软硬件联调 (7)5.1正面图 (7)5.2反面接线 (8)5.3测试结果 (8)结束语 (9)参考文献 (9)附录 (10)附录1 protel原理图 (10)附录2 PCB图 (11)附录3 protues仿真图 (12)附录4 程序清单 (12)附录5元器件清单 (17)1概述1.1课题的研究意义和目的1、通过本实验的设计初步了解单片机工作原理和各功能端口的相关设置;2、掌握PROTEUS软件的安装和配置过程;3、学会绘制电路原理图;4、了解装载程序和调试;5、PROTEUS VSM 与uVision3的联调;6、用单片机仿真软件,并进行调试;7、掌握单片机相应的编程步骤,了解秒表相关的工作流程;8、熟悉KEIL\PROTEUS等相关软件的使用。
2方案论证2.1 STC89C52主要功能特性1、兼容MCS51指令系统2、8k可反复擦写(大于1000次)Flash ROM;3、32个双向I/O口;4、256x8bit部RAM;5、3个16位可编程定时/计数器中断;6、时钟频率0-24MHz;7、2个串行中断,可编程UART串行通道;8、2个外部中断源,共8个中断源;9、2个读写中断口线,3级加密位;10、低功耗空闲和掉电模式,软件设置睡眠和唤醒功能;11、有PDIP、PQFP、TQFP及PLCC等几种封装形式,以适应不同产品的需求。
STC89C52为8 位通用微处理器,采用工业标准的C51核,在部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。
功能包括对会聚主IC 部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。
1、关于1602液晶的电气参数一般市场上的1602液晶使用的驱动器为HD44780U或HD44780S,市场上大部分液晶用的是后者。
HD44780S的供电电压为5V±10%,而HD44780U 的供电电压为2.7V~5.5V。
也就是说,绝大部分1602液晶只能工作在5V 电压下,其供电电压必须为5V。
经过试验发现,1602液晶的供电虽然必须为5V,但其控制总线和数据总线可以用3.3V电平(因为对于TTL电平,一般大于2.5V以上都算高电平,不过最可靠的是大于3.6V),只不过在3.3V 电平下,数据的通信速度会大大降低,这一点需要在写驱动时注意。
需要时,可以将MCU的IO配置为漏极开路方式,用上拉电阻拉到5V电平;实在不能配置为漏极开路方式时,请查阅MCU的电气参数,在允许的条件下,直接使用电阻弱上拉也可以。
2、硬件连接1602液晶可以使用4位或8位通信模式,通信可以是双向的或单向的,双向通信主要是为了读取LCD忙标志和AC地址寄存器和DDRAM和CGRAM中的值,一般用处不大,因为1602不支持点阵绘图功能。
在连接时,注意4位通信方式下,LCD只使用DB7~DB4,一般情况下会使用MCU 某端口的高4位或低4位与之连接,注意写驱动时在必要的情况下对端口的其它几位要保护,防止破坏其数据;当然如果没有使用其它4位时则不必要保护(奇怪,不使用其它4位干嘛用4位通信方式嘛?)。
还要注意的是,如果需要双向通信,则必须选择既能做输入又能做输出的IO口,特别是对于RS、RW和E这三条控制线,若能选择支持位寻址的IO口则可以方便编程。
3、底层驱动问题通用1602液晶的时序如图:(1)、写时序(2)、读时序总的说来,按照这个时序图来编写驱动程序是不会出什么问题的,只是要深刻理解时序图中各参数的涵义。
编程中要特别关注E这根控制线。
写操作的时序应该是:①、RS=0(写指令寄存器)或RS=1(写数据寄存器);②、RW=0(写操作);③、将数据写到数据线上;④、E=1;⑤、E=0 。
#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit RS=P2^0;sbit RW=P2^1;sbit E=P2^2;sbit key1=P2^3;sbit key2=P2^4;sbit key3=P2^5;void delay(void);void init(void);void wc51r(uchar i);void wc51ddr(uchar i);void fbusy(void);void LCD_xianshi(void);void delay_zs(uint z);void tiaoshi(void);uchar hour,hour1,min,min1,sec,sec1,aa,bb,num1,num2,num3,flag;uchar year1,year2,year3,year4,month,month1,month2,day,day1,day2; unsigned int year;uchar tab[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};void main(){init();while(1){LCD_xianshi();}}void init(){// key1=1;key2=1;key3=1;num1=12;year=2010;month=11;day=15;// wc51r(0x01);wc51r(0x38);wc51r(0x0c);wc51r(0x06);TMOD=0x01; //工作方式1TH0=(65536-5000)/256; //定时器高位装初值计数溢出一次为50ms TL0=(65536-5000)%256; //定时器低位装初值EA=1; //CPU开中断ET0=1; //允许T0中断// ET1=1;TR0=1; //启动T0工作// TR1=1;}void fbusy(){RW=1;RS=0;E=1;while(!P1&0x80);E=0;delay();}void wc51r(uchar j){fbusy();E=0;RS=0;RW=0;E=1;P1=j;E=0;delay();}void wc51ddr(uchar j){fbusy();E=0;RS=1;RW=0;E=1;P1=j;E=0;delay();}void delay(){uchar i,j;for(j=0;j<10;j++)for(i=0;i<10;i++);}/*void delay_zs(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}*/void LCD_xianshi(){year1=year/1000;year2=year/100%10;year3=year%100/10;year4=year%10;month1=month/10;month2=month%10;day1=day/10;day2=day%10;hour=num1/10;hour1=num1%10;min=num2/10;min1=num2%10;sec=num3/10;sec1=num3%10;wc51r(0x84); //起始地址为第1行第1列,0x85为第1行第6列;0xc0为第2行第1列wc51ddr(tab[hour]); //显示1wc51ddr(tab[hour1]); //显示2wc51ddr(0x3a); //显示:wc51ddr(tab[min]); //显示0wc51ddr(tab[min1]); //显示0wc51ddr(0x3a); //显示:wc51ddr(tab[sec]);wc51ddr(tab[sec1]);wc51r(0xc3);wc51ddr(tab[year1]);wc51ddr(tab[year2]);wc51ddr(tab[year3]);wc51ddr(tab[year4]);wc51ddr('-');wc51ddr(tab[month1]);wc51ddr(tab[month2]);wc51ddr('-');wc51ddr(tab[day1]);wc51ddr(tab[day2]);}/*void tiaoshi(void){while(key1){TR0=0;if(key2==0){LCD_xianshi;num3++;if(num3==60){num3=0;num2++;}}else if(key3==0)num2++;}// while(key1);// if(key1==0){ET0=1;TR0=1;flag=0;}}*///************************定时器中断程序**************************// void timer0() interrupt 1{TH0=(65536-50000)/256; //重装计数初值TL0=(65536-50000)%256;aa++;if(aa==20) //计数20次后恰为20x50ms==1s{aa=0;num3++; //秒加1if(num3==60) //秒计数到60后清零{num3=0;num2++;if(num2==60){num2=0;num1++;if(num1==24){num1=0;day++;if(month%2==0){if(day==31){day=0;month++;if(month==13){month=0;year++;}}}else if(month%2==1){if(day==32){day=0;month++;if(month==13){month=0;year++;}}}}}}}}//************************定时器中断程序**************************// /*void timer1() interrupt 3{TH1=(65536-50000)/256; //重装计数初值TL1=(65536-50000)%256;bb++;if(bb%20==0){if(key1==0){ET0=0;TR0=0;flag=1;}}}*/#include <msp430g2452.h>unsigned char table[] ={"0123456789"};unsigned char hanzi1[8]={0x04,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02};//年 unsigned char hanzi2[8]={0x0f,0x09,0x0f,0x09,0x0f,0x09,0x13,0x11};//月 unsigned char hanzi3[8]={0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00};//日unsigned char num;void delay_1ms(void){unsigned int i;for (i=0;i<1140;i++);}void delay_nms(unsigned int n){unsigned int i=0;for (i=0;i<n;i++)delay_1ms();}void write_com(unsigned int com){//lcdrs = 0;P2OUT&= 0xfd; P1OUT = com; delay_nms(5); //lcden = 1;P2OUT|= 0x01; delay_nms(5); P2OUT&= 0xfe; }void write_dat(unsigned int dat) {//lcdrs = 1;P2OUT |= 0x02; P1OUT = dat; delay_nms(5); //lcden=1;P2OUT|= 0x01; delay_nms(5); // lcden=0;P2OUT&= 0xfe; }void init() {write_com(0x38);// write_com(0x0f);// write_com(0x01);// write_com(0x06);// // write_com(0x07);//整屏移动 delay_nms(10); }void CGRAM_LCD(unsigned char *hz,unsigned char temp) {unsigned char s; for(s=0;s<8;s++) {write_com(temp+s);write_dat(*(hz+s)); } }void main(void) {WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1DIR |= 0xff; // P1.2 output P2DIR |= 0xff; init();CGRAM_LCD(hanzi1,0x40); CGRAM_LCD(hanzi2,0x48); CGRAM_LCD(ha nzi3,0x50);write_com(0x80); write_dat(table[2]); delay_nms(100);write_com(0x80+0x01); write_dat(table[0]); delay_nms(100);write_com(0x80+0x02); write_dat(table[1]); delay_nms(100);write_com(0x80+0x03); write_dat(table[2]);delay_nms(100);write_com(0x80+0x04); write_dat(0); delay_nms(100);write_com(0x80+0x06); write_dat(table[6]); delay_nms(100);write_com(0x80+0x07); write_dat(1); delay_nms(100);write_com(0x80+0x09); write_dat(table[2]); delay_nms(100);write_com(0x80+0x0a); write_dat(2); while(1); }。
LCD1602液晶秒表C51程序此程序是基于51hei单片机开发板上面写的,如需要移植到自己的电路上,修改相应的端口即可,开发板完整的电路图下载: 点这里(注意:只需要看1602部分即可,其他部分可以忽略)/*************************************************** *********************** @file main.c* @author xr* @date 2014年5月8日22:11:33 -- 2014年5月9日12:03:49* @version V1.2.3* @brief LCD1602液晶跑表单片机STC89C52RC MCU 晶振 11.0592MHZ************************************************* ***********************/#include ;/* 系统时钟 */#define SYS_XTAL (11059200UL/12)/* 定时器T0重载值 */unsigned char thr0, tlr0;unsigned char thr1, tlr1;/* 跑表计数 */unsigned char timer[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; //分别表示跑表的各个位上的数字bit flag10ms = 0;extern bit stopflag;//跑表走停标志位extern void InitalLCD1602();extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);extern void KeyDriver();extern void KeyScan();void DisplayTimer();void ConfigTimer0(unsigned int xms);void ConfigTimer1(unsigned int xms);/* 主函数main() */void main(void){ConfigTimer0(10); //定时10msConfigTimer1(1);InitalLCD1602();LcdShowStr(0, 0, "stopwatch");LcdShowStr(2, 1, "0000000.00s"); //液晶初始化显示LcdShowStr(10, 0, "stop!");while (1){KeyDriver();DisplayTimer();if ((flag10ms == 1) && (stopflag == 1)){flag10ms = 0;timer[0]++;if (timer[0] >; 9){timer[0] = 0;timer[1]++;if (timer[1] >; 9){timer[1] = 0;timer[2]++;if (timer[2] >; 9) {timer[2] = 0;timer[3]++;if (timer[3] >; 9) {timer[3] = 0;timer[4]++;if (timer[4] >; 9) {timer[4] = 0;timer[5]++;if (timer[5] >; 9) {timer[5] = 0;timer[6]++;if (timer[6] >; 9) {timer[6] = 0;timer[7]++;if (timer[7] >; 9){timer[7] = 0;timer[8]++;if (timer[8] >; 9){timer[8] = 0;}}}}}}}}}}}}/* 将跑表时间显示到液晶上 */ void DisplayTimer(){unsigned char str[20];/* 分解timer */str[0] = timer[8] + '0';str[1] = timer[7] + '0';str[2] = timer[6] + '0';str[3] = timer[5] + '0';str[4] = timer[4] + '0';str[5] = timer[3] + '0';str[6] = timer[2] + '0';str[7] = '.';str[8] = timer[1] + '0';str[9] = timer[0] + '0';str[10] = '\0';LcdShowStr(2, 1, str);}/* 定时器T0配置 */void ConfigTimer0(unsigned int xms) {unsigned long tmp;tmp = (SYS_XTAL * xms) / 1000;tmp = 65536-tmp + 18;thr0 = (unsigned char)(tmp >;>; 8) ; tlr0 = (unsigned char)tmp;TMOD &= 0xF0; //清零T0控制位TMOD |= 0x01; //定时器方式1TH0 = thr0;TL0 = tlr0;TR0 = 1; //开启timer0ET0 = 1; //开启T0中断EA = 1; //开启总中断}/* 配置定时器T1 */void ConfigTimer1(unsigned int xms) {unsigned long tmp;tmp = (SYS_XTAL * xms) / 1000;tmp = 65536 - tmp + 18;thr1 = (unsigned char)(tmp >;>; 8); tlr1 = (unsigned char)tmp;TMOD &= 0x0F;TMOD |= 0x10;TH1 = thr1;TL1 = tlr1;TR1 = 1;ET1 = 1;EA = 1;}/* 定时器T0中断服务 */void Timer0_ISP() interrupt 1{TH0 = thr0;TL0 = tlr0;flag10ms = 1; //定时10ms}/* 定时器T1中断服务 */void Timer1_ISP() interrupt 3{TH1 = thr1;TL1 = tlr1; //定时1msKeyScan();}/*************************************************** *********************** @file Lcd1602.c* @author xr* @date 2014年5月7日13:33:17* @version V1.2.3* @brief LCD1602液晶底层驱动************************************************* ***********************/#include ;//LCD1602_IOsbit LCD1602_RS = P1^0;sbit LCD1602_RW = P1^1;sbit LCD1602_EN = P1^5;#define LCD1602_DB P0/* 液晶忙碌等待 */void LCD1602Wait(){unsigned char sta;LCD1602_DB = 0xFF;//总线拉高,检测液晶状态字LCD1602_RS = 0;LCD1602_RW = 1;do{LCD1602_EN = 1;sta = LCD1602_DB;LCD1602_EN = 0;//避免液晶输出数据} while (sta & 0x80);//状态字最高位STA7 == 0空闲,1忙碌}/* 液晶写命令 */void LCD1602WriteCmd(unsigned char cmd){LCD1602Wait();LCD1602_RS = 0;LCD1602_RW = 0;LCD1602_EN = 0;LCD1602_DB = cmd;LCD1602_EN = 1;LCD1602_EN = 0;}/* 液晶写数据 */void LCD1602WriteData(unsigned char dat){LCD1602Wait();LCD1602_RS = 1;LCD1602_RW = 0;LCD1602_EN = 0;LCD1602_DB = dat;LCD1602_EN = 1;LCD1602_EN = 0;}/* 液晶初始化 */void InitalLCD1602(){LCD1602WriteCmd(0x38);LCD1602WriteCmd(0x0C);LCD1602WriteCmd(0x06);LCD1602WriteCmd(0x01);//清屏}/* 写数据到液晶上,字符串str,坐标(x, y),地址addr */void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str){unsigned char addr;if (y == 0){addr = 0x00 + x;}else{addr = 0x40 + x;}LCD1602WriteCmd(addr | 0x80);while (*str != '\0'){LCD1602WriteData(*str++);}}/*************************************************** *********************** @file keyboard.c* @author xr* @date 2014年5月8日22:11:33 -- 2014年5月9日12:03:49* @version V1.2.3* @brief 按键驱动单片机STC89C52RC MCU 晶振11.0592MHZ************************************************* ***********************/#include ;/* 按键输出输入端口定义 */sbit KEY_IN1 = P2^4;sbit KEY_IN2 = P2^5;sbit KEY_IN3 = P2^6;sbit KEY_IN4 = P2^7;sbit KEY_OUT1 = P2^3;sbit KEY_OUT2 = P2^2;sbit KEY_OUT3 = P2^1;sbit KEY_OUT4 = P2^0;extern unsigned char timer[9]; //分别表示跑表的各个位上的数字/* 按键当前状态 */unsigned char volatile keySta[4][4] = {{1, 1, 1, 1},{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};/* 按键对应标准PC键盘编码 */const unsigned char code keyCodeMap[4][4] = {{'1', '2', '3', 0x26}, /* 数字键 1, 2, 3 和向上键 */{'4', '5', '6', 0x25}, /* 数字键 4, 5, 6 和向左键 */{'7', '8', '9', 0x28}, /* 数字键 7, 8, 9 和向下键 */{'0', 0x1B, 0x0D, 0x27} /* 数字键 0 和向右键*/};bit stopflag = 0;//跑表走停标志位 0 停止,1运行void KeyAction(unsigned char keycode);void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);/* 按键驱动函数 */void KeyDriver(){/* 上一次按键的备份值 */static unsigned char keybackup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};for (i = 0; i < 4; i++){for (j = 0; j < 4; j++){if (keySta[i][j] != keybackup[i][j]) //当前按键状态和上一次的按键状态不同{ //按键有动作if (keybackup[i][j] != 0) //上一次按键是弹起 {KeyAction(keyCodeMap[i][j]); //当前按键是想、按下}keybackup[i][j] = keySta[i][j]; //备份当前按键值}}}}/* 按键扫描函数 */void KeyScan(){static unsigned char keyout = 0;//按键行索引static unsigned char keybuf[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};/* 按键消抖 */keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN4;/* 更新按键的值 */for (i = 0; i < 4; i++){if ((keybuf[keyout][i] & 0x1F) == 0x1F){//五次检测按键的值都是1keySta[keyout][i] = 1;}else if ((keybuf[keyout][i] & 0x1F) == 0x00) {//五次检测的按键值都是0keySta[keyout][i] = 0;}}/* 按键行索引++ */keyout++;keyout &= 0x03;//到4归零/* 根据按键索引选择行按键进行扫描 */switch (keyout){case 0: KEY_OUT1 = 0; KEY_OUT4 = 1;//选择第一行按键case 1: KEY_OUT2 = 0; KEY_OUT1 = 1;case 2: KEY_OUT3 = 0; KEY_OUT2 = 1;case 3: KEY_OUT4 = 0; KEY_OUT3 = 1;default: break;}}/* 按键动作函数 */void KeyAction(unsigned char keycode){unsigned char i = 0;if (keycode == 0x1B) //ESC{/* 跑表复位 */stopflag = 0;for (i = 0; i < 9; i++){timer[i] = 0;}LcdShowStr(2, 1, "0000000.00s"); LcdShowStr(10, 0, "reset!");}else if (keycode == 0x0D) //回车键跑表走停{if (stopflag == 0){stopflag = 1;LcdShowStr(10, 0, "start!");}else{stopflag = 0;LcdShowStr(10, 0, "stop! "); //多写入一个空格}}}。
今日做一个简单1602应用案例—-设计一个秒表。
要求:具有秒表启动和复位功能按键,秒表计时时间实时显示在LCD1602。
1.系统的硬件电路原理图:2.系统的程序设计2.1 头文件、全局变量和函数的声明#include “LCD_1602.h”#includeunsigned char Disp_Buffer[10];//这个可以稍微设置大一点,不影响结果显示,显示的时候遇到字符串结束标志就结束//定义二个位变量,分别对应按键开始按键和停止复位按键sbit key_set=P3^2;sbit key_reset=P3^3;unsigned char TIme_count=0;unsigned int TIme_S=0;void TImer_inial();//定时器初始化void delay(unsigned int i);//延时函数void start();//启动秒表void stop();//停止复位秒表void second_cal_show();//秒的计算与显示2.2 主程序主程序主要完成显示屏的初始化和初始化显示、定时器的初始化,注意定时初始化的时候不启动。
启动有开始按键控制,不按下开始键不启动定时器。
初始化完了,在while循环中调用start();确定是否启动定时器,调用stop();根据按键状态确定是否停止秒表并复位;调用second_cal_show(); 进行秒的计算和显示。
void main(){InitLcd1602();LcdShowStr(0, 0, “Current : 0 S”);LcdShowStr(0, 1, “Last: 0 S”);TImer_inial();while(1){start();stop();second_cal_show();}}2.3 子程序2.3.1 初始定时器:定时器T0工作在模式1,定时器定时时间0.02秒。
void timer_inial(){TMOD = 0X01;//TH0=0XB8;//定时0.02sTL0=0X00;}2.3.2 延时函数:软件延时,主要用按键软件消抖//延时函数void delay(unsigned int i){unsigned int k;for(k=0;k2.3.3 启动函数:检测按键是否按下,按键如果按下则启动定时器T0,并从0开始计数。
源程序代码://名称:用1602LCD设计的秒表//说明:首先按下K1键时开始计时,自此按下时暂停,第三次按下时继续累积计时,再次按下时停止计时,K2键用于清零秒表。
//#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define delayNOP ( ) ﹛_nop_( ); _nop_( ); _nop_( ); _nop_( );﹜//LCD控制函数void LCD_Initialize( );void LCD_Set_POS(uchar);void LCD_Write_Date(uchar);void Display_String(uchar﹡,uchar);sbit K1 = P1^0;sbit K2 = P1^1;sbit BEEP = P3^0;sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;uchar KeyCount = 0;uchar code msg1[] = ﹛〞Second Watch 0 〞﹜;uchar code msg2[] = ﹛〞>>>> 0 〞﹜;uchar code Prompts[] [16] ={﹛〞:: 1- - - - > 〞﹜,﹛〞:: 1- - - - > ::2 〞﹜,﹛〞:: 1 - >2 ::3- - > 〞﹜,﹛〞:: 1 - >2 ::3- - >4 〞﹜};// 计时缓冲与显示缓冲uchar Time_Buffer[] ={0,0,0,0};uchar LCD_Display_Buffer[]={〞00: 00: 00:00〞}; //// 蜂鸣器//void Beep ()﹛uchar i,j = 70;for (i = 0;i< 180;i++ )﹛while(--j);BEEP = ~BEEP;﹜BEEP = 0;﹜//// 延时//void DelayX(uint ms){uchar i;while(ms--) for (i= 0;i< 120;i++);﹜//// 显示计时//void Show_Second( ){uchar i;LCD_Set_POS(0x45); //设置LCD显示起点for(i = 3;i != 0xff ;i--);{//将两位整数的1/100s,秒,分,时转换为8位数字字符LCD_Display_Buffer[2﹡i+1] = Time_Buffer[i] / 10 + ˊ0 ˊ;LCD_Display_Buffer[2﹡i] = Time_Buffer[i] % 10 + ˊ0 ˊ;//在 = 3,2,1,0时分别显示时,分,秒,1/100sLCD_Writer_Date(LCD_Display_Buffer[2﹡i+1])LCD_Writer_Date(LCD_Display_Buffer[2﹡i])LCD_Writer_Date(ˊ: ˊ)}}//// Time0中断//Void Time0( ) interrupt 1 using 0{THO = -10000 / 256;TLO = -10000 % 256;Time_Buffer[0] ++if(Time_Buffer[0] == 100){Time_Buffer[0] = 0; Time_Buffer[1]++;}if(Time_Buffer[1] == 60) //秒{Time_Buffer[1] = 0; Time_Buffer[2]++;}if(Time_Buffer[2] == 60) //分{Time_Buffer[2] = 0; Time_Buffer[3]++;}if(Time_Buffer[3] == 24) //时Time_Buffer[3] = 0;}////主函数//void main( ){uchar i;IE = 0x82;TMOD = 0x01;THO = -10000 / 256;TLO = -10000 % 256;LCD_Initialize( );Display_String(msg1,0x00);Display_String(msg2,0x40);While(1){if(k1 == 0){DelayX(100);i = ++KeyCount;switch (i){case 1:case 3: TRO = 1;Display_String(Prompts[i-1],0);Break;case 2:case 4: TRO = 0;Display_String(Prompts[i-1],0);break;default:TRO = 0;break;}While (K1 == 0); // 等待释放K1键Beep( );}elseif(K2 == 0){TRO = 0;KeyCount = 0;for(i = 0;i < 4; i++)Time_Buffer [i] = 0; // 清零计数缓冲Display_String(msg1,0);Beep( );DelayX(100);while (K2 == 0); // 等待释放K2键}Show_Second( );}}//// 1602LCD显示驱动函数//#include 〈reg51.h〉#include 〈intrins.h〉#define uchar unsigned char#define uint unsigned int#define DellayNOP( )﹛_nop_( ); _nop_( ); _nop_( ); _nop_( );﹜sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;bit LCD_Busy_Check( );void LCD_Initialize( );void LCD_Set_POS(uchar);void LCD_Write_Command(uchar);void LCD_Write_ Date(uchar);//// 延时//void DelayMS(uint ms){uchar t;while(ms--) for (t =0;t < 120;t++);}//// LCD忙检查//bit LCD_Busy_Check( );{bit Rsult;LCD_RS = 0; LCD_RW = 1; LCD_EN = 1;DelayNOP( );Result = (bit)(p0 ﹠ 0x80);LCD_EN = 0return Result;}//// 向LCD写指令//void LCD_Write_Command(uchar cmd);{while(LCD_Busy_Check() );LCD_RS = 0; LCD_RW = 0; LCD_EN = 0;_nop_( ); _nop_( );pO = cmd; DelayNOP( );LCD_EN = 1;DelayNOP( );LCD_EN = 0;}//// 向LCD写数据//void LCD_Write_Date(uchar str);{while(LCD_Busy_Check() );LCD_RS = 1; LCD_RW = 0; LCD_EN = 0;pO = str; DelayNOP( ); LCD_EN = 1;DelayNOP( );LCD_EN = 0;}//// 初始化LCD//void LCD_Initialize( );{DelayMS(5); LCD_Write_Command(0x38);DelayMS(5); LCD_Write_Command(0x0c);DelayMS(5); LCD_Write_Command(0x06);DelayMS(5); LCD_Write_Command(0x01);DelayMS(5);}//// 设置显示位置//void LCD_Set_POS(uchar Poition){LCD_Write_Command(Position ︱ 0x80);}////显示函数,在LCD指定行上显示字符串//void Display_String(uchar﹡str,uchar LineNO){uchar k;LCD_Set_POS(LineNO);for (k = 0;k < 16;k++) LCD_Write_Date(str[k])}最新文件---------------- 仅供参考--------------------已改成-----------word文本--------------------- 方便更改赠人玫瑰,手留余香。