yyq_007 发表于 2026-6-29 16:06:21

基于6引脚8.8.8.数码管的99.9秒显示器

    1.电路板电路原理
   “擎天柱Ai8051U转89C52-DIP40核心板”,用AI8051U-34k64单片机的timer0产生100us中断,作查理复用方式的LED的底层驱动,timer1中断产生1s计时,累加计时产生1s时间,制作0~99.9计时器,P33外接按键控制定时器启动、暂停、清零,单排6脚3位8.8.8.数码管显示。


   2. 6引脚8.8.8.数码管的电路结构
   3.源代码
   
//主程序文件 main.c
//AI8051U驱动三位8.8.8数码管显示的999s计时器下载成功   32bit模式

/**********************************************************
三位8.8.8数码管,共6个引脚,引脚组合
---    PIN1PIN2PIN3PIN4PIN5PIN6 列/阳极
PIN1    --    DP1   DP2    --   --    --
PIN2    --    --    F1    G1    C1    --
PIN3    --    A1    --    F2    G2    E2
PIN4    --    B1    D2    --    A2    D3
PIN5    G3    E1    B2    C2    --    F3
PIN6    A3    D1    B3    E3    C3    --
行/阴极
********************************************************/


#include "AI8051U.h"                     //调用头文件 手册 AI8051U.PDF
#include "stc32_stc8_usb.h"                //调用头文件
#include "intrins.h"                          //调用头文件
#include "led.h"            //调用led扫描头文件
#include "timer.h"            //调用timer初始化头文件
#include "key.h"            //调用按键扫描头文件
//#include "def.h"                   //调用定义数据类型头文件main.c里包含该头文件

#define MAIN_Fosc      24000000UL   //时钟24MHZ

//全局变量声明
volatile u8 T1_1Sflag=0;          //timer1溢出标志
volatile bit key_stime_ok;      //10ms按键时间标志
volatile u8 T1_100ms,T1_1S = 0;   //100ms,1s计时单元
volatile u8 buff;            //显存

void main(void)
{
          u16 T1_1S=0,T1_cnt=0;         //T1秒计时,及10ms计时
          u8 times = 0,Key_value = 0;   //按键次数,键值

    WTST = 0;      //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    P_SW2 |= EAXFR;//扩展寄存器(XFR)访问使能
    CKCON = 0;       //提高访问XRAM速度
       
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    //P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

       Timer0_init( );             //timer0初始化函数
       Timer1_init( );             //timer1初始化函数
       EA= 1;                   // 开总中断   
   ET0 = 1;                  // 定时/计数器0允许中断
   ET1 = 1;                  // 定时/计数器1允许中断
   while (1)
{
          
                if(key_stime_ok)          //10s按键扫描时间到
                {
                   key_stime_ok = 0;      //10ms按键时间标志清0
                       if(read_key())         //读取键值
                       {
                               times++;             //按键次数加1
                           if(3 == times)       //按键次数达3次
         times = 0;         //按键次数清0
                               switch (times)       //根据按键次数执行不同的动作
                                  {
                                          case 1:
                                                      TR1 = 1;    //T0开始运行
                                              break;
                                          case 2:
                                                      TR1 = 0;    //T0暂停运行
                                              break;
                                                case 0:
                                                      TR1 = 0;       //T0停止运行
                                                      T1_100ms = 0;//100ms计时单元清0
                                                      T1_1S = 0;   //1s计时器清0
                                              break;
                               }
                       }
   }                       
                if(1==T1_1Sflag)          //如果timer1定时1s溢出标志为1
           {
                           T1_1Sflag = 0;      // 必须声明为volatile,防止编译器优化,后面可以省略延时
         //DG_Display(buff,0,buff,0,buff);   //显示xx.x
                           if(++T1_cnt == 100)   //10ms*100=1s
                               {
                                           T1_cnt = 0;                               
                                           //P2^=0xff;       //调试用
                                           T1_1S++;
                                       if(T1_1S > 99)
                                               T1_1S = 0;

                               }
   }
   //DG_Display(buff,0,buff,1,buff);   //显示xx.x 放此处无法显示100ms
   buff =         T1_1S / 10; buff =         T1_1S % 10; buff = T1_100ms;
}
}

