yyq_007 发表于 2026-6-24 22:38:53

基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向左滚动进入

      “擎天柱Ai8051U转89C52-DIP40核心板”附赠的实例很丰富,AI8051U-DEMO-CODE-V1.2文件里有8bit的实例,也有32bit的实例,各有80多个实例,定时器程序见“02-Timer0-Timer1-Timer2-Timer3-Timer4测试程序”,如果用其他Ai8051新片时,可以合理舍去不存在的Timer,上次用延时的方式驱动16x16LED点阵显示多个汉字,这次采用定时器0延时,驱动16x16LED点阵显示汉字,汉字向左循环滚动进入。
      开发板上的16x16LED点阵原理图:

    Proteus仿真图:
   源代码:
//版本2在16x16LED点阵上多个汉字向左滚动进入
//向左滚动进入容易
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/*---------------------------------------------------------------------*/

/*************功能说明    **************
32bit
本例程基于AI8051U为主控芯片进行编写测试。
T0中断100us显示1列


******************************************/

#include "AI8051U.h"
#include "stdio.h"
#include "intrins.h"

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

#define MAIN_Fosc      24000000UL

//==========================================================================
//各定时器加载初值

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

//#define Timer0_Reload   (MAIN_Fosc / 1000)      //Timer 0 中断频率, 1000次/秒,初值24000
#define Timer1_Reload   (MAIN_Fosc / 2000)      //Timer 1 中断频率, 2000次/秒
#define Timer2_Reload   (MAIN_Fosc / 3000)      //Timer 2 中断频率, 3000次/秒
#define Timer3_Reload   (MAIN_Fosc / 4000)      //Timer 3 中断频率, 4000次/秒
#define Timer4_Reload   (MAIN_Fosc / 5000)      //Timer 4 中断频率, 5000次/秒

void    Timer0_init(void);
//void    Timer1_init(void);
//void    Timer2_init(void);
//void    Timer3_init(void);
//void    Timer4_init(void);

bit T0_flag = 0;
#define DUAN1 P0           //段码直驱,NPN管同相驱动,硬件:下半列,bit7在前
#define DUAN2 P2   //段码直驱,NPN管同相驱动,硬件:上半列,bit7在前
#define SCAN P1             //扫描码经4-16译码器驱动

u8 codetab1 [ ]={          
                  //PCtoLCD2002完美版取码软件 阴码 逆向(低位在前。但字节在前?) 逐列   

// 威(0) 海(1) 市(2) 文(3) 登(4) 技(5) 师(6) 学(7) 院(8)
       
//"威"字为STC取码软件:无法生成

0x00,0x80,0x00,0x60,0xF8,0x1F,0x48,0x82,0x48,0x8A,0x48,0x56,0xC8,0x23,0x48,0x52,
0x48,0x8E,0x48,0x40,0xFF,0x27,0x08,0x18,0x09,0x26,0xCA,0x41,0x08,0xF0,0x00,0x00,/*"威",0*/

0x10,0x04,0x60,0x04,0x02,0x7C,0x0C,0x03,0xC0,0x00,0x10,0x01,0x08,0x1D,0xF7,0x13,
0x14,0x11,0x54,0x55,0x94,0x99,0x14,0x51,0xF4,0x3F,0x04,0x11,0x00,0x01,0x00,0x00,/*"海",1*/

0x00,0x00,0x08,0x00,0x88,0x3F,0x88,0x00,0x88,0x00,0x88,0x00,0x89,0x00,0xFA,0xFF,
0x88,0x00,0x88,0x00,0x88,0x10,0x88,0x20,0x88,0x1F,0x08,0x00,0x00,0x00,0x00,0x00,/*"市",2*/

0x08,0x80,0x08,0x80,0x08,0x40,0x38,0x40,0xC8,0x20,0x08,0x11,0x09,0x0A,0x0E,0x04,
0x08,0x0A,0x08,0x11,0xC8,0x20,0x38,0x40,0x08,0x40,0x08,0x80,0x08,0x80,0x00,0x00,/*"文",3*/

0x00,0x01,0x00,0x41,0x8A,0x40,0x52,0x4F,0x22,0x59,0x5A,0x69,0x46,0x49,0x40,0x49,
0x47,0x49,0x58,0x69,0x24,0x59,0x52,0x4F,0x88,0x40,0x04,0x41,0x00,0x01,0x00,0x00,/*"登",4*/

0x10,0x04,0x10,0x44,0x10,0x82,0xFF,0x7F,0x10,0x01,0x90,0x80,0x08,0x80,0x88,0x40,
0x88,0x43,0x88,0x2C,0xFF,0x10,0x88,0x28,0x88,0x46,0x88,0x81,0x08,0x80,0x00,0x00,/*"技",5*/

0x00,0x00,0xFC,0x87,0x00,0x40,0x00,0x30,0xFF,0x0F,0x00,0x00,0x02,0x00,0xE2,0x1F,
0x22,0x00,0x22,0x00,0xFE,0xFF,0x22,0x08,0x22,0x10,0xE2,0x0F,0x02,0x00,0x00,0x00,/*"师",6*/

0x40,0x04,0x30,0x04,0x11,0x04,0x96,0x04,0x90,0x04,0x90,0x44,0x91,0x84,0x96,0x7E,
0x90,0x06,0x90,0x05,0x98,0x04,0x14,0x04,0x13,0x04,0x50,0x04,0x30,0x04,0x00,0x00,/*"学",7*/

0x00,0x00,0xFE,0xFF,0x22,0x04,0x5A,0x08,0x86,0x07,0x10,0x80,0x0C,0x41,0x24,0x31,
0x24,0x0F,0x25,0x01,0x26,0x01,0x24,0x3F,0x24,0x41,0x14,0x41,0x0C,0x71,0x00,0x00,/*"院",8*/
};   //

