单片机秒表程序 80C51

单片机秒表程序 80C51,第1张

//1602 34键盘 蜂鸣器 时钟-闹钟 程序 希望对你有帮助

//功能键

//模式1或模式4时

//12 进入模式2; 11 进入模式3 ;1 退出模式4(当前为模式4),转为模式1

//模式2时

//12 退出模式2,回到上一模式; 11 光标移位; 1-9 数字键

//模式3时

//12 光标移位; 11 退出模式3,回到上一模式; 1-9 数字键

#include "reg51h"

#include"intrinsh"

#define NOP();{_nop_(); _nop_(); _nop_(); _nop_();} / 定义空 *** 作指令 /

#define uchar unsigned char

#define uint unsigned int

uchar ii = 1;

uchar mod = 1; //用于标志当前模式 1表示正常工作(没有闹钟),1表示设置时间,2表示设置闹钟,4表示正常工作的同时闹钟还要显示

uchar mod_last = 0; //记录上一模式

uchar n; //辅助延时 1s 的计数变量,用于定时器0

uint n_T1; //用于定时器1

uchar hour,min,sec; //时间

uchar hour_r,min_r,sec_r; //闹钟时间

uchar h_temp,m_temp,s_temp;

uchar time[]={0, 0, 0, 0, 0, 0};

uchar time_r[]={0, 0, 0, 0, 0, 0};

sbit bell= P1^7; /蜂鸣器/

bit FLAG0=0; // 扫描键盘的标志位

uchar ptr = 13; // 哪个键按下了?

uchar ptr_last = 0; //上一次扫描键盘值,通过和这次比较,用于检测上升沿

uchar count = 0; //设置时间时记住设置到哪位(时2位,分2位,秒2位,共6位,依次为1到6)?

bit mm = 0; //闪烁扫描的标志位,0 不显示,1 显示

sbit LCD_RS=P2^5; //RS为液晶的寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

sbit LCD_EN=P2^7; //E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。

sbit LCD_RW=P2^6; //RW为读写信号线,高电平时进行读 *** 作,低电平时进行写 *** 作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。

uchar time_h,time_l; //校正定时器的临时变量

void delay(uint x) //简单延时

{

uchar j;

while(x-->0) //判断完x是否大于0,无论结果,x就--

{

for(j=0;j<125;j++)

{;}

}

}

void scan_key(void) /扫描键盘副程式/

{

uchar a1=0xF7,i,m; /A1=0XF7列扫描初值,I行/

FLAG0=0; /设按键回应旗号为0,键盘扫描计数指标为0/

for(i=1;i<5;i++) /键盘3个扫描列/

{

P1=a1; /列扫描输出,读入P1存入M,以便侦测行与侦测按键是否放开/

m=P1;

switch(m&0x87) /取行的高4位元,侦测那一行被按/

{

case 0x83:

{

if(i==1)ptr=1;

if(i==2)ptr=4;

if(i==3)ptr=7;

if(i==4)ptr=10;

FLAG0=1; /是则设FLAG0=1表有按键输入/

} break; /跳出此循环/

case 0x85:

{

if(i==1)ptr=2;

if(i==2)ptr=5;

if(i==3)ptr=8;

if(i==4)ptr=11;

FLAG0=1; /是则设FLAG0=1表有按键输入/

}break; /跳出此循环/

case 0x86:

{

if(i==1)ptr=3;

if(i==2)ptr=6;

if(i==3)ptr=9;

if(i==4)ptr=12;

FLAG0=1; /是则设FLAG0=1表有按键输入/

}break; /跳出此循环/

default: break; /跳出此循环/

}

if(FLAG0==1)break; /不为1,则扫描列右移,扫描下一列/

a1=(a1<<1)|0x87;

}

//检测到按键就让蜂鸣器响一下

if(FLAG0)

{

bell = 0;

delay(160);

bell = 1;

}

}

void LCD_STROBE(void) /LCD闸门滤波,或者说液晶使能?/

{

LCD_EN=1;

NOP();

LCD_EN=0;

}

unsigned char lcd_read_cmd_nowait(void)

{

unsigned char readc;

LCD_RW=1; //读模式 当RS为低电平RW为高电平时可以读忙信号

LCD_EN=1; //关液晶?

NOP();

readc=P0;

LCD_EN=0; / 返回写入液晶的默认模式/

LCD_RW=0; //低电平时进行写 *** 作

return(readc);

}

void lcd_check_busy(void) /当液晶不再busy,或者等待时间足够长时,返回/

{

unsigned int retry;

unsigned char c;

for(retry=1000;retry>0;retry--) //如果一直都忙,重试1000次???

{

c=lcd_read_cmd_nowait(); / Check busy bit If zero, no longer busy/

if(0==(c&0x80)) //与 *** 作

break; //如果c的最高位为0,退出重试,说明不忙

}

}

void lcd_cmd(unsigned char c) /发一个命令到液晶/

{

P0=c;

LCD_STROBE(); // LCD闸门滤波 有什么用?液晶使能?

}

void lcd_data(unsigned char c) /发数据到液晶/

