51单片机学习笔记_4 IO扩展:LED 点阵

文章介绍了如何利用74HC595芯片进行IO扩展,以驱动LED点阵。通过串行输入、并行输出的特性,该芯片能有效增加单片机的输出端口。文中详细阐述了74HC595的工作原理,包括OE低电平有效、移位寄存器和存储寄存器的作用。示例代码展示了如何编写程序控制LED点阵,并解释了点亮特定点的方法。

IO 扩展(串转并)-74HC595

前面接的一些输入输出设备都是直接连接的单片机 IO 口,单片机仅有的 IO 口非常有限。而使用 IO 扩展可以大量增加可使用的端口。比如后面要使用的 LED 点阵,8*8个格子,使用扩展 IO 输入就更为合适。如果多级联一个,就又有了8位输出,能实现16*16的点阵。

由图可知,OE 低电平有效,因此 LED 点阵旁的跳线帽一定要接到 OE-GND 一端。

74HC595 是一个位移缓存器,有8位串行输入、并行输出,并行输出是三态输出(高电平、低电平、高阻抗)。比如一次输入一个比特,输入八次,并行输出可以输出一个8位的字 1010 1010.

输出是由 VCC 驱动的,原理有那么一点像三极管。因为单片机内部是弱上拉,输出不足以点亮 LED 点阵,所以抛开 IO 口不够的问题,也不能直接接到 LED 点阵上,至少要有三极管。

点亮 LED 点阵

image-20230130004758073

image-20230130004829583

传入数据如列是0100 0000,行是0000 0001,则代表最后一行第二列的点会被点亮。

SRCLK:移位寄存器,数据先传输到移位寄存器中。移位寄存器上升沿时移位,再接收下一次数据。

RCLK:存储寄存器。存储寄存器上升沿时把寄存器中所有数据都通过端口输出。

相当于手枪,每次 SRCLK 上升时我们填入一枚子弹,RCLK 上升时把弹夹塞入。

QH 是级联用的。

列数据直接输入引脚,行数据输入 IO 拓展。

