HC595级联原理及实例 - STM32

news2024/10/6 12:27:29

        74HC595的最重要的功能就是:串行输入,并行输出。其次,74HC595里面有2个8位寄存器:移位寄存器、存储寄存器。74HC595的数据来源只有一个口,一次只能输入一个位,那么连续输入8次,就可以积攒为一个字节了。

引脚图

14脚:DIN(SER),串行数据输入引脚

13脚:OE,  输出使能控制脚,它是低电才使能输出,所以接GND

12脚:RCK,存储寄存器时钟输入引脚。上升沿时,数据从移位寄存器转存带存储寄存器。

11脚:SCK,移位寄存器时钟引脚,上升沿时,移位寄存器中的bit 数据整体后移,并接受新的bit(从SER输入)。

10脚:SCLR,低电平时,清空移位寄存器中已有的bit数据,一般不用,接高电平即可。

9 脚 :串行数据出口引脚。当移位寄存器中的数据多于8bit时,会把已有的bit“挤出去”,就是从这里出去的。用于595的级联。

Qx:并行输出引脚

使用参数

VCC:2V~6V,5V最好

I Qn:+- 35mA

移位寄存器

74HC595的14脚:DIN,是串行数据输入口。595的数据来源只有这一个口,一次只能输入一个位,那么连续输入8次,就可以积攒为一个字节了。

74HC595的11脚,(shift register clock input) 移位寄存器时钟引脚。上升沿有效。
首先我们要介绍这个引脚的作用,当一个新的位数据要进来时,已经进入的位数据就在移位寄存器时钟脉冲的控制下,整体后移,让出位置。

上升沿:电平从低到高的那个过程。移位寄存器时钟在上升沿这个过程中才起作用。

存储寄存器

595是怎么将移位寄存器的数据转移到存储寄存器。存储寄存器是直接和8个输出引脚相通的,将移位寄存器的数据转移到存储寄存器后,Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 就可以接收到我们开始输入的一个字节的数据。所谓存储寄存器,就是数据可以存在这个寄存器中,并不会随着一次输出就消失,只要595不断电,也没有新的数据从移位寄存器中过来,数据就一直不变且有效。新的数据过来后,存储寄存器中的数据就会被覆盖更新。

74HC595的12脚: (storage register clock input ) 存储寄存器时钟
数据从位移寄存器转移到存储寄存器,也是需要时钟脉冲驱动的,这就是12脚的作用。它也是上升沿有效。

74HC595级联

通过上面的介绍,见识到595的厉害了吧。138译码器通过3个输入口控制8个输出口,而且还只能是特定的8个输出值,而595只用了一个输入口就可以输任意的8位数据,可谓短小精悍。

你觉的1位控制8位输出还不够?

在上面的程序中用到的9脚,没用起作用,如果要让2个595串联起来的话,就需要它了。想一下,我们将移位寄存器的8个位填满后,再往移位寄存器中塞一个会怎么样?也许你想到了。对!移位寄存器的最后一个位数据会被挤出去,从哪里出去?就是从9脚输出的。如果我们把第一个595的9脚连接到第二个的串行数据输入脚SER,那么,就形成了595的级联。这样,如果我们用2个595组合成了一个新的超级595,这个超级595的移位寄存器和存储寄存器的容量都翻倍了,1口控制16口,有木有!你还可以继续级联下去!

74HC595级联实例

#ifndef __HC_595_H__
#define __HC_595_H__	

#include "stm32h7xx_hal.h"


// HC595的16位输出端定义位号
// Q0 - 0 .....Q15 -15
#define DIO_HC_A0           (6)
#define DIO_HC_B0           (7)
#define DIO_HC_C0           (0)
#define DIO_HC_A1           (15)
#define DIO_HC_B1           (8)
#define DIO_HC_C1           (1)
#define DIO_HC_A2           (10)
#define DIO_HC_B2           (13)
#define DIO_HC_C2           (14)
/* RLY */
#define DIO_RLY0            (5)
#define DIO_RLY1            (2)
/* S1 S2 */
#define DIO_S1              (11)
#define DIO_S2              (12)
/* CUR */
#define DIO_CUR             (9)

/*----------------------------------------- HC595 引脚配置宏 -----------------------------------------------*/

#define HC_595_DIN_ENABLE     		 __HAL_RCC_GPIOE_CLK_ENABLE()			// 使能DIN引脚时钟
#define HC_595_DIN_PORT   			 GPIOE                 					// DIN引脚端口
#define HC_595_DIN_PIN     		 	 GPIO_PIN_1  							// DIN引脚
         
