要实现一个16×16小的LED点阵循环滚动显示“XXXXXXXx”字样。
Proteus、Keil、PCtoLCD2002
略
略
取字模软件,简单实用,类似软件有很多
链接:https://pan.baidu.com/s/1rgO3B-a85U7wOkJXvk7bSw
提取码:og69
4-16线译码器
1-11&13-17 :输出端。(outputs (acTIve LOW))
12:GND电源地 (ground (0 V))
18-19:使能输入端、低电平有效 (enable inputs (acTIve LOW))
20-23:地址输入端 (address inputs)
24:VCC电源正 (posiTIve supply voltage)
3态高速位移寄存器。串行输入,并行输出。
14脚:DS,串行数据输入引脚
12脚:ST_CP,存储寄存器时钟输入引脚。上升沿时,数据从移位寄存器转存带存储寄存器。
11脚:SH_CP,移位寄存器时钟引脚,上升沿时,移位寄存器中的数据整体后移,并接受新的数据(从DS输入)。
10脚:MR,低电平时,清空移位寄存器中已有的数据,一般不用,接高电平即可。
13脚:OE,输出使能控制脚,它是低电才使能输出,所以接GND
9脚:串行数据输出引脚。当移位寄存器中的数据多于8位时,会把已有的位“挤出去”,就是从这里出去的。用于595的级联。
1-7脚:Q1-Q7并行输出引脚
使用详解:https://blog.csdn.net/weixin_43808473/article/details/106567336
Proteus提供了四种LED点阵
红色点阵和其他三种的极性不同
使用详解:https://blog.csdn.net/weixin_43808473/article/details/106571339
void delay(uint i)
接收一个无符号整数i,将执行125次空语句作为循环体循环i次,每循环一次约消耗1ms,循环i次则延时了ims。
void Send(uchar Data,uchar Data1)
参数是两个无符号字符型数据(两位十六进制数),程序将该数8位二进制格式的首位加载到74595芯片的输入端,SH_CP上升沿触发。发送一次后该数左移一位,第二位变成首位,SH_CP上升沿触发,将对应的值送到595芯片上,以此类推,循环8次后实现了一个8位二进制数(2位十六进制数)的串行输出。依次将两个参数的串行输出到两篇595上后,ST_CP上升沿触发595芯片的并行输出。
void main (void)
主函数中,三层循环嵌套,最里层循环通过控制P1口的值间接控制74154芯片的输出,依次点亮点阵的第一列、第二列·····以实现位选的目的,最里层循环只循环32次,即控制32列,循环体每次调用串行发送子函数,参数为字模数组中相邻的两个值,例如第一次参数为a[0]和a[1],第二次参数为a[2]和a[3],以此类推。以显示一帧图像。其中语句n=(i+j)%(num*32);
中n为数组的第n号元素,i是列选择数,j是当前帧数,num是要显示的字数(num×32是字模数组中元素的个数),取余运算实现了循环滚动的功能。
第二层循环控制将这一帧图像显示一次或重复多次,通过控制一帧图像刷新的次数来控制图像滚动的速度,刷新次数越多,滚动速度越慢。
最外层循环使图像滚动,每循环一次为一帧,循环次数为要显示的动态图像的帧数,动态图像的帧数取决于字模的宽度(列数)。
定义j和n为无符号整型变量,可使图像最大长度达到65566列(2048个字),极大的拓宽了使用范围。
#include
#include
#define unsigned char uchar;
#define unsigned int uint;
uchar code ldis[] =
{
0xF7,0xDF,0xF9,0xDF,0xBF,0x81,0xCE,0x7F,0xFF,0xFF,0xDF,0xFF,0xD8,0x0F,0xDB,0xDF,0xDB,0xDF,0xD8,0x0F,0xDF,0xFD,0xDF,0xFE,0xC0,0x01,0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,/*"河",0*/
0xFF,0xFB,0xFB,0xF9,0xFB,0xFB,0xFB,0xF7,0xFB,0xF7,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x03,0xFD,0xFD,0xFB,0xFD,0xF7,0xFD,0xEF,0xFD,0xFF,0xE1,0xFF,0xFF,/*"北",1*/
0xFF,0xFF,0xC0,0x1E,0xFF,0xFD,0xFF,0xF3,0x00,0x0F,0xFF,0xFF,0xBF,0xFF,0xB8,0x07,0xBB,0xFF,0xBB,0xFF,0x80,0x00,0xBB,0xEF,0xBB,0xF7,0xB8,0x0F,0xBF,0xFF,0xFF,0xFF,/*"师",2*/
0xDF,0xFF,0xDD,0xEF,0xDE,0x6F,0xD7,0xE1,0xD9,0xDF,0x0F,0x3F,0xDF,0xFF,0xD8,0x03,0xDB,0xFD,0x0B,0xFD,0xDB,0xBD,0xDB,0xDD,0xD8,0x3D,0xDF,0xFD,0xDF,0xE1,0xFF,0xFF,/*"范",3*/
0xFB,0xFE,0xFB,0xFE,0xFB,0xFD,0xFB,0xFB,0xFB,0xF7,0xFB,0xCF,0xFB,0x3F,0x00,0xFF,0xFB,0x3F,0xFB,0xCF,0xFB,0xF7,0xFB,0xFB,0xFB,0xFD,0xFB,0xFE,0xFB,0xFE,0xFF,0xFF,/*"大",4*/
0xFD,0xDF,0xF3,0xDF,0x77,0xDF,0x96,0xDF,0xF6,0xDF,0xF6,0xDD,0x76,0xDE,0x96,0x81,0xF6,0x9F,0xF6,0x5F,0xE6,0xDF,0xD7,0xDF,0x37,0xDF,0xF5,0xDF,0xF3,0xDF,0xFF,0xFF,/*"学",5*/
0xDF,0xF7,0xDB,0xEF,0xDD,0x9F,0xDE,0x7F,0xD9,0xBE,0xC6,0xCD,0xFD,0xFB,0xF3,0xE7,0x0F,0x9F,0xEC,0x7F,0xEF,0x9F,0xEF,0xE7,0xEB,0xFB,0xE7,0xFD,0xFF,0xFE,0xFF,0xFF,/*"欢",6*/
0xFD,0xFF,0xFD,0xFD,0xBD,0xFB,0xCC,0x07,0xFF,0xFB,0xFF,0xFD,0xC0,0x0D,0xDF,0xDD,0xBF,0xBD,0xFF,0xFD,0xC0,0x01,0xDF,0xBD,0xDF,0xDD,0xC0,0x3D,0xFF,0xFD,0xFF,0xFF,/*"迎",7*/
0xFB,0xFD,0xF7,0xF3,0xEF,0xFF,0xC0,0x11,0x3B,0xFE,0xF7,0x7E,0xEE,0xEE,0x19,0xB2,0xDF,0xDE,0xD0,0x3E,0xDF,0xFE,0xDB,0xF8,0xD5,0xFF,0xCE,0x77,0xFF,0xF9,0xFF,0xFF,/*"您",8*/
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};/*空白*/
/**********函数声明********************/
void delay(uint i);
void Send(uchar Data,uchar Data1);
/***********************************/
sbit SH_CP = P3^4; //串行输入时钟,上升沿有效
sbit ST_CP = P3^5; //串行寄存器时钟,上升沿有效
sbit DS = P3^7;
sbit DS1 = P3^6;
void main()
{
uint i,j,k,n,num;
num=10; //
while(1)
{
for(j=0;j<num*32;j+=2) //这个图像一共几列就几帧
{
for(k=0;k<1;k++)//重复显示一帧数据多少次,调节滚动速度
{
P1=0x00;
for(i=0;i<32;i+=2)
{
n=(i+j)%(num*32);
P1++; //x轴移位
Send(ldis[n],ldis[n+1]);
ST_CP = 0; //ST_CP=0-1并行送出一排
_nop_();
ST_CP = 1;
delay(1);
}
}
}
}
}
//发送一个字节数据给595再并行输出
void Send(uchar Data,uchar Data1)
{
char i;
for(i=0;i<8;i++)
{
SH_CP = 0; //SH_CP=0-1串行输入一位
DS=0x80&Data;
DS1=0x80&Data1;
_nop_();
SH_CP = 1;
_nop_(); //上升沿让串行输入时钟变成高电平 并延时一个时钟周期
Data=_crol_(Data,1);
Data1=_crol_(Data1,1);
}
}
void delay(uint i)
{
uchar j;
while(i--)
for(j=0;j<125;j++);
}
没有采用片间级联的方式,我选择了用P1.4脚控制154的使能端,如下图
第一片154(U4)的使能端短接后连接P1.4;第二片154(U38)的使能端短接后连接P1.4非;
如此 当P1<16时,U4工作,U38不工作,P1>15时,U4停止工作,U38开始工作。
修改前
/**其他部分和外层循环不变**/
for(i=0;i<32;i+=2)
{
//循环体不变
}
修改后
/**其他部分和外层循环**/
for(i=0;i<64;i+=2)
{
//循环体不变
}
so,如果要再扩,就是128、256等等,至于硬件上同上,具体方法下面会写。
假如行数不变只研究列,理论上单片机控制的154可以无限扩展,直到用完IO口(当然用完IO口也有办法)。但是刷新率不够,会产生显示不全的情况。
下面只提供一个思路:
前面是用P1.4控制使能端,一位二进制数有0和1两种情况,可以选择两片。那P1.4、P1.5两位数就有00、01、10、11四种情况,就可以控制四片。
使能端一共就两位,如果要扩到8片呢?我们可以用3-8线译码器74138,16片?32片?我们可以用4-16线译码器74154替换138,以此类推······
当然,还是那句话,理论上是可以的,实际上是实现不了的,不是糟蹋钱的问题,是真的刷新率不够。
这次的课程设计只是一个简单的认识,生活中我们常见的电子屏当然不会是这么做的,但是这是基础,是我们走向更复杂的项目的第一步。