{

lcd_check_busy(); //出这个函数时 LCD_RW=0;

LCD_RS=1; //作用?为高电平时选择数据寄存器 当RS为高电平RW为低电平时可以写入数据

NOP();

P0=c; //向P0输入数据

LCD_STROBE();

LCD_RS=0; //作用?为低电平时选择指令寄存器 当RS和RW共同为低电平时,可以写入指令或者写入显示的地址 为下一次的lcd_cmd() 做准备

}

void lcd_puts(const char s) /写一串字符到液晶/

{

while(s) //如果指针所指有内容

lcd_data(s++); //先输出 s ,然后 s 进行 ++ *** 作;s是指针,s是指针的内容

}

void clear_display(void) /液晶清屏/

{

lcd_cmd(0xc0); //第二行

lcd_puts(" ");

lcd_cmd(0x80); //第一行

lcd_puts(" ");

}

void lcd_init(void) /液晶初始化/

{

LCD_RS=0; //选指令寄存器

LCD_EN=0; //

LCD_RW=0; //RW为读写信号线,高电平时进行读 *** 作,低电平时进行写 *** 作。当RS和RW共同为低电平时,可以写入指令或者写入显示的地址。工作时都为低?

delay(5000/125); //为什么要延时?延时5000us = 5 ms 大概

P0=0x3f; // Set Function: 8位接口,两行显示,510点阵 0x3f

LCD_STROBE();

lcd_cmd(0x38);//8 bits interface,2 lines display5×点阵7//但是这块东西最多支持58所以510没意义

lcd_cmd(0x0f);//Display On(整体显示), Cursor(指针、光标) On, Blink(指针:闪烁、眨闪) on

lcd_cmd(0x01); //Display Clear 也可以写成 0x1(所有内容消除,把光标定位到第一行第一位)

lcd_cmd(0x06); //Entry Mode (set cursor move direction: cursor moves increase,(Specifies shift of display)display is not shifted

//指令3:(D2 = 1); (D1):光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移; (D0): S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效

clear_display();

}

void change(void)

{

time[0]=hour/10; //时间更新

time[1]=hour%10;

time[2]=min/10;

time[3]=min%10;

time[4]=sec/10;

time[5]=sec%10;

time_r[0]=hour_r/10; //闹时更新,只有在模式3中才会??,在其他时候也不影响

time_r[1]=hour_r%10;

time_r[2]=min_r/10;

time_r[3]=min_r%10;

time_r[4]=sec_r/10;

time_r[5]=sec_r%10;

}

void display(uchar tmp)

{

switch(tmp)

{

case 0 : lcd_puts("0"); break;

case 1 : lcd_puts("1"); break;

case 2 : lcd_puts("2"); break;

case 3 : lcd_puts("3"); break;

case 4 : lcd_puts("4"); break;

case 5 : lcd_puts("5"); break;

case 6 : lcd_puts("6"); break;

case 7 : lcd_puts("7"); break;

case 8 : lcd_puts("8"); break;

case 9 : lcd_puts("9"); break;

default : ;

}

}

void scan() //正常工作时扫描液晶

{

lcd_cmd(0xc0);

if(mod == 3||mod == 4)

lcd_puts("T: "); //共16位

else if(mod == 1||mod == 2)

lcd_puts(" "); //共16位

lcd_cmd(0xc4); //时

display(time[0]);

lcd_cmd(0xc5);

display(time[1]);

lcd_cmd(0xc6);

lcd_puts(":");

lcd_cmd(0xc7); //分

display(time[2]);

lcd_cmd(0xc8);

display(time[3]);

lcd_cmd(0xc9);

lcd_puts(":");

lcd_cmd(0xca); //秒

display(time[4]);

lcd_cmd(0xcb);

display(time[5]);

lcd_cmd(0xcc);

lcd_puts(" ");

if(mod == 3||mod == 4) //模式3与模式4时,扫描第一行显示

{

lcd_cmd(0x80); //前面四位

if(mod == 3)

lcd_puts("SR: "); //共16位,SR 设置闹钟

else

lcd_puts("R: "); //共16位

lcd_cmd(0x84); //闹时

display(time_r[0]);

lcd_cmd(0x85);

display(time_r[1]);

lcd_cmd(0x86);

lcd_puts(":");

lcd_cmd(0x87); //闹分

display(time_r[2]);

lcd_cmd(0x88);

display(time_r[3]);

lcd_cmd(0x89);

lcd_puts(":");

lcd_cmd(0x8a); //闹秒

display(time_r[4]);

lcd_cmd(0x8b);

display(time_r[5]);

lcd_cmd(0x8c); //最后四位

lcd_puts(" ");

}

else if(mod == 1)

{

lcd_cmd(0x80); //液晶地址 第一行 0x80 到 0x8f ,第二行 0xc0 到 0xcf

lcd_puts(" Time is: ");

}

else if(mod == 2)

{

lcd_cmd(0x80); //液晶地址 第一行 0x80 到 0x8f ,第二行 0xc0 到 0xcf

lcd_puts(" Set Time: ");

}

}

void scan_wink() //用于进入模式(设置时间、设置闹钟)时的扫描液晶,具有闪烁功能

