1602lcd显示的秒表
1602LCD显示的秒表 C语言程序
源程序代码://名称:用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]) }。
单片机LCD1602A秒表程序
ORG 0030H
MAIN:
ACALL SET_LCD
;LCD 初始化设置子程序
TOOP:
ACALL WR_THL ACALL RESET_18B20
;将报警上下线写入暂存寄存器 ;18B20 复位子程序
JNB FLAG,TOOP1
;18B20 不存在
ACALL MEU_OK
;显示"OK"菜单
ACALL RE_THL
6
嵌入式应用软件园,版权所有,请勿转载/销售。
第 2 章 程序功能
1.1 程序功能 程序中包含 LCM 用到的所有函数:初始化、写指令、写数据、判
忙碌、清屏幕。 在单片机的 P1 端口上接有 LCD 模块,用来显示计时时间。P3.3、
P3.4 端口分别接有按键 K1、K2,做秒表的计时控制按钮。 K1:暂停和起动秒表。只能暂停和起动二次。 K2:重新开始计时,计时值从 0 开始。
1.2 操作方法 1. 按一下 K2 键,准备计时。 2. 按一下 K1 键,计时开始。 3. 按一下 K1 键,暂停计时。 4. 按一下 K1 键,计时开始,在第 2 步的基础上累计时。 5. 按一下 K1 键,暂停计时。 6. 重复第 1~5 步,循环使用秒表。
7
1.3 原理图
嵌入式应用软件园,版权所有,请勿转载/销售。
MOV A,#0CCH
;跳过 ROM 匹配
ACALL WRITE_18B20
;调写入子程序
MOV A,#44H
;发出温度转换命令
ACALL WRITE_18B20
;调写入子程序
ACALL RESET_18B20
;调复位子程序
MOV A,#0CCH
;跳过 ROM 匹配
1602lcd显示的秒表(1)
目录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通信等。
第10章 用LCD1602显示的秒表设计
10.2 硬件设计
图10-2 用LCD1602显示的秒表电路原理图
3
10.3 程序设计
开始 初始化 初始显示
按键1是否按下? N
Y
按键1次数加1
按键1次数等于1、3
按键1次数等于2、4
开定时器
关定时器
显示第1次(或第3次) 按下的提示信息
显示第2次(或第4次) 按下的提示信息
break
break
秒计数单元=60? N
分计数单元=60? N
时计数单元=24? N
中断返回
Y 秒计数器清零,分加1
Y 分计数器清零,时加1
Y 时计数器清零
图10-4 定时器中断程序
5
10.4 仿真与实验结果
图10-5 1602LCD显示的秒表Proteus仿真电路
6
10.4 仿真与实验结果
图10-6 多孔板实验结果
第10章用LCD1602显示的秒表设计
10.1 项目任务 10.2 硬件设计 10.3 程序设计 10.4 仿真与实验结果
1
ቤተ መጻሕፍቲ ባይዱ
10.1 项目任务
用STC89C52单片机与LCD1602液晶显示器设计并制作一个秒 表,实现秒表的计时、暂停与清零等基本功能,每秒自动加1, 至59秒后再回到00,如此循环。运用“开始”、“暂停”、 “复位”按键实现对秒表计时的控制。
7
按键2是否按下? N
Y
关定时器
清零计时缓冲单元
显示清零提示信息
执行beep子程序
执行beep子程序
显示秒信息
图10-3 1602LCD显示的秒表主程序流程图
程序清单见课程设计指导书或配套仿真软件
4
功能完整的1602LCD时钟实验
功能完整的1602LCD时钟实验摘要本设计基于单⽚机技术原理,以单⽚机芯⽚STC89C52作为核⼼控制器,通过硬件电路的制作以及软件程序的编制,设计制作出⼀个多功能数字时钟系统。
单⽚机扩展的LCD显⽰器⽤来显⽰年、⽉、⽇、时、分、秒计数单元中的值。
整个设计包括两⼤部分: 硬件部分和软件部分,以单⽚机为核⼼, 配以⼀定的外围电路和软件。
硬件是整个系统的基础, 软件部分则要合理、充分地⽀持和使⽤系统的硬件, 从⽽完成系统所要完成的任务。
本设计采⽤LCD液晶显⽰,电路简单使⽤⼴泛。
该时钟系统主要由时钟模块、闹钟模块、液晶显⽰模块、键盘控制模块以及信号提⽰模块组成。
能够准确显⽰时间(显⽰格式为年:⽉:⽇:时时:分分:秒秒,24⼩时制),可随时进⾏时间调整,具有闹钟时间设置、闹钟开/关、⽌闹功能。
设计以硬件软件化为指导思想,充分发挥单⽚机功能,⼤部分功能通过软件编程来实现,电路简单明了,系统稳定性⾼。
单⽚机在这种情况下诞⽣了基于单⽚机电⼦时钟。
关键词:单⽚机 LCD1602 数字钟This design based on the single chip microcomputer principle, taking single-chip chip STC89C52 as core controller, through the hardware circuit and software production procedure formulation, designed and produced a multi-function digital clock system. SCM extended LCD display used to display date and time, minutes and seconds counting unit of values. The whole design includes two parts, hardware and software of, based on singlechip, match with certain peripheral circuit and software. Hardware is based in the whole system, the software part then be reasonable and fully support and use the system hardware, thus completing system to complete the task. This design USES the LCD, simple circuit is widely used. This clock system mainly by the clock module, alarm module, LCD module, keyboard control module and signal hint module. To accurately display the time (display format for years: month: day: always: component: seconds seconds, 24-hour system), available for time to adjust, with alarm time setting, alarm clock on/off, stop joking function. Design with hardware and software into guiding ideology, give full play to the SCM functions, most functions through software programming realize, circuit straightforward, stability of the system is high. SCM in this case was born based on single-chip electronic clock. Keywords: SCM LCD1602 digital clock前⾔数字钟是采⽤数字电路实现对时,分,秒数字显⽰的计时装置,⼴泛⽤于个⼈家庭,车站, 码头办公室等公共场所,成为⼈们⽇常⽣活中不可少的必需品,由于数字集成电路的发展和⽯英晶体振荡器的⼴泛应⽤,使得数字钟的精度,远远超过⽼式钟表, 钟表的数字化给⼈们⽣产⽣活带来了极⼤的⽅便,⽽且⼤⼤地扩展了钟表原先的报时功能。
lcd1602液晶显示数字钟
{
time[1]=0;//超过,分清零
time[0]++;//小时加1
if(time[0]>23)//是否超过23
{
time[0]=0; //小时清零
•}
•
}
时间计算
• void main(void)
•{
•
uchar i;
•
•
while(1)
•
{
• 计时
for(i=0;i<250;i++)//循环调用显示程序250次,实现1秒
display_code[]={0x3f,0x60,0x5b,0x4 f,0x66,0x5d,0x7d,0x07,0x7f,0x6f,0x 40}; • uchar time[4]={0,0,0,0}; //时间初 值全为0
• void delay(void);//延时0.5毫秒 •{
定时1秒
• uchar i;
• for(i=250;i>0;i--);
•}
• void display()
/*程序用于P0口接数码管的断码,P2接数码管的位码*/
•{
•
uchar i,k;
•
k=0x80;
//k初始化,指向第一位数码管
•
for(i=0;i<8;i++) //循环8次,i值为0~7
•
{
•
P2=0;
//关闭显示
•
P0=display_code[time[i]/10]; //输出十位数的断码
•
•
{
•
display();//调用动态显示,动态显示一次约4毫秒
•
}
带LCD1602液晶显示多功能数字时钟
带LCD1602液晶显示多功能数字时钟******************************************************************** ******************************************带LCD1602液晶显示的多功能数字时钟设计者: bluemanzyp(巨蟹座风云)硬件载体: EP2C8Q208 Amy电子FPGA学习板设计时间: 2009年4月1日,V1.0版最后修改时间: 2009年8月23日,V3.0版说明:1. 本设计全部采用数字电路和状态机的设计方法,没有采用任何CPU的IP 核。
2. 本设计的目的是为了练习状态机的设计技巧,以及方便生活^_^3. 有些EP2C8Q208 Amy电子FPGA学习板上的蜂鸣器是电平型的,给高电平就响,给低电平就不响,这样可能造成振铃的音质很差并且声音太小。
建议将蜂鸣器换成脉冲型的,给什么频率的信号,响什么频率的声音。
另外,最好测试一下蜂鸣器在哪些频率下声音最大,选择这些音量大的频率工作。
4. 如果要在其他型号的板子上用,请自己进行引脚锁定。
5. 系统需要的最小资源:占用1100个逻辑单元LC,8个按键,LCD1602液晶,3个拨码开关,3个发光二极管。
另外可以选配4×4小键盘,方便设置时钟。
******************************************************************** ******************************************多功能数字时钟的功能和特点:1. 上电1s复位功能,手动复位功能,复位会给出1s振铃信号;2. 基本时钟计时功能;3. 闹钟功能;4. 计数器倒计时功能;5. 整点报时功能;6. 闹钟具有懒人模式功能,如果启动懒人模式,闹钟振铃每隔一分钟就响一次,如果不启动懒人模式,闹钟振铃响一分钟就停止;7. 任意键关闭闹钟振铃功能(与懒人模式有关);8. 计数器自动装载功能,可实现00h:00m:15s---99h:59m:59s的循环定时振铃;9. 计数器手动启动功能;10. 一键启动或关闭闹钟或者计数器功能;11. 自动检验时钟、闹钟、和计数器设置数字的正确性,不正确的数字不能被输入系统;12. 液晶LCD1602显示,可同时查看时间和闹钟设置时间或者计数器时间;13. 菜单设置功能,人机界面友好;14. 30秒不操作,自动退出菜单功能;15. 8个基本按键:“?”、“?”、“?”、“?”、“确定”、“取消”、“闹钟开关alarm_sw”和“计数器开关cntalm_sw”完成全部操作;16. 可以插上4×4小键盘进行快速操作;17. 键盘自动消抖;18. 4×4小键盘快捷键;19. 用4×4小键盘设置时间或闹钟或计数器数字时,正确设置一位数字后,自动移到下一位数字进行设置;20. “?”、“?”键连击功能实现快速数字设定;21. 时钟后台计时功能,查看菜单不会影响时钟计时。
LCD1602液晶秒表C51程序
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! "); //多写入一个空格}}}。
1602LCD的指令说明及时序
1602LCD的指令说明及时序
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示模式设置
I/D:光标移动方向,高电平右移,低电平左移
S:屏幕上所有文字是否左移或者右移,高电平表示有效,低电平则无效。
时序如表所示
指令4:显示开关控制
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示
C:控制光标的开与关,高电平表示有光标,低电平表示无光标
B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
指令5:光标或显示移位
S/C:高电平时移动显示的文字,低电平时移动光标
指令6:功能设置命令
DL:高电平时为位总线,低电平时为8位总线;N:低电平时为单行显示,高电平时双行显示;F:低电平时显示5X7的点阵字符,高电平时显示5X10的点阵字符
指令7:字符发生器RAM地址设置
指令8:DDRAM地址设置
指令9:读忙信号和光标地址
BF:忙标志位,高电平表示忙,此时模块不能接收命令或者数据低电平表示不忙
指令10:写数据
指令11:读数据。
1602显示秒表
/**********************BST-V51实验开发板例程************************* 平台:BST-V51 + Keil U3 + STC89C52* 名称:1602显示秒表******************************************************************* ** 描述:** ** 上电后液晶屏先显示信息,接着按下K3,定时开始,再次按下** ** K3暂停,第3次按下显示累积计时,第4次按下暂停计时,任何时候按下K4* * ** 计数清零。
** ** *************************************************************************/#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar KeyCount=0;sbit K3 = P3^6;sbit K4 = P3^7;sbit BEEP = P2^3; //蜂鸣器uchar code cdis1[ ] = {" STOPWA TCH 0 "};uchar code cdis2[ ] = {" BST-V51 "};uchar code cdis3[ ] = {"TIME "};uchar code cdis4[ ] = {" BEGIN COUNT 1 "};uchar code cdis5[ ] = {" PAUSE COUNT 2 "};uchar code cdis6[ ] = {" BEGIN COUNT 3 "};uchar code cdis7[ ] = {" PAUSE COUNT 4 "};uchar code cdis8[ ] = {" "};sbit LCD_RS = P1^0;sbit LCD_RW = P1^1;sbit LCD_EN = P2^5;#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};uchar display[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};uchar display2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/********************************************************* 延时函数*********************************************************/void Delay(uint num)//延时函数{while( --num );}/********************************************************* 蜂鸣器响一声**********************************************************/ void beep(){unsigned char y;for (y=0;y<180;y++){BEEP=!BEEP; //BEEP取反Delay(70);}BEEP=1; //关闭蜂鸣器}/********************************************************* 延时函数1*********************************************************/ void delay1(int ms){unsigned char n;while(ms--){for(n = 0; n<250; n++){_nop_();_nop_();_nop_();_nop_();}}}/*********************************************************** ** 检查LCD忙状态* * lcd_busy为1时,忙,等待。
基于51单片机的用 LCD1602 显示时钟的程序
用LCD1602 显示的时钟2012-04-30 15:04有这样一个题目:求一个为51 单片机编写的LCD 电子时钟的设计,简单就好!希望说一下怎么设计这个时钟,都需要些什么东西,最重要的——把这个设计需要的程序写出来。
设计的任务:以单片机控制的时钟,在LCD 显示器上显示当前的时间。
设计的基本要求:1.使用文字型LCD 显示器显示当前时间。
2.显示格式为“时时:分分:秒秒”。
3.用4个功能键操作来设置当前时间。
各个功能键的功能如下:K1:进入设置现在的时间。
K2:设置小时。
K3:设置分钟。
K4:确认完成设置。
4. 程序执行后工作指示灯LED 闪烁,表示程序开始执行,LCD 显示“00:00:00”,然后开始计时。
题目链接:/question/416705477.html//==================================================提到设计时钟,很多人都想到了时钟芯片DS1302,都说它简单、准确。
其实,这是个误区。
仅仅使用一般的单片机,简单的编程,达到相同DS1302 的准确度,并不是难事。
如果不要求计算平闰年、不要求分清大小月、不要求计算星期几,只是要求一个简单的时钟(及日历),用DS1302,就是自寻烦恼。
大家可以打开题目链接,看看其中的一些答案,就可以看出使用DS1302 是多么的繁琐了,简直就是一场噩梦。
做而论道以前就使用普通的单片机和LCD1602 设计过《时钟与日历》,程序设计的非常合理,时间精度就完全取决于晶振的精度。
设计出来的时钟,几个月都差不上一秒。
针对这个题目,做而论道翻出了以前的设计,删节了一些不需要的功能,设计出了符合题目要求的时钟,用PROTEUS 仿真截图如下:程序用C 语言编写,全部代码如下://---------------------------------------------------#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define KEY_IO P3#define LCD_IO P0sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;sbit SPK = P1^2;sbit LED = P2^4;bit new_s, modify = 0;char t0, sec = 50, min = 59, hour = 23;char code LCD_line1[] = "Designed by ZELD"; char code LCD_line2[] = "Timer: 00:00:00 "; char Timer_buf[] = "23:59:50";//---------------------------------------------------void delay(uint z){uint x, y;for(x = z; x > 0; x--) for(y = 100; y > 0; y--);//---------------------------------------------------void W_LCD_Com(uchar com) //写指令{LCD_RS = 0; LCD_IO = com; // LCD_RS和R/W都为低电平时,写入指令LCD_EN = 1; delay(5); LCD_EN = 0; //用EN输入一个高脉冲}//---------------------------------------------------void W_LCD_Dat(uchar dat) //写数据{LCD_RS = 1; LCD_IO = dat; // LCD_RS为高、R/W为低时,写入数据LCD_EN = 1; delay(5); LCD_EN = 0; //用EN输入一个高脉冲}//---------------------------------------------------void W_LCD_STR(uchar *s) //写字符串{while(*s) W_LCD_Dat(*s++);}//---------------------------------------------------void W_BUFF(void) //填写显示缓冲区{Timer_buf[7] = sec % 10 + 48; Timer_buf[6] = sec / 10 + 48;Timer_buf[4] = min % 10 + 48; Timer_buf[3] = min / 10 + 48;Timer_buf[1] = hour % 10 + 48;Timer_buf[0] = hour / 10 + 48;W_LCD_Com(0xc0 + 7); W_LCD_STR(Timer_buf);}//---------------------------------------------------uchar read_key(void){uchar x1, x2;KEY_IO = 255;x1 = KEY_IO;if (x1 != 255) {delay(100);x2 = KEY_IO;if (x1 != x2) return 255;while(x2 != 255) x2 = KEY_IO;if (x1 == 0x7f) return 0;else if (x1 == 0xbf) return 1;else if (x1 == 0xdf) return 2;else if (x1 == 0xef) return 3;else if (x1 == 0xf7) return 4;}return 255;//---------------------------------------------------void Init(){LCD_RW = 0;W_LCD_Com(0x38); delay(50);W_LCD_Com(0x0c);W_LCD_Com(0x06);W_LCD_Com(0x01);W_LCD_Com(0x80); W_LCD_STR(LCD_line1);W_LCD_Com(0xC0); W_LCD_STR(LCD_line2);TMOD = 0x01; //T0定时方式1TH0 = 0x4c;TR0 = 1; //启动T0PT0 = 1; //高优先级, 以保证定时精度ET0 = 1;EA = 1;}//---------------------------------------------------void main(){uint i, j;uchar Key;Init();while(1) {//-------------------------------if (new_s) { //如果出现了新的一秒, 修改时间new_s = 0; sec++; sec %= 60;if(!sec) { min++; min %= 60;if(!min) { hour++; hour %= 24;}}W_BUFF(); //写显示//-------------------------------if (!sec && !min) { //整点报时for (i = 0; i < 200; i++) {SPK = 0; for (j = 0; j < 100; j++);SPK = 1; for (j = 0; j < 100; j++);} }}//-------------------------------Key = read_key(); //读出按键switch(Key) { //分别处理四个按键case 0: modify = 1; break;case 1: if(modify) {min++; min %= 60; W_BUFF(); break;}case 2: if(modify) {hour++; hour %= 24; W_BUFF(); break;}case 3: modify = 0; break;} }}//---------------------------------------------------void timer0(void) interrupt 1 //T0中断函数, 50ms执行一次{TH0 = 0x4c;t0++; t0 %= 20; //20, 一秒钟if(t0 == 0) {new_s = 1; LED = ~LED;}if(modify) LED = 0;}//===================================================呵呵,全部程序,也不过120 行左右。
1602液晶显示(年月日时分秒星期)
电子钟—1602液晶显示(年月日时分秒星期)/* 以下是电子钟的c51源程序,用1602液晶显示,虽然程序很庞大,但容易看懂。
改程序花了我两三天的时间才弄好的,现在放在此分享。
*/#include<AT89X52.H>#include<intrins.h>#define uchar unsigned char#define uint unsigned int#define T 49998#define T1 64536sbit rs=P2^0;sbit rw=P2^1;sbit en=P2^2;uchar key,n,loca=0,allow=0,cout;uchar week;uchar time[6]={0,6,15,12,30,0}; //对应、月、日、时、分、秒?uint year=2009;void delay(uint ms){uint i;for(;ms>0;ms--){for(i=246;i>0;i--);}}void timer0() interrupt 1{TH0=(65536-T)/256;TL0=(65535-T)%256;n++;}void time_addsec(){if(20<=n){n=0;time[5]++; //产生秒}}uchar key_scan(){uchar i,j,key,temp;uchar code scan[]={0xfe,0xfd,0xfb,0xf7};uchar code keyb[]={0x7e,0xbe,0xde,0xee,0x7d,0xbd,0xdd,0xed,0x7b,0xbb,0xdb,0xeb,0x77,0xb7,0xd7,0xe7};for(i=0;i<4;i++){P3=scan[i];_nop_();temp=P3;if(temp!=scan[i]){for(j=0;j<16;j++){if(keyb[j]==P3){delay(50);// while(keyb[j]==P3);//松手操作// delay(20);// while(keyb[j]==P3);key=j+1;break;}if(keyb[j] != P3){key=0;}}}}return key;}bit lcd_bz()//1602检忙{bit v;rs=0;rw=1;en=1;_nop_();v=(bit)(P0&0x80);en=0;return v;}void lcd_wcmd(uchar cmd)//1602写命令{while(lcd_bz());rs=0;rw=0;en=0;_nop_();P0=cmd;_nop_();en=1;_nop_();_nop_();en=0;_nop_();rs=0;}void lcd_wdat(uchar dat)//1602写数据{while(lcd_bz());rs=1;rw=0;en=0;_nop_();P0=dat;_nop_();en=1;_nop_();;en=0;}void lcd_wstr(uchar *str)//1602写字符串{uchar i;for(i=0;str[i]!='\0';i++){lcd_wdat(str[i]);}}void lcd_pos(uchar pos)//光标定位{while(lcd_bz());lcd_wcmd(pos|0x80);}/*void lcd_cur(){switch(loca){case 0 : lcd_pos(0x46); case 1 : lcd_pos(0x49); case 2 : lcd_pos(0x05); case 3 : lcd_pos(0x08); case 4 : lcd_pos(0x0b); }}*/void lcd_rmove()//光标右移{if(1==allow){if(loca >= 0 && loca < 5) {loca++;}}}void lcd_lmove(){if(1==allow){if(loca > 0 && loca <= 5) {loca--;}}}void lcd_addtime()//调时间加{uint dat ;if(1==allow)switch(loca){case 0 :{dat=year;dat++;year=dat;delay(100);break;}case 1 :{dat=time[1];dat++;if(dat>12)dat=1;time[1]=dat;delay(100);break; }case 2 :{dat=time[2];dat++;if(dat>30)dat=1;time[2]=dat;delay(100);break; }case 3 :{dat=time[3];dat++;if(dat>24)dat=1;time[3]=dat;delay(100);break; }case 4 :{dat=time[4];dat++;if(dat>60)dat=1;time[4]=dat;delay(100);break; }case 5 :{dat=time[5];dat++;if(dat>60)dat=1;time[5]=dat;delay(100);break; }}}void lcd_detime()//调时间减{int dat ;if(1==allow)switch(loca){case 0 :{dat=year;dat--;if(dat<0)dat=2000;year=dat;delay(100);break;}case 1 :{dat=time[1];dat--;if(dat<0)dat=12;time[1]=dat;delay(100);break; }case 2 :{dat=time[2];dat--;if(dat<0)dat=30;time[2]=dat;delay(100);break; }case 3 :{dat=time[3];dat--;if(dat<0)dat=23;time[3]=dat;delay(100);break; }case 4 :{dat=time[4];dat--;if(dat<0)dat=59;time[4]=dat;delay(100);break; }case 5 :{dat=time[5];dat--;if(dat<0)dat=59;time[5]=dat;delay(100);break;}}}void function(){uchar key=key_scan();switch(key){case 5 : lcd_lmove();break;case 6 : lcd_rmove();break;case 7 : lcd_addtime();break;case 8 : lcd_detime();break;case 9 : lcd_wcmd(0x0f);allow=1;break; //显示光标case 10 : lcd_wcmd(0x0c);allow=0;break; //关闭光标}}bit year_tell() //判断是否闰年是1 否0{if((year%4 == 0 && year%100 !=0) || year%400 == 0) return 1;else return 0;}uint count1(uint year , uchar mon , uchar day)//以下count1到count3都是为了计算对应的星期{uint m;switch(mon){case 1 : m=366-day; break;case 2 : m=335-day; break;case 3 : m=306-day; break;case 4 : m=275-day; break;case 5 : m=245-day; break;case 6 : m=214-day; break;case 7 : m=184-day; break;case 8 : m=153-day; break;case 9 : m=122-day; break;case 10 : m=92-day; break;case 11 : m=61-day; break;case 12 : m=31-day; break;default : ;}if(!(year%4 == 0 && year%100 != 0 || year%400 == 0)){if(mon<=2){m=m-1;}}return(m);}uint count2(uint year , uchar mon , uchar day){uint m;if(year%4 == 0 && year%100 != 0 || year%400 == 0){m=366-count1(year , mon , day);}else{m=365-count1(year , mon , day);}return m;}uint count3(uint year1 , uint year2){uint m=0;uchar i;uint n=year2-year1;for(i=1;i<n;i++){if((year1+i)%4 == 0 && (year1+i)%100 != 0 || (year1+i)%400 == 0) {m+=366;}else{m+=365;}}return m;}uchar week_tell()//判断对应的星期{uchar w;w=(count1(1901,1,7)+count2(year,time[1],time[2])+count3(1901,year)+1)%7; if(w!=0)return w;else return 7;}void timecount()//时间计算{if(time[5]>=60) //sec{time[5]=0;time[4]++;}if(time[4]>=60)//min{time[4]=0;time[3]++;}if(time[3]>=24)//hour{time[3]=0;time[2]++; //day}switch(time[1]) //mon{case 1 : if(time[2]>=31){time[2]=0; time[1]++;}case 2 :if(1==year_tell()){if(time[2]>29){time[2]=0; time[1]++;}}else{if(time[2]>28){time[2]=0; time[1]++;}}case 3 : if(time[2]>=31){time[2]=0; time[1]++;}case 4 : if(time[2]>=30){time[2]=0; time[1]++;}case 5 : if(time[2]>=31){time[2]=0; time[1]++;}case 6 : if(time[2]>=30){time[2]=0; time[1]++;} case 7 : if(time[2]>=31){time[2]=0; time[1]++;} case 8 : if(time[2]>=31){time[2]=0; time[1]++;} case 9 : if(time[2]>=30){time[2]=0; time[1]++;} case 10 : if(time[2]>=31){time[2]=0; time[1]++;} case 11 : if(time[2]>=30){time[2]=0; time[1]++;} case 12 : if(time[2]>=31){time[2]=0; time[1]++;} }if(time[1]>12){time[1]=0;year++;}}/*void lcd_clear(){lcd_wcmd(0x01);_nop_();}*/void lcd_display(uchar p)//液晶显示{uchar i,j;uchar str_com[14];str_com[13]=year/1000;str_com[12]=(year/100)%10;str_com[11]=(year%100)/10;str_com[10]=year%10;str_com[9]=time[1]/10;str_com[8]=time[1]%10;str_com[7]=time[2]/10;str_com[6]=time[2]%10;str_com[5]=time[3]/10;str_com[4]=time[3]%10;str_com[3]=time[4]/10;str_com[2]=time[4]%10;str_com[1]=time[5]/10;str_com[0]=time[5]%10;if(0==p)//非设定状态{lcd_pos(0x07);for(i=0,j=0;i<8;i++,j++){if(2==i || 5==i){lcd_wdat(':');j--;}elselcd_wdat(str_com[j]+48);}lcd_pos(0x49);for(i=6,j=6;i<16;i++,j++){if(8==i || 11==i){lcd_wdat('-');j--;}elselcd_wdat(str_com[j]+48);}delay(1 );lcd_wcmd(0x06);lcd_pos(0x4c);switch(week_tell()){case 1 : lcd_wstr("Mon");break;case 2 : lcd_wstr("Tue");break;case 3 : lcd_wstr("Wen");break;case 4 : lcd_wstr("Thu");break;case 5 : lcd_wstr("Fri");break;case 6 : lcd_wstr("Sat");break;case 7 : lcd_wstr("Sun");break;}delay(1 );lcd_wcmd(0x04);}else if(1==p)//时间设定状态{lcd_pos(0x07);lcd_wdat(str_com[0]+48);lcd_wdat(str_com[1]+48);switch(loca) //下面是让光标定在选择位,以便光标稳定的闪烁{case 0 : lcd_pos(0x43);break; case 1 : lcd_pos(0x46);break; case 2 : lcd_pos(0x49);break; case 3 : lcd_pos(0x01);break; case 4 : lcd_pos(0x04);break; case 5 : lcd_pos(0x07);break; }}}void lcd_init()//液晶初始化{delay(15);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x38);while(lcd_bz());lcd_wcmd(0x0e);while(lcd_bz());lcd_wcmd(0x01);}void init(){TMOD=0x11;TH0=(65536-T)/256;TL0=(65536-T)%256;TH1=T1;TL1=T1;EA=1;TR0=1;ET0=1;TR1=0;ET1=1;}main(){init();lcd_init();while(1){// delay(3);// lcd_clear();delay(1 );lcd_wcmd(0x04);time_addsec();timecount();function();lcd_display(1);cout++;if(cout>=50){cout=0;lcd_display(0);}}}//程序到此结束,估计看了有点晕,不过没关系,程序是没有错的,定时很准,经调试在几个小时之后也达到分秒不差,晶振是12M。
通过51单片机及lcd1602实现可记录十组的秒表功能
#include<stdlib.h> //包含随机函数rand()的定义文件
#include<intrins.h> //包含_nop_()函数定义的头文件
sbit RS=P2^6; //寄存器选择位,将RS位定义为P2.0引脚
***************************************************/
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
unsigned char BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
最新1602LCD显示秒表汇编汇总
1602L C D显示秒表汇编//******************************************************************** *******//; K2=P3.3 K4=P3.5;* 1602LCD显示秒表 *;* K2 --- 控制按键 *;* 按一下计时,再按一下暂停计时 *;*;* K4 --- 清零按键: *;* 在任何状态下,按一下K4,均可清零。
*;* *;---------------------------------------;晶振 11.0592M;定时器0,方式1;计时中断程序每隔10ms中断一次;---------------------------------------TLOW EQU 0CH ;定时器初值THIGH EQU 0DCHHOUR EQU 30HMIN EQU 31HSEC EQU 32HSEC0 EQU 33H ;10ms计数值KEY_D EQU 34H ;为键当前的端口状况KEY_S EQU 35H ;为键上次的端口状况X EQU 36H ;LCD 地址变量KEY_C EQU 37H ;键计数单元;K1 EQU P3.2K2 EQU P3.3;K3 EQU P3.4K4 EQU P3.5BEEP EQU P2.4RS EQU P3.5 ;LCD控制端口定义 RW EQU P3.6EN EQU P3.7;---------------------------------------------------- ORG 0000HJMP STARTORG 0BHJMP T0_INT;---------------------------------------------------- START: MOV R3,#00HMOV SP,#60HCLR ENCALL SET_LCDCALL INIT ;初始化变量MOV KEY_S,#01HCALL INIT_TIMER ;初始化定时器 ; CALL MENULOOP: CALL CONV ;时间计数处理CALL SKEYMOV KEY_S,KEY_DJZ XPMOV A, KEY_SJB ACC.0,XPCLR AMOV B,AINC R3MOV A,R3MOV B,#2DIV ABMOV A,BCALL BZJZ XPPSETB TR0 ;启动中断MOV DPTR,#MADJ ;显示执行信息CALL P_KEYSJMP XPXPP:CLR TR0MOV DPTR,#MADJ1CALL P_KEYXP: JB K4,LOOP ;判清零键是否按?MOV R3,#00HCALL BZJMP START;-----------------------------------------------------P_KEY: MOV A,#1 ;第一行显示CALL LCD_PRINTRET;-------------------------------------------------------SKEY: CLR A ;判是否有键按下子程序MOV KEY_D,AMOV C,K2RLC AORL KEY_D,AMOV A,KEY_DXRL A,KEY_S ;有键按下,A 中内容不为零 RET;--------------------------------------------------------;LMESS1: DB " ",0 ;LCD 第一行显示消息;LMESS2: DB "TIME ",0 ;LCD 第二行显示消息;--------------------------------------------------------INIT: CLR A ;初始化控制变量MOV SEC,AMOV MIN,AMOV HOUR,AMOV KEY_D,AMOV KEY_S,ASETB BEEPCLR TR0RET;------------------------------------------------------------INIT_TIMER: ;初始化定时器接口MOV TMOD,#01H ;设置定时器0 工作模式为模式1 MOV IE, #82H ;启用定时器0 中断产生MOV TL0,#TLOWMOV TH0,#THIGHRET;-------------------------------------------------------------T0_INT:PUSH ACC ;定时器0计时中断程序MOV TL0,#TLOWMOV TH0,#THIGHINC SEC0MOV A,SEC0 ;10ms 计数值加1CJNE A,#100,TTMOV SEC0,#0INC SEC ;秒加1MOV A,SECCJNE A,#60,TTINC MIN ;分加1MOV SEC,#0MOV A,MINCJNE A,#60,TTINC HOUR ;时加1MOV MIN,#0MOV A,HOURCJNE A,#24,TTMOV SEC,#0 ;秒、分、时单元清0MOV MIN,#0MOV HOUR,#0TT: POP ACCRETI;-------------------------------------------------------; 在第二行显示数字;-------------------------------------------------------SHOW_DIG2: ;在 LCD 的第二行显示数字 MOV B,#10 ;设置被除数DIV AB ;结果A存商数,B存余数ADD A,#30H ;A为十位数,转换为字符PUSH B ;B放入堆栈暂存MOV B,X ;设置 LCD 显示的位置CALL LCDP2 ;由 LCD 显示出来POP B ;MOV A,B ;B为个位数ADD A,#30H ;转换为字符INC X ;LCD 显示位置加1MOV B,X ;设置 LCD 显示的位置CALL LCDP2 ;由 LCD 显示出来RET;-------------------------------------------;转换为 ASCII 码并显示;-------------------------------------------CONV:MOV A,HOUR ;加载小时数据MOV X,#5 ;设置位置CALL SHOW_DIG2 ;显示数据INC X ;MOV A,#':' ;MOV B,X ;CALL LCDP2 ;MOV A,MIN ;加载分钟数据INC X ;设置位置CALL SHOW_DIG2 ;显示数据INC X ;MOV A,#':' ;MOV B,X ;CALL LCDP2 ;MOV A,SEC ;加载秒数数据INC X ;设置位置CALL SHOW_DIG2 ;显示数据INC X ;MOV A,#':' ;MOV B,X ;CALL LCDP2 ;MOV A,SEC0 ;加载秒数数据INC X ;设置位置CALL SHOW_DIG2RET;---------------------------------------------------------; LCD CONTROL;---------------------------------------------------------SET_LCD: ;对 LCD 做初始化设置及测试 CLR ENCALL INIT_LCD ;初始化 LCDMOV R5,#10CALL DELAYMOV DPTR,#MMENU ;指针指到显示消息1MOV A,#1 ;显示在第一行CALL LCD_PRINTMOV DPTR,#SLF ;指针指到显示消息2MOV A,#2 ;显示在第二行CALL LCD_PRINTRET;----------------------------------------------------------INIT_LCD1: ;LCD 控制指令初始化MOV A,#38H ;双列显示,字形5*7点阵CALL WCOM ;call delay1MOV A,#0CH ;开显示,显示光标,光标不闪烁 CALL WCOM ;call delay1MOV A,#01H ;清除 LCD 显示屏CALL WCOM ;call delay1RET;---------------------------------------------------------- ENABLE: ;写指令CLR RS ;RS=L,RW=L,E=高脉冲CLR RW ;D0-D7=指令码SETB ENACALL DELAY1CLR ENRET;----------------------------------------------------------LCD_PRINT: ;在LCD的第一行或第二行显示字符CJNE A,#1,LINE2 ;判断是否为第一行LINE1: MOV A,#80H ;设置 LCD 的第一行地址 CALL WCOM ;写入命令CALL CLR_LINE ;清除该行字符数据MOV A,#80H ;设置 LCD 的第一行地址CALL WCOM ;写入命令JMP FILLLINE2: MOV A,#0C0H ;设置 LCD 的第二行地址 CALL WCOM ;写入命令CALL CLR_LINE ;清除该行字符数据MOV A,#0C0H ;设置 LCD 的第二行地址CALL WCOMFILL: CLR A ;填入字符MOVC A,@A+DPTR ;由消息区取出字符CJNE A,#0,LC1 ;判断是否为结束码RETLC1: CALL WDATA ;写入数据INC DPTR ;指针加1JMP FILL ;继续填入字符RET;-------------------------------------------------------CLR_LINE: ;清除该行 LCD 的字符MOV R0,#16CL1: MOV A,#' 'CALL WDATADJNZ R0,CL1RET;-------------------------------------------------------DE: MOV R7,#250 ;延时500微秒DJNZ R7,$RET;-------------------------------------------------------EN1:CLR RWSETB EN ;短脉冲产生启用信号CALL DECLR ENCALL DERET;------------------------------------------------------INIT_LCD: ;8位I/O控制 LCD 接口初始化 MOV P1,#38H ;双列显示,字形5*7点阵call enablecall delay1MOV P1,#38H ;双列显示,字形5*7点阵call enablecall delay1MOV P1,#38H ;双列显示,字形5*7点阵call enablecall delay1CALL INIT_LCD1RET;-----------------------------------------------------WCOM: ;以8位控制方式将命令写至LCD MOV P1,A ;写入命令call enableRET;-----------------------------------------------------WDATA: ;以8位控制方式将数据写至LCD MOV P1,A ;写入数据SETB RS ;设置写入数据CALL EN1RET;-----------------------------------------------------;第二行显示字符;----------------------------------------------------- LCDP2: ;在LCD的第二行显示字符 PUSH ACC ;MOV A,B ;设置显示地址ADD A,#0C0H ;设置LCD的第二行地址 CALL WCOM ;写入命令POP ACC ;由堆栈取出ACALL WDATA ;写入数据RET;---------------------------------------------------- DELAY: ;延时10MSMOV R6,#50D1: MOV R7,#100DJNZ R7,$DJNZ R6,D1DJNZ R5,DELAYRET;----------------------------------------------------- DELAY1: ;延时5MSMOV R6,#25D2: MOV R7,#100DJNZ R7,$DJNZ R6,D2RET;----------------------------------------------------- BZ: ;蜂鸣器MOV R6,#100B1: CALL DEXCPL BEEPDJNZ R6,B1MOV R5,#10CALL DELAYRETDEX: MOV R7,#180DE1: NOPDJNZ R7,DE1RET;------------------------------------------------- MMENU: DB " SECOND-CLOCK 0 ",0slf: DB "TIME ",0 ;LCD 第二行显示消息MADJ: DB " BEGIN COUNT ",0MADJ1: DB " PAUST COUNT ",0END。
基于LCD1602的简易秒表的设计与实现
数字电路与逻辑设计实验报告学院:电子工程学院班级: 2014211212姓名:学号:班内序号:一、设计课题的任务要求简易秒表的设计与实现设计制作一个计时精度为百分之一秒的计时秒表基本要求:1.用LCD1602液晶屏显示计时;2.秒表计时长度为23小时59分59.99秒;3.用BTN0作为启动/停止开关;4.用BTN1作为复位开关,在任何情况下,只要按下复位开关,秒表都要无条件执行清零操作。
提高要求:1.增加定时器功能,可根据用户设定的时间进行倒计时,时间到0后蜂鸣器报警提示;2.自拟其他功能。
二、系统设计(设计思路、总体框图、分块设计)1.设计思路:①分别设计6进制计数器、10进制计数器和24进制计数器用于秒表计时部分。
具体来说:将两个10进制计数器级联分别作为秒表的十分秒位(最小单位为0.1秒)和百分秒位(最小单位为0.01秒);将一个10进制计数器和6进制计数器级联,分别作为秒表秒钟部分的个位(最小单位为1秒)和十位(最小单位为10秒);再将一个10进制计数器和6进制计数器级联,分别作为秒表分钟部分的个位(最小单位为1分钟)和十位(最小单位为10分钟);将24进制计数器作为秒表小时部分,其中低位输出作为秒表小时部分的个位(最小单位为1小时),高位输出作为秒表小时部分的十位(最小单位为10小时)。
最后把秒表百分秒、十分秒部分、秒钟部分、分钟部分、小时部分这四部分级联起来便构成了简易数字秒表的计时部分。
②将各个计数器部分的输出信号通过译码模块,变成LCD1602液晶屏能够读取并从而显示相关字符的8位二进制数据。
再定义一个存储器ram,存储各个计数器部分的输出信号经过译码部分之后得到的数据,然后将这个存储器ram代表的数据在LCD1602液晶屏上显示。
③考虑到秒表的最小计时长度为0.01秒(频率为100HZ),如果系统时钟设置为50MHZ,则需要500000分频;实验时发现LCD1602液晶屏的时钟在1KHZ时,显示效果较好,故需要在系统时钟为50MHZ的基础上进行50000分频。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录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电源供电,外围电路配置简单,价格便宜,具有很高的性价比。
2 课题方案设计2.1系统设计目的设计一个单片机控制的秒表系统,利用单片机的定时器计数器定时和计数的原理,结合显示电路、LCD液晶显示器以及按键来设计计数器。
将软、硬件有机地结合起来,使得系统能够正确的进行加、减计时,液晶显示器能够正确的显示时间。
使学生增进对单片机的感性认识,加深对单片机理论方面的理解。
掌握单片机的内部功能模块的应用,如定时器/计数器、中断、片内外存贮器、I/O口、串行口通讯等。
同时了解和掌握单片机应用系统的软硬件设计过程、方法及实现,为以后设计和实现单片机应用系统打下良好基础。
(1)使用集成数字电路或单片机作为主控制芯片(2)使用LCD来显示现在的时间,显示格式为:上行显示:Current Time;下行显示:时时:分分:秒秒;(3)具有调整日期与时间的功能。
2.2系统结构模块论证系统结构如图2-1所示。
图2-1 用1602LCD设计的秒表系统框图2.2.1 显示部分显示部分是本次设计的重要部分,一般有以下两种方案:方案一:采用LED显示,在单片机应用系统中最常用的LED数码管为7段数码管,可利用LED显示器灵活地构成所要求位数的显示,分静态显示和动态显示。
对于静态显示方式,所需的译码驱动装置很多,引线多而复杂,且可靠性也较低。
而对于动态显示方式,虽可以避免静态显示的问题,但设计上如果处理不当,易造成亮度低,有闪烁等问题。
方案二:采用LCD显示。
是一种低功耗显示器件,具有显示内容丰富、体积小、重量轻、寿命长、使用方便、安全省电等优点,在计算器、万用表、袖珍式仪表和低功耗微机应用系统中得到广泛使用。
其显示的质量高,每个显示器每一点在收到信号后就一直保持那种彩色和亮度,恒定发光,而不像阳极射线管显示器那样刷新亮点,画面质量高且不闪烁。
鉴于上述原因,我们采用方案二。
3 系统硬件设计3.1 总体设计本系统中,硬件电路主要有电源电路,晶振电路,复位电路,显示电路以及一些按键电路等,本系统采用STC89C52单片机为中心器件,利用定时器计数器定时和记数的原理,结合硬件电路如电源电路,晶振电路,复位电路,显示电路,蜂鸣器电路以及一些按键电路等来设计计数器,将软、硬件有机地结合起来。
硬件系统采用PROTEUS功能来实现,简单且易于观察,在仿真中就可以观察到实际的工作状态。
3.2 单片机运行的最小系统3.2.1 电源电路电源电路是系统最基本的部分,任何电路都离不开电源部分,随着半导体工艺的发展,稳压电路也采用集成电路器件来制成。
可采用独立的稳压电源。
这种供电方式的优点是稳压可靠,且有各种成熟电路可供选择。
由集成稳压器具有体积小,外界线路简单,使用方便,工作可靠等优点。
因此,在各种电子设备中应用十分普遍,为了跟上时代的发展,可采用W7800系列三端稳压器,主要利用它的输出电压是固定的在使用中不能进行调整等优点。
但这次设计为了电源的简洁,采用了USB接口为循环彩灯系统电路提供稳定5V 的工作电压这样能使整体电路更简洁,更节约成本,从而减少硬件设计的复杂性。
3.2.2晶振电路STC89C52内部的振荡电路是一个高增益反相放大器,引脚RXD和TXD分别是此反向振荡放大器的输入端和输出端。
该反向放大器可以配置为内部方式的片内振荡器。
如图2-2 所示,这里选用12MHE的内部振荡方式,电路如下:电容器C1,C2起稳定振荡频率,快速起振的作用,C1,C2可在20~100PF之间取,这里取30PF,接线时要使晶振振荡器尽可能接近单片机。
图3-1晶体振荡电路3.2.3复位电路采用上电+按键复位电路,上电后,由于电容充电,使RST 持续一段时间高电平时间。
当单片机已在运行之中时,按下复位按键也能使RST 持续一段时间的高电平,从而实现上电加开关复位的操作。
这不仅能时单片机复位,而且还能使单片机的外围芯片也同时复位,当程序出现错误时,可以随时使电路复位。
复位是单片机的初始化操作。
其主要功能是把PC 初始化为0000H ,使单片机从0000H 单元开始执行程序。
除了进入系统的正常初始化之外,当由于程序运行出错或操作错误使系统处于死锁状态时,为摆脱困境,也需按复位键重新启动。
除PC 之外,复位操作还对其他一些寄存器有影响,它们的复位状态如表1所示。
表1 一些寄存器的复位状态寄存器 复位状态 寄存器 复位状态 PC 0000H TCON 00H ACC 00H TL0 00H PSW 00H TH0 00H SP 07H TL1 00H DPTR 0000H TH1 00H P0-P3 FFH SCON 00H IP XX000000B SBUF 不定 IE 0X000000BPCON 0XXX0000BTMOD00H因STC89C52单片机需高电平(3.7~5.5V )复位,且复位时流入单片机的电流不能超过10mA 。
具体参数:根据所需要的复位参数可得当按下SW 键时出现两个机器周期的高电平在单片机REST 端产生的压降等于:221R R R V CC•+=V 17.4102.015=Ω•Ω+K K K V )(上电自动复位图3-2 复位电路3.3 显示电路显示电路既可以选用液晶显示器,也可以选用数码管显示,我们采用液晶显示电路1602LCD引脚接口说明3.3.1引脚说明:3脚:VL,液晶显示偏压信号,用于调整LCD1602的显示对比度,一般会外接电位器用以调整偏压信号,此脚电压为0时可以得到最强的对比度。
4脚:RS,数据/命令选择端,当此脚为高电平时,可以对1602进行数据字节的传输操作,而为低电平时,则是进行命令字节的传输操作。
命令字节,即是用来对LCD1602的一些工作方式作设置的字节;数据字节,即使用以在1602上显示字节。
5脚:R/W,读写选择端。
当此脚为高电平可对LCD1602进行读数据操作,反之进行写数据操作。
6脚:E,使能信号,其实是LCD1602的数据控制时钟信号,利用该信号的上升沿实现对LCD1602的数据传输。
7~14脚:8位并行数据口,使得对LCD1602的数据读写大为方便。
基本操作时序:(1)读状态:输入:RS=L,RW=H,E=H;输出:D0~D7=状态字(2)写指令:输入:RS=L,RW=L,D0~D7=指令码,E=高脉冲;输出:无(3)读数据:输入:RS=H,RW=H,E=H;输出:D0~D7=数据(4)写数据:输入:RS=H,RW=L,D0~D7=数据,E=高脉冲;输出:无需要两个写时序:①当我们要写指令字,设置LCD1602的工作方式时:需要把RS置为低电平,RW 置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入。
②当我们要写入数据字,在1602上实现显示时:需要把RS置为高电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入。
3.4 单片机STC89C52STC89C52是一种带8K字节闪烁可编程可檫除只读存储器的低电压,高性能COMOS8的微处理器,具有8K在系统可编程Flash存储器。
3.4.1主要特性STC89C52单片机采用高性能的静态80C51设计,并采用先进工艺制造,还带有非易失去性FLASH程序储器。
它是一种高性能、低功耗的8位CMOS微处理芯片,市场上应用最多。
其主要性能如下:(1)8KB Flash ROM,可以擦除1000次以上,数据保存10年。
(2)256字节内部RAM。
(3)电源控制模式:(4)-时钟可停止和恢复;空闲模式;-掉电模式。
(5)6个中断源。
(6)4个中断优先级。
(7)4个8位I/O口。
(8)全双工增强型UART。
(9)3个16位定时器/计数器:T0、T1、T2。
(10)全静态工作方式:0-24MHz3.4.2功能特性概述STC89C52提供以下标准功能:8K字节Flash闪速存储器,256字节内部RAM,32个I/O口线,3个16位定时/计数器,一个6向量两级中断结构,一个全双工串行通信口,片内震荡器及时钟电路。
同时,STCT89C52可降至0Hz 的静态逻辑系操作,并支持两种软件可选的节电工作模式。
空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信接口及中断系统继续工作。
掉电方式保存RAM中的内容,但震荡器停止工作并禁止其他所有部件工作直到下一个硬件复位。
3.4.3主要引脚及芯片基本工作条件说明40个引脚中,正电源和地线两根,外置石英振荡器的时钟线两根,4组8位共32个I/O口,中断口线与P3口线复用。
Pin9:RESET/V pd复位信号复用脚,当8052通电,时钟电路开始工作,在RESET 引脚上出现2个时钟周期以上的高电平,系统即初始复位。
STC89C52的复位方式可以是自动复位,也可以是手动复位,如图2 -3 复位电路。