STC89C52控制74HC595,74HC138双色16x16点阵屏循环显示汉字
简介
常见的LED点阵除了使用MAX7219, 还有一部分是使用74HC595, 前者能主动刷新, 后者需要上位机主动扫描刷新.
手里这块是德飞莱的16x16LED点阵模块, 板上印的型号LY-LED16x16B V2.0, 这个型号有两种配置, 单色或者双色. 双色多一个IO口用于控制另一个颜色. 下图是板子背面, 这个是单色的配置, 有几个焊盘是空的, 8x8LED的引脚也有部分是空的.

运行机制
LED点阵的显示主要是通过74HC595和74HC138这两个逻辑芯片
74HC138 译码器/decoder
74HC138接受3位二进制地址输入(A0, A1, A2), 当使能时提供8个互斥的低有效输出(Y0至Y7). 在这个模块中, 74HC138负责行扫描, 每次扫描其中一行, 行的位置由ABCD这4个脚控制, 对应了两片74HC138, 每片控制8个行, 通过P0.0-P0.3, 可以对指定的行拉低电平.
通信方式是直接通过IO高低电平控制.
74HC595 8位移位寄存器输出锁存器
74HC595是一个串行输入, 并行输出的移位寄存器, 包含一个串行移位输入(Ds), 一个串行移位输出(Q7’), 一个异步的低电平复位; 存储寄存器有一个8位的并行的具备三态的总线输出, 当使能OE时(低电平使能), 存储寄存器的数据输出到总线.
在这个模块中, 74HC595负责准备当前行上的数据, 这个数据有 16 bit, 对应 2 byte, 对应每个汉字, 有16x16个点, 就是16个 16 bit, 每次扫描时, 配合74HC138将正在扫描的那行的2个字节内容送到总线上去, 同样是两片74HC595, 每片负责8个bit.
通信方式是SPI, 串行输入-锁存-并行输出的方式
上位机代码
STC89C52RC
连接方式
R1 => P2.4 红色数据信号
D => P0.3
C => P0.2
B => P0.1
A => P0.0 A-D用于控制16行,通过2路 HC138 控制
LATCH => P2.6 锁存
SCK => P2.5 时钟
G1 => P0.4 绿色数据信号, 如果使用单红色屏此信号无需连接
OE => P2.1 可以用IO引脚PWM控制亮度, 或者使用此引脚控制拖尾现象
+5V => 5V
GND => GND
代码
#include<reg52.h>
sbit G1 = P0^4; //数据引脚,屏上标识G1
sbit OE = P2^1; //使能引脚,屏上标识EN/OE
sbit R1 = P2^4; //数据引脚,屏上标识R1
sbit T_CLK = P2^5; //时钟引脚,屏上标识CLK
sbit T_STR = P2^6; //锁存引脚,屏上标识LATCH
unsigned char pos=0;
unsigned char tab[8];
unsigned char DIS[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};//行数据
/*-----------------------------------------------
16x16汉字取模数据
------------------------------------------------*/
unsigned char code hztest[][32]= //二维数组, 每个汉字32个字节
{
/*-- 文字: 电 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x01,0x00,0x01,0x00,0x01,0xF8,0x3F,0x08,0x21,0x08,0x21,0x08,0x21,0xF8,0x3F,
0x08,0x21,0x08,0x21,0x08,0x21,0xF8,0x3F,0x0A,0x21,0x02,0x01,0x02,0x01,0xFE,0x00,
/*-- 文字: 子 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x00,0xF8,0x7F,0x10,0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x00,0x01,0xFE,0xFF,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,
/*-- 文字: 工 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x00,0x00,0x00,0xFC,0x7F,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0xFE,0xFF,0x00,0x00,0x00,0x00,
/*-- 文字: 程 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x08,0xFC,0x1D,0x04,0xF1,0x04,0x11,0x04,0x11,0xFC,0xFD,0x00,0x10,0x00,0x30,
0xFE,0x39,0x20,0x54,0x20,0x54,0xFC,0x91,0x20,0x10,0x20,0x10,0xFE,0x13,0x00,0x10,
/*-- 文字: 信 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x40,0x08,0x20,0x08,0xFE,0x0B,0x00,0x10,0x00,0x10,0xFC,0x31,0x00,0x30,0x00,0x50,
0xFC,0x91,0x00,0x10,0x00,0x10,0xFC,0x11,0x04,0x11,0x04,0x11,0xFC,0x11,0x04,0x11,
/*-- 文字: 息 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x01,0x00,0x02,0xF0,0x1F,0x10,0x10,0xF0,0x1F,0x10,0x10,0xF0,0x1F,0x10,0x10,
0xF0,0x1F,0x10,0x10,0x00,0x01,0x84,0x08,0x92,0x48,0x12,0x48,0xF0,0x87,0x00,0x00,
/*-- 文字: 科 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x10,0x08,0x10,0x1D,0x90,0xF0,0x90,0x10,0x10,0x10,0x10,0xFD,0x90,0x10,0x90,0x38,
0x10,0x34,0x1E,0x50,0xF0,0x53,0x10,0x90,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
/*-- 文字: 学 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x08,0x22,0x08,0x11,0x10,0x11,0x20,0x00,0xFE,0x7F,0x02,0x40,0x04,0x80,0xE0,0x1F,
0x40,0x00,0x80,0x01,0xFE,0xFF,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,
};
/*-----------------------------------------------
向595写入一个字节, 红色
------------------------------------------------*/
void InputByte(unsigned char dat)
{
unsigned char i;
for(i = 8; i > 0; i--)
{
R1 = !(dat & 0x01);
T_CLK = 0;
T_CLK = 1;
dat = dat >> 1;
}
}
/*-----------------------------------------------
向595写入一个字节, 绿色
------------------------------------------------*/
void InputByteG(unsigned char dat)
{
unsigned char i;
for(i = 8; i > 0; i--)
{
G1 = !(dat & 0x01);
T_CLK = 0;
T_CLK = 1;
dat = dat >> 1;
}
}
/*-----------------------------------------------
向595写入两个字节 双色
------------------------------------------------*/
void Input2Byte(unsigned char DataR1, unsigned char DataG1) //写一个字节
{
unsigned char i;
for(i=8; i>0; i--)
{
R1 = !(DataR1&0x01);
G1 = !(DataG1&0x01);
T_CLK = 0;
T_CLK = 1;
DataR1 = DataR1 >> 1;
DataG1 = DataG1 >> 1;
}
}
/*-----------------------------------------------
初始化定时器,做为动态扫描
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10;
EA=1; //总中断使能
ET1=1; //定时中断使能
TR1=1; //打开定时器开关
}
/*-----------------------------------------------
主程序
------------------------------------------------*/
main()
{
unsigned int i;
unsigned char a;
Init_Timer1(); //初始化定时器
while(1)
{
for(i = 0; i < 1000; i++); // 延时
a++;
if(a == 8) a = 0; // 汉字循环
pos = a;
}
}
/*-----------------------------------------------
定时器执行动态扫描
------------------------------------------------*/
void Timer1_isr(void) interrupt 3
{
static unsigned char count, j;
unsigned char i;
TH1=0xff; // 重装初值
TL1=0;
T_STR=0; // 锁存释放
for(j = 0; j < 1; j++) //取当前汉字在i位置的2个字节,数据传输完成后锁存输出
{
InputByte(hztest[j+pos][i]);
InputByte(hztest[j+pos][i+1]);
}
OE = 1; // 关闭屏幕, 如果没有使用该引脚控制则会出现拖影现象
T_STR=1; // 锁存有效, 此时一行的数据显示到屏上
P0 = DIS[count] | 0xF0; //低4位对应P0.0-P0.3, 通过HC138 4-16译码器, 循环扫描其他15行
OE = 0; // 打开屏幕
count++;
i += 2; // 当前汉字下一位置
if(count == 16) count = 0;
if(i == 32) i = 0;
}
另一份代码, 驱动4块16x16的595
/*-----------------------------------------------
名称:595控制4汉字点阵屏
论坛:www.doflye.net
编写:shifang
日期:2009.5
修改:无 51单片机
内容:屏+5V、GND连接电源5V
P0.0-P0.3分别连接A、B、C、D,用于控制16行,通过2路HC138控制
SCK时钟连接P2.5
LATCH锁存连接P2.6
R1红色数据信号连接至P2.4
G1绿色数据信号连接至P0.4,如果使用单红色屏此信号无需连接
OE使能端一般接GND,可以用IO引脚PWM控制亮度
或者使用此引脚控制拖尾现象。
现象:使用普通速度51系列单片机。1个汉字显示屏,向左流动显示多句话,重复循环显示。
------------------------------------------------*/
#include<reg52.h>
sbit T_STR = P2^6; //锁存引脚,屏上标识位STR
sbit R1 = P2^4; //数据引脚,屏上标识R1
sbit G1 = P0^4; //数据引脚,屏上标识G1
sbit T_CLK = P2^5; //时钟引脚,屏上标识位CLK
sbit OE = P2^1; //使能引脚,屏上标识EN/OE
unsigned char MoveBitNum,MoveBitNumtemp,IncNum;//移动位数,临时移动位数,大于一个字节增加字节数
unsigned int HzNum;//汉字个数
unsigned char buff[10];
/*-----------------------------------------------
16x16汉字取模数据
------------------------------------------------*/
unsigned char code hztest[][32]= //取模选择字节倒序 ,正序得出的字是反的,可以在软件中设置自动倒叙
{
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, //前面一屏大小的空字符,不显示,这里根据屏的大小修改,这个是1个汉字屏
//所以写入1个汉字
/*-- 文字: 电 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x01,0x00,0x01,0x00,0x01,0xF8,0x3F,0x08,0x21,0x08,0x21,0x08,0x21,0xF8,0x3F,
0x08,0x21,0x08,0x21,0x08,0x21,0xF8,0x3F,0x0A,0x21,0x02,0x01,0x02,0x01,0xFE,0x00,
/*-- 文字: 子 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x00,0xF8,0x7F,0x10,0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x00,0x01,0xFE,0xFF,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,
/*-- 文字: 工 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x00,0x00,0x00,0xFC,0x7F,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0xFE,0xFF,0x00,0x00,0x00,0x00,
/*-- 文字: 程 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x08,0xFC,0x1D,0x04,0xF1,0x04,0x11,0x04,0x11,0xFC,0xFD,0x00,0x10,0x00,0x30,
0xFE,0x39,0x20,0x54,0x20,0x54,0xFC,0x91,0x20,0x10,0x20,0x10,0xFE,0x13,0x00,0x10,
/*-- 文字: 信 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x40,0x08,0x20,0x08,0xFE,0x0B,0x00,0x10,0x00,0x10,0xFC,0x31,0x00,0x30,0x00,0x50,
0xFC,0x91,0x00,0x10,0x00,0x10,0xFC,0x11,0x04,0x11,0x04,0x11,0xFC,0x11,0x04,0x11,
/*-- 文字: 息 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x01,0x00,0x02,0xF0,0x1F,0x10,0x10,0xF0,0x1F,0x10,0x10,0xF0,0x1F,0x10,0x10,
0xF0,0x1F,0x10,0x10,0x00,0x01,0x84,0x08,0x92,0x48,0x12,0x48,0xF0,0x87,0x00,0x00,
/*-- 文字: 科 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x10,0x08,0x10,0x1D,0x90,0xF0,0x90,0x10,0x10,0x10,0x10,0xFD,0x90,0x10,0x90,0x38,
0x10,0x34,0x1E,0x50,0xF0,0x53,0x10,0x90,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
/*-- 文字: 学 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x08,0x22,0x08,0x11,0x10,0x11,0x20,0x00,0xFE,0x7F,0x02,0x40,0x04,0x80,0xE0,0x1F,
0x40,0x00,0x80,0x01,0xFE,0xFF,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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,
};
/*-----------------------------------------------
向595写入一个字节 单红色
------------------------------------------------*/
void InputByte( unsigned char DataR1) //写一个字节
{
unsigned char i;
for(i=8; i>0; i--)
{
R1 = !(DataR1&0x01);
T_CLK = 0;
T_CLK = 1;
DataR1 = DataR1 >> 1;
}
}
/*-----------------------------------------------
向595写入两个字节 双色
------------------------------------------------*/
void Input2Byte( unsigned char DataR1,unsigned char DataG1) //写一个字节
{
unsigned char i;
for(i=8; i>0; i--)
{
R1 = !(DataR1&0x01);
G1 = !(DataG1&0x01);
T_CLK = 0;
T_CLK = 1;
DataR1 = DataR1 >> 1;
DataG1 = DataG1 >> 1;
}
}
/*-----------------------------------------------
延时程序
------------------------------------------------*/
void Delay(unsigned int t)
{
while(--t);
}
/*-----------------------------------------------
主程序
------------------------------------------------*/
main()
{
unsigned char count;//16行扫描数据,范围0-15
unsigned int i, j;
unsigned char temp;
while(1)
{
i++;
if(i==60)//更改流动速度,1T单片机和12T单片机速度大约5-8倍,注意更改参数
{
i=0;
MoveBitNum++;
if(MoveBitNum==16)//每次移动完一个汉字大小后循环
{
MoveBitNum=0;
HzNum+=1; //调用下一个汉字
if(HzNum >= 9)//需要显示的汉字个数,包括前面的一屏空字符的个数,后面清屏的空字符不包含在内,这里是(汉字个数+1)
HzNum = 0; //完全显示完后循环调用
}
}
Delay(1);//控制扫描频率
for(j=0;j<2;j++) //取每个汉字的前2个字节,
{ //汉字个数+1
buff[j+j]=hztest[HzNum+j][count+count]; //每次移动完一个汉字后,选择下一个汉字
buff[j+j+1]=hztest[HzNum+j][count+count+1];
}
if(MoveBitNum<8) // 判读移动距离是大于一个字节还是小于一个字节,因为一个字节左移右移最大只能8位
{ IncNum=0; MoveBitNumtemp=MoveBitNum; }
else
{ IncNum=1; MoveBitNumtemp=MoveBitNum-8;}//大于8就减去8得到的数值还是小于8
T_STR=0; //锁存无效
for(j=0;j<2;j++) //按bit的方式移动缓冲区的内容,然后输出到595,即取出的数值每个字节左移一定的位数,
{ //后面左移出的数据整合到前面的字节中,保持数据的连续性
temp=(buff[j+IncNum]>>MoveBitNumtemp)|(buff[j+1+IncNum]<<(8-MoveBitNumtemp));//这句比较重要,需要自行拿出2个字节的数据模拟分析
Input2Byte(temp,temp);//输出到595
}//8个字节传输完锁存输出
OE = 1;
P0=count;//用P0口的前4位控制16行,屏内部通过4-16译码器工作,循环扫描16行
T_STR=1; //锁存有效,此时一行的数据显示到屏上
OE = 0;
count++;
if(count==16)
count=0;
}
}
STC89C52控制74HC595,74HC138双色16x16点阵屏循环显示汉字的更多相关文章
- 【玩转单片机系列001】 08接口双色LED显示屏驱动方式探索
前些日子,从淘宝上购得一块08接口的双色LED显示屏(打算做个音乐频谱显示器),捣鼓了好几天,终于搞清楚了其控制原理,在这里做个总结,算是备忘吧. 1.LED显示屏的扫描方式 LED显示屏的扫描方式有 ...
- 完美C++(第5版)(双色)
完美C++(第5版)(双色) 薛正华 沈庚 韦远科 译 ISBN 978-7-121-23198-8 2014年6月出版 定价:148.00元 788页 16开 内容提要 <完美C++(第5版) ...
- css实现双色饼图
from:wx--前端早读课 首先回想用css画三角形的方法: <div class="triangle"></div> .triangle { displ ...
- HTML5移动开发即学即用(双色) 王志刚 pdf扫描版
HTML5已经广泛应用于各智能移动终端设备上,而且绝大部分技术已经被各种最新版本的测览器所支持:逐一剖析HTML5标准中包含的最新技术,详细介绍了HTML5新标准中提供的各种API,各种各样的应用实例 ...
- js 控制Div循环显示 非插件版
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【MM系列】SAP MM模块-控制采购订单中某些项目的输出显示
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-控制采购订单中某些 ...
- 用一个I/O口控制1个三色指示灯, 2个单色指示灯
http://www.baiheee.com/Documents/081207/081207184434.htm http://www.baiheee.com/Documents/081207/081 ...
- 3.6.使用STC89C52控制MC20解析GPS的经纬度数据上传到指定服务器
需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...
- 3.4 使用STC89C52控制MC20解析GPS的经纬度数据在LCD1602上显示
需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...
- 3.3 使用STC89C52控制MC20通过GPRS远程发送数据
需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...
随机推荐
- 07-逻辑仿真工具VCS-Post processing with VCD+ files
逻辑仿真工具-VCS 编译完成不会产生波形,仿真完成之后,生成波形文件,通过dve产看波形 vcd是波形文件的格式,但是所占的内存比较大,后面出现了vpd(VCD+)波形文件 将一些系统函数嵌入到源代 ...
- 新建Maven工程没有src/main...目录?
0.必看:详细的Maven项目介绍 1.问题 我新建的Maven项目的pom.xml为空,且无法被识别,同时项目目录没有src/main等等 2.解决 这里设置的JDK版本不对,我选用了JDK19 但 ...
- vocode-markdown导出pdf插件
1. 背景 在vocode中编辑markdown格式文本文件,并将其导出为pdf格式文件 2. 插件 在 vscode的扩展市场中搜索插件"Markdown PDF" 并安装 选中 ...
- [转帖]goproxy的设置
goproxy.io 是全球最早的 Go modules 镜像代理服务之一 [大陆地区建议使用 proxy.golang.com.cn],采用 CDN 加速服务为开发者提供依赖下载, 该服务由一批热爱 ...
- [转帖]enq: TX - row lock contention故障处理一则
https://www.cnblogs.com/zhchoutai/p/7088826.html 一个非常easy的问题,之所以让我对这个问题进行总结.一是由于没我想象的简单,在处理的过程中遇到了 ...
- [转帖]cx_Oracle.DatabaseError: ORA-28040
背景: python第三方库cx-Oracle连接Oracle数据库报错 ORA-28040 cx_Oracle.DatabaseError: ORA-28040: No matching authe ...
- [转帖]手把手教你在QEMU上运行RISC-V Linux
https://kernel.0voice.com/forum.php?mod=viewthread&tid=3080 嵌入式Linux内核 发布于 2023-3-15 14:44:37 ...
- 给无网络的CentOS服务器下载rpm包的一个解决办法
很多公司的服务器为了安全都在内网, 是无法直接连接互联网的, 无法连接互联网就无法使用yum等的包管理器安装rpm包等. 有时候一些rpm包还是能很好的提高性能的, 所以可以使用多种方式获取rpm包进 ...
- 对于Vue3和Ts的心得和思考
作者:京东物流 吴云阔 1 前言 Vue3已经正式发布了一段时间了,各种生态已经成熟.最近使用taro+vue3重构冷链的小程序,经过了一段时间的开发和使用,有了一些自己的思考. 总的来说,Vue3无 ...
- Gorm日志设置
Logger Gorm提供了一个默认的logger实现,默认情况下日志数据级别为warn,同时输出慢SQL: Default = New(log.New(os.Stdout, "\r\n&q ...