|
我想,74HC595的驱动网上有大把的例子,我也曾经参考过别人的。
但是,有时候控制起来确实不太方便。
能不能像IO口一样的来控制74HC595的输出了?
驱动LED,驱动数码管,驱动继电器。。。。
答案是有的。
这也是我在项目中总结出来的,不敢独享,
赠人玫瑰,手有余香。
先来看看原理图。
2组2片74HC595级联,可以扩展32个输出口,当然还可以一直级联下去。1组74HC595级联具体可以扩多少个输出口,
没有试过。
为了驱动和控制方便,2片一组足够了。
下面来看看软件部分。
#define ON 1
#define OFF 0
/*
* 定义引脚
*/
/* 时钟信号线引脚定义 */
sbit HC595CLK1 = P0^3;
/* 片选信号线引脚定义 */
sbit HC595RCK1 = P4^3;
/* 数据输入引脚定义 */
sbit HC595DATA1 = P7^7;
/* 时钟信号线引脚定义 */
sbit HC595CLK2 = P7^6;
/* 片选信号线引脚定义 */
sbit HC595RCK2 = P7^5;
/* 数据输入引脚定义 */
sbit HC595DATA2 = P7^4;
/******************************************************
* 函数名称:SendData
* 函数功能:74HC595数据的发送
* 入口参数:unsigned int uiDataOne, unsigned int uiDataTwo
* 出口参数:void
*******************************************************/
void SendData_0_15(unsigned int uiDataOne, unsigned int uiDataTwo)
{
unsigned int i = 0;
/* 将片选信号置为低电平 */
HC595RCK1 = 0;
/* 输入第一个数据:uiDataOne */
for (i = 0; i < 8; i++)
{
/* 给出脉冲信号,首先将CLK置为0 */
HC595CLK1 = 0;
if (0 != (uiDataOne & 0x80))
{
HC595DATA1 = 1;
}
else
{
HC595DATA1 = 0;
}
/* 给出脉冲信号,首先将CLK置为1 */
HC595CLK1 = 1;
/* 准备第二个数据 */
uiDataOne = uiDataOne << 1;
}
/* 输入第二个数据:uiDataTwo */
for (i = 0; i < 8; i++)
{
/* 给出脉冲信号,首先将CLK置为0 */
HC595CLK1 = 0;
if (0 != (uiDataTwo & 0x80))
{
HC595DATA1 = 1;
}
else
{
HC595DATA1 = 0;
}
/* 给出脉冲信号,首先将CLK置为1 */
HC595CLK1 = 1;
/* 准备第二个数据 */
uiDataTwo = uiDataTwo << 1;
}
/* 将片选信号置为高电平 */
HC595RCK1 = 1;
}
/******************************************************
* 函数名称:SendData
* 函数功能:74HC595数据的发送
* 入口参数:unsigned int uiDataOne, unsigned int uiDataTwo
* 出口参数:void
*******************************************************/
void SendData_16_31(unsigned int uiDataOne, unsigned int uiDataTwo)
{
unsigned int i = 0;
/* 将片选信号置为低电平 */
HC595RCK2 = 0;
/* 输入第一个数据:uiDataOne */
for (i = 0; i < 8; i++)
{
/* 给出脉冲信号,首先将CLK置为0 */
HC595CLK2 = 0;
if (0 != (uiDataOne & 0x80))
{
HC595DATA2 = 1;
}
else
{
HC595DATA2 = 0;
}
/* 给出脉冲信号,首先将CLK置为1 */
HC595CLK2 = 1;
/* 准备第二个数据 */
uiDataOne = uiDataOne << 1;
}
/* 输入第二个数据:uiDataTwo */
for (i = 0; i < 8; i++)
{
/* 给出脉冲信号,首先将CLK置为0 */
HC595CLK2 = 0;
if (0 != (uiDataTwo & 0x80))
{
HC595DATA2 = 1;
}
else
{
HC595DATA2 = 0;
}
/* 给出脉冲信号,首先将CLK置为1 */
HC595CLK2 = 1;
/* 准备第二个数据 */
uiDataTwo = uiDataTwo << 1;
}
/* 将片选信号置为高电平 */
HC595RCK2 = 1;
}
普通IO口模拟SPI,中规中矩。和大多数驱动一样。
重点部分是控制部分。
.h文件中有4个对外函数,如下。
extern void hc595_init( void );
extern void SendData_0_15(unsigned int uiDataOne, unsigned int uiDataTwo);
extern void SendData_16_31(unsigned int uiDataOne, unsigned int uiDataTwo);
extern void HC595_0_31_OutCtr(unsigned char ucNumber,unsigned char ucState);
重点是
void HC595_0_31_OutCtr(unsigned char ucNumber,unsigned char ucState)
因为,我这是扩展32个输出口,所以是单个输出。想控制数码管的可以按照此方法修改。
void HC595_0_31_OutCtr(unsigned char ucNumber,unsigned char ucState)
{
// datas.u16_Data = uiDat;
if((ucNumber>=0) && (ucNumber<=15))
{
switch(ucNumber)
{
case 0:
datas1.bits.u8_D0 = ucState;
break;
case 1:
datas1.bits.u8_D1 = ucState;
break;
case 2:
datas1.bits.u8_D2 = ucState;
break;
case 3:
datas1.bits.u8_D3 = ucState;
break;
case 4:
datas1.bits.u8_D4 = ucState;
break;
case 5:
datas1.bits.u8_D5 = ucState;
break;
case 6:
datas1.bits.u8_D6 = ucState;
break;
case 7:
datas1.bits.u8_D7 = ucState;
break;
case 8:
datas1.bits.u8_D8 = ucState;
break;
case 9:
datas1.bits.u8_D9 = ucState;
break;
case 10:
datas1.bits.u8_D10 = ucState;
break;
case 11:
datas1.bits.u8_D11 = ucState;
break;
case 12:
datas1.bits.u8_D12 = ucState;
break;
case 13:
datas1.bits.u8_D13 = ucState;
break;
case 14:
datas1.bits.u8_D14 = ucState;
break;
case 15:
datas1.bits.u8_D15 = ucState;
break;
default:
break;
}
SendData_0_15(datas1.Bytes.u8_data_L,datas1.Bytes.u8_data_H);
}
else if((ucNumber>=16) && (ucNumber <= 31))
{
switch(ucNumber)
{
case 16:
datas2.bits.u8_D0 = ucState;
break;
case 17:
datas2.bits.u8_D1 = ucState;
break;
case 18:
datas2.bits.u8_D2 = ucState;
break;
case 19:
datas2.bits.u8_D3 = ucState;
break;
case 20:
datas2.bits.u8_D4 = ucState;
break;
case 21:
datas2.bits.u8_D5 = ucState;
break;
case 22:
datas2.bits.u8_D6 = ucState;
break;
case 23:
datas2.bits.u8_D7 = ucState;
break;
case 24:
datas2.bits.u8_D8 = ucState;
break;
case 25:
datas2.bits.u8_D9 = ucState;
break;
case 26:
datas2.bits.u8_D10 = ucState;
break;
case 27:
datas2.bits.u8_D11 = ucState;
break;
case 28:
datas2.bits.u8_D12 = ucState;
break;
case 29:
datas2.bits.u8_D13 = ucState;
break;
case 30:
datas2.bits.u8_D14 = ucState;
break;
case 31:
datas2.bits.u8_D15 = ucState;
break;
default:
break;
}
SendData_16_31(datas2.Bytes.u8_data_L,datas2.Bytes.u8_data_H);
}
}
32个输出口,像IO口一样,想那个高电平,那个就输出高电平,想那个输出低电平,就低电平。
不会影响其他31个输出口的状态。这才是关键。代码量少,简单易懂,明明白白。
这里还对输出口做了翻转,像IO口一样。
没有用高深的写法,就是想看着简单易懂。
所有文件截图:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
打赏
-
查看全部打赏
|