数码管作为最廉价的输出设备,在各种自动化设备中有很大的应用,最简单普通的显示方式为动态刷新显示,称为假动态显示,即通过分时扫描每一位,利于人眼的视觉停留现象,造成一种静态显示的效果,如下图所示:
C51单片机由于运行速度很慢,在高刷新频率下,单片机的资源耗费很厉害,这样单片机就不可以再进行大量的计算工作,实际上,单片机在刷新时,只需要周期性的改变GPIO口的状态就可以了,剩下的时间其实都是在空转的状态下,我们能不能将这个空转的状态拿来用呢?当然是可以的啦,这里,我们利用单片机的定时器周期地产能中断,在中断内进行数码管的刷新工作,就可以将等待中断的这个CPU时间拿来做别的事情了。 硬件电路:
代码贴过来: 主函数
#include "shumaguan.h"
#include "timer.h"
sbit sw_jdq=P1^0;//定义一位继电器操作
void main(void)
{
int cnt=0;//设定初值
timer_init();//初始化定时器
while(1)
{
value_now = cnt;//送初值到显示缓存
delay(50);
cnt++;
sw_jdq=~sw_jdq;//切换继电器状态
if(cnt>9999)//数值超出界线,回归最小
cnt=-999;
}
}
数码管驱动函数
#include "shumaguan.h"
#define DType 1 //define the Digital LED type, 1: VCC in common, 0: GND in common
#if DType==1
/*--------------------------------------------------------
Set the digital LED display code
From left to right for
0,1,2,3,4,5,6,7,8,9,a.b,c,d,e,f,dp,-,
--------------------------------------------------------*/
uchar code DS_BUF[]={0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 ,
0x83 , 0xc6 , 0xa1 , 0x86 , 0x8e , 0x7f , 0xbf , 0xff };
#else
uchar code DS_BUF[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 , 0x6b , 0x7d , 0x07 , 0x7f , 0x6f , 0x77 ,
0x7c , 0x39 , 0x5e , 0x79 , 0x71 , 0x80 , 0x40 , 0x00 };
#endif
uchar xdata buf_sm[4]; //set display buffer
uchar frash_cnt=0;//刷新计数器
uchar wei_buf=0x10;//位输出计数器
/*--------------------------
Compute the number from Value
value: something to display, range from -999 to 9999, suport float
--------------------------*/
void calc_sm(float value)
{
uint tmp=0;
if(value>=0)//输入值为正数,不显示负号
{
if(value>9999)//输入值大于9999,显示----
{
buf_sm[0]=17;
buf_sm[1]=17;
buf_sm[2]=17;
buf_sm[3]=17;
}
else if(value>=1000)//输入值大于999,只显示整数
{
tmp=value;
buf_sm[0]=tmp/1000;
buf_sm[1]=tmp%1000/100;
buf_sm[2]=tmp%100/10;
buf_sm[3]=tmp%10;
}
else if(value>=100)//显示一位小数
{
tmp=value*10;
buf_sm[0]=tmp/1000;
buf_sm[1]=tmp%1000/100;
buf_sm[2]=(tmp%100/10)+20;
buf_sm[3]=tmp%10;
}
else if(value>=10)//显示两位小数
{
tmp=value*100;
buf_sm[0]=tmp/1000;
buf_sm[1]=(tmp%1000/100)+20;
buf_sm[2]=tmp%100/10;
buf_sm[3]=tmp%10;
}
else//显示三位小数
{
tmp=value*1000;
buf_sm[0]=(tmp/1000)+20;
buf_sm[1]=tmp%1000/100;
buf_sm[2]=tmp%100/10;
buf_sm[3]=tmp%10;
}
}
else//输入值小于0,显示负号,其余同上
{
if((value<0)&&(value>-10))
{
tmp=value*100;
tmp=abs(tmp);
buf_sm[0]=17;
buf_sm[1]=(tmp/100)+20;
buf_sm[2]=tmp%100/10;
buf_sm[3]=tmp%10;
}
else if((value<=-10)&&(value>-100))
{
tmp=value*10;
tmp=abs(tmp);
buf_sm[0]=17;
buf_sm[1]=(tmp/100);
buf_sm[2]=tmp%100/10+20;
buf_sm[3]=tmp%10;
}
else if((value<=-100)&&(value>-1000))
{
tmp=value;
tmp=abs(tmp);
buf_sm[0]=17;
buf_sm[1]=(tmp/100);
buf_sm[2]=tmp%100/10;
buf_sm[3]=tmp%10;
}
}
}
/*
显示部分,每执行一次,显示的位左移一位,移到最左边时,重新回到最右边,开始下一次刷新。
定义有小数点的位+20,每次送断码,检查大于20,段与0x7f添加小数点。
*/
void display()
{
if(frash_cnt<=3)
{
wei |=0xf0;//数码管的消隐
if(buf_sm[3-frash_cnt]>=20)
{
duan = (DS_BUF[(buf_sm[3-frash_cnt])-20]&0x7f);//显示小数点
}
else
duan = DS_BUF[buf_sm[3-frash_cnt]];//不显示小数点
wei = ~wei_buf;
wei_buf <<=1;//显示位左移一位
frash_cnt++;
}
else
{
wei |=0xf0;//数码管的消隐
frash_cnt=0;
wei_buf=0x10;//显示位回到最右边
}
}
/*
数码管自用延时
*/
void delay(uint i)
{
uchar j;
for(;i>0;i--)
for(j=0;j<120;j++);
}
数码管头文件
#ifndef _shumaguan_h_
#define _shumaguan_h_
#include "math.h"
#include "reg52.h"
#define duan P0
#define wei P2
#define uchar unsigned char
#define uint unsigned int
extern uchar frash_cnt;
extern uchar wei_buf;
void calc_sm(float value);
void display();
void delay(uint i);
#endif
定时器配置及中断服务函数
#include "reg52.h"
#include "timer.h"
#include "shumaguan.h"
float xdata value=0 , value_now = 0;
void timer_init()
{
TMOD = 0x02; //set timer0 as mode1 (16-bit)
TL0 = T1MS; //initial timer0 low byte
TH0 = T1MS; //initial timer0 high byte
TR0 = 1; //timer0 start running
ET0 = 1; //enable timer0 interrupt
EA = 1; //open global interrupt switch
}
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
if(value!=value_now)//检测显示值与当前值是否匹配
{
value=value_now;//刷新显示值
calc_sm(value_now);//重新计算显示值的输出缓冲区
}
display();//刷新数码管显示
}
定时器头文件
#ifndef _timer_h_
#define _timer_h_
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
//-----------------------------------------------
/* define constants */
//#define FOSC 11059200L
#define FOSC 12000000L
#define T1MS 0 //1ms timer calculation method in 12T mode
//-----------------------------------------------
extern float xdata value , value_now;
void timer_init();
#endif