u8 code   tab2={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};       //扫描码

/******************** 主函数 **************************/
void main(void)
{
    //u16 j = 0;         //1个字的字节数
          u16zishu = 0;       //字数
    u8 lie = 0;          //每个字的列数,1列2个字节,兼作取码序号
          u8 times = 0;      //每个字重复显示的遍数

        WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0xff;   //设置P0为推挽输出
    P1M1 = 0x00;   P1M0 = 0xff;   //设置P1为推挽输出
    P2M1 = 0x00;   P2M0 = 0xff;   //设置P2为推挽输出       

          //不用的端口要配置为准双向口,确保系统的稳定性和可靠性
          P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口



    Timer0_init();
//    Timer1_init();
//    Timer2_init();
//    Timer3_init();
//    Timer4_init();

                TF0 = 0;                //清除TF0标志
                ET0 = 1;    //打开T0中断
                EA = 1;   //打开总中断
    while (1)
                {
                        LOOP:
                        if(1 == T0_flag)
                        {
                                T0_flag = 0;
                  DUAN2 = 0x00;             //清屏
                  DUAN1 = 0x00;             //清屏
                                DUAN2 = tab1;      //此处DUAN2先输出数据,上半列
                                                              
                  DUAN1 = tab1;          //此处DUAN1后输出数据,下半列
                  SCAN = tab2;                      //0~15列

              lie += 2;         //下一列
              if(lie < 32)      //一个汉字16列,32个字节的数据
                goto LOOP;      //从最外层的if语句跳出来
                                lie = 0;            //下个字的首列
                                //P3 ^= 0xff;      //测试用
                                if(++times < 100)//一个屏重复显示遍数,1屏维持时间
                             gotoLOOP;   //从最外层的if语句跳出来
      times = 0;
                                if(++zishu < (8 * 16))    //9个字,共(9-1)*160列,无乱码
                             gotoLOOP;         //从最外层的if语句跳出来
      zishu = 0;
                        }
                }
}

//========================================================================
// 函数: void Timer0_init(void)
// 描述: timer0初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
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
}

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

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

    #elif ((Timer2_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET2 = 1;    //允许中断
    //T2_CT = 1;//计数
      T2_CT = 0;//定时
    //T2CLKO = 1; //输出时钟
      T2CLKO = 0; //不输出时钟

      #if (Timer2_Reload < 65536UL)
            T2x12 = 1;    //1T mode
            T2H = (u8)((65536UL - Timer2_Reload) / 256);
            T2L = (u8)((65536UL - Timer2_Reload) % 256);
      #else
            T2x12 = 0;    //12T mode
            T2H = (u8)((65536UL - Timer2_Reload/12) / 256);
            T2L = (u8)((65536UL - Timer2_Reload/12) % 256);
      #endif

      T2R = 1;    //开始运行

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

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

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

    #elif ((Timer3_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET3 = 1;    //允许中断
    //T3_CT = 1;//计数
      T3_CT = 0;//定时
    //T3CLKO = 1; //输出时钟
      T3CLKO = 0; //不输出时钟

      #if (Timer3_Reload < 65536UL)
            T3x12 = 1;    //1T mode
            T3H = (u8)((65536UL - Timer3_Reload) / 256);
            T3L = (u8)((65536UL - Timer3_Reload) % 256);
      #else
            T3x12 = 0;    //12T mode
            T3H = (u8)((65536UL - Timer3_Reload/12) / 256);
            T3L = (u8)((65536UL - Timer3_Reload/12) % 256);
      #endif

      T3R = 1;    //开始运行

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

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

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

    #elif ((Timer4_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET4 = 1;    //允许中断
    //T4_CT = 1;//计数
      T4_CT = 0;//定时
    //T4CLKO = 1; //输出时钟
      T4CLKO = 0; //不输出时钟

      #if (Timer4_Reload < 65536UL)
            T4x12 = 1;    //1T mode
            T4H = (u8)((65536UL - Timer4_Reload) / 256);
            T4L = (u8)((65536UL - Timer4_Reload) % 256);
      #else
            T4x12 = 0;    //12T mode
            T4H = (u8)((65536UL - Timer4_Reload/12) / 256);
            T4L = (u8)((65536UL - Timer4_Reload/12) % 256);
      #endif

      T4R = 1;    //开始运行

    #else
      #error "Timer4设置的中断过慢!"
    #endif
}
******************************************/
//========================================================================
// 函数: void timer0_int (void) interrupt TIMER0_VECTOR
// 描述:timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer0_int (void) interrupt 1
{
   //P07 = ~P07;
                        T0_flag = 1;         //T0中断标志置1
}