//========================================================================
// 函数: void timer0_int (void) interrupt TIMER0_VECTOR
// 描述:timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer0_int (void) interrupt 1   //100us中断一次
{
           static u8 T0_cnt = 0;
               Led_under_deal( );                    //数码管灯阵扫描函数
               if(++T0_cnt == 100)            //满100us*100=10ms
               {
                       T0_cnt = 0;
                       key_stime_ok = 1;                        //按键扫描标志置1
                       DG_Display(buff,0,buff,1,buff);   //显示xx.x
               }
                       
}
//========================================================================
// 函数: void timer1_int (void) interrupt TIMER1_VECTOR
// 描述:timer1中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer1_int (void) interrupt 3
{
    static u8 T1_cnt = 0;
          if(++T1_cnt == 50)   //满2ms*50=100ms
                {
                        T1_cnt = 0;
                        T1_100ms++;         //T1定时100ms单元加1
                        if(10 == T1_100ms)
                        {
                                T1_100ms = 0;
                                T1_1Sflag = 1;          //timer1定时1s溢出标志置1
                        }
                }
}
//按键扫描C文件   key.c
#include "key.h"      //调用按键扫描头文件
#include "AI8051U.h"                //调用头文件 手册 AI8051U.PDF

//======基于状态机的按键处理程序=============================
sbit KWIN = P3^3;         //单按键位置INT1
#define key_state_00   //状态0,初态,无按键按下
#define key_state_11    //状态1,按键确认态
#define key_state_22    //状态2,计时1

unsigned char read_key(void)
{
        static unsigned char key_state = 0;
        unsigned char key_press, key_return = 0;
        P3M1 &= ~(1 << 3);   P3M0 &= ~(1 << 3);   //P33设置为准双向口
        P3 |= 1 << 3;      //P33写1
        key_press = KWIN;       // 读按键I/O电平
        switch (key_state)
        {
                case key_state_0:// 按键初始态
                                if (!key_press) key_state = key_state_1;// 键被按下,状态转换到键确认态
                                break;
                case key_state_1:// 按键确认态
                                        if (!key_press)
            {
                key_return = 1;// 输出"1"
                                                        key_state = key_state_2;// 按键仍按下,状态转换到计时1
            }
                                else
                                                key_state = key_state_0;// 按键已抬起,转换到按键初始态
                                break;
                case key_state_2:
                                if (key_press)
         key_state = key_state_0;// 按键已释放,转换到按键初始态
                                break;

}
    return key_return;
}



//LED驱动函数C文件   led.c
#include "led.h"
/**********************************************************
三位8.8.8数码管,共6个引脚,引脚组合
---    PIN1PIN2PIN3PIN4PIN5PIN6 列/阳极
PIN1    --    DP1   DP2    --   --    --
PIN2    --    --    F1    G1    C1    --
PIN3    --    A1    --    F2    G2    E2
PIN4    --    B1    D2    --    A2    D3
PIN5    G3    E1    B2    C2    --    F3
PIN6    A3    D1    B3    E3    C3    --
行/阴极
********************************************************/
ByteBit_Union DG1_Flag = {0};    //变量不可以放led.h文件里定义
ByteBit_Union DG2_Flag = {0};    //此处定义可以加初值
ByteBit_Union DG3_Flag = {0};
/*********************************************************
函数:Led_under_deal
描述:    LED底层处理(正反扫)(100us 中断)
输入值: 无
输出值: 无
返回值: 无
**********************************************************/