{

uchar position;

if(mod == 2) //设置时间模式,闪烁第二行

position = 0xc4;

else if(mod == 3) //设置闹钟模式,闪烁第一行

position = 0x84;

for(ii = 1; ii<=6; ii++)

{

if(count == ii)

{

if(ii <= 2)

lcd_cmd(position+ii-1);

else if(ii>= 5)

lcd_cmd(position+ii-1+2);

else

lcd_cmd(position+ii-1+1);

}

}

if(mm) //该亮

{

if(mod == 2)

display(time[count-1]);

else if(mod == 3)

display(time_r[count-1]);

}

if(!mm&&(count>=1&&count<=6)) //不该亮(即是显示空格)

lcd_puts(" ");

mm = !mm; //翻转亮与不亮的模式

}

void in_judge()

{

if((mod == 1||mod == 4)&&(ptr == 12&&ptr_last != 12)) //判断是否要进入设置时钟模式

{

mod_last = mod;

mod = 2;

TR0 = 0; //停止计时

}

else if((mod == 1||mod == 4)&&(ptr == 11&&ptr_last != 11)) //判断是否要进入设置闹钟模式

{

mod_last = mod;

mod = 3;

hour_r = 0; //初始化闹钟时间为00:00:00

min_r = 0;

sec_r = 0;

}

}

void out_judge()

{

if(mod == 2&&(ptr == 12&&ptr_last !=12)) //判断是否要退出设置时钟模式

{

mod = mod_last;

TH0=0x4c; /定时50ms,110592MHz/

TL0=0x00;

TR0=1; //开始计时

n=20;

}

else if(mod == 3&&(ptr == 11&&ptr_last != 11)) //判断是否要退出设置闹钟模式

{

mod = 4;

mod_last = mod;

}

else if(mod == 4&&(ptr == 10&&ptr_last != 10))

{

TR1 = 0;

mod = 1;

}

}

void shift_judge() //在模式2和模式3中的移位判断

{

if(ptr == mod+9&&ptr_last != mod+9) //模式2 mod+2 = 11,模式3 mod+2 = 12

{

count++;

if(count>6)

count = count%6;

}

}

void ptr_last_update()

{

if(!FLAG0||ptr<13) //更新上一次的按键值

{

if(!FLAG0)

ptr = 13;

ptr_last = ptr;

}

}

void main()

{

TMOD=0x11; //定时器0和定时器1都为方式1 16位定时器

TH0=0x4c; /定时50ms,110592MHz/

TL0=0x00;

TR0=1;

n=20;

IE=0x8a; //定时器0和定时器1都中断使能

IP=0x02; //定时器0具有最高优先级

hour=0; //时钟初始化

min=0;

sec=0;

hour_r = 0; //闹钟初始化

min_r = 0;

sec_r = 0;

lcd_init(); //液晶初始化

lcd_cmd(0x0c); //去掉光标

mod = 1; //初始化模式为1 正常模式

mod_last = 1;

while(1)

{

count = 1;

scan_key();//扫描键盘

out_judge();//判断是否要从模式4退出到模式1

in_judge();//判断是否进入模式2或模式3

ptr_last_update();//更新ptr_last

while(mod == 2||mod == 3)

{

change();

scan();

scan_wink(); //闪烁扫描

delay(150);

if(mod == 2) //暂时变量保存

{

h_temp = hour;

m_temp = min;

s_temp = sec;

}

else

{

h_temp = hour_r;

m_temp = min_r;

s_temp = sec_r;

}

if(count == 1) //处理输入

{

if(ptr >= 1&&ptr <=3)

h_temp = 10(ptr-1)+h_temp%10;

}

else if(count == 2)

{

if(ptr >= 1&&ptr <=4)

h_temp = (h_temp/10)10+ptr-1;

}

else if((count == 3||count ==5)&&(ptr>=1&&ptr<=6))

{

if(count == 3)

m_temp = 10(ptr-1)+m_temp%10;

else

s_temp = 10(ptr-1)+s_temp%10;

}

else if((count == 4||count == 6)&&(ptr>=1&&ptr<=10))

{

if(count == 4)

m_temp = (m_temp/10)10+ptr-1;

else

s_temp = (s_temp/10)10+ptr-1;

}

if(mod == 2) //暂时变量返回

{

hour = h_temp;

min = m_temp;

sec = s_temp;

}

else

{

hour_r = h_temp;

min_r = m_temp;

sec_r = s_temp;

}

//change();

scan_key(); //下次一扫描键盘

out_judge();

shift_judge();

ptr_last_update();

}

change(); //回到模式1或模式4

scan();

delay(30);

}

}

void time_50ms() interrupt 1 //定时器0的中断处理程序 50MS

