1、在16*16点阵上滚动显示汉字
2、在16*16点阵上滚动显示汉字--程序编写
3、在16*16点阵上滚动显示汉字--仿真演示
参考程序:
/*********************************************************************
修改时间:2020年4月22日19:42
功能:16*16LED点阵显示
目的:用两种滚动模式显示”安徽工商职业学院“
显示方式:列扫描方式
取模软件:PCtoLCD2002完美版
**********************************************************************/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit datal595=P1^0; //列数据线
sbit datah595=P1^1; //行数据线
sbit clk595=P1^2; //数据输入时钟线
sbit str595=P1^3; //输出存储器锁存时钟线
sbit oe595=P1^4; //oe输出使能
//取模方式:阴码、逐列式、逆向、十六进制、C51格式自定义 (使用Pctolcd2002软件)
uchar code displaydata[]= //在ROM中定义一个可变长度数组,供用户填充一定个数的字模
{ //可填充的最大字模数取决于您所选用的单片机ROM空间大小
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,0x40,0x00,0x30,0xFC,0x0F,0x04,0x40,0x44,0x40,0x84,0x41,0x04,0x4E,0x25,0x40,
0xC6,0x40,0x04,0x63,0x04,0x50,0x04,0x4C,0x04,0x43,0xE4,0x40,0x04,0x40,0x00,0x00,/*"应",0*/
0x00,0x80,0x00,0x60,0xFE,0x1F,0x22,0x02,0x22,0x02,0x22,0x02,0x22,0x02,0xFE,0x7F,
0x22,0x02,0x22,0x02,0x22,0x42,0x22,0x82,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,/*"用",1*/
0x00,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0xFC,0x3F,
0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x00,0x20,0x00,0x00,/*"工",2*/
0x24,0x08,0x24,0x06,0xA4,0x01,0xFE,0xFF,0x23,0x01,0x22,0x06,0x00,0x40,0x3E,0x49,
0x22,0x49,0x22,0x49,0x22,0x7F,0x22,0x49,0x22,0x49,0x3E,0x49,0x00,0x41,0x00,0x00,/*"程",3*/
//至此字模插入结束
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
};
/*----------------------------------
函数名字:delay_ms
形式参数:无字符整型 i:延时多少
函数功能:以1ms为单位的函数延时
返 回 值:无
------------------------------------*/
void delay_ms(uint i)
{
uint j;
for(;i>0;i--)
for(j=110;j>0;j--);
}
/*----------------------------------
函数名字:senddata
形式参数:无字符整型 datah:行的数据
无字符整型 datal:列的数据
函数功能:把数据发送给芯片74HC595
返 回 值:无
------------------------------------*/
void senddata(uint datah,uint datal) //向行和列的4个595同时发送数据,显示其中的一列数据
{
uchar i=0;
uint m,n;
oe595=0;
str595=0;
for(;i<16;i++) //行和列各有两片595驱动,所以行和列分别需要连续送两个字节数据
{
clk595=0;
m=datah; //行为高电平驱动
n=~datal; //列为低电平驱动
m&=0x8000;
n&=0x8000;
datah595=(bit)m; //在每个clk周期,同时送出行和列的1bit串行数据
datal595=(bit)n;
datah<<=1;
datal<<=1;
clk595=1;
}
str595=1; //一列数据送完,锁存到输出端进行显示
str595=0;
}
/*----------------------------------
函数名字:char_max
形式参数:无字符字符型 *dat:两个8位数据的第一个数据的地址
函数功能:受到取模软件的限制,需要对字模表的数据进行重新排列
将两个8位的数据拼成显示所需16位的数据
返回值 :uint:返回排列好的值
------------------------------------*/
uint char_max(uchar *dat)
{
uint l,h;
h = (uint)*(dat+1); //16位中的高字节数据
h <<= 8;
h &=0xff00;
l = (uint)*dat; //16位中的低字节数据
l &= 0x00ff;
return l|h;
}
/*----------------------------------
函数名字:horizontal
形式参数:无字符字符型 time:字符移动的速度
无字符字符型 counth:移动全部字符所需的列数
无符号字符型指针 p:字符显示数据的首地址
函数功能:显示字符水平移动
返回值 :无
------------------------------------*/
void horizontal(uchar time,uint count,uchar *p) //水平移动
{
uint datah,datal; //datah是行数据,datal是列选通
uchar x,y;
uint z;
for(z=0;z<count;z++) //显示字模表中的所有汉字(包括有用字模前后的的清屏数据)
{
for(y=0;y<time;y++) //该屏数据重复显示time次后刷新,实际上这是水平移动的速度
{
for(x=0;x<16;x++) //发送一整屏数据,16个16位
{
p += 2;
datah = char_max(p);
datal = 0x0001<<x; //列选通位移到相应的列上进行选通
// datah=~datah; //去掉此行前面的注释则水平移动程反白显示
senddata(datah,datal); //将行和列数据发送出去进行一列的显示
}
p-=32; //指针恢复为这个汉字首地址,准备重复显示该屏数据time次
} //该屏数据经过了time次的显示,显示数据准备更新
p+=2; //指向了该汉字的下一列,左移一列汉字
} //移动了字模表中的所有汉字,左移过程结束
oe595=1;
}
/*----------------------------------
函数名字: vertical
形式参数: 无字符字符型 a:半角标志 ;如果 a=16 则字符显示数据中出现了半角字
无字符字符型 time:字符移动的速度
无字符字符型 counth:移动全部字符所需的行数
无符号字符型 指针 p:字符显示数据的首地址
函数功能: 显示字符垂直移动
返回值 : 无
------------------------------------*/
void vertical(uchar a,uchar time,uint countv,uchar *p) //垂直移动
{
uint datah,datal; //datah是行数据,datal是列选通
uchar x,y,e,w=0;
uint z;
uint datah1,datah2;
uchar *q;
q=p+32;
for(z=countv;z>0;z--) //显示字模表中的所有汉字(包括有用字模前后的的清屏数据)
{
for(e=0;e<16;e++) //拼字的过程,从一个汉字完整地过渡到下一个汉字
{
for(y=0;y<time;y++) //该屏数据重复显示time次后刷新,实际上这是垂直移动的速度
{
for(x=0;x<16;x++) //发送一整屏数据,16个16位
{
/*处理p所指向汉字某一列的拼接*/
p += 2;
datah1 = char_max(p);
datah1>>=w; //这行语句改为左移同时下处改为右移,则显示向下移动
/*处理下一个汉字相应列的拼接*/
q += 2;
datah2 = char_max(q);
datah2 <<= (16-w); //这行语句改为右移同时上处改为左移,则显示向下移动
/*准备显示这列数据*/
datah = datah1|datah2; //此时进行拼接某汉字某一列的运算操作
datal = 0x0001<<x; //列选通位移到相应的列上进行选通
//datah=~datah; //去掉此行前面的注释则垂直移动程反白显示
senddata(datah,datal);
} //一整屏数据发送完毕
p-=32;q-=32; //指针恢复为这个汉字首地址,准备重复显示该屏数据time次
} //该屏数据经过了time次的显示,显示数据准备更新
w++; //显示上移w行的拼接数据移位位数加1
if(w>=16) w=0; //如果上移了15行,w归0,结束此次拼字循环
} //此次拼字循环结束
/*开始对下一组汉字进行拼字操作*/
if((a==16)&&(z==2)) //如果字模表中含有半个汉字并且显示最后一组汉字
{ p+=32;q+=16; } //则q+16,相当于用16个零填充不足的半个汉字
else //其它情况下
{ p+=32;q+=32; } //p和q一律指向下一个汉字
} //拼完字模表中的所有汉字,上移过程结束(注:上移是现象,拼字是本质)
oe595=1;
}
void main(void)
{
uchar time=8; //调整这个值的大小将会改变汉字移动的速度
uint size=sizeof(displaydata); //计算出上述在ROM中定义的可变长度字模表填充数据后的大小
uint countv=((size-2)>>5)-1; // 8 //这些个汉字水平移动全部完成所需要的拼字次数
uint counth=countv<<4; //128 //这些个汉字水平移动全部完成所需要的左移列数
uchar a=(uchar)((size-2)%32); //判断字模表中是否会出现一个半角的数字或符号或字母
if(a==16) //如果余数为16,说明出现了半角情况
{
counth+=8; //这时左移时需要多移动8列
countv+=1; //而右移时需要多拼一个汉字
}
while(1)
{
horizontal(time,counth,displaydata); //将字模表中的所有汉字进行水平移动
delay_ms(2000);
vertical(a,time,countv,displaydata); //将字模表中的所有汉字进行垂直移动
delay_ms(2000);
}
}