void Led_under_deal(void)
{
        static    unsigned char led_disp_step = 0; //static
        //全部端口为输入口
        led_io_1_in;
        led_io_2_in;
        led_io_3_in;
        led_io_4_in;
        led_io_5_in;
        led_io_6_in;

        clr_led_io_1;//
        clr_led_io_2;
        clr_led_io_3;
        clr_led_io_4;
        clr_led_io_5;
        clr_led_io_6;
        //根据引脚组合按行扫描
        if(led_disp_step==0)   //第一行
        {
                if(DG1_DP)
                {
                        led_io_2_out;
                        set_led_io_2;
                }
                if(DG2_DP)
                {
                        led_io_3_out;
                        set_led_io_3;
                }
                led_io_1_out;
                clr_led_io_1;
        }
        else if(led_disp_step==1)//第二行
        {
                if(DG1_F)
                {
                        led_io_3_out;
                        set_led_io_3;
                }
                if(DG1_G)
                {
                        led_io_4_out;
                        set_led_io_4;
                }
                if(DG1_C)
                {
                        led_io_5_out;
                        set_led_io_5;
                }
                led_io_2_out;
                clr_led_io_2;
        }
        else if(led_disp_step==2) //第三行
        {
                if(DG1_A)
                {
                        led_io_2_out;
                        set_led_io_2;
                }
                if(DG2_F)
                {
                        led_io_4_out;
                        set_led_io_4;
                }
                if(DG2_G)
                {
                        led_io_5_out;
                        set_led_io_5;
                }
                if(DG2_E)
                {
                        led_io_6_out;
                        set_led_io_6;
                }
                led_io_3_out;
                clr_led_io_3;
        }
        else if(led_disp_step==3)//第四行
        {
                if(DG1_B)
                {
                        led_io_2_out;
                        set_led_io_2;
                }
                if(DG2_D)
                {
                        led_io_3_out;
                        set_led_io_3;
                }
                if(DG2_A)
                {
                        led_io_5_out;
                        set_led_io_5;
                }
                if(DG3_D)
                {
                        led_io_6_out;
                        set_led_io_6;
                }
                led_io_4_out;
                clr_led_io_4;
        }
        else if(led_disp_step==4)//第5行
        {
                if(DG3_G)
                {
                        led_io_1_out;
                        set_led_io_1;
                }
                if(DG1_E)
                {
                        led_io_2_out;
                        set_led_io_2;
                }
                if(DG2_B)
                {
                        led_io_3_out;
                        set_led_io_3;
                }
                if(DG2_C)
                {
                        led_io_4_out;
                        set_led_io_4;
                }
                if(DG3_F)
                {
                        led_io_6_out;
                        set_led_io_6;
                }
                led_io_5_out;
                clr_led_io_5;
        }
        else if(led_disp_step==5)//第6行
        {
                if(DG3_A)
                {
                        led_io_1_out;
                        set_led_io_1;
                }
                if(DG1_D)
                {
                        led_io_2_out;
                        set_led_io_2;
                }
                if(DG3_B)
                {
                        led_io_3_out;
                        set_led_io_3;
                }
                if(DG3_E)
                {
                        led_io_4_out;
                        set_led_io_4;
                }
                if(DG3_C)
                {
                        led_io_5_out;
                        set_led_io_5;
                }
                led_io_6_out;
                clr_led_io_6;
        }
        led_disp_step++;
        if(led_disp_step>=6)led_disp_step=0;
}