{

/TR1 = 0; //多了这段 46个指令周期,没有的话 24 22/2 = 11

time_h = TH1+0x4c;

time_l = TL0+0x07;

time_h = TH1;

time_l = TL0;

TR1 = 0;

time_h = TH1+0x4c;

time_l = TL0+0x07;

time_h = TH1;

time_l = TL0;/

TR0 = 0;

time_h = TH0; //用于补偿进入中断过程的耗时

time_l = TL0;

TH0=0x4c+time_h; //算不算两条指令??YES 3cb0 本来TL0 = 0xb0 要加11条指令才能补偿下面从TR0=0后到TR0=1完

TL0=0x0b+time_l; //但是实验板上的是110592 变成了 4C00H

TR0=1; //启动计时器

TF0=0; //计时器溢出归位

n--;

if(n==0)

{

if(sec == 59)

{

sec = 0;

if(min == 59 )

{

min = 0;

if(hour == 23)

{

hour = 0;

}

else

hour++;

}

else

min++;

}

else

sec++;

n=20;

if((hour == hour_r&&min == min_r&&sec == sec_r)&&mod == 4) // 闹时到了,触发闹铃

{

TH1 = 0xdc;

TL1 = 0x00;

n_T1 = 12000;

TR1 = 1;

}

}

}

void time_10ms() interrupt 3 //闹铃响2分钟 计12000次

{

TR1 = 0;

time_h = TH1;

time_l = TL1;

TH1 = 0xdc+time_h; //算不算两条指令??YES 3cb0 本来TL0 = 0x00 要加11条指令才能补偿下面从TR1=0后到TR1=1完

TL1 = 0x0b+time_l; //但是实验板上的是110592 变成了 4C00H

TR1=1; //启动计时器

TF1=0; //计时器溢出归位

n_T1--;

if((n_T1%50) == 0) //响的时间间隔为500ms

bell = !bell;

if(n_T1 <= 0) //响够了

{

TR1 = 0;

mod = 1;

bell = 1; //不响

n_T1 = 12000;

}

}

我这个程序是在dos窗口下的计时器,比较简单:

#include <timeh>

#include <stdioh>

#include <stdlibh>

void main()

{

clock_t start, finish, clsfinish;

/计算一次清屏 *** 作所用的时钟数/

double time_used_in_cls = 0;

start = clock();

system("CLS");

clsfinish = clock();

time_used_in_cls = double(clsfinish - start); //执行一次清屏 *** 作所用的时钟数(后面会用到,这样更精确)

int i = 59;

printf("计时开始:\n");

while(i >= 0)

{

start = finish = clock();

if(i == 59)

finish += time_used_in_cls;

/1秒刷新一次(循环控制)/

while(finish-start < CLOCKS_PER_SEC - time_used_in_cls)

finish = clock();

system("CLS"); //清屏函数

printf("%d", i--);

}

}

网上关于C语言时间函数的介绍很多的,你可以查一下。

STACK1 SEGMENT STACK

DW 200 DUP ()

STACK1 ENDS

DATA SEGMENT

SPACE DB 1000 DUP (' ')

PATTERN DB 6 DUP (' '),0C9H,26 DUP (0CDH),0BBH,6 DUP (' ')

DB 6 DUP (' '),0BAH,26 DUP (20H),0BAH,6 DUP (' ')

DB 6 DUP (' '),0C8H,26 DUP (0CDH),0BCH,6 DUP (' ')

DBUFFER DB 8 DUP (':'),12 DUP (' ')

DBUFFER1 DB 20 DUP (' ')

STR1 DB 0DH,0AH, 'PLEASE INPUT DATE(D) OR TIME(T) OR QUIT(Q): $'

DATA ENDS

CODE SEGMENT

ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK1

START: MOV AX,0001H ;设置显示方式为4025彩色文本方式

INT 10H

MOV AX,DATA

MOV DS,AX

MOV ES,AX

MOV BP,OFFSET SPACE

MOV DX,0B00H

MOV CX,1000

MOV BX,0040H

MOV AX,1300H

INT 10H

MOV BP,OFFSET PATTERN ;显示矩形条

MOV DX,0B00H

MOV CX,120

MOV BX,004EH

MOV AX,1301H

INT 10H

LEA DX,STR1 ;显示提示信息

MOV AH,9

INT 21H

MOV AH,1 ;从键盘输入单个字符

INT 21H

CMP AL,44H ;AL='D'?

JNE A

CALL DATE ;显示系统日期

A: CMP AL,54H ;AL='T'?

JNE B

CALL TIME ;显示系统时间

B: CMP AL,51H ;AL='Q'?

JNE START

MOV AH,4CH ;返回dos状态

INT 21H

DATE PROC NEAR ;显示日期子程序

dis:MOV AH,2AH ;取日期

INT 21H

MOV SI,0

MOV AX,CX

MOV BX,100

DIV BL

MOV BL,AH

CALL BCDASC1 ;日期数值转换成相应的ASCII码字符

MOV AL,BL

CALL BCDASC1

INC SI

MOV AL,DH

CALL BCDASC1

INC SI

MOV AL,DL

CALL BCDASC1

MOV BP,OFFSET DBUFFER1

MOV DX,0C0DH

MOV CX,20

MOV BX,004EH

MOV AX,1301H

INT 10H

MOV AH,02H ;设置光标位置

MOV DX,0300H

MOV BH,0

INT 10H

MOV BX,0018H

REPEA: MOV CX,0FFFFH ;延时

REPEAT:LOOP REPEAT

DEC BX

JNZ REPEA

MOV AH,01H ;读键盘缓冲区字符到AL寄存器

INT 16H

JE dis

JMP START

MOV AX,4C00H

INT 21H

RET

DATE ENDP

