//此程序实现计时秒表功能,时钟显示范围00.00~99.99秒,分辨度:0.01秒
#include "p18f458.h"
unsigned char s[4]; //定义0.01 秒、0.1 秒、1秒、10秒计时器
unsigned char k,data,sreg;
unsigned int i;
const table[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90};
//不带小数点的显示段码表
const table0[10]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};
//带小数点的显示段码表
void clkint(void);
//TMR0初始化子程序
void tmint()
{
T0CON=0XCF; //设定TMR0L工作于8位定时器方式
//内部时钟,TMR0不用分频
INTCON=0X20; //总中断禁止,TMR0中断允许,清除TMR0的中断标志
INTCON2bits.TMR0IP=1; //TMR0中断高优先级
RCONbits.IPEN=1; //使能中断优先级
}
//系统其它部分初始化子程序
void initial()
{
TRISA=0x00; //A口设置为输出
TRISB=0XF0; //RB1输出,RB4输入
TRISC=0x00; //SDO引脚为输出,SCK引脚为输出
TRISE=0x00; //E口设置为输出
SSPCON1=0x30; //SSPEN=1;CKP=1,FOSC/4
SSPSTAT=0xC0; //时钟下降沿发送数据
PIR1=0; //清除SSPIF标志
data=0X00; //待显示的寄存器赋初值
PORTBbits.RB1=0;
PORTAbits.RA3=0;
PORTE=0; //将K1,K2,K3,K4四条列线置0
}
//SPI传输数据子程序
void SPILED(char data)
{
SSPBUF=data; //启动发送
do
{
;
}while(PIR1bits.SSPIF==0);
PIR1bits.SSPIF=0;
}
//显示子程序,显示4位数
void dispaly()
{
PORTAbits.RA5=0; //准备锁存
for(k=0;k<4;k++)
{
data=s[k];
if(k==2) data=table0[data]; //个位需要显示小数点
else data=table[data];
SPILED(data); //发送显示段码
}
for(k=0;k<4;k++)
{
data=0xFF;
SPILED(data); //连续发送4个DARK,使显示好看一些
}
PORTAbits.RA5=1; //最后给锁存信号,代表显示任务完成
}
//软件延时子程序
void DELAY()
{
for(i = 3553; --i ;)
continue;
}
//键扫描子程序
void KEYSCAN()
{
while(1)
{
dispaly(); //调用一次显示子程序
while(PORTBbits.RB4==0)
{
DELAY(); //若有键按下,则软件延时
break;
}
if (PORTBbits.RB4==0) break; //若还有键按下,则终止循环扫描,返回
}
}
//等键松开子程序
void keyrelax()
{
while(1)
{
dispaly(); //调用一次显示子程序
if (PORTBbits.RB4==1) break; //为防止按键过于灵敏,每次等键松开才返回
}
}
/*高优先级中断向量*/
#pragma code InterruptVectorHigh=0x08
void InterruptVectorHigh (void)
{
_asm
goto clkint //跳到中断程序
_endasm
}
//中断服务程序
#pragma code
#pragma interrupt clkint
void clkint()
{
TMR0=0X13; //对TMR0写入一个调整值。因为写入TMR0后接着的
//两个周期不能增量,中断需要3个周期的响应时间,
//以及C语言自动进行现场保护要消耗周期
INTCONbits.T0IF=0; //清除中断标志
sreg=sreg+1; //中断计数器加1
if(sreg==40) //中断次数为40后,才对S0,S1,S2,S3 操作
{
sreg=0;
s[0]=s[0]+1;
if(s[0]==10)
{
s[0]=0 ;
s[1]=s[1]+1;
if(s[1]==10)
{
s[1]=0 ;
s[2]=s[2]+1;
if(s[2]==10)
{
s[2]=0;
s[3]=s[3]+1;
if(s[3]==10) s[3]=0;
}
}
}
}
}[page]
//主程序
//http://www.51hei.com 提供此单片机程序有问题请联系
main()
{
tmint(); //TMR0初始化
initial(); //spi显示初始化及系统其它部分初始化
INTCONbits.GIE=0; //总中断禁止
while(1)
{
for(k=0;k<4;k++)
{
s[k]=0;
}
sreg=0; //赋显示初值
dispaly(); //调用一次显示子程序
KEYSCAN(); //键扫描,直到开始键按下
keyrelax(); //等键松开
INTCONbits.GIE=1; //总中断允许
KEYSCAN(); //键扫描直到停止键按下,在键扫描时有显示
keyrelax(); //等键松开
INTCONbits.GIE=0; //总中断禁止
KEYSCAN(); //键扫描到清0键按下,在键扫描时有显示
keyrelax(); //等键松开
}
}
---------------------汇编语言版本的pic单片机计时秒表程序设计--------------------------------------;此程序实现计时秒表功能
;时钟显示范围:00.00秒-99.99秒,分辨度:0.01秒
;通过按键来启动计时、停止计时及清0
;即第一次按下任意键开始计时,第二次按下任意键停止计时 ;第三次按下任意键使LED清0,等待下一次计时开始
LIST P=18F458
INCLUDE "P18F458.INC"
S0 EQU 0X20 ;0.01 秒计时器
S1 EQU S0+1 ;0.1 秒计时器
S2 EQU S0+2 ;1 秒计时器
S3 EQU S0+3 ;10 秒计时器
SREG EQU S0+4 ;软计数器
LEDF EQU S0+5 ;显示的LED的位置指示寄存器
XW_TEMP EQU S0+6 ;用于中断中保护W的值
XHOSTS EQU S0+7 ;用于中断中保护STATUS的值
DEYH EQU S0+8
DEYL EQU S0+9 ;以上两个寄存器用于软件延时
HOSTF EQU S0+0A ;用于中断中保护FSR0L的值
TEMP EQU S0+0B ;用于存放临时值
ORG 0X00
GOTO MAIN
ORG 0X08
GOTO CLKINT ;转向中断服务程序
ORG 0X30
;数字到段码的转换子程序(最好放在程序开头,避免超过2K的空间发生跨页读表)
;************不带小数点的共阳极码表**************
CONVERT ADDWF PCL,1
RETLW 0XC0 ;0,显示段码与具体的硬件连接有关
RETLW 0XF9 ;1
RETLW 0XA4 ;2
RETLW 0XB0 ;3
RETLW 0X99 ;4
RETLW 0X92 ;5
RETLW 0X82 ;6
RETLW 0XD8 ;7
RETLW 0X80 ;8
RETLW 0X90 ;9
RETLW 0X88 ;A
RETLW 0X83 ;B
RETLW 0XC6 ;C
RETLW 0XA1 ;D
RETLW 0X86 ;E
RETLW 0X8E ;F
RETLW 0X7F ;"."
RETLW 0XBF ;"-"
RETLW 0X89 ;H
RETLW 0XFF ;DARK
RETURN
;*********带小数点的共阳极码表***********
CONVERT2 ADDWF PCL,1
RETLW 0X40 ;0
RETLW 0X79 ;1
RETLW 0X24 ;2
RETLW 0X30 ;3
RETLW 0X19 ;4
RETLW 0X12 ;5
RETLW 0X02 ;6
RETLW 0X78 ;7
RETLW 0X00 ;8
RETLW 0X10 ;9
RETURN
;***********SPI发送显示子模块************
TRANSMIT
CLRF PORTA ;LACK送低电平,为锁存做准备
MOVWF SSPBUF ;启动发送
WAIT NOP
BTFSS PIR1,SSPIF
GOTO WAIT ;等待发送结束
BCF PIR1,SSPIF ;清除中断标志
RETURN
;***********显示子程序模块************
DISPLAY
MOVLW 0X01
MOVWF LEDF
MOVLW 0XA0
MOVWF FSR0L
AGAINXIAN
MOVF LEDF,W
SUBLW 0X03
BTFSS STATUS,Z
GOTO XIANB
MOVF INDF0,W
CALL CONVERT2 ;若是个位,则查带小数点的码表
GOTO TRAN
XIANB MOVF INDF0,W
CALL CONVERT
TRAN CALL TRANSMIT ;发送一个显示数据
INCF FSR0L
INCF LEDF
MOVF LEDF,W
SUBLW 0X05
BTFSS STATUS,Z
GOTO AGAINXIAN
MOVLW 0X01
MOVWF LEDF
XIANDARK
MOVLW 0X27
CALL CONVERT
CALL TRANSMIT
INCF LEDF
MOVF LEDF,W
SUBLW 0X05
BTFSS STATUS,Z
GOTO XIANDARK ;显示4个"DARK"
BSF PORTA,5 ;最后给一个锁存信号,代表一次显示任务完成
RETURN
;********** S0计数溢出处理子程序***************
CS0
CLRF S0
INCF S1
RETURN
;********** S1计数溢出处理子程序***************
CS1
CLRF S1
INCF S2
RETURN
;********** S2计数溢出处理子程序***************
CS2
CLRF S2
INCF S3
RETURN
;********** S3计数溢出处理子程序***************
CS3
CLRF S3
RETURN
;***********时钟中断服务程序*******************
CLKINT
MOVWF XW_TEMP ;保存W的值
SWAPF STATUS,W
MOVWF XHOSTS ;暂存STATUS的值
MOVF FSR0L,W
MOVWF HOSTF ;保存FSR0L的值。以上程序为中断现场保护
MOVLW 0X13
MOVWF TMR0L ;对TMR0L写入一个调整值,因为写入
;TMR0L后接着的两个周期不能增量
BCF INTCON,T0IF ;清除中断标志
INCF SREG
MOVF SREG,W
SUBLW 0X28 ;TMR0L 每250us中断一次
BTFSS STATUS,Z ;其中断40次后才执行对S0 S1 S2 S3 的操作
GOTO TIFAN
CLRF SREG
INCF S0
MOVF S0,W
SUBLW 0X0A
BTFSC STATUS,Z
CALL CS0
MOVF S1,W
SUBLW 0X0A
BTFSC STATUS,Z
CALL CS1
MOVF S2,W
SUBLW 0X0A
BTFSC STATUS,Z
CALL CS2
MOVF S3,W
SUBLW 0X0A
BTFSC STATUS,Z
CALL CS3
TIFAN
MOVF HOSTF,W ;以下为中断现场恢复
MOVWF FSR0L ;恢复间接寻址指针FSR0L的值
SWAPF XHOSTS,W
MOVWF STATUS ;恢复STATUS的值
SWAPF XW_TEMP,1
SWAPF XW_TEMP,W ;恢复W的值
RETFIE [page]
;*********** TMR0初始化子程序***************
CLKINSUB
MOVLW 0XCF
MOVWF T0CON ;设定TMR0L工作于8位定时器方式
;内部时钟,TMR0不用分频
BCF INTCON,TMR0IF ;清除TMR0的中断标志
BCF INTCON,GIE ;总中断禁止
BSF INTCON,TMR0IE ;TMR0中断允许
BSF INTCON2,2 ;TMR0中断高优先级
BSF RCON,7 ;使能中断优先级
RETURN
;***************系统初始化子程序*****************
MAINSUB
BCF TRISA,5 ;置RA5为输出方式,以输出锁存信号
BCF TRISB,1
BCF TRISA,3
BCF TRISE,0
BCF TRISE,1
BSF TRISB,4 ;设置与键盘有关的各口的输入输出方式
BCF TRISC,5
BCF TRISC,3 ;设置SCK与SDO为输出方式
BCF INTCON,GIE ;关闭所有中断
MOVLW 0XC0
MOVWF SSPSTAT ;设置SSPSTAT寄存器
MOVLW 0X30
MOVWF SSPCON1 ;设置SPI的控制方式,允许SSP方式,
;并且时钟下降沿发送,与"74HC595当
;其SCLK从低到高平跳变时,串行输入数据
;(DI)移入寄存器"的特点相对应
RETURN ;返回
;***********键扫描子程序********************
KEYSCAN
BCF PORTB,1
BCF PORTA,3
BCF PORTE,0
BCF PORTE,1 ;送低电平至K1,K2,K3,K4
RETURN
;*********键盘去抖子程序(8ms的延时)******************
KEYDELAY
MOVLW 0X0A
MOVWF DEYH
AGAIN2 MOVLW 0XFF
MOVWF DEYL
AGAIN1 DECFSZ DEYL,1
GOTO AGAIN1
DECFSZ DEYH,1
GOTO AGAIN2 ;具体程序语句参考3. 2节
RETURN
;*************显示缓冲区处理子程序****************
XIANHUAN
MOVLW 0XA0
MOVWF FSR0L
RLNCF S0,0
MOVWF TEMP
INCF TEMP,0
MOVWF INDF0
INCF FSR0L
RLNCF S1,0
MOVWF TEMP
INCF TEMP,0
MOVWF INDF0
INCF FSR0L
RLNCF S2,0
MOVWF TEMP
INCF TEMP,0
MOVWF INDF0
INCF FSR0L
RLNCF S3,0
MOVWF TEMP
INCF TEMP,0
MOVWF INDF0
RETURN
;**************主程序******************
MAIN NOP
CALL MAINSUB ;系统初始化
CALL CLKINSUB ;调用时钟初始化子程序
DENJIAN BCF INTCON,GIE
CLRF S0
CLRF S1
CLRF S2
CLRF S3
CLRF SREG
CLRF LEDF ;S0=S1=S2=S3=0
CALL XIANHUAN ;把S3、S2、S1、S0的值装入显示缓冲区
CALL DISPLAY ;显示
DENAN BCF INTCON,GIE ;关中断
CALL KEYSCAN ;进行键扫描
BTFSS PORTB,4
GOTO XIAODOU1 ;如起始键按下,则消抖动
GOTO DENAN ;如起始键没按下,则继续等待
XIAODOU1
CALL KEYDELAY ;延时消抖动
CALL KEYSCAN ;再次进行键扫描
BTFSC PORTB,4
GOTO DENAN ;若为干扰,则再次等待键按下
CLRF S0
CLRF S1
CLRF S2
CLRF S3
CLRF SREG ;设置新一次计时的初始条件
WAITS CALL KEYSCAN
BTFSS PORTB,4
GOTO WAITS ;为了防止按键过于灵敏,等键松开后再进行
;下面的操作
BSF INTCON,GIE ;开总中断
HERE CALL XIANHUAN ;显示缓冲区处理
CALL DISPLAY ;即时更新显示内容
CALL KEYSCAN
BTFSS PORTB,4
GOTO XIAODOU ;若停止计时键按下,则消抖
GOTO HERE ;若停止计时键没按下,则继续等待中断计时
XIAODOU
CALL DISPLAY ;利用消抖动时间调用显示程序
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL DISPLAY
CALL KEYSCAN
BTFSC PORTB,4
GOTO HERE ;若为干扰,则继续等待停止键按下
BCF INTCON,GIE ;若停止键按下,则禁止中断
CALL DISPLAY ;若不为干扰,则禁止中断,更新显示内容
WAITR CALL KEYSCAN
BTFSS PORTB,4
GOTO WAITR ;为了防止按键过于灵敏,等键松开后再进行
;下面的操作
DENDAI CALL KEYSCAN
BTFSC PORTB,4
GOTO DENDAI ;循环进行键扫描,等待清0键按下
CALL KEYDELAY ;延时消抖
CALL KEYSCAN
BTFSC PORTB,4
GOTO DENDAI
WAIT19 CALL KEYSCAN
BTFSS PORTB,4
GOTO WAIT19 ;等键松开
GOTO DENJIAN ;新一次计时开始
END
上一篇:PIC18F458单片机休眠状态工作方式与激活
下一篇:PIC单片机CAN总线通讯汇编程序
推荐阅读最新更新时间:2024-03-16 13:14