51单片机任务,设计一个频率计,在数码管中显示。
我写的代码显示不了数据,不知道有什么问题,希望有朋友能帮忙解决。
```c
#include <at89x52.h>
/*段码表************************************************************/
#define SEGA 0X80
#define SEGB 0X40
#define SEGC 0X20
#define SEGD 0X10
#define SEGE 0X8
#define SEGF 0X4
#define SEGG 0X2
#define SEGH 0X1
code unsigned char SEGTAB[]={
SEGA+SEGB+SEGC+SEGD+SEGE+SEGF,// ;0
SEGB+SEGC,// ;1
SEGA+SEGB+SEGD+SEGE+SEGG,// ;2
SEGA+SEGB+SEGC+SEGD+SEGG,// ;3
SEGB+SEGC+SEGF+SEGG ,// ;4
SEGA+SEGC+SEGD+SEGF+SEGG,// ;5
SEGA+SEGC+SEGD+SEGE+SEGF+SEGG,// ;6
SEGA+SEGB+SEGC ,// ;7
SEGA+SEGB+SEGC+SEGD+SEGE+SEGF+SEGG,// ;8
SEGA+SEGB+SEGC+SEGD+SEGF+SEGG,// ;9
SEGA+SEGB+SEGC+SEGE+SEGF+SEGG,// ;A
SEGC+SEGD+SEGE+SEGF+SEGG ,// ;B
SEGA+SEGD+SEGE+SEGF ,// ;C
SEGB+SEGC+SEGD+SEGE+SEGG ,// ;D
SEGA+SEGD+SEGE+SEGF+SEGG ,// ;E
SEGA+SEGE+SEGF+SEGG ,// ;F
SEGB+SEGC+SEGE+SEGF+SEGG ,// ;H
};
code unsigned char BitSel[8]={
0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f};
//延时
void delay(unsigned char ms)
{
unsigned int dly;
while(ms--)
{
dly = 89; //定义89差不多是一微秒
while(dly--)
{;}
}
}
unsigned char smg_buffer[8];
unsigned char T0count; //T0的计数器值
unsigned char timecount; //计时计数器值
unsigned char flag=0; //标志位
unsigned long x; //频率值
void DispDrv()
{
static unsigned char i;
for(i = 0;i < 8;i++)
{
P0=SEGTAB[smg_buffer[i]]; //输出待显示数据
P2=BitSel[i];
delay(2);
P2=0xff; //初始化选择引脚
}
}
//中断初始化
void Timer0_INIT()
{
TMOD=0x15; //设置定时器工作方式
TH0=0;
TL0=0;
TH1=(65536-5000)/256;
TL1=(65536-5000)%256; //初始化T1
TR1=1;
TR0=1;
ET0=1;
ET1=1;
}
//定时器T1中断服务子函数
void t1(void) interrupt 3 using 0
{
TH1=(65536-5000)/256;
TL1=(65536-5000)%256; //初始化T1预装值,1ms定时
timecount++; //扫描
if(timecount==200) //秒定时
{
TR0=0; //启动T0
timecount=0;
flag=1;
}
DispDrv();
}
//定时器T0中断服务子函数
void t0(void) interrupt 1 using 0
{
T0count++;
}
//频率计算
void fre(void)
{
unsigned char i;
x=T0count*65536+TH0*256+TL0; //得到T0的16位计数器值
for(i=0;i<8;i++)
{
smg_buffer[i]=0;
}
smg_buffer[0] = x/10000000%10;
smg_buffer[1] = x/1000000%10;
smg_buffer[2] = x/100000%10;
smg_buffer[3] = x/10000%10;
smg_buffer[4] = x/1000%10;
smg_buffer[5] = x/100%10;
smg_buffer[6] = x/10%10;
smg_buffer[7] = x%10;
timecount=0;
T0count=0;
}
void main()
{
Timer0_INIT();
EA = 1;
while(1){
if(flag==1)
{
flag=0;
fre(); //频率计算函数
TH0=0;
TL0=0;
TR0=1;
}
delay(10); // 延时10毫秒
}
}
在中断里改变的全局变量,比如T0count, flag之类的,定义和声明的时候需要加上volatile。
数码管非常常见,就是8字形管,形状很红路灯的倒计时一样,不过红绿灯是用多个LED模拟数码管,
从上图可以看到一个数码管有8段组成,abcdefg七段组成数字,dp是小数点,而七段数码管就 是少了dp小数点;数码管的abcdefg分别对应P0的低7位,dp对应第8位;由于我们的是共阴极的,所以只要在对应的段上加上高电平就可以点亮这个数码管。
我们的代码实现如下:
#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
#define TUBE P0 //定义宏变量
sbit S1=P2^2; //这三位是片选,我们的板子上有8个数码管,通过片选可以让任意一个有效;
sbit S2=P2^3;
sbit S3=P2^4;
u8 code digit_table[]={//定义每一个数字对应的数码管值
0x3f/*0*/, 0x06/*1*/, 0x5b/*2*/, 0x4f/*3*/,
0x66/*4*/, 0x6d/*5*/, 0x7d/*6*/, 0x07/*7*/,
0x7f/*8*/, 0x6f/*9*/, 0x77/*A*/, 0x7c/*b*/,
0x39/*C*/, 0x5e/*d*/, 0x79/*E*/, 0x71/*F*/,
0x00
};
void select_tube(u8 n)
{
S1=n%2;
S2=n/2%2;
S3=n/4%2;
}
void delay_ms(u16 n)
{
u8 i;
while(n--)
{
i = 111;
while(i--);
}
}
void main()
{
u8 j;
while(1)
{
for(j=0; j < 16; j++)
{
select_tube(0);
TUBE=digit_table[j];
delay_ms(300);
}
}
}
这个程序的效果就是让第一个数码管循环显示0-F。
u8 code digit_table[]={//定义每一个数字对应的数码管值
0x3f/*0*/, 0x06/*1*/, 0x5b/*2*/, 0x4f/*3*/,
0x66/*4*/, 0x6d/*5*/, 0x7d/*6*/, 0x07/*7*/,
0x7f/*8*/, 0x6f/*9*/, 0x77/*A*/, 0x7c/*b*/,
0x39/*C*/, 0x5e/*d*/, 0x79/*E*/, 0x71/*F*/,
0x00
};
大家有没有发现这里有个code关键字,我也是第一次遇到,C语音中没有这个关键字,这个关键字是用来告诉编译器数组digit_table放在代码段,而不是放在默认的数据段;
放在代码段可以减小程序的体积,但是会放在代码段的变量是不能修改的,必须是只读的;
我还遇到一个疑问,正常来说如果放在代码段,code应该会增大,而data应该会减小;反过来如果放在数据段,data应该变大,而code应该变小,但结果却是放在代码段,data和code都变小了,如下:
没有使用code编译时:
Program Size: data=26.0 xdata=0 code=230
使用code编译时:
Program Size: data=9.0 xdata=0 code=99
这是一个值得研究的问题!