基于proteus的51单片机开发实例16-简易秒表
1. 基于proteus的51单片机开发实例16-简易秒表
1.1. 实验目的
本实例中我们来加深对51单片机定时器/计数器的理解,及定时器定时功能的使用方法,利用定时功能来实现一个简易秒表,该秒表通过两位数码管显示0~99秒的计时,并且可以通过按键实现秒表的启动、停止、清零。
图1 简易秒表电路
1.2. 设计思路
之所以说是简易秒表,因为我们平时所见到的秒表不仅有秒时间的变化,还有毫秒的变化,如下面的动图所示。而我们实现的秒表只有秒数的变化,没有毫秒级的变化。
图2 更精确的秒表
本例的设计思路是使用一个按键来控制秒表的启动、停止、清零功能。具体实现过程是:第一次按下按键,秒表开始工作,两位数码管从00开始显示,每秒显示的数字加1,一直加到99,然后再从00开始显示;当第二次按下按键,数码管的显示停止,同时数码管正在显示的数字不再变化;第三次按下按键,数码管的数字清零,变为显示00。
1.3. 基础知识
本例设计的基础知识有定时器的工作原理;数码管的显示原理,按键检测识别原理,这些我们在之前已经学习过了。
本例的另一个重点是程序代码比之前的代码复杂了,代码中涉及了端口位定义,位变量定义,数组的定义及初始化,函数的定义,C语言中switch case语句的使用等等;我们将在代码部分一一解释。
1.4. 电路设计
本实例的电路图如图1所示。单片机的P0和P1口接两个共阳极数码管,用于秒表显示。按键连接到P3.4端口,P3.4口在按键未按下时处于高电平,按键按下后,变为低电平。
1.5. 程序设计
本实例的程序代码如下所示。
这个程序代码中有很多知识点,我们来学习一下。
1、头文件包含#include <AT89x52.h>
这个语句的作用是将预定义好的51单片机的端口定义、寄存器定义等各种信息包含进来。例如我们在程序中用到的P3^4,EA,TH0等,我们之所以可以直接使用这些名称,就是因为在这个头文件中已经帮我们定义好了。如果程序中没有这条头文件包含的语句,则凡是用到这些名称的语句都会报错。
图3 51单片机头文件部分内容
2、位定义
在程序中有这些语句sbit K1 = P3^4; bit Key_State; 这两个都是位定义语句,只不过两者还有些区别,sbit是定义端口的某一位,而bit则定义一个位数据,这个位数据只有两个值0或1。
3、数组的定义和初始化
看一下这个语句unsigned char DSY_CODE[]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90
}
这个语句实现的功能就是在定义的同时初始化了数组中各元素的值。细心的人可能会发现,这个数组中元素个数没有定义,这是C语言的一个特色:数组定义的同时初始化的话,如果不定义数组元素的个数,那么默认按照初始化的值的个数设置。
再看这个unsigned char ViewData[2]; 只是定义了数组,没有初始化数组元素的值,所以必须指明数组元素的个数,并且如果程序中要对这个数组赋值的话,只能一个一个的赋值,ViewData[0]=0xC0;ViewData[1]=0xC0;而不能直接这样赋值ViewData[2]={0xc0,0xc0};这就是数组定义的同时初始化和数组只定义不初始化时的区别。
4、全局变量
全局变量必须在所有函数之前定义,并且全局变量在程序运行期间,它的值是不变的,除非程序中人为改变了这个值。
5、函数的定义和声明
函数可以在调用之前先声明,然后再调用它的函数之后定义,也可以在声明的同时定义,本例中就是在声明的同时定义。函数的声明只要一句话,例如void Key_Event_Handle(void);而函数的定义是指将函数要实现的功能写出来,具体说就是把函数的内容补充完善。
6、switch case语句
switch case语句属于判断语句,switch后面括号中的变量就是判断条件,这个判断条件只能是整数,不能是小数。每个case语句后面的功能执行完后,最好加一个break语句,以跳出整个判断结构,否则只要下面的case条件满足,就一直执行,这样容易造成混乱。
关于51单片机C语言编程的一些知识,今天就先说到这里,后面我们会有更多了解。
1.6. 实例仿真
编译程序后,将生成的hex文件载入proteus电路的单片机中,开始仿真,仿真时随时按下按键(要默记按键是第几次按下),观察两位数码管显示数字的变化,充分理解该实例的功能实现。
下面视频是本实例的仿真过程。
视频加载中...
1.7. 总结
通过本实例的学习,我们更加熟悉了51单片机定时器/计数器的定时功能,同时也更多的了解了51单片机C语言程序设计中的端口位定义,位变量定义,数组的定义及初始化,函数的定义,C语言中switch case语句的使用等等编程方法,这对我们继续深入掌握编程知识很有用处。
单片机秒表实例
下面是用单片机来实现秒表功能的一个例子, 该源程序已在实验板上调试通过,可直接引用,并可利用软件编程的灵活性,加以拓展,实现更为复杂的功能。
#include <pic.h>
#include <math.h>
//此程序实现计时秒表功能,时钟显示范围 00.00~95.99 秒,分辨度:0.01 秒
unsigned char s0,s1,s2,s3;
//定义 0.01 秒、0.1 秒、1 秒、10 秒计时器
unsigned char s[4];
unsigned char k ,data ,sreg;
unsigned int i;
const table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90};
//不带小数点的显示段码表
const table0[10]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};
//带小数点的显示段码表//TMR0 初始化子程序
void tmint()
{
T0CS=0;//TMR0 工作于定时器方式
PSA=1;//TMR0 不用分频
T0IF=0;//清除 TMR0 的中断标志
T0IE=1;//TMR0 中断允许
}
//spi 显示初始化子程序
void SPIINIT()
{
PIR1=0;
SSPCON=0x30;
SSPSTAT=0xC0;
//设置 SPI 的控制方式,允许 SSP 方式,并且时钟下降沿发送。与"74HC595,当其//SCLK 从低到高跳变时,串行输入寄存器"的特点相对应
TRISC=0xD7;//SDO 引脚为输出,SCK 引脚为输出
TRISA5=0;//RA5 引脚置为输出,输出显示锁存信号
}
//系统其它部分初始化子程序
void initial()
{
TRISB1=0;
TRISB2=0;
TRISB4=1;
TRISB5=1;//设置与键盘有关的各口的输入输出方式
RB1=0;
RB2=0;//建立键盘扫描的初始条件
}
//SPI 传输数据子程序
void SPILED(data)
{
SSPBUF=data;//启动发送
do {
;
}while(SSPIF==0);
SSPIF=0;
}
//显示子程序,显示 4 位数
void dispaly()
{
RA5=0;//准备锁存
for(k=4;k>0;k--)
{
data=s[k-1];
if(k==3) data=table0[data];//第二位需要显示小数点
else data=table[data];
SPILED(data);//发送显示段码
}
for(k=0;k<4;k++)
{
data=0xFF;
SPILED(data);//连续发送 4 个 DARK,使显示好看一些
}
RA5=1;//最后给锁存信号,代表显示任务完成
}
//软件延时子程序
void DELAY()
{
for(i = 3553;--i ;) continue;
}
//键扫描子程序
void KEYSCAN()
{
while(1){
while(1)
{
dispaly();//调用一次显示子程序
if ((RB5==0)||(RB4==0)) break;
}
DELAY();//若有键按下,则软件延时
if ((RB5==0)||(RB4==0)) break;
//若还有键按下,则终止循环扫描,返回
}
}
//等键松开子程序
void keyrelax()
{
while(1){
dispaly();//调用一次显示子程序
if ((RB5==1)&&(RB4==1)) break;
} //为防止按键过于灵敏,每次等键松开才返回
}
//系统赋值初始化子程序
void inizhi()
{
s0=0x00;
s[0]=s0;
s1=0x00;
s[1]=s1;
s2=0x00;
s[2]=s2;
s3=0x00;
s[3]=s3;//s0=s1=s2=s3=0,并放入显示缓冲数组中
sreg=0x00;//tmr0 中断次数寄存器清 0
}
//中断服务程序
void interrupt clkint(void)
{
TMR0=0X13;
//对 TMR0 写入一个调整值。因为写入 TMR0 后接着的
//两个周期不能增量,中断需要 3 个周期的响应时间,
//以及 C 语言自动进行现场保护要消耗周期
T0IF=0;//清除中断标志
CLRWDT();
sreg=sreg+1;//中断计数器加 1
if(sreg==40) //中断次数为 40 后,才对 S0,S1,S2,S3 操作
{
sreg=0;
s0=s0+1;
if(s0==10){
s0=0 ;
s1=s1+1;
if(s1==10){
s1=0 ;
s2=s2+1;
if(s2==10){
s2=0;
s3=s3+1;
if(s3==10) s3=0 ;
}
}
}
}
s[0]=s0;
s[1]=s1;
s[2]=s2;
s[3]=s3;
}
//主程序
main()
{
OPTION=0XFF;
tmint();//TMR0 初始化
SPIINIT();//spi 显示初始化
initial();//系统其它部分初始化
di();//总中断禁止
while(1) {
inizhi();//系统赋值初始化
KEYSCAN();//键扫描,直到开始键按下
keyrelax();//等键松开
ei();//总中断允许
KEYSCAN();//键扫描直到停止键按下,在键扫描时有显示
keyrelax() ;//等键松开
di();//总中断禁止
KEYSCAN();//键扫描到清 0 键按下,在键扫描时有显示
keyrelax() ;//等键松开
}
}
相关问答
单片机 ( 秒表 制作)?,制作 单片机 服务体验如何??[回答]很简单啊,用单片机定时器先定时20ms,再计数50次,即1s,再计数24次,即24秒。计时结束后输出控制信息值LED端口就行了!手打不易,如有帮助请采纳,谢谢!!...
0秒的定时器作用?用于精确定时,如秒表,时钟。还有就是在单片机正常工作时,如果调用延时函数来延时的话,那么单片机在此期间就无法处理其他任务了,如探测其他的一些数据变化量...
没接大功率电器,电表走字太快是什么原因造成的?应"悟空小秘书"邀答!没接大功率电器,把表走字太快是什么原因造成的?1⃣️听电站的老干部讲过,过去的老式电表时代,总表与分表总和悬殊特大,当然有电损...应"悟.....