#include "reg52.h"
//编写程序先定义管脚和端口。管脚用sbit,端口宏定义
#define LED_MATRIX P0
sbit SRCLK=P3^6;
//因为 RCLK 是关键字不能被复用了
sbit rCLK=P3^5;
sbit SER=P3^4;
unsigned char hc_led_arr[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void delay(int i){while(i--);}

void hc_write_data(unsigned char c){
	//要传入8个输入,需要循环
	int i=0;
	for(i;i<8;i++){
		//注意 芯片传数据先传高位 再传低位,所以要反着写。这个问题在write函数内部解决,传入的数据和想要的形式一样就好。
		//通过移位获取
		SER=c>>7;
		//想获取下一位寄存器,需要移位寄存器移位。需要创造上升沿
		SRCLK=0;
		//芯片一般给定一个延时时间,经过这个时间之后才能处理完毕
		delay(1);
		SRCLK=1;
		delay(1);
		//让传入数据的次高位变为下次循环的高位
		c<<=1;
	}
	//最后通过存储寄存器的上升沿,传输全部数据
	rCLK=0;
	delay(1);
	rCLK=1;
}
void main(){
	LED_MATRIX=0x00;
	while(1){
		 int i=0;
		 for(i;i<8;i++){
		 	hc_write_data(0x00);//消隐
		 	hc_write_data(hc_led_arr[i]);
			delay(500000);
		 }
	}
}

比如0000 0001,传入LED阵列的数据是:每轮循环传入最高位的值,并且所有数据向左移动一位。因此前7轮 SER 传入都是0,最后一轮 SER 传入1,最下面一行全亮。

LED 点阵实验

上面的方法只能确定某一具体的行被点亮。可不可以具体确定哪些点点亮的方法?

我们让想被点亮的点列为低电平,行为高电平,就会被点亮。如果我们只想点亮第一行第一列的点,只需行脚只有第一行接高电平,列脚只有第一列接低电平即可。

所以只要先让第一列为低电平,其他列为高天平来只读取第一列,遍历所有行检查第一列哪些点应该被点亮;然后第二列,第三列……一次类推,每轮循环不用消除上次的结果即可。

#include "reg52.h"
//编写程序先定义管脚和端口。管脚用sbit,端口宏定义
#define LED_MATRIX P0
sbit SRCLK=P3^6;
sbit rCLK=P3^5;
sbit SER=P3^4;
unsigned char hc_led_arr[8]={0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};
unsigned char col[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
void delay(int i){while(i--);}

void hc_write_data(unsigned char c){
	//要传入8个输入,需要循环
	int i=0;
	for(i;i<8;i++){
		//注意 芯片传数据先传高位 再传低位,所以要反着写
		//通过移位获取
		SER=c>>7;
		//想获取下一位寄存器,需要移位寄存器移位。需要创造上升沿
		SRCLK=0;
		//芯片一般给定一个延时时间,经过这个时间之后才能处理完毕
		delay(1);
		SRCLK=1;
		delay(1);
		//让传入数据的次高位变为下次循环的高位
		c<<=1;
	}
	//最后通过存储寄存器的上升沿,传输全部数据
	rCLK=0;
	delay(1);
	rCLK=1;
}
void main(){
	LED_MATRIX=0x00;
	while(1){
		 int i=0;
		 for(i;i<8;i++){
		 	LED_MATRIX=col[i];
		 	hc_write_data(hc_led_arr[i]);
             //不知道为什么,下面两部分不写图形会偏移。不知道会不会有大佬解答一下
			delay(100);
			hc_write_data(0x00);
		 }
	}
}

点阵的具体图案生成方法:字模提取软件。

image-20220908234813283

<think> 首先,用户查询是关于STC89C52单片机点阵模块与单片机的连接方式。用户指定了引用[1]、[2]和[3],这些引用提供了关于LED点阵模块的代码示例和信息。 从引用中提取关键信息: - 引用[1]:显示了代码,其中使用了引脚定义如SRCLK、RCLK和SER,连接到P3端口。代码用于显示数字0在LED点阵上。 - 引用[2]:讨论了动态显示,使用74HC595芯片进行控制。代码展示了通过74HC595驱动点阵模块。 - 引用[3]:是关于LED点阵屏显示图形和动画的学习笔记,提到了开发板的使用。 用户的问题焦点是连接方式:STC89C52单片机点阵模块的连接。 在嵌入式系统中,LED点阵模块通常通过移位寄存器(如74HC595)连接到单片机,因为点阵有多个LED需要控制,直接连接会占用太多IO口。74HC595允许串行输入到并行输出,减少IO需求。 从引用中: - 引用[1]:定义了sbit SRCLK=P3^6; sbit RCLK=P3^5; sbit SER=P3^6; 这似乎有错误,因为SER和SRCLK都用了P3^6?在代码中,SRCLK和SER都指向P3^6,这可能是笔误。实际中,SRCLK(移位寄存器时钟)和SER(串行数据输入)通常是不同引脚。但代码中两者都是P3^6,这有冲突。 - 引用[2]:提到了#include "74HC595.h",暗示使用74HC595芯片驱动点阵。函数_74HC595_Show用于设置列数据。 连接方式: 1. **点阵模块类型**:常见的8x8 LED点阵有行和列引脚。行是阳极,列是阴极,或反之。需要连接行线和列线。 2. **使用74HC595**:74HC595是8位移位寄存器,可以级联。它用于控制点阵的行或列。 3. **典型连接**: - 单片机通过SPI或类似协议连接到74HC595。 - SER(串行数据)连接到单片机的一个IO口。 - SRCLK(移位时钟)连接到另一个IO口。 - RCLK(锁存时钟)连接到另一个IO口。 - 74HC595的输出连接到点阵模块的行或列。 - 点阵的另一边可能连接到单片机的其他IO口或另一个74HC595。 在引用[1]的代码中: - SER、SRCLK、RCLK定义了引脚。 - ledduan数组可能是段选(对应列),ledwei数组是位选(对应行)。 - Hc595SendByte函数发送数据到74HC595。 在引用[2]中,直接使用_74HC595_Show函数,参数是列索引和数据。 所以,一般连接方式: - 单片机通过三个引脚控制74HC595: SER (数据), SRCLK (时钟), RCLK (锁存)。 - 74HC595的输出连接到点阵的列(或行),而点阵的行(或列)通过单片机的其他IO口控制或另一个74HC595。 在动态显示中: - 行(或列)被轮流激活,同时发送对应列(或行)的数据。 对于用户的问题:stc89c52单片机点阵模块与单片机的连接方式。 基于引用,总结: - 引脚连接如引用[1]所示:SRCLK、RCLK、SER连接到P3端口。 - 但注意,在引用[1]中,SRCLK和SER都用了P3^6,这是冲突;可能是个错误,实际中它们应该是不同引脚。 - 点阵模块的引脚直接连接到74HC595的输出,而74HC595的输入来自单片机。 更准确地说: - 单片机控制74HC595的SER、SRCLK、RCLK。 - 74HC595的输出连接到点阵的列引脚。 - 点阵的行引脚可能连接到单片机的另一个端口,如P0在引用[1]中用于位选(P0=ledwei[i];)。 在引用[1]代码中: - P0用于控制行(位选),通过ledwei数组。 - Hc595SendByte用于控制列(段选),通过ledduan数组发送到74HC595。 所以,连接方式: - 点阵的行引脚连接到单片机的P0端口(或其他端口)。 - 点阵的列引脚连接到74HC595的输出。 - 74HC595的SER、SRCLK、RCLK分别连接到单片机的P3^6(SER?)、P3^6(SRCLK?但冲突)、P3^5(RCLK)。在引用[1],sbit SRCLK=P3^6; sbit RCLK=P3^5; sbit SER=P3^6; SER和SRCLK同一引脚,不合理。可能代码有误,或实际中用了不同引脚。 在引用[2],使用自定义函数_74HC595_Show,暗示74HC595驱动。 因此,标准连接方式: - 使用74HC595减少IO口。 - 单片机引脚: - SER 到 74HC595的DS (数据输入) - SRCLK 到 74HC595的SHCP (移位时钟) - RCLK 到 74HC595的STCP (锁存时钟) - 74HC595的Q0-Q7输出到点阵的列引脚。 - 点阵的行引脚连接到单片机的另一个端口,如P0或P2,用于选择哪一行激活。 在动态扫描中,行是位选,列是段选。 回答结构: - 先解释一般连接原理。 - 然后基于引用提供具体示例。 - 保持结构清晰。 - 最后生成相关问题。 使用中文回答。 添加引用标识。 数学表达式用$...$格式,但这里可能不涉及数学。 独立公式用$$...$$,但可能不需要。 生成相关问题。 </think> 基于您提供的引用内容,我将详细解释STC89C52单片机LED点阵模块(通常是8×8点阵)的连接方式。连接的核心是通过**74HC595移位寄存器芯片**来扩展IO端口,因为点阵模块有64LED(8行×8列),直接连接会占用单片机太多IO口。74HC595允许通过串行通信(只需3个IO口)控制多个输出,实现动态扫描显示[^1][^2]。以下是逐步说明: ### 1. **连接原理概述** - **点阵模块结构**:8×8 LED点阵通常由**行引脚**和**列引脚**组成。行引脚对应LED的阳极(或阴极,取决于模块类型),列引脚对应阴极(或阳极)。动态扫描时,单片机逐行激活(位选),同时通过74HC595发送列数据(段选),利用人眼视觉暂留效应显示图形[^2][^3]。 - **74HC595作用**:作为移位寄存器,它将单片机的串行数据转换为并行输出,驱动点阵的列线。这减少了IO需求(只需3个单片机引脚)。 - **单片机引脚分配**: - STC89C52的P0、P1、P2、P3端口可用于控制。 - 典型连接: - **行控制**:直接连接到单片机的某个端口(如P0),用于选择当前激活的行。 - **列控制**:通过74HC595连接到单片机,74HC595的输出(Q0-Q7)驱动点阵的列线。 - 74HC595的控制引脚: - **SER**(串行数据输入):连接到单片机的一个IO口(如P3.6)。 - **SRCLK**(移位时钟):连接到另一个IO口(如P3.6或避免冲突的其他引脚)。 - **RCLK**(锁存时钟):连接到另一个IO口(如P3.5)。 注意:引用[1]中代码可能存在引脚冲突(SER和SRCLK都定义为P3^6),实际硬件连接时需确保引脚独立以避免错误[^1]。 ### 2. **具体连接方式(基于引用示例)** 以下是基于引用[1]和[2]的典型连接方案(假设使用共阴极8×8点阵模块): - **74HC595与单片机的连接**: - `SER`(74HC595的DS引脚) → 连接到单片机的`P3.6`(在引用[1]中定义为`SER`)。 - `SRCLK`(74HC595的SHCP引脚) → 连接到单片机的`P3.6`(引用[1]定义为`SRCLK`,但需注意冲突;推荐改用其他引脚如P3.4)。 - `RCLK`(74HC595的STCP引脚) → 连接到单片机的`P3.5`(引用[1]定义为`RCLK`)。 - 74HC595的输出`Q0-Q7` → 连接到点阵模块的**列引脚**(列控制)。 - **点阵模块与单片机的直接连接**: - 点阵的**行引脚** → 连接到单片机的`P0端口`(在引用[1]中,行选择通过`P0=ledwei[i]`实现,`ledwei`数组对应位选码)。 - 点阵的GND/VCC → 根据模块类型连接到电源(通常需限流电阻)。 - **完整连接图示例**: ``` STC89C52单片机: P3.5 (RCLK) → 74HC595的STCP P3.6 (SER/SRCLK) → 74HC595的DS和SHCP(注意:推荐SRCLK改用P3.4避免冲突) P0端口(P0.0-P0.7) → 点阵行引脚(行1-行8) 74HC595: Q0-Q7 → 点阵列引脚(列1-列8) VCC → 5V电源 GND → 地 ``` ### 3. **动态扫描工作流程** - **步骤1**:单片机通过`P0`端口激活一行(例如,发送`ledwei[i]`码选择第i行)。 - **步骤2**:通过`Hc595SendByte`函数(引用[1])发送列数据(如`ledduan[i]`)到74HC595,控制该行哪些LED亮。 - **步骤3**:短暂延时后,切换到下一行,并清除上一行数据(消影)。 - 循环执行,实现稳定显示(人眼无法察觉闪烁)[^1][^2]。 ### 4. **注意事项** - **引脚冲突问题**:引用[1]中`SER`和`SRCLK`都使用P3.6,这可能导致功能错误。实际连接时,应分配不同引脚(例如SRCLK用P3.4)。 - **驱动能力**:点阵LED需限流电阻(通常220Ω)防止过流;74HC595输出电流有限,可级联多个芯片用于更大点阵。 - **软件控制**:代码需包含延时函数(如`delay(100)`)和动态扫描逻辑,引用[1][^1]和[2][^2]提供了基础实现。 - **模块类型**:确认点阵是共阴或共阳(引用示例为共阴),连接方式可能需调整。 ### 5. **参考代码片段(基于引用[1]简化)** ```c #include <reg51.h> sbit SRCLK = P3^6; // 移位时钟(建议改为P3.4避免冲突) sbit RCLK = P3^5; // 锁存时钟 sbit SER = P3^6; // 串行数据(与SRCLK冲突时需调整) void Hc595SendByte(u8 dat) { // 发送数据到74HC595(代码见引用[1]) } int main() { while(1) { for(int i=0; i<8; i++) { P0 = ledwei[i]; // 选择行(位选) Hc595SendByte(ledduan[i]); // 发送列数据(段选) delay(100); // 延时 Hc595SendByte(0x00); // 消影 } } } ``` 此代码驱动点阵显示数字"0",连接方式基于上述描述[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰海宽松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值