/*数码全显或全关*/
void DG_ALL(unsigned char EN_DIS)
{
        if(EN_DIS)        //全开
        {
                DG1_Flag.byte = 0xff;
                DG2_Flag.byte = 0xff;
      DG3_Flag.byte = 0xff;       
        }
        else        //全关
        {
                DG1_Flag.byte = 0;
                DG2_Flag.byte = 0;                               
                DG3_Flag.byte = 0;
        }
}
//3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3)
{       
        DG_ALL(0);//全写0,灭
    if(1 == dp1) DG1_DP = 1;   //显示第一位.
    if(1 == dp2) DG2_DP = 1;   //显示第二位.
        switch(num1)
        {
                case 0:        //A.B.C.D.E.F
            //if(1 == dp1) DG1_DP = 1;   //.
                        DG1_A = 1;DG1_B = 1;DG1_C = 1;
            DG1_D = 1;DG1_E = 1;DG1_F = 1;         
                        break;
                case 1:        //B.C
                  DG1_B = 1;DG1_C = 1;       
                        break;
                case 2:        //A.B.D.E.G
                  DG1_A = 1;DG1_B = 1;DG1_D = 1;
            DG1_E = 1;DG1_G = 1;
                        break;               
                case 3:        //A.B.C.D.G
                  DG1_A = 1;DG1_B = 1;DG1_C = 1;
            DG1_D = 1;DG1_G = 1;       
                        break;
                case 4:        //B.C.F.G
                  DG1_B = 1;DG1_C = 1;DG1_F = 1;
                        DG1_G = 1;       
                        break;
                case 5:        //A.C.D.F.G
                  DG1_A = 1;
                        DG1_C = 1;DG1_D = 1;
                        DG1_F = 1;DG1_G = 1;       
                        break;       
                case 6:        //A.C.D.E.F.G
                  DG1_A = 1;DG1_C = 1;DG1_D = 1;
                        DG1_E = 1;DG1_F = 1;DG1_G = 1;       
                        break;               
                case 7:        //A.B.C
                  DG1_A = 1;DG1_B = 1;DG1_C = 1;       
                        break;
                case 8:        //A.B.C.D.E.F.G
                  DG1_A = 1;DG1_B = 1;DG1_C = 1;DG1_D = 1;
                        DG1_E = 1;DG1_F = 1;DG1_G = 1;       
                        break;
                case 9:        //A.B.C.D.F.G
                  DG1_A = 1;DG1_B = 1;DG1_C = 1;
            DG1_D = 1;DG1_F = 1;DG1_G = 1;               
                        break;
      default:break;                       
        }
        switch(num2)
        {
                case 0:        //A.B.C.D.E.F
         //if(1 == dp2) DG2_DP = 1;   //.
                        DG2_A = 1;DG2_B = 1;DG2_C = 1;
            DG2_D = 1;DG2_E = 1;DG2_F = 1;      
                        break;
                case 1:        //B.C
                        DG2_B = 1;DG2_C = 1;
                        break;
                case 2:        //A.B.D.E.G
                        DG2_A = 1;DG2_B = 1;DG2_D = 1;
                        DG2_E = 1;DG2_G = 1;
                        break;               
                case 3:        //A.B.C.D.G
                        DG2_A = 1;DG2_B = 1;DG2_C = 1;
            DG2_D = 1;DG2_G = 1;
                        break;
                case 4:        //B.C.F.G
                        DG2_B = 1;DG2_C = 1;DG2_F = 1;DG2_G = 1;
                        break;
                case 5:        //A.C.D.F.G
                        DG2_A = 1;DG2_C = 1;DG2_D = 1;
                        DG2_F = 1;DG2_G = 1;
                        break;       
                case 6:        //A.C.D.E.F.G
                        DG2_A = 1;DG2_C = 1;DG2_D = 1;
                        DG2_E = 1;DG2_F = 1;DG2_G = 1;
                        break;               
                case 7:        //A.B.C
                        DG2_A = 1;DG2_B = 1;DG2_C = 1;
                        break;
                case 8:        //A.B.C.D.E.F.G
                        DG2_A = 1;DG2_B = 1;DG2_C = 1;DG2_D = 1;
                        DG2_E = 1;DG2_F = 1;DG2_G = 1;
                        break;
                case 9:        //A.B.C.D.F.G
                        DG2_A = 1;DG2_B = 1;DG2_C = 1;
            DG2_D = 1;DG2_F = 1;DG2_G = 1;
                        break;
      default:break;                       
        }

        switch(num3)
        {
                case 0:        //A.B.C.D.E.F
                        DG3_A = 1;DG3_B = 1;DG3_C = 1;
            DG3_D = 1;DG3_E = 1;DG3_F = 1;      
                        break;
                case 1:        //B.C
                        DG3_B = 1;DG3_C = 1;
                        break;
                case 2:        //A.B.D.E.G
                        DG3_A = 1;DG3_B = 1;DG3_D = 1;
            DG3_E = 1;DG3_G = 1;
                        break;               
                case 3:        //A.B.C.D.G
                        DG3_A = 1;DG3_B = 1;DG3_C = 1;
            DG3_D = 1;DG3_G = 1;
                        break;
                case 4:        //B.C.F.G
                        DG3_B = 1;DG3_C = 1;
                        DG3_F = 1;DG3_G = 1;
                        break;
                case 5:        //A.C.D.F.G
                        DG3_A = 1;DG3_C = 1;DG3_D = 1;
            DG3_F = 1;DG3_G = 1;
                        break;       
                case 6:        //A.C.D.E.F.G
                        DG3_A = 1;DG3_C = 1;DG3_D = 1;
                        DG3_E = 1;DG3_F = 1;DG3_G = 1;
                        break;               
                case 7:        //A.B.C
                        DG3_A = 1;DG3_B = 1;DG3_C = 1;
                        break;
                case 8:        //A.B.C.D.E.F.G
                        DG3_A = 1;DG3_B = 1;DG3_C = 1;DG3_D = 1;
                        DG3_E = 1;DG3_F = 1;DG3_G = 1;
                        break;
                case 9:        //A.B.C.D.F.G
                        DG3_A = 1;DG3_B = 1;DG3_C = 1;
            DG3_D = 1;DG3_F = 1;DG3_G = 1;
                        break;
      default:break;                       
        }
       
}//led扫描头文件led.h
#ifndef __LED_H__            
#define __LED_H__

