关于两位数码管进行交通信号系统控制的c51代码理解问题

问题遇到的现象和发生背景

单片机交通信号灯控制的一段代码,其中黄灯显示5s,被吞了一秒,第一个绿灯倒计时到最后1s切换的,第二个绿灯显示30s也被吞了一秒,从29s开始的,第二个黄灯从第4s倒数到0s,理解上可能是程序顺序的问题,但是想了好多也没解决
初始状态1南北绿灯通车,东西红灯亮。过25s,转状态2,南北绿灯闪烁5s。转状态3南北绿灯灭南北黄灯亮,东西红灯继续亮,过5s,再转状态4,南北黄灯灭,东西绿灯通车,南北红灯亮。过25s,转状态5,东西绿灯闪烁5s。转状态6,东西绿灯灭东西黄灯亮,南北红灯继续亮,过5s,又循环至状态1。
p0.0--0.2为东西方向的红黄绿LED
p0.3--0.5为南北方向的红黄绿LED
p1.0--1.7为位选段,p2.0--2.1为段选位

问题相关代码,请勿粘贴截图
#include <reg51.h>
typedef unsigned char u8;//对unsigned char类型变量起一个别名叫u8便于编写
typedef unsigned int u16;//对unsigned int类型变量起一个别名叫u16便于编写
sbit shi=P2^0;
sbit ge=P2^1;
u16 date=0;
u8 code weil[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极的数码管7SEG-MPX2-CC-BLUE显示数字0~9(CA是共阳的,CC是共阴的)    
u8 a=30,b=30,c=6,d=6;    //各个状态数码管显示位,a是状态1,c是状态3,b是状态4,d是状态6
void delay(u16 i)     //延时函数
{    u16 m,n;
     for(m=0;m<i;m++)
         for(n=0;n<120;n++);     
}
void smg(u16 x)            //数码管显示函数
{ u16 g,s;       
     g=x%10;
     s=x/10%10;         //将数据位(a,b,c,d)拆分为个位,十位后进行分别显示
     /* s=dat%100/10;            
     g=dat%100%10/1; */  //另一种方法
     shi=0;                    //shi 第一位数码管为0 为亮
     ge=1;                    //ge 第二位数码管为1 不亮
     P1=weil[s];   //算是字节操作控制数码管中的8个发光二极管的发光,两位数码管经过很快速度的切换显示,形成计时(动态显示方式)
     delay(10);
     shi=1;
     ge=0;
     P1=weil[g];
     delay(10);                //消影,消除数码管残影
     P1=0x00;               //切换动画
}

void init()             //初始化定时器0
{          
     TMOD=0x01;        //使用定时器T0的模式1
     TH0 = 0xD8;      
       TL0 = 0xF0;      //65536-10000=55536=D8F0(十六进制),设置定时时间10毫秒
     EA=1;             //总中断允许
     ET0=1;              //定时器中断源允许
     TR0=1;              //启动定时器T0                                                
}
void run()
{         
         if(date<30)
              {
                P0=0xDE;        //对P0进行赋值为0xDE 南北绿灯亮
                if(date>=25&&date<30)   //最后5s进行闪烁
                {
                    P0=0x3E;    
                    delay(2);
                    P0=0xDE;
                    delay(2);
                }    
                  smg(a);        //数码管显示计时
              }
             /*if(dat>=25&&dat<=30)
             {
                 P0=0x3E;    
                delay(1);
                P0=0xDE;
                delay(1);
                smg(a);
             }*/        //显示效果不好,绿灯黄灯切换有延迟,可能是使用了两个显示函数的原因吧
        if(date>=30&&date<35)
             {
                 P0=0xEE;      //对P0进行赋值为0xEE 南北黄灯亮
                smg(c);          //数码管显示计时
            }
        if(date>=35&&date<65)
            {
                P0=0xF3;       //对P0进行赋值为0xF3 东西绿灯亮
                if(date>=60&&date<65)  //最后5s进行闪烁
                {
                   P0=0xF7;
                   delay(2);
                   P0=0xF3;
                   delay(2);        
                }          
                smg(b);           //数码管显示计时
            }
        /*if(dat>=60&&dat<=65)
            {
               P0=0xF7;
               delay(1);
               P0=0xF3;
               delay(1);
               smg(b);
            }*/        //显示效果不好,绿灯黄灯切换有延迟,可能是使用了两个显示函数的原因吧
        if(date>=65&&date<70)
            {
                P0=0xF5;      //对P0进行赋值为0xF5 东西黄灯亮
                smg(d);
            }
        if(date==70)
            {
                date=0; a=30,b=30,c=5,d=5; //dat计时到一定值,对数据初始化操作
            }    
}

void handle()
{
     if(date<30)              //dat计时每小于30则对显示数据a进行自减          
           a--;                  //南北绿灯计时     
     if(date>=30&&date<35)      //dat计时每大于30并小于35则对显示数据c进行自减    
           c--;                  //南北黄灯计时          
     if(date>=35&&date<65)      //dat计时每大于35并小于65则对显示数据b进行自减  
           b--;                  //东西绿灯计时
     if(date>=65&&date<70)      //dat计时每大于65并小于70则对显示数据d进行自减     
           d--;                  //东西黄灯计时     
}            
void main()                 //主函数
{ 
    u8 i=0;    
    init();                  //初始化定时器0
    while(1)
    { 
           if(TF0==1)            //判断溢出标志位TF0 为1表示进入定时器中断
            {  
               TF0=0;
               TH0 = 0xD8;          //重新赋值
                  TL0 = 0xF0;       
               i++;                //对i进行自增并进行判断使其每次计时时间接近1秒
               if(i==45)
                {      
                    i=0;
                    date++;        //对数据date进行自增,并进入数据处理函数
                    handle();                         
                } 
               run();              //最后进入实现函数      
            }         
    }
}
运行结果及报错内容

无报错

我的解答思路和尝试过的方法

我把abcd的数值各自提高了一(从5到了6)发现被吞的是最后一秒了(即每个绿灯或者黄灯亮的时间最后一秒不显示之间而进行直接切换了)

我想要达到的结果

预期效果是南北绿灯和东西红灯先亮25s,然后5s内闪烁,到0s切换成黄灯(东西红灯继续亮)亮5s,到0s切换成南北绿灯和黄灯熄灭,东西红灯亮,重复上述过程