51单片机C语言问题

51单片机任务,设计一个频率计,在数码管中显示。

我写的代码显示不了数据,不知道有什么问题,希望有朋友能帮忙解决。

img


```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。

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7753934
  • 这篇博客也不错, 你可以看下利用51单片机统计脉冲个数,即时输出显示
  • 除此之外, 这篇博客: 【51单片机】静态数码管显示中的 什么是数码管? 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 数码管非常常见,就是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

    这是一个值得研究的问题!

  • 您还可以看一下 朱有鹏老师的巫妖王51单片机开发板配套视频课程课程中的 选择巫妖王51单片机开发板的优势小节, 巩固相关知识点