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单片机的应用有更深刻的认识。