#include "AI8051U.h"                //调用头文件 手册 AI8051U.PDF
#include "def.h"                   //调用定义数据类型头文件


//typedef         unsigned char        u8;
//typedef         unsigned int        u16;
//typedef         unsigned long        u32;

//#define u8unsigned char
//#define u16unsigned int
       

typedef union
{
        unsigned char byte;
        struct{
                unsigned char bit0:1;
                unsigned char bit1:1;
                unsigned char bit2:1;
                unsigned char bit3:1;
                unsigned char bit4:1;
                unsigned char bit5:1;
                unsigned char bit6:1;
                unsigned char bit7:1;
        }Bits;
}ByteBit_Union;


//#defineled_io_6P05   //led io口
//#defineled_io_5P04   //led io口
//#defineled_io_4P03   //led io口
//#defineled_io_3P02   //led io口
//#defineled_io_2P01   //led io口
//#defineled_io_1P00   //led io口

//某位清0
//#defineclr_led_io_6   P0 &=~(1<<5)      //led_io_6=0
#defineclr_led_io_6   P05 = 0
#defineclr_led_io_5   P04 = 0         //led io口清0
#defineclr_led_io_4   P03 = 0         //led io口清0
#defineclr_led_io_3   P02 = 0         //led io口清0
#defineclr_led_io_2   P01 = 0          //led io口清0
#defineclr_led_io_1   P00 = 0          //led io口清0

//某位置1
//#defineset_led_io_6   P0 |=(1<<5)   //led io口写1
#defineset_led_io_6   P05 = 1
#defineset_led_io_5   P04 = 1      //led io口写1
#defineset_led_io_4   P03 = 1      //led io口写1
#defineset_led_io_3   P02 = 1      //led io口写1
#defineset_led_io_2   P01 = 1       //led io口写1
#defineset_led_io_1   P00 = 1       //led io口写1


#defineled_io_6_in{P0M1 |=1<<5;P0M0 &= ~(1<<5);}   //io6置为高阻输入
#defineled_io_5_in{P0M1 |=1<<4;P0M0 &= ~(1<<4);}        //io5置为输入
#defineled_io_4_in{P0M1 |=1<<3;P0M0 &= ~(1<<3);}        //io4置为输入
#defineled_io_3_in{P0M1 |=1<<2;P0M0 &= ~(1<<2);}        //io3置为输入
#defineled_io_2_in{P0M1 |=1<<1;P0M0 &= ~(1<<1);}        //io2置为输入
#defineled_io_1_in{P0M1 |=1<<0;P0M0 &= ~(1<<0);}        //io1置为输入



#defineled_io_6_out{P0M1 &= ~(1<<5);P0M0|=1<<5;}
#defineled_io_5_out{P0M1 &= ~(1<<4);P0M0|=1<<4;}   //io5置为推挽输出
#defineled_io_4_out{P0M1 &= ~(1<<3);P0M0|=1<<3;}   //io4置为输出
#defineled_io_3_out{P0M1 &= ~(1<<2);P0M0|=1<<2;}   //io3置为输出
#defineled_io_2_out{P0M1 &= ~(1<<1);P0M0|=1<<1;}   //io2置为输出
#defineled_io_1_out{P0M1 &= ~(1<<0);P0M0|=1<<0;}   //io1置为输出

