基于“擎天柱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方式编程,定时器初始化和中断函数采用官方文件,多余部分屏蔽了,通过手机录的视频也不闪烁。
AI8051U支持8bit模式
多方面与89C5x相似
学生用户学习 采用上述代码,为何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;
}
}
基于“擎天柱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、动画效果
基于“擎天柱Ai8051U转89C52-DIP40核心板”驱动16x16LED点阵显示汉字向右滚动进入的视
1075107510751075网络有问题,不出现则以,一出现竟这么多。 点阵LED应用
功耗大概有多少 狂热主宰 发表于 2026-6-26 10:33
点阵LED应用
功耗大概有多少
这一个,用usb供电的,未测量
yyq_007 发表于 2026-6-26 10:48
这一个,用usb供电的,未测量
通常应用在广告牌方面
物料选型需要考虑
选择合适器件
页:
[1]