/*********************************************
//========================================================================
// 函数: void timer1_int (void) interrupt TIMER1_VECTOR
// 描述:timer1中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer1_int (void) interrupt 3
{
   P06 = ~P06;
}

//========================================================================
// 函数: void timer2_int (void) interrupt TIMER2_VECTOR
// 描述:timer2中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer2_int (void) interrupt 12
{
    P05 = ~P05;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
}

//========================================================================
// 函数: void timer3_int (void) interrupt TIMER3_VECTOR
// 描述:timer3中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer3_int(void) interrupt 19
{
    P04 = ~P04;
}

//========================================================================
// 函数: void timer4_int (void) interrupt TIMER4_VECTOR
// 描述:timer4中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer4_int(void) interrupt 20
{
    P03 = ~P03;
}
***********************************************************************/

为了充分发挥Ai8051U单片机的特性,这里采用timer0产生100us中断,采用32bit方式编程,定时器初始化和中断函数采用官方文件,多余部分屏蔽了,通过手机录的视频也不闪烁。













狂热主宰 发表于 2026-6-24 23:52:24

AI8051U支持8bit模式
多方面与89C5x相似
学生用户学习

yyq_007 发表于 2026-6-25 14:59:22

采用上述代码,为何STC带的取码软件却无法取到相同的数据码,试遍8种逐列取码方式都不行,最后还是用PCtoLCD2002完美版取码软件 阴码 逆向(低位在前。低字节在前) 逐列 ,软件中规定:   从第一列开始向下每取8个点作为一个字节,如果最后不足8个点就补满8位。取模顺序是从低到高,即第一个点作为最低位。如*-------取为00000001,这一点STC还有待改进。
程序中的代码:                           
    DUAN2 = tab1;      //此处DUAN2先输出数据,上半列
    DUAN1 = tab1;          //此处DUAN1后输出数据,下半列
1、如果始终令 zishu=0,则只显示首字“威”,并屏蔽以下代码:
//if(++zishu < (8 * 16))    //9个字,共(9-1)*160列,无乱码
//   gotoLOOP;         //从最外层的if语句跳出来
//zishu = 0;
2、无限循环部分,按如下改动可以循环显示所有的汉字。
    while (1)
                {
                        LOOP:
                        if(1 == T0_flag)
                        {
                                T0_flag = 0;
                  DUAN2 = 0x00;             //清屏
                  DUAN1 = 0x00;             //清屏
                                DUAN2 = tab1;      //此处DUAN2先输出数据,上半列,32* zishu可以找到下个汉字
                                                              
                  DUAN1 = tab1;          //此处DUAN1后输出数据,下半列,32* zishu可以找到下个汉字
                  SCAN = tab2;                      //0~15列

              lie += 2;         //下一列
              if(lie < 32)      //一个汉字16列,32个字节的数据
                goto LOOP;      //从最外层的if语句跳出来
                                lie = 0;            //下个字的首列
                                //P3 ^= 0xff;      //测试用
                                if(++times < 100)//一个屏重复显示遍数,1屏维持时间
                             gotoLOOP;   //从最外层的if语句跳出来
      times = 0;
                                if(++zishu < 9)    //9个字,无乱码
                             gotoLOOP;         //从最外层的if语句跳出来
      zishu = 0;
                        }
                }

yyq_007 发表于 2026-6-26 10:07:58

基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向右滚动进入