/*数码管段显*/
extern ByteBit_Union DG1_Flag;
#define DG1_A DG1_Flag.Bits.bit0
#define DG1_B DG1_Flag.Bits.bit1
#define DG1_C DG1_Flag.Bits.bit2
#define DG1_D DG1_Flag.Bits.bit3
#define DG1_E DG1_Flag.Bits.bit4
#define DG1_F DG1_Flag.Bits.bit5
#define DG1_G DG1_Flag.Bits.bit6
#define DG1_DP DG1_Flag.Bits.bit7

extern ByteBit_Union DG2_Flag;
#define DG2_A DG2_Flag.Bits.bit0
#define DG2_B DG2_Flag.Bits.bit1
#define DG2_C DG2_Flag.Bits.bit2
#define DG2_D DG2_Flag.Bits.bit3
#define DG2_E DG2_Flag.Bits.bit4
#define DG2_F DG2_Flag.Bits.bit5
#define DG2_G DG2_Flag.Bits.bit6
#define DG2_DP DG2_Flag.Bits.bit7

extern ByteBit_Union DG3_Flag;
#define DG3_A DG3_Flag.Bits.bit0
#define DG3_B DG3_Flag.Bits.bit1
#define DG3_C DG3_Flag.Bits.bit2
#define DG3_D DG3_Flag.Bits.bit3
#define DG3_E DG3_Flag.Bits.bit4
#define DG3_F DG3_Flag.Bits.bit5
#define DG3_G DG3_Flag.Bits.bit6
//#define DG3_DP DG3_Flag.Bits.bit7

void Led_under_deal(void);                //数码管灯阵扫描函数,100us调用一次
void DG_ALL(unsigned char EN_DIS);        //数码全显或全关
//3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3);

//extern ByteBit_Union DG1_Flag;    //变量放led.h文件里声明需加extern修饰
//extern ByteBit_Union DG2_Flag;    //但不可定义,加上初值
//extern ByteBit_Union DG3_Flag;

#endif
//timer初始化C文件
#include "timer.h"      //调用timer初始化头文件
#include "AI8051U.h"                //调用头文件 手册 AI8051U.PDF
       

#define MAIN_Fosc      24000000UL   //时钟24MHZ

//24MHZ,1T,一条指令耗时1/24us,定时100us,初值2400
//Timer 0 中断频率, 10000次/秒,定时100us,1/100us=10000HZ
#define Timer0_Reload   (MAIN_Fosc / 10000)   //定时100us
#define Timer1_Reload   (MAIN_Fosc / 48000)   //定时2ms