TIME PROC NEAR ;显示时间子程序

DISPLAY1:MOV SI,0

MOV BX,100

DIV BL

MOV AH,2CH ;取时间

INT 21H

MOV AL,CH

CALL BCDASC ;将时间数值转换成ASCII码字符

INC SI

MOV AL,CL

CALL BCDASC

INC SI

MOV AL,DH

CALL BCDASC

MOV BP,OFFSET DBUFFER

MOV DX,0C0DH

MOV CX,20

MOV BX,004EH

MOV AX,1301H

INT 10H

MOV AH,02H

MOV DX,0300H

MOV BH,0

INT 10H

MOV BX,0018H

RE: MOV CX,0FFFFH

REA: LOOP REA

DEC BX

JNZ RE

MOV AH,01H

INT 16H

JE DISPLAY1

JMP START

MOV AX,4C00H

INT 21H

RET

TIME ENDP

BCDASC PROC NEAR ;时间数值转换成ASCII码字符子程序

PUSH BX

CBW

MOV BL,10

DIV BL

ADD AL,'0'

MOV DBUFFER[SI],AL

INC SI

ADD AH,'0'

MOV DBUFFER[SI],AH

INC SI

POP BX

RET

BCDASC ENDP

BCDASC1 PROC NEAR ;日期数值转换成ASCII码字符子程序

PUSH BX

CBW

MOV BL,10

DIV BL

ADD AL,'0'

MOV DBUFFER1[SI],AL

INC SI

ADD AH,'0'

MOV DBUFFER1[SI],AH

INC SI

POP BX

RET

BCDASC1 ENDP

CODE ENDS

END START

cursor equ 45H

attrib equ 2fh

code segment

assume cs:code,ds:code

start:

jmp go

oldcur dw

OLD1C DW 2 DUP()

NEWINT1C:

PUSHF

CALL DWORD PTR CS:OLD1C

push ax

PUSH BX

PUSH CX

PUSH DX

XOR BH,BH

MOV AH,3

INT 10H

MOV CS:OLDCUR,DX

MOV AH,2

xor bh,bh

MOV DX,CURSOR

INT 10H

MOV AH,2 ;读取系统时钟

INT 1AH

PUSH DX

PUSH CX

POP BX

PUSH BX

CALL SHOWBYTE

CALL SHOWCOLON

POP BX

XCHG BH,BL

CALL SHOWBYTE

CALL SHOWCOLON

POP BX

CALL SHOWBYTE

MOV DX,CS:OLDCUR

MOV AH,2

XOR BH,BH

INT 10H

POP DX

POP CX

POP BX

POP AX

IRET

SHOWBYTE PROC NEAR

PUSH BX

MOV CL,4

MOV AL,BH

SHR AL,CL

ADD AL,30H

CALL SHOW

CALL CURMOVE

POP BX

MOV AL,BH

AND AL,0FH

ADD AL,30H

CALL SHOW

CALL CURMOVE

RET

SHOWBYTE ENDP

SHOWCOLON PROC NEAR

MOV AL,':'

CALL SHOW

CALL CURMOVE

RET

SHOWCOLON ENDP

CURMOVE PROC NEAR

PUSH AX

PUSH BX

PUSH CX

PUSH DX

MOV AH,3

MOV BH,0

INT 10H

INC DL

MOV AH,2

INT 10H

POP DX

POP CX

POP BX

POP AX

RET

CURMOVE ENDP

SHOW PROC NEAR

PUSH AX

PUSH BX

PUSH CX

MOV AH,09H

MOV BX,attrib

MOV CX,1

INT 10H

POP CX

POP BX

POP AX

RET

SHOW ENDP

GO:

PUSH CS

POP DS

MOV AX,351CH ;取中断向量

INT 21H

MOV OLD1C,BX;保存原中断向量

MOV BX,ES

MOV OLD1C+2,BX

MOV DX,OFFSET NEWINT1C ;置新的中断向量

MOV AX,251CH

INT 21H

MOV DX,OFFSET GO

SUB DX,OFFSET START

MOV CL,4

SHR DX,CL

ADD DX,11H

MOV AX,3100H ;结束并驻留

INT 21H

CODE ENDS

END START

第一步,打开vb

第二部,添加一个计时器timer,一个文字标签label

第三部,输入代码,代码如下

Private Sub Form_Load()

picClockMove (MeScaleWidth - 8 210) / 2, (MeScaleHeight - 315) / 2, 8 210, 315

Dim i&

For i = 0 To 7

picClockPaintPicture picNumberPicture, i 210, 0, 210, 315, IIf((i = 2) Or (i = 5), 12, 10) 210, 0, 210, 315

Next i

End Sub

Private Sub Timer1_Timer()

Dim cNow$, i&

cNow = Format(Now, "hh:mm:ss")

For i = 0 To 7

If Mid(cNow, i + 1, 1) <> ":" Then

picClockPaintPicture picNumberPicture, i 210, 0, 210, 315, Val(Mid(cNow, i + 1, 1)) 210, 0, 210, 315

End If

Next i

End Sub

望采纳

上面的代码错了,下面是正确代码

Private Sub Form_Load()

Timer1Enabled = True

