C51单片机控制74HC595模块,驱动LED实现流水灯效果

C51单片机控制74HC595模块,驱动LED实现流水灯效果

引言

我们知道单片机的IO资源十分有限,那么在有限的资源下需要实现更多功能,就需要借助外接扩展的形式实现了。我们需要控制若干个LED,来实现流水灯效果。显然单片机自身的资源是不够的。这个时候我们可以使用IO扩展来实现。本文使用的是74HC595 io扩展模块,实现一个简单的流水灯效果。有兴趣的同学,可以通过级联更多的模块,和改变数据内容,设计更多好玩的效果。

74HC595 介绍

74HC595是一款由TI公司制造的集成电路,通常用于扩展单片机的I/O口。它能够通过单个串行接口接收数据,并将其转换为并行输出,从而允许单片机通过几个端口控制多个输出设备。
具体来说,74HC595包含一个8位移位寄存器、一个存储器和一个三态输出缓冲器。当数据被写入移位寄存器时,它会被存储在存储器中,并通过输出缓冲器传递出去。由于74HC595使用串行接口接收数据,因此它只需要三个输入引脚(数据输入、时钟和锁存器启用引脚),就可以控制8个独立的输出引脚。
74HC595的一个常见用途是用于控制一组LED灯或其他输出设备。例如,如果您有一个单片机只有几个可用的I/O口,但需要控制大量的LED,则可以使用74HC595扩展I/O口的数量。只需将数据写入74HC595,并使用其提供的8个输出引脚来控制LED即可。这样,您就不再需要额外的I/O口来控制每个LED,而只需要使用单个串行接口即可。
74HC595还支持级联,这意味着您可以将多个74HC595连接在一起,以获得更高的输出端口数量。这种特性使得74HC595成为扩展I/O口的理想选择,特别是在需要控制大量设备的情况下。

开发环境与硬件平台

  • C51单片机型号:STC12LE5A60S2
  • 集成开发环境:STC-ISP
  • 开发板:STC12LE5A60S2 开发板
  • 接线方式SI:P3.5; STR:P3.7; SCK_R:P4.0; VCC; GND

在这里插入图片描述

代码解析

引用与定义

#include "STC12C5A60S2.H"

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;

// IO引脚定义
sbit SI     =    P3^5;	  //LDSI,串行数据输入口
sbit STR    =    P3^7;	  //LDSTR,并行数据输出控制端口
sbit SCK_R  =    P4^0;	  //LDSCK, 串行时钟信号端口

上述代码段引入了单片机相关的头文件,并定义了一些基本的数据类型。IO引脚的定义通过sbit进行,分别表示串行数据输入口、并行数据输出控制端口和串行时钟信号端口。

延时函数

void sendDelay_ms(uint32_t t)
{
    t <<= 6;
    while (t)
    {
        t--;
    }
}

sendDelay_ms 函数实现了一个微秒级别的延时函数,用于在数据发送时进行时间控制。

发送字节和多字节函数

void sentbyte(uint8_t byte)
{
    // 发送一个字节的数据
    // ...
}

void sendBytes(uint8_t *p, uint8_t len)
{
    // 发送多个字节的数据
    // ...
}

这两个函数用于通过串行通信向级联LED模块发送字节和多字节的数据。通过控制串行时钟和数据输入引脚,将数据发送给级联的LED模块。

流水灯效果

main()
{
    // 初始设置,发送一个特定的字节数据
    sentbyte(0x0F);
    // 初始延时
    delay(15000);

    while(1)
    {
        // 清空value数组
        for (i = 0; i < pMI01ADeviceCnt; i++)
        {
            value[i] = 0xFF;
        }

        // 计算要点亮的LED的位置
        byteNum = mi01aStep / 8;
        bitNum = mi01aStep % 8;
        temp = 0x80 >> bitNum;
        temp = ~temp;
        value[byteNum] = temp;

        // 更新计数,循环播放流水灯效果
        if (++mi01aStep >= (pMI01ADeviceCnt << 3))
        {
            mi01aStep = 0;
        }
        
        // 发送字节数据,控制LED点亮
        sendBytes(value, pMI01ADeviceCnt);
        // 延时,控制流水灯速度
        delay(200);
    }
}