1.硬件电路
见x.png
2.擎天柱Ai8051U转89C52-DIP40核心板
见11.jpg
3.汉字取码软件与取码
采用PCtolc2002,见图12.png
由于端口改了,用STC下载器自带的点阵生成工具按逐列取码,8种方式竟没有一种适合,没办法,只得采用PCtolc2002软件生成点阵数据,但又不甘心,STC的生态做得这么好,不会出这么明显的错误吧,由于初次使用STC取码工具,由于自己的疏忽,STC取码工具中还有一个存储顺序栏未改动,本例取码模式:扫描模式选:垂直扫描,从上到下,从左到右,存储顺序:低位优先,生成的代码与PCtoLCD2002一样。
   启动STC下载软件,执行菜单命令:工具\字库生成工具,即可打开取码工具,很方便,见图14.png。
想要向右滚动显示“技师学院好”+2黑屏,取码要按“好院学师技”+2黑屏,加上2屏黑屏码可以确保显示时无乱码。
硬件电路的一列从上到下,依次是P27~20、P07~00,输入数据P2=0x17,P0=0x55,扫描码输入0x00,可见最右边的1列点亮,P2=B1110 1000,P0=B10101010,所以取码要逆序(低位在前,低字节在前),扫描是自右向左逐列扫描。
4、编程
原则:先找到最后一个字的最后一列(15列)的2个字节并扫描,即字库表中最后的2个0x00,前一个送P2口,后一个送P0口,扫描码(0~15)也要先找到最后1列的扫描码,即15。
为了充分发挥Ai8051U单片机的性能,采用100us定时中断,从而提高刷新率,这样在录像的时候也无闪烁感。
//版本3在16x16LED点阵上多个汉字向右滚动进入难
//基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向右滚动进入
//

/*************功能说明    **************
32bit   Keil uVision C251_32bit开发
T0中断100us显示1列

******************************************/

#include "AI8051U.h"
#include "stdio.h"
#include "intrins.h"

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

#define MAIN_Fosc      24000000UL

//==========================================================================
//各定时器加载初值

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

//#define Timer0_Reload   (MAIN_Fosc / 1000)      //Timer 0 中断频率, 1000次/秒,初值24000
//#define Timer1_Reload   (MAIN_Fosc / 2000)      //Timer 1 中断频率, 2000次/秒
//#define Timer2_Reload   (MAIN_Fosc / 3000)      //Timer 2 中断频率, 3000次/秒
//#define Timer3_Reload   (MAIN_Fosc / 4000)      //Timer 3 中断频率, 4000次/秒
//#define Timer4_Reload   (MAIN_Fosc / 5000)      //Timer 4 中断频率, 5000次/秒

void    Timer0_init(void);
//void    Timer1_init(void);
//void    Timer2_init(void);
//void    Timer3_init(void);
//void    Timer4_init(void);

bit T0_flag = 0;      //T0中断标志
#define DUAN1 P0           //段码直驱,NPN管同相驱动,硬件:下半列,bit7在前
#define DUAN2 P2   //段码直驱,NPN管同相驱动,硬件:上半列,bit7在前
#define SCAN P1             //扫描码经4-16译码器驱动