Timer1Interval = 300

End Sub

Private Sub Timer1_Timer()

Label1 = Now

End Sub

一、程序窗口设计步骤

(1)用AppWizard生成一个名为Clock的单文档(SDI)程序框架。为了简化应用程序,在第四步时去掉Docking toolbar和Initial status bar选择项(不删除也可),其他各选项均可用缺省设置。

(2)编辑项目的菜单资源,在主框架窗口的主菜单(IDR_MAINFRAME)中添加一个名为“时钟控制”的下拉菜单。在“时钟控制”菜单中添加三个菜单选项“启动时钟”、“停止时钟”和“时间设置”。并在菜单属性项中设定“启动时钟”菜单的ID标号为ID_START,“停止时钟”菜单的ID标号为ID_STOP,“时间设置”菜单的ID标号为ID_SETTIME。为了简化菜单,可删除系统原有的“文件”、“编辑”菜单项。

(3)利用ClassWizard为视图类添加菜单命令处理函数。进入ClassWizard的Message Maps选项卡,选择Class Name项为CClockView类,在Object IDs列表框中分别选择新添加的菜单选项的ID,在Messages列表框中选择COMMAND,按下Add Function按钮添加成员函数。ClassWizard会为“启动时钟”、“停止时钟”和“时间设置”菜单选项添加相应的消息响应函数OnStart ( )、OnStop ( )和OnSettime ( )。

(4)利用ClassWizard为视图类添加定时器和鼠标消息处理函数。进入ClassWizard的Message Maps选项卡,选择Class Name项为 CClockView类,在Messages列表框中分别选择定时器消息WM_TIMER和鼠标消息WM_LBUTIONDOWN,按下Add Function按钮添加成员函数。ClassWizard会添加相应的定时器和鼠标消息响应函数OnTimer和OnLButtonDown。

(5)使用Developer Studio菜单的Insert / Resource…选项调出Insert Source对话框,为项目添加新的对话框资源。在对话框属性中,修改对话框名为“时间设定”。在对话框中增加用来输入年、月、日、时、分、秒的编辑框控件。

通过控件属性,将年、月、日、时、分、秒等编辑控件的ID改为IDC_YEAR、IDC_MONTH、IDC_DAY、IDC_HOUR、IDC_MINUTE和IDC_SECOND。

(6)利用ClassWizard自动建立对话框类。进入ClassWizard后,d出一个对话框询问是否要为该对话框模板建立类。按下“OK”按钮,会d出New Class对话框,在Name栏填写对话框类的名称CSetTimeDlg后按“OK”按钮,即可为对话框创建一个对应的类。

(7) 利用ClassWizard为对话框类添加与各控件对应的数据成员。选择MemberVariables选项卡,确保Class Name项为对话框CSetTimeDlg类,然后在选项卡下方的窗口中选择各控件的ID并按下“Add Variable…”按钮,为其添加对应成员变量。

控制ID

变量类型

变量名

变量范围

IDC_YEAR

int

m_Year

0~3000

IDC_MONTH

int

m_Month

1~12

IDC_DAY

int

m_Day

1~31

IDC_HOUR

int

m_Hour

0~23

IDC_MINUTE

int

m_Minute

0~59

IDC_SECOND

int

m_Second

0~59

最后一列为变量取值范围。

(8)编辑工程的图标资源,在Resource View选项窗口中修改Icon结点所包含的主框架图标(IDR_MAINFRAME)。此步非必须。

(9)完成以上工作后,即可修改程序框架,添加必要的代码。

二、主要源代码:

按以下步骤向视图类(CClockView)添加下列数据成员及成员函数。

(1) 添加表示年、月、日、时、分、秒的变量。

int year;

int month;

int day;

int hour;

int minute;

int second;

(2) 添加秒表的计数变量。

int watch;

(3) 添加时钟的画笔及画刷变量。

CPen m_HouPen, m_MinPen, m_SecPen; // 各种针的画笔

CBrush m_MarkBrush; // 表盘标记的画刷

(4) 添加时钟控制变量。

CPoint m_Center; // 表的中心

double m_Radius; // 表的半径

CPoint m_Hour [2], m_OldHour [2]; // 时针当前及前一次位置

CPoint m_Minute [2], m_OldMin [2]; // 分针当前及前一次位置

CPoint m_Second [2], m_OldSec [2]; // 秒针当前及前一次位置

(5) 添加秒表的两个按钮位置变量。

CRect m_WatchStart;

CRect m_WatchStop;

(6) 添加两个函数,计算时钟各指针位置。

void SetClock (int hour, int minute, int second);

CPoint GetPoint (int nLenth, int nValue);

(7) 在视图类构造函数中增加初始化语句,之前加上头文件

#include<ctime>

CClockView::CClockView()