//官方文件
void Timer0_init(void)
{
      TR0 = 0;    //停止计数

    #if (Timer0_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer0设置的中断过快!"

    #elif ((Timer0_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET0 = 1;    //允许中断
    //PT0 = 1;    //高优先级中断
      TMOD &= ~0x03;
      TMOD |= 0;//工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
    //T0_CT = 1;//计数
      T0_CT = 0;//定时
    //T0CLKO = 1; //输出时钟
      T0CLKO = 0; //不输出时钟

      #if (Timer0_Reload < 65536UL)
            T0x12 = 1;//1T mode
            TH0 = (u8)((65536UL - Timer0_Reload) / 256);
            TL0 = (u8)((65536UL - Timer0_Reload) % 256);
      #else
            T0x12 = 0;//12T mode
            TH0 = (u8)((65536UL - Timer0_Reload/12) / 256);
            TL0 = (u8)((65536UL - Timer0_Reload/12) % 256);
      #endif

      TR0 = 1;    //开始运行

    #else
      #error "Timer0设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void Timer1_init(void)
// 描述: timer1初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer1_init(void)
{
      TR1 = 0;    //停止计数

    #if (Timer1_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer1设置的中断过快!"

    #elif ((Timer1_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET1 = 1;    //允许中断
    //PT1 = 1;    //高优先级中断
      TMOD &= ~0x30;
      TMOD |= (0 << 4);   //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装
    //T1_CT = 1;//计数
      T1_CT = 0;//定时
    //T1CLKO = 1; //输出时钟
      T1CLKO = 0; //不输出时钟

      #if (Timer1_Reload < 65536UL)
            T1x12 = 1;//1T mode
            TH1 = (u8)((65536UL - Timer1_Reload) / 256);
            TL1 = (u8)((65536UL - Timer1_Reload) % 256);
      #else
            T1x12 = 0;//12T mode
            TH1 = (u8)((65536UL - Timer1_Reload/12) / 256);
            TL1 = (u8)((65536UL - Timer1_Reload/12) % 256);
      #endif

      //TR1 = 1;    //开始运行

    #else
      #error "Timer1设置的中断过慢!"
    #endif
}
//timer.h4.视频效果

狂热主宰 发表于 2026-6-29 16:26:22

这种方式用少量io引脚
而io需支持高阻

晓飛飛 发表于 2026-6-29 16:31:05

显示驱动部分要是有详细注释就更好了{:qiang:}

狂热主宰 发表于 2026-6-29 16:33:56

经典的89系列没有高阻模式

yyq_007 发表于 2026-6-29 17:18:02

1. LED底层处理(正反扫)(100us 中断)

void Led_under_deal(void)
要结合表格三位8.8.8数码管,共6个引脚,引脚组合
---    PIN1PIN2PIN3PIN4PIN5PIN6   列/阳极
PIN1    --    DP1   DP2    --   --    --            第一行
PIN2    --    --    F1    G1    C1    --            第2行
PIN3    --    A1    --    F2    G2    E2
PIN4    --    B1    D2    --    A2    D3
PIN5    G3    E1    B2    C2    --    F3
PIN6    A3    D1    B3    E3    C3    --
行/阴极
例如      if(led_disp_step==0)   //第一行
45.         {
46.                 if(DG1_DP)      //点亮DG1_DP
47.                 {
48.                         led_io_2_out;    //正极输出口
49.                         set_led_io_2;   //正极输出1
50.                 }
51.                 if(DG2_DP)         //点亮DG2_DP
52.                 {
53.                         led_io_3_out;    //正极输出口
54.                         set_led_io_3;   //输出1
55.                 }
56.                 led_io_1_out;       //负极输出口
57.                 clr_led_io_1;      //负极输出0
58.         }
为了可以使用每一段,定义了联合位域结构体。
2. //3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3)
{      
      case 0:      //A.B.C.D.E.F这里实际采用了共阴数码管的字段码,显示0,码是0x3f,其他类似

yyq_007 发表于 2026-6-29 17:21:05

为了限流,每一个LED引脚串联了47欧+47欧电阻

wulin 发表于 2026-6-30 08:12:20

yyq_007 发表于 2026-6-29 17:21
为了限流,每一个LED引脚串联了47欧+47欧电阻

https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=24176&pid=219748

梁工 发表于 2026-6-30 10:59:46

楼主程序整得比较复杂,其实这种数码管有规律的,按照其规律驱动,程序会比较简单。

这种数码管常见于移动电源(充电宝)、无线话筒、小家电上。
大量使用的充电宝的驱动方式,N个IO最多可以驱动N(N-1)个LED,称之为“查理复用”,驱动原则是:
分N个时隙驱动,每次驱动时一个IO做COM驱动,另外(N-1)个IO做SEG驱动。
先把所有IO设置为高阻。
对于共阴,不显示的SEG为高阻,显示的SEG推挽输出1, COM推挽输出0。
对于共阳,不显示的SEG为高阻,显示的SEG推挽输出0, COM推挽输出1。

狂热主宰 发表于 2026-6-30 11:22:45

梁工 发表于 2026-6-30 10:59
楼主程序整得比较复杂,其实这种数码管有规律的,按照其规律驱动,程序会比较简单。

这种数码管常见于移动 ...

学习初期自个思考的常见写法
后期可尝试整理使用循环和数组
逻辑整合简化可能程序到百行左右

晓飛飛 发表于 2026-6-30 13:40:50

yyq_007 发表于 2026-6-29 17:21
为了限流,每一个LED引脚串联了47欧+47欧电阻
从我的实践经验来看,相比高阻模式+推挽模式+外部限流电阻的组合,使用开漏模式+内部上拉实现的效果更好一些,而且更省物料
查理复用结构的数码管每个IO都串限流电阻的话,容易出现部分笔划亮度不均匀的情况
页: [1] 2
查看完整版本: 基于6引脚8.8.8.数码管的99.9秒显示器