#define HC_595_RCK_ENABLE     		 __HAL_RCC_GPIOE_CLK_ENABLE()			// 使能RCK引脚时钟
#define HC_595_RCK_PORT   			 GPIOE                 					// RCK引脚端口
#define HC_595_RCK_PIN     		 	 GPIO_PIN_3  							// RCK引脚

#define HC_595_SCK_ENABLE     		 __HAL_RCC_GPIOE_CLK_ENABLE()			// 使能SCK引脚时钟
#define HC_595_SCK_PORT   			 GPIOE                 					// SCK引脚端口
#define HC_595_SCK_PIN     		 	 GPIO_PIN_2  							// SCK引脚

#define HC_595_SCLR_ENABLE     		 __HAL_RCC_GPIOC_CLK_ENABLE()			// 使能SCLR引脚时钟
#define HC_595_SCLR_PORT   			 GPIOC                 					// SCLR引脚端口
#define HC_595_SCLR_PIN     		 GPIO_PIN_4  								// SCLR引脚

/*-------------------------------------------- IO口操作 ---------------------------------------------------*/   

#define HC_595_DIN(a)	if (a)	\
										HAL_GPIO_WritePin(HC_595_DIN_PORT, HC_595_DIN_PIN, GPIO_PIN_SET); \
									else		\
										HAL_GPIO_WritePin(HC_595_DIN_PORT, HC_595_DIN_PIN, GPIO_PIN_RESET)	

#define HC_595_RCK(a)	if (a)	\
										HAL_GPIO_WritePin(HC_595_RCK_PORT, HC_595_RCK_PIN, GPIO_PIN_SET); \
									else		\
										HAL_GPIO_WritePin(HC_595_RCK_PORT, HC_595_RCK_PIN, GPIO_PIN_RESET)	
									
#define HC_595_SCK(a)	if (a)	\
										HAL_GPIO_WritePin(HC_595_SCK_PORT, HC_595_SCK_PIN, GPIO_PIN_SET); \
									else		\
										HAL_GPIO_WritePin(HC_595_SCK_PORT, HC_595_SCK_PIN, GPIO_PIN_RESET)	

#define HC_595_SCLR(a)	if (a)	\
										HAL_GPIO_WritePin(HC_595_SCLR_PORT, HC_595_SCLR_PIN, GPIO_PIN_SET); \
									else		\
										HAL_GPIO_WritePin(HC_595_SCLR_PORT, HC_595_SCLR_PIN, GPIO_PIN_RESET)	
																		

// 函数声明
void HC_595_GPIO_Config(void);
void HC_595_Send_Byte(unsigned short Q15_Q0);
void HC595_Write_QX(unsigned short index,unsigned short sta);
									
#endif
#include "hc595.h"

static unsigned short Q0_Q15_S = 0;

/*****************************************************************************************
*	函数名: HC595_Delay
*	入口参数: t - 延时时间,以时钟周期数为单位
*	返回值: 无
*	函数功能: 简单延时函数
*	说明: 为了移植的简便性且对延时精度要求不高,所以不需要使用定时器做延时
******************************************************************************************/
void HC595_Delay(unsigned int t)
{
	while(t--); // 简单的循环延时,延时时间由入口参数 t 决定
}


/*****************************************************************************************
*	函数名: HC_595_GPIO_Config
*	入口参数: 无
*	返回值: 无
*	函数功能: 初始化移位寄存器的 GPIO 口
*	说明: 配置数据输入引脚(DIN)、存储寄存器时钟引脚(RCK)、移位寄存器时钟引脚(SCK)和清除引脚(SCLR)为推挽输出模式,
*		 不带上下拉,速度配置为低速。然后将这些引脚初始化,并设置初始电平状态。
******************************************************************************************/
void HC_595_GPIO_Config(void)
{	
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	// 初始化IO口时钟
	HC_595_DIN_ENABLE;
	HC_595_RCK_ENABLE;
	HC_595_SCK_ENABLE;	
	HC_595_SCLR_ENABLE;	
	
	// 配置DIN引脚
	GPIO_InitStruct.Pin 			= HC_595_DIN_PIN;
	GPIO_InitStruct.Mode 			= GPIO_MODE_OUTPUT_PP;	// 推挽输出
	GPIO_InitStruct.Pull 			= GPIO_NOPULL;			// 不带上下拉
	GPIO_InitStruct.Speed 			= GPIO_SPEED_FREQ_LOW;	// 低速
	HAL_GPIO_Init(HC_595_DIN_PORT, &GPIO_InitStruct);

	// 配置RCK引脚
	GPIO_InitStruct.Pin 			= HC_595_RCK_PIN;
	HAL_GPIO_Init(HC_595_RCK_PORT, &GPIO_InitStruct);		

	// 配置SCK引脚
	GPIO_InitStruct.Pin			= HC_595_SCK_PIN;
	HAL_GPIO_Init(HC_595_SCK_PORT, &GPIO_InitStruct);				

	// 配置SCLR引脚
	GPIO_InitStruct.Pin 			= HC_595_SCLR_PIN;
	GPIO_InitStruct.Pull 			= GPIO_PULLUP;			// 上拉
	HAL_GPIO_Init(HC_595_SCLR_PORT, &GPIO_InitStruct);

	// 初始化引脚状态
	HAL_GPIO_WritePin(HC_595_RCK_PORT, HC_595_RCK_PIN, GPIO_PIN_RESET);	// RCK输出低电平
	HAL_GPIO_WritePin(HC_595_SCK_PORT, HC_595_SCK_PIN, GPIO_PIN_RESET);	// SCK输出低电平
	HAL_GPIO_WritePin(HC_595_SCLR_PORT, HC_595_SCLR_PIN, GPIO_PIN_SET);	// SCLR输出高电平
}