{

// 设定时间

char time[32];

SYSTEMTIME st;

GetLocalTime(&st);

day = stwDay;

hour = stwHour;

minute = stwMinute;

month = stwMonth;

second = stwSecond;

year = stwYear;

// 设定画笔/画刷

m_HouPen CreatePen (PS_SOLID, 5, RGB (255, 0, 0) ); // 时针画笔

m_MinPen CreatePen (PS_SOLID, 3, RGB (0, 0, 250) ); // 分针画笔

m_SecPen CreatePen (PS_SOLID, 1, RGB (0, 0, 0) ); // 秒针画笔

m_MarkBrush CreateSolidBrush (RGB (250, 250, 0) );

// 设定表心位置

m_Center x = 200;

m_Center y = 200;

// 设定时钟半径

m_Radius = 200;

// 计算指针位置

SetClock (hour, minute, second);

// 设定秒表计数器及按钮位置

watch = 0;

m_WatchStart = CRect (480, 310, 560, 340); // 启动钮

m_WatchStop = CRect (590, 310, 670, 340); // 停止钮

}

编写指针位置计算函数SetClock和GetPoint。首先在ClockView cpp文件头部添加下面两行代码,以便进行数学计算。

#include "mathh"

#define PI 314159265

然后添加下列代码:

//计算各个指针位置的函数

void CClockView::SetClock(int hour, int minute, int second)

{

hour=hour5;

hour=hour+minute/12;

// 保存时针原位置

m_OldHour [0] = m_Hour[0];

m_OldHour [1] = m_Hour[1];

// 计算时针当前位置

m_Hour[0]= GetPoint(int(m_Radius/2),hour);

m_Hour[1]= GetPoint(7,hour + 30);

// 保存分针原位置

m_OldMin[0]= m_Minute[0];

m_OldMin[1]= m_Minute[1];

// 计算分针当前位置

m_Minute[0]=GetPoint(int(m_Radius7/10), minute);

m_Minute[1]=GetPoint(10, minute+30);

// 保存秒针原位置

m_OldSec [0] = m_Second [0];

m_OldSec [1] = m_Second [1];

// 计算秒针当前位置

m_Second [0]= GetPoint (int(m_Radius 8/10), second);

m_Second [1] = GetPoint (30, second + 30);

}

// 计算以表心为原点的指针的端点位置

CPoint CClockView ::GetPoint (int nLenth, int nValue)

{

CPoint p;

double angle = nValue PI /30-PI/2;

px = m_Centerx + (int) (nLenth cos(angle));

py = m_Centery + (int) (nLenth sin(angle));

return p;

}

绘制表盘上的标记、时针、分针和秒针,并显示数字时钟及秒表,在OnDraw函数中添加下面代码:

void CClockView::OnDraw(CDC pDC)

{

CClockDoc pDoc = GetDocument();

ASSERT_VALID(pDoc);

// 绘制表盘上的标记

pDC->SelectObject(m_MarkBrush);

int k=0;

for(int i=0;i<60;i++)

{

CPoint pt=GetPoint(175,i);

if (i%5==0)

{

//显示表盘上的数字

CString str[12]={"12","1","2","3","4","5","6","7","8","9","10","11"};

pDC->TextOut(ptx-5,pty-5,str[k]);

k++;

}else

{

//显示数字之间的圆圈

pDC->Ellipse(ptx-2,pty-2,ptx+2,pty+2);

}

}

// 画时针

pDC->SelectObject (m_HouPen);

if (m_OldHour[0]!= m_Hour[0])

{

// 用白色覆盖原位置时针

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldHour [0] );

pDC->LineTo(m_OldHour [1] );

pDC->SetROP2(R2_COPYPEN);

//时针绘制

pDC->MoveTo(m_Hour[0]);

pDC->LineTo(m_Hour[1]);

}

else

{

// 时针绘制

pDC->MoveTo(m_Hour[0]);

pDC->LineTo(m_Hour[1]);

}

// 画分针

pDC->SelectObject (m_MinPen);

if (m_OldMin[0]!=m_Minute[0])

{

// 用白色覆盖原位置分针

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldMin[0]);

pDC->LineTo(m_OldMin[1]);

pDC->SetROP2(R2_COPYPEN);

// 分针绘制

pDC->MoveTo(m_Minute[0]);

pDC->LineTo(m_Minute[1]);

}

else

{

// 分针绘制

pDC->MoveTo(m_Minute[0]);

pDC->LineTo(m_Minute[1]);

}

// 用白色覆盖原位置秒针

pDC->SelectObject(m_SecPen);

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldSec[0]);

pDC->LineTo(m_OldSec[1]);

pDC->SetROP2(R2_COPYPEN);

// 秒针绘制

pDC->MoveTo(m_Second[0]);

pDC->LineTo(m_Second[1]);

// 数字时钟显示

pDC->SelectStockObject(WHITE_BRUSH);

pDC->Rectangle(450,30,700,180);

pDC->TextOut(535,20,"当前时间");

CString m_Date,m_Time;

m_DateFormat ("% 4d年%4d月%4d日",year,month,day);

pDC->TextOut(510,70,m_Date);

m_TimeFormat("%4d点%4d分%4d秒",hour,minute,second);

pDC->TextOut(510,100,m_Time);

// 秒表显示

pDC->Rectangle(450,220,700,370);

pDC->TextOut(545,200,"秒 表");

int minSec= watch%100;

int Sec=(watch/100)%60;

int Min=(watch/100)/60;

m_TimeFormat("% 02d: % 02d: % 02d",Min,Sec,minSec);

