本帖最后由 菜鸟与大神 于 2014-5-18 20:07 编辑
求大神们帮我看看这程序能工作吗
源程序
/*16*16点阵屏的显示*/
#include <reg51.h>
#include <intrins.h>
#define DATAOUT P2 //指定P2口作为输出
sbit DATA=DATAOUT^0; //列数据输出位
sbit SCLH=DATAOUT^1; //列扫描时钟位
sbit SCLT=DATAOUT^2; //列数据锁存位
sbit AB=DATAOUT^4; //行数据输出位
sbit SCK=DATAOUT^5; //行扫描时钟位
unsigned char Temp; //定义变量
unsigned char lhj[32];//32字节RAM作为16*16点阵屏显示缓存
void display(); //做为点阵扫描函数,将显示缓存的数据输出到点阵屏
void displayS(unsigned int
timer);//指定时间扫描显示
void displaymove(unsigned char *lp,unsigned char c,unsigned char timer);
void displaymovetb(unsigned char din,unsigned char *lp,unsigned char timer);
void delay(unsigned int a);//延时子函数
void right_display();//右移子程序
void up_display();//上移子程序
void main(void) //主入口函数
{
unsigned char i=0,j=0;
SCON = 0x50; /* SCON: 模式 1, 8-bit UART, 使能接收 */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xFD; /* TH1: reload value for 9600 baud @ 11.0592MHz */
TR1 = 1; /* TR1: timer 1 run */
EA = 1; /*打开总中断*/
ES = 1; /*打开串口中断*/
for(i=0;i<32;i++)
lhj
=GUANG;//将"广"字数据复制到显示缓存
while(1)
{
displayS(1); //显示"广"字约1秒
displaymove(DONG,5,7); //将从"东"开始的5个汉字从右向左移动
displayS(1); //等持约1秒
displaymovetb(1,0,10); //将点阵上显示的内容向下以10的速度移出,
displayS(1); //等待1秒
displaymovetb(0,GUANG,10); //将"广"字以10的速度向上移动
displaymovetb(0,DONG,10); //将"东"字以10的速度向上移动
displaymovetb(0,JI,10); //将"技"字以10的速度向上移动
displaymovetb(0,SU,10); //将"术"字以10的速度向上移动
displaymovetb(0,SHI,10); //将"师"字以10的速度向上移动
displaymovetb(0,FAN,10); //将"范"字以10的速度向上移动
displaymovetb(0,0,10); //以10的速度向上清空
displayS(1); //等待1秒
displaymovetb(1,GUANG,10); //将"广"以10的速度向下移动
right_display();//右移子程序
up_display();//上移子程序
}
}
void display()//显示
{
unsigned char i,ia,j,tmp; //定义变量
DATAOUT=0XFF; //置位高电平做准备
AB=0; //将行数据位清0,准备移位
for(i=0;i<16;i++)
{ //循环输出16行数据
SCK=0; //为行移位做准备
SCLT=0; //为列锁存做准备
for(ia=2;ia>0;ia--)
{ //每行16个点,循环位移两个字节
//循环两次
tmp=~lhj[i*2+ia]; //读取点阵数据做输出,
for(j=0;j<8;j++)
{ //循环两次,每次移一个字节,
SCLH=0; //为列移位做准备
DATA=tmp&0x01; //将数据低位做输出,
tmp>>=1; //将数据缓冲右移一位,为下次输出做准备
SCLH=1; //将DATA上的数据移入寄存器
} //移入单字节结束
} //移入两个字节结束
SCK=1; //SCK拉高,行数据移位,相应行拉低
SCLT=1; //SCLT拉高
AB=1; //行数据位只在第一行时为0,其它时候都为1,
}
j=64;
while(j--); //每一行的显示,保持了两字节的移位时间,
SCK=0; //
SCK=1; //将最后一行数据移出
}
void displayS(unsigned int timer)//指定时间扫描显示
{
unsigned char i;
while(timer--)
{ //当timer=1时,大约1秒时间
i=130;
while(i--);
display();
}
}
void displaymove(unsigned char *lp,unsigned char c,unsigned char timer)
//显示汉字内容的移动效果,LP指向要显示第一个字的首地址,C表示显示字的个数,
{
unsigned char i=0,j=0,ia=0;
unsigned int tmp=0,timerc=0;
unsigned char tmp2[16];
c*=2; //因一个汉字32字节组成,要分开半个汉字16字节处理,因此这里乘以2
for(i=0;i<16;i++)
tmp2[1]=0; //将缓冲区清0,
while(c)
{ //循环处理
if(lp!=0)
{ //当lp指向的地址为0时,直接用组缓冲0补上,效果是将当前显示的内容移出
tmp=c%2; //取余,目的是为了判断处理汉字的前半部份还是后半部份
for(i=0;i<16;i++)
{
tmp2=lp[i*2+tmp]; //取半个汉字点阵数据,16字节
}
if(tmp) //当tmp为1时,表时一个字数组处理完成,将地址转到下一个字
lp+=32;
}
//--------------
tmp=8; //变量再次利用
while(tmp)
{
ia=0; //做为点阵数组的元素
for(i=0;i<16;i++)
{//移动是16行同时移,因此要处理16个字节
lhj[ia]<<=1; //移当前显示缓冲的前半行字节
if(lhj[ia+1]&0x80) //判断后半行字节的高位是否为1, lhj[ia]++;
ia++;
lhj[ia]<<=1; //移当前显示缓冲的后半行字节
if(tmp2&0x80) //判断下一个要显示汉字的前半行字节的高位是否为1,
lhj[ia]++;
ia++;
tmp2<<=1; //下一个要显示汉字的半行字节向高位移一位准备下一次取位
}
tmp--;
timerc=timer; //处理完16行,调用显示函数更新点阵
while(timerc--) //循环做为处理的速度,即移动的速度
display();
}
c--; //移完一半,进入下一半或下一个汉字,直到结束
}
}
void displaymovetb(unsigned char din,unsigned char *lp,unsigned char timer)
//上下移动内容,din:1为向下,0为向上,lp指向要移入的内容,timer为移动速度
{
unsigned char i=0,j=0,ia=0;
unsigned int tmp=0,timerc=0;
if(din)
{ //判断移动方向,向下
ia=32; //要移入第一个汉字的数组元素
i=16; //行索引
while(i--)
{ //逐行处理
j=30;
while(j)
{
j--;
lhj[j+2]=lhj[j]; //将上一行的内容复制到下一行,
}
if(lp==0)
{ //最后一行的处理,判断移入的内容是否为空,是用0移入
lhj[0]=0;
lhj[1]=0;
}
else
{ //否则,取字数组处理
ia--;
lhj[1]=lp[ia];
ia--;
lhj[0]=lp[ia];
}
timerc=timer; //处理完16行,调用显示函数更新点阵
while(timerc--) //循环做为处理的速度,即移动的速度
display();
}
}
else
{ //移动方向,向上
ia=0; //向上移动,移入汉字从低位开始
for(i=0;i<16;i++)
{ //处理16行
for(j=0;j<30;j++) //将下一行的内容复制到上一行,
lhj[j]=lhj[j+2];
if(lp==0)
{ //最后一行的处理,判断移入的内容是否为空,是用0移入
lhj[30]=0;
lhj[31]=0;
}
else
{ //否则,取字数组处理
lhj[30]=lp[ia];
lhj[31]=lp[ia+1];
ia+=2;
}
timerc=timer; //处理完16行,调用显示函数更新点阵
while(timerc--) //循环做为处理的速度,即移动的速度
display();
}
}
}
void delay(unsigned int a) //延时
{
while(a--);
}
void right_display()//右移子程序
{
int i;
while(0xF2==Temp)//输入r,右移
{
for(i=0;i<32;i++)
lhj=GUANG;//将"广"字数据复制到显示缓存
displayS(2); //显示"广"字约1秒
displaymove(DONG,5,7); //将从"东"开始的5个汉字从右向左移动
for(i=0;i<32;i++)
lhj=GUANG;//将"广"字数据复制到显示缓存
}
}
void up_display()//上移子程序
{
int i;
while(0xF5==Temp)//输入u,上移
{
displaymovetb(0,GUANG,10); //将"广"字以10的速度向上移动
displaymovetb(0,DONG,10); //将"东"字以10的速度向上移动
displaymovetb(0,JI,10); //将"技"字以10的速度向上移动
displaymovetb(0,SU,10); //将"术"字以10的速度向上移动
displaymovetb(0,SHI,10); //将"师"字以10的速度向上移动
displaymovetb(0,FAN,10); //将"范"字以10的速度向上移动
displaymovetb(0,0,10); //以10的速度向上清空
for(i=0;i<32;i++)
lhj=GUANG;//将"广"字数据复制到显示缓存
}
}
void UART_SER (void) interrupt 4 //串行中断服务程序
{
if(RI==1) //判断是接收中断产生
{
RI=0; //标志位清零
Temp=SBUF; //读入缓冲区的值
SBUF=Temp; //把接收到的值再发回电脑端
}
if(TI==1)//如果是发送标志位,清零
TI=0;
}
三极管用来放大呀,从74hc164出来的电流驱动不了16个二极管,所以加个放大,仿真是显示不出字,胡乱显示一些,基本上都是一列一列的亮。关键是我想知道这程序能不能实现动态显示。我是机械电子专业的,不太懂c语言编程的单片机程序。
看你是广技师的,把keil和proteus工程文件发给我看看,不敢保能弄出来的。
我找到问题的所在了,具体怎么弄还得你自己去弄。
还是三极管的问题。74HC164输出是没有问题的,但是进过三极管后输出都是高电平,因此都是整列整列的显示。
仿真的时候管脚是红 {MOD}就是高电平,蓝 {MOD}就是低电平,灰 {MOD}就是电平不确定。
不要用三极管,用反相器增大输出电流。74HC164输出经过74HC04反相输入到点阵。
至于程序有没有问题我就不知道了。有问题再上来问。
一周热门 更多>