u8 codetab1 [ ]={          


//为何STC带的取码软件却无法取到相同的数据码,试遍8种逐列取码方式都不行,原来还有存储顺序
//那项未选择,选择垂直扫描,从上到下,从左到右,低位优先,生成的代码与PCtoLCD2002一样
       
//用PCtoLCD2002完美版取码软件 阴码 逆向(低位在前,低字节在前) 逐列 ,
//软件中规定:   从第一列开始向下每取8个点作为一个字节,如果最后不足8个点就补满8位。
//取模顺序是从低到高,即第一个点作为最低位。如*-------取为00000001。

//想向右滚动显示“技师学院好”+2黑屏,取码要按“好院学师技”+2黑屏
       
//向右滚动显示5个汉字,要先显示最后一个字的最末一列的2个码
//好(0) 院(1) 学(2) 师(3) 技(4)
        //逆向

0x10,0x40,0x10,0x22,0xF0,0x15,0x1F,0x08,0x10,0x16,0xF0,0x61,0x00,0x00,0x80,0x00,
0x82,0x40,0x82,0x80,0xE2,0x7F,0x92,0x00,0x8A,0x00,0x86,0x00,0x80,0x00,0x00,0x00,/*"好",0*/

0x00,0x00,0xFE,0xFF,0x22,0x04,0x5A,0x08,0x86,0x07,0x10,0x80,0x0C,0x41,0x24,0x31,
0x24,0x0F,0x25,0x01,0x26,0x01,0x24,0x3F,0x24,0x41,0x14,0x41,0x0C,0x71,0x00,0x00,/*"院",1*/

0x40,0x04,0x30,0x04,0x11,0x04,0x96,0x04,0x90,0x04,0x90,0x44,0x91,0x84,0x96,0x7E,
0x90,0x06,0x90,0x05,0x98,0x04,0x14,0x04,0x13,0x04,0x50,0x04,0x30,0x04,0x00,0x00,/*"学",2*/

0x00,0x00,0xFC,0x87,0x00,0x40,0x00,0x30,0xFF,0x0F,0x00,0x00,0x02,0x00,0xE2,0x1F,
0x22,0x00,0x22,0x00,0xFE,0xFF,0x22,0x08,0x22,0x10,0xE2,0x0F,0x02,0x00,0x00,0x00,/*"师",3*/

0x10,0x04,0x10,0x44,0x10,0x82,0xFF,0x7F,0x10,0x01,0x90,0x80,0x08,0x80,0x88,0x40,
0x88,0x43,0x88,0x2C,0xFF,0x10,0x88,0x28,0x88,0x46,0x88,0x81,0x08,0x80,0x00,0x00,/*"技",4*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   //黑屏
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   //黑屏

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   //黑屏
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   //黑屏

};   //

u8 code   tab2={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};       //扫描码

/******************** 主函数 **************************/
void main(void)
{
    //u16 j = 0;         //1个字的字节数
          u16zishu = 6 * 16;//总列数,7个字,总列数取(7-1) * 16无乱码
    u8 lie = 0;          //每个字的列数,1列2个字节,兼作取码序号
          u8 times = 0;      //每个字重复显示的遍数

        WTST = 0;    //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1;   //扩展寄存器(XFR)访问使能
    CKCON = 0;   //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0xff;   //设置P0为推挽输出
    P1M1 = 0x00;   P1M0 = 0xff;   //设置P1为推挽输出
    P2M1 = 0x00;   P2M0 = 0xff;   //设置P2为推挽输出       

          //不用的端口要配置为准双向口,确保系统的稳定性和可靠性
          P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口



    Timer0_init();//T0初始化
      
                TF0 = 0;                //清除TF0标志
                ET0 = 1;    //打开T0中断
                EA = 1;   //打开总中断
    while (1)
                {       //原则:先找到最后一个字的最后一列(15列)的2个字节并扫描
                        LOOP:
                        if(1 == T0_flag)
                        {
                                T0_flag = 0;
                  DUAN2 = 0x00;             //清屏
                  DUAN1 = 0x00;             //清屏
                                DUAN2 = tab1;         //此处DUAN2先输出数据
                                                              
                  DUAN1 = tab1;             //此处DUAN1后输出数据
                  SCAN = tab2[ 15-lie / 2];       //0~15列

              lie += 2;         //下一列
              if(lie < 32)      //一个汉字16列,32个字节的数据
                goto LOOP;      //从最外层的if语句跳出来
                                lie = 0;            //下个字的首列
                                //P3 ^= 0xff;      //测试用
                                if(++times < 100)//一个屏重复显示遍数,1屏维持时间
                             gotoLOOP;    //从最外层的if语句跳出来
      times = 0;
                                if(--zishu > 0)    //7个字,共(7-1)*16列,无乱码
                             gotoLOOP;       //从最外层的if语句跳出来
      zishu = 6 * 16;
               }
        }
}

//========================================================================
// 函数: void Timer0_init(void)
// 描述: timer0初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
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 timer0_int (void) interrupt TIMER0_VECTOR
// 描述:timer0中断函数.
// 参数: none.
// 返回: none.1074
// 版本: V1.0, 2015-1-12
//========================================================================
void timer0_int (void) interrupt 1
{
   //P07 = ~P07;
                        T0_flag = 1;         //T0中断标志置1
}

5、动画效果










yyq_007 发表于 2026-6-26 10:11:39

基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向右滚动进入的视

1075107510751075

yyq_007 发表于 2026-6-26 10:14:02

网络有问题,不出现则以,一出现竟这么多。

狂热主宰 发表于 2026-6-26 10:33:52

点阵LED应用
功耗大概有多少

yyq_007 发表于 2026-6-26 10:48:59

狂热主宰 发表于 2026-6-26 10:33
点阵LED应用
功耗大概有多少

这一个,用usb供电的,未测量

狂热主宰 发表于 2026-6-26 10:52:52

yyq_007 发表于 2026-6-26 10:48
这一个,用usb供电的,未测量

通常应用在广告牌方面
物料选型需要考虑
选择合适器件
页: [1]
查看完整版本: 基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向左滚动进入