/*****************************************************************************************
*	函数名: HC_595_Send_Byte
*	入口参数: Q15_Q0 - 要发送的16位数据
*	返回值: 无
*	函数功能: 向移位寄存器发送一个16位数据
*	说明: 首先设置移位寄存器的控制引脚为初始状态,然后逐位发送数据,最后将数据加载到移位寄存器中。
******************************************************************************************/
void HC_595_Send_Byte(unsigned short Q15_Q0)
{
	// 设置移位寄存器的控制引脚初始状态
	HC_595_DIN(0);
	HC_595_RCK(0);
	HC_595_SCK(0);

	HC595_Delay(10);	
	
	for( int i = 0 ; i < 16 ; i ++ )
	{
		// 逐位发送数据
		HC_595_SCK(0);
		if( Q15_Q0 & 0x8000 )
		{
			HC_595_DIN(1);
		}
		else
		{
			HC_595_DIN(0);
		}
		HC595_Delay(1);		
		HC_595_SCK(1);		// 移位寄存器输入一个字节数据
		HC595_Delay(1);
		Q15_Q0 <<= 1;
	}
	
	// 将数据加载到移位寄存器中
	HC_595_RCK(1);			// 存储寄存器输入,Q1-Q15输出
	HC595_Delay(1);
	
	HC_595_RCK(0);
	HC_595_SCK(0);
}

/* w_gpio_sem */
static unsigned char w_gpio_sem = 0;

/*****************************************************************************************
*	函数名: HC595_Write_QX
*	入口参数: index - 输出引脚的编号,sta - 输出状态,1为高电平,0为低电平
*	返回值: 无
*	函数功能: 控制移位寄存器的输出引脚状态
*	说明: 根据输入的输出引脚编号和状态,更新移位寄存器中对应引脚的状态,并发送更新后的状态到移位寄存器。
******************************************************************************************/
void HC595_Write_QX(unsigned short index,unsigned short sta)
{
	// 检查是否有其他操作在进行
	if( w_gpio_sem )
	{
		return;
	}
	
	// 锁定
	w_gpio_sem = 1;
	
	// 检查输出引脚编号是否合法
	if( index > 16 )
	{
		return;
	}
	
	// 根据状态设置输出引脚状态
	if( sta )
	{
		Q0_Q15_S |= ( 1 << index );
	}
	else
	{
		Q0_Q15_S &=~ ( 1 << index );
	}
	
	// 更新移位寄存器中的输出状态
	HC_595_Send_Byte(Q0_Q15_S);
	
	// 解锁
	w_gpio_sem = 0;	
}

  1. HC_595_GPIO_Config: 初始化HC595芯片的GPIO口,包括数据输入引脚(DIN)、存储寄存器时钟引脚(RCK)、移位寄存器时钟引脚(SCK)和清除引脚(SCLR)。配置这些引脚为推挽输出模式,并设置初始电平状态。

  2. HC_595_Send_Byte: 向HC595芯片发送一个16位数据,通过移位寄存器将数据加载到芯片中,控制输出引脚的状态。

  3. HC595_Write_QX: 根据输入的输出引脚编号和状态,更新移位寄存器中对应引脚的状态,并通过 HC_595_Send_Byte 函数发送更新后的状态到移位寄存器。

  4. HC595_Delay: 简单的延时函数,用于产生一定时间的延时,以时钟周期数为单位。