pDC->TextOut(535,260,m_Time);

pDC->Rectangle(&m_WatchStart);

pDC->Rectangle(&m_WatchStop);

pDC->TextOut(m_WatchStartleft + 18,m_WatchStarttop + 5,"启动");

pDC->TextOut(m_WatchStopleft + 18,m_WatchStoptop + 5,"停止");

}

请注意将表示时间的整数转换为CString字符串类型的方法以及秒表的显示方法。另外,watch计数器以1/100秒为计数单位,每达到100则秒数加1。

按照下列步骤增加时钟控制代码:

修改Onstart和OnStop函数,设置时钟运动消息。按比正常时钟快20倍的假定,50ms产生一个消息。本程序采用和正常时间同步,即1000ms产生一个消息, 其代码为:

void CClockView::OnStart()

{

SetTimer (1, 1000, NULL);

}

void CClockView::OnStop()

{

KillTimer (1);

}

修改OnTimer函数,正确计算并处理年、月、日、时、分、秒等变量的联动变化 ,其代码为:

void CClockView::OnTimer(UINT nIDEvent)

{

if (nIDEvent == 1)

{

second++; // 秒增加

if (second>59)

{

second=0;

minute++; // 分增加

}

if (minute>59)

{

minute= 0;

hour++; // 小时增加

}

if (hour>23)

{

hour=0;

day++; // 日增加

}

switch(month)

{

case 1: // 大月

case 3:

case 5:

case 7:

case 8:

case 10:

case 12:

if (day>31)

{

day= 1;

month++; // 月增加

}

break;

case 4: // 小月

case 6:

case 9:

case 11:

if (day>30)

{

day=1;

month++; // 月增加

}

break;

case 2:

if (year%4 ==0 && day>29) // 润二月

{

day=1;

month++; // 月增加

}

if (year%4!=0 && day>28) // 二月

{

day=1;

month++;

}

break;

}

if (month > 12)

{

// 年增加

year++;

month=1;

}

SetClock (hour, minute, second);

Invalidate (false);

}

// 秒表定时器消息处理

if (nIDEvent == 2)

{

watch++;

Invalidate (false);

}

CView::OnTimer(nIDEvent);

}

添加时间设置对话框代码。

首先在ClockView cpp文件头部添加下列语句:

#include “SetTimeDlg h”

在时间设定对话框类的构造函数中,做如下修改,将初始日期设为当前时间,之前要加上头文件

#include<ctime>

CSetTimeDlg::CSetTimeDlg(CWnd pParent /=NULL/)

: CDialog(CSetTimeDlg::IDD, pParent)

{

//||AFX_DATA_INIT(CSetTimeDlg)

char time[32];

SYSTEMTIME st;

GetLocalTime(&st);

m_Day = stwDay;

m_Hour = stwHour;

m_Minute = stwMinute;

m_Month = stwMonth;

m_Second = stwSecond;

m_Year = stwYear;// ||AFX_DATA_INIT

}

最后,在OnSettime函数中添加代码如下:

void CClockView::OnSettime()

{

CSetTimeDlg SetDlg;

if (SetDlgDoModal ()==IDOK)

{

year=SetDlgm_Year;

month= SetDlgm_Month;

day= SetDlgm_Day;

hour=SetDlgm_Hour;

minute=SetDlgm_Minute;

second=SetDlgm_Second;

}

// 计算各指针位置

SetClock (hour,minute,second);

Invalidate (true);

}

按以下步骤设计秒表控制程序:

在OnLButtonDown函数中增加下列内容,以便响应单击秒表启动、停止框所发出的消息:

void CClockView::OnLButtonDown(UINT nFlags, CPoint point)

{

if (m_WatchStartPtInRect(point))

{

watch=0;

SetTimer(2,10,NULL);

}

if (m_WatchStopPtInRect(point))

{

KillTimer (2);

}

CView::OnLButtonDown(nFlags, point);

}

编译,连接,运行程序。

运行结果:

1、秒表计时有三种时间模式:

(1)累积计时:

按[+]键开始、停止、再开始计时(时间累计),计时完毕,按[—]键计时归零。

(2)间隔计时:

按[+]键开始计时,按[—]键一次停止秒表并显示间隔时间,心率读数和间隔时间将存入记忆中以便查看。间隔时间显示5秒后秒表将持续计时。重复此程序以便读取间隔时间,再下一点终止按[—]键记录此时点相关信息,如此重复。[+]键停止计时,按[—]键计时归零。

(3)终点计时:

按[+]键开始计时,按[—]键显示第一人的完成时间,并作记录以便之后查看,5秒后计时将继续计时。重复此程序,可查看每一人的终点时间。按[+]键停止秒表,按[—]键计时归零。

2、注意:一旦秒表功能被激活,在使用其他主功能模式或子功能模式时,在区域3将一直保持显示“stopwatch秒表”,表明秒表功能处于被激活状态。

以上就是关于单片机秒表程序 80C51全部的内容,包括:单片机秒表程序 80C51、如何实现倒计时59秒表的c语言程序,不用中断。谢谢啊,很急、用汇编语言编写一个时钟程序,能显示时分秒的,还要有秒表就是计时器的功能,等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10076988.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存