main 函数中,通过调用 sentbyte 函数发送一个特定的字节数据(0x0F)进行初始化设置,并进行了延时。之后,通过一个主循环,不断地更新 value 数组的值,使得特定LED点亮,然后通过 sendBytes 函数将数据发送给级联LED模块,实现流水灯效果。整体的速度由 delay(200) 控制。

完整代码如下

#include	"STC12C5A60S2.H"


typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;

//需配置所有输出IO为输出
sbit SI     =    P3^5;	  //LDSI,串行数据输入口
sbit STR    =    P3^7;	  //LDSTR,并行数据输出控制端口
sbit SCK_R  =    P4^0;	  //LDSCK, 串行时钟信号端口
//#define LDEN            //LDEN, 芯片使能管脚,为高时:所有并行输出口为高阻态。
						  //为低时:芯片使能。也可以把该管脚直接接地或者焊接电阻R1。

//以下是操作IO的示例
#define SET_SI_H            (SI = 1);
#define SET_SI_L            (SI = 0);
#define SET_STR_H           (STR = 1);
#define SET_STR_L           (STR = 0);
#define SET_SCK_R_H         (SCK_R = 1);
#define SET_SCK_R_L         (SCK_R = 0);

void sendDelay_ms(uint32_t t)
{
    t <<= 6;
    while (t)
    {
        t--;
    }
}

/**
 * @brief 发送一个字节,即控制一个扩展芯片
 * 
 * @param byte 
 */
void sentbyte(uint8_t byte)
{
    uint8_t i;
    for(i=0;i<8;i++)
    {
        SET_SCK_R_L;
        if(byte&0x80)
        {
        SET_SI_H;
        }
        else
        {
        SET_SI_L;
        }
        
        byte = byte<<1;
        SET_SCK_R_H;
    }  
    SET_STR_L;
    sendDelay_ms(3);
    SET_STR_H; 						  
}

/**
 * @brief 发送多个字节,即控制多个级联控制板
 * 
 * @param p 数据首地址
 * @param len 数据长度
 */
void sendBytes(uint8_t *p, uint8_t len)
{
    uint8_t i, byte;

    if (!len)
    {
        return;
    }
    

    while (len)
    {
        len--;

        byte = *p++;
        for(i=0;i<8;i++)
        {
            SET_SCK_R_L;
            if(byte&0x80)
            {
                SET_SI_H;
            }
            else
            {
                SET_SI_L;
            }
            
            byte = byte<<1;
            SET_SCK_R_H;
        }
    }
    
    SET_STR_L;
    sendDelay_ms(3);
    SET_STR_H;
}




void delay(time)
{
	unsigned i,j;
	for(i=time;i>0;i--)
		for(j= 110;j>0;j--);
}


/*********************************************************
主函数													 *
**********************************************************/
/**
 * 简单的流水灯效果,对级联模块进行点亮测试
 * 示例中的led为低电平驱动点亮
*/
main()
{
  //测试数据,长度3,代表3个模块级联,可自行设置数据
  uint8_t value[3] = {0x01, 0x02, 0x04};
  uint8_t mi01aStep = 0;
  uint8_t pMI01ADeviceCnt = 3; //级联的设备数量
  uint8_t byteNum, bitNum;
  uint8_t temp;
  uint8_t i;
  sentbyte(0x0F);
  delay(15000);
	while(1)
	{
    for ( i = 0; i < pMI01ADeviceCnt; i++)
    {
        value[i] = 0xFF;
    }
    byteNum = mi01aStep / 8;
    bitNum = mi01aStep % 8;
    temp = 0x80 >> bitNum;
    temp = ~temp;
    value[byteNum] = temp;

    if (++mi01aStep >= (pMI01ADeviceCnt << 3))
    {
        mi01aStep = 0;
    }
    
    sendBytes(value, pMI01ADeviceCnt);
		delay(200);
	}


}

结语

通过以上代码解析,我们深入理解了基于C51单片机的流水灯控制程序。从初始化设置到流水灯效果的实现,了解了C51单片机的基本编程思想和IO控制方法。这是一个经典的嵌入式系统开发案例,希望通过本文的介绍,读者对C51单片机的应用有更深刻的认识。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值