注意 

HC595的DIN输入端输出的数据会从Q0开始,继续输入,之前的Q0数据会移位至Q1,一直循环。

完整的输入一个字节数据,假设输入的是unsigned char Q_byte =(高)1011 1111(低) 。因为HC_595_Send_Byte程序中是从高位开始发送的,最高位的数据再经过完整的一个字节循环后就被push到了Q7(很像队列)

Q0 = 1;Q1=1;Q2=1;Q3=1;Q4=1;Q5=1;Q6=0;Q7=1;

我们要改变Q0-Q7中的某个位做法:

假设改变Q3位,则把 (高)1011 0111(低)重新写入HC595中。

Q_byte = Q_byte & ~ (1<<3)  = 1011 1111 & 1111 0111 = 1011 0111;

这是一个595的情况,级联情况下同理,代码,处理的就是级联情况。所以应用HC595_Write_QX函数就可以操作Q0-Q15任意一个输出位的电平了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1468882.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

H桥电流回路分析(单极性调制)

当Q7Q16导通时&#xff0c;是Q7高低电平切换&#xff0c;Q16一直导通 当Q7导通时&#xff0c;电感为左正右负&#xff08;电感起到阻碍电流变化的作用&#xff09;为红色线 当Q7关断的时候&#xff0c;电感&#xff08;作为源&#xff09;为左负右正&#xff0c;此时电流回路…

Stable Diffusion 3 发布及其重大改进

1. 引言 就在 OpenAI 发布可以生成令人瞠目的视频的 Sora 和谷歌披露支持多达 150 万个Token上下文的 Gemini 1.5 的几天后&#xff0c;Stability AI 最近展示了 Stable Diffusion 3 的预览版。 闲话少说&#xff0c;我们快来看看吧&#xff01; 2. 什么是Stable Diffusion…

RHEL9安装Python2.7

RHEL9作为2022年5月新推出的版本&#xff0c;较RHEL8有了很多地方的改进&#xff0c;而且自带很多包&#xff0c;功能非常强大&#xff0c;稳定性和流畅度也较先前版本有了很大的提升。RHEL9自带python3.9&#xff0c;但是过高版本的python不可避免地会导致一些旧版本包地不兼容…

《Docker 简易速速上手小册》第1章 Docker 基础入门(2024 最新版)

文章目录 1.1 Docker 简介与历史1.1.1 Docker 基础知识1.1.2 重点案例&#xff1a;Python Web 应用的 Docker 化1.1.3 拓展案例 1&#xff1a;使用 Docker 进行 Python 数据分析1.1.4 拓展案例 2&#xff1a;Docker 中的 Python 机器学习环境 1.2 安装与配置 Docker1.2.1 重点基…

主机开机正常但是显示器不亮怎么办 电脑故障问题解答

随着科技的不断发展&#xff0c;电脑或许已经是我们日常生活中最常接触的设备之一了。但是设备毕竟是设备&#xff0c;用久了自然会出毛病&#xff0c;开机的时候&#xff0c;主机开了&#xff0c;但是电脑显示屏不亮&#xff0c;这时候我们该怎么处理呢?下面我就来介绍几种解…

ES坑-创建索引使用_下划线-黑马旅游搜不到

学ES的时候&#xff0c;星级过滤无效 找不到数据。 需要 但是我们在创建的时候使用的是keyword 通过研究发现&#xff0c;我们导入数据的时候应该默认的为starName 我get库时候发现有2个字段 所以通过star_name搜索因为都是空数据搜不到&#xff0c;而starName类型为text所以…

MFC由初值终值步长生成数值序列

matlab的冒号运算符可以生成数值序列; 下面来生成自己的数值序列; vc6新建一个对话框工程; 放几个控件;添加成员变量如下; void CMycolonDlg::OnButton1() {// TODO: Add your control notification handler code hereUpdateData(TRUE);double d1, d2;CString str1, …

Qt MDI应用方法:QMdiArea和QMdiSubWindows类

重点&#xff1a; 1.使用MDI应用程序&#xff0c;需要在主窗口的工作区放置一个QMdiArea组件。 并将QMdiArea组件设置成中心窗口 2.MDI有两个显示模式&#xff1a;Tab多页显示模式和子窗口显示模式 子窗口显示模式有两种显示方法&#xff1a;窗口级联展开和平铺展开 窗口级联…

[electron]官方示例解析

官方例子 github链接 main.js const { app, BrowserWindow } require(electron)说句实话这里的语法是有部分看不懂的。导入模块虽然electron有很多模块。但是这里只是用到了app 和 BrowserWindow function createWindow () {// Create the browser window.const mainWindo…

零基础学编程,编程简单学,中文编程工具下载及工具箱进度条构件的用法

一、前言 今天给大家分享的中文编程开发语言工具 进度条构件的用法。 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载——常用工具下载——编程工具免费版下载及实例源码下载。 进度条 进度…

Javase补充-Arrays类的常用方法汇总

文章目录 一 . 排序方法二 . 查找方法三 . 判断是否相等的方法四 . 拷贝方法五 . 填充方法 一 . 排序方法 我们第一个要介绍的就是sort方法 这个排序实现的底层逻辑应该是十分复杂的,以我们目前的水平体系应该无法理解,我们今天尝试用我们可以理解的一种排序算法,插入排序来模…

Nodejs+vue图书阅读评分个性化推荐系统

此系统设计主要采用的是nodejs语言来进行开发&#xff0c;采用 vue框架技术&#xff0c;对于各个模块设计制作有一定的安全性&#xff1b;数据库方面主要采用的是MySQL来进行开发&#xff0c;其特点是稳定性好&#xff0c;数据库存储容量大&#xff0c;处理能力快等优势&#x…

C#,动态规划(DP)模拟退火(Simulated Annealing)算法与源代码

1 模拟退火 *问题:**给定一个成本函数f:r^n–>r*&#xff0c;找到一个 n 元组&#xff0c;该元组最小化 f 的值。请注意&#xff0c;最小化函数值在算法上等同于最大化(因为我们可以将成本函数重新定义为 1-f)。 很多有微积分/分析背景的人可能都熟悉单变量函数的简单优化。…

Linux---进程间通信(下)

1、System V 共享内存 原理如下图 系统调用接口介绍 int shmget(key_t key, size_t size, int shmflg) 功能&#xff1a;用来创建共享内存 参数 key&#xff1a;这个共享内存段名字&#xff0c;内核用key来标识共享内存size&#xff1a;共享内存大小shmflg&#xff1a;由九个权…

留子厨房开发日志

以下记录了使用go语言框架Beego&#xff0c;Mysql数据库&#xff0c;Redis数据库实现一个点菜/菜谱应用API的全过程。 技术方案 github地址 数据库设计 新建数据库&#xff1a; CREATE DATABASE menu;新建数据表&#xff1a; CREATE TABLE menu ( id int(10) unsigned NOT …

Docker 第十九章 : 阿里云个人镜像仓使用

Docker 第十九章 : 阿里云个人镜像仓使用 本章知识点: 如何创建镜像库,如何设置密码,如何登录与退出个人镜像仓,如何本地打镜像,如何将本地镜像推送到个人镜像库。 背景 在项目YapiDocker部署中,因读取mongo:latest 版本不一致,导致后续执行步骤的异常。遇到此场景…

OpenCV Mat实例详解 六

本文将接着OpenCV Mat实例详解继续介绍OpenCV Mat类的操作符及公有成员函数。 Mat & operator Mat & operator (const Mat &m) 将一个Mat对象赋值个另一个Mat对象。 Mat & operator (const MatExpr &expr) 将一个Mat表达式值赋值给Mat对象 Mat & op…

【高德地图】Android高德地图绘制标记点Marker

&#x1f4d6;第4章 Android高德地图绘制标记点Marker ✅绘制默认 Marker✅绘制多个Marker✅绘制自定义 Marker✅Marker点击事件✅Marker动画效果✅Marker拖拽事件✅绘制默认 Infowindow&#x1f6a9;隐藏InfoWindow 弹框 ✅绘制自定义 InfoWindow&#x1f6a9;实现 InfoWindow…

Covalent Network(CQT)与 Movement Labs 达成合作,重新定义 M2 系统区块链数据可用性与性能

Covalent Network&#xff08;CQT&#xff09;是行业领先的多链索引器&#xff0c;正在与 Movement Labs 的 M2 展开具有突破性意义的合作。M2 是以太坊上的首个 Move-EVM&#xff08;MEVM&#xff09;ZK rollup 。这一战略合作标志着先进的实时数据索引和部署工具&#xff0c;…

Sora - 探索AI视频模型的无限可能

Sora - 探索AI视频模型的无限可能 随着人工智能技术的飞速发展,AI视频模型已成为科技领域的新热点。而在这个浪潮中,OpenAI推出的首个AI视频模型Sora,以其卓越的性能和前瞻性的技术,引领着AI视频领域的创新发展。让我们将一起探讨Sora的技术特点、应用场景以及对未来创作方…