74HC595
- 1、74HC595簡介
- 2、代碼演示
- 2.1、驅動8位流水燈
- 3、74HC595級聯
- 3.1、驅動16位流水燈
- 3.2、驅動8位數碼管
- 3.3、驅動8x8點陣屏幕
- 3.4、8x8點陣屏幕滾動顯示
1、74HC595簡介
在51單片機中IO引腳資源十分的緊缺,所以常常需要使用75HC595芯片進行驅動那些需要占用多個IO引腳的芯片。那么75HC595是是什么喃?
74H595是一款串轉并移位控制的芯片,通過移位的方式將串行輸入的數據變為并行輸出的數據。
引腳 | 功能 |
---|---|
VCC | 供電正極(2v~6v) |
GND | 供電負極 |
DS | 串行數據輸入引腳(8位) |
Q7~Q0 | 并行數據輸出引腳(Q7對應數據高位) |
SHCP | 移位寄存器時鐘輸入 |
STCP | 輸出寄存器時鐘輸入 |
Q7S | 8位數據串行輸出引腳(常用于級聯) |
OE | 輸出使能引腳 |
2、代碼演示
2.1、驅動8位流水燈
①H595.c文件的代碼如下:
#include "H595.h"/*** 使用74HC595串行數據轉換位并行數據* Byte:輸入的串行數據*/
void HC595_Driver(unsigned char Byte)
{unsigned char i = 0;HC595_ST = 0;for(i = 0; i < 8; i++){HC595_SH = 0; //SH低電平,將數據寫入到輸入數據引腳上HC595_DS = (Byte & (0x80 >> i));//高位先行HC595_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} HC595_ST = 1; //595的ST引腳來一個上升沿將移位寄存器的數據移到存儲寄存器HC595_OE = 0; //輸出使能
}
②H595.h文件的代碼如下:
#ifndef __H595_H
#define __H595_H
#include <REGX52.H> //包含51頭文件,里面全是寄存器地址sbit HC595_SH = P1^2; //移位時鐘引腳
sbit HC595_DS = P1^3; //HC595輸入數據口
sbit HC595_ST = P1^4; //存儲時鐘引腳
sbit HC595_OE = P1^5; //輸出使能引腳void HC595_Driver(unsigned char Byte);#endif
③main.c文件的代碼如下:
#include "H595.h"
#include "Delay.h"
#include "Timer.h"void main(void)
{Time0_Intrrupt_Init();while(1){unsigned char temp = 0x01;unsigned char i;for(i = 1; i < 8; i++) //循環7次{HC595_Driver(temp);temp <<= 1; //循環結束num = 1000 0000Delay_ms(500); //延時500ms}for(i = 1; i < 8; i++) //循環7次{HC595_Driver(temp);temp >>= 1; //循環結束num = 0000 0001Delay_ms(500); //延時500ms}}
}
3、74HC595級聯
綜上:74HC595的Q7S引腳是串行輸出引腳,常常用于多片的75HC595芯片的級聯。2片級聯,則可看成一個2字節數據串轉并移位寄存器,4片級聯,則可看成4字節數據串轉并移位寄存器。
如圖:2片74HC595進行級聯,他們的SH引腳,ST引腳,OE引腳都連接在一起,第一片H595芯片的Q7S連接著第二片芯片的數據輸入引腳。
3.1、驅動16位流水燈
①H595.c文件的代碼如下:
/*** 2片74HC595的級聯* HByte:高位字節的數據* LByte:低位字節的數據*/
void HC595_Cascade(unsigned char HByte, unsigned char LByte)
{ unsigned char i = 0;HC595_ST = 0;/* 將高位字節的數據移位到第一個595里面 */for(i = 0; i < 8; i++){HC595_SH = 0;HC595_DS = (HByte & (0x80 >> i));//高位先行HC595_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} /* 將高位字節的數據移位到第二個595里面,低位字節的數據移到第一個595里面 */for(i = 0; i < 8; i++){HC595_SH = 0;HC595_DS = (LByte & (0x80 >> i));//高位先行HC595_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} HC595_ST = 1; //595的ST引腳來一個上升沿將移位寄存器的數據移到存儲寄存器HC595_OE = 0; //輸出使能
}
②H595.h文件的代碼如下:
#ifndef __H595_H
#define __H595_H
#include <REGX52.H> //包含51頭文件,里面全是寄存器地址sbit HC595_SH = P1^2; //移位時鐘引腳
sbit HC595_DS = P1^3; //HC595輸入數據口
sbit HC595_ST = P1^4; //存儲時鐘引腳
sbit HC595_OE = P1^5; //輸出使能引腳void HC595_Cascade(unsigned char HByte, unsigned char LByte);;#endif
③main.c文件的代碼如下:
#include "H595.h"
#include "Delay.h"
#include "Timer.h"void main(void)
{Time0_Intrrupt_Init();while(1){unsigned char Htemp = 0x01;unsigned char Ltemp = 0x01;unsigned char i;for(i = 1; i < 8; i++) //循環7次{HC595_Cascade(0x00, Ltemp);Ltemp <<= 1; //S循環結束num = 1000 0000Delay_ms(500); //延時500ms}HC595_Cascade(0x00, Ltemp);Delay_ms(500); //延時500msfor(i = 1; i < 8; i++) //循環7次{HC595_Cascade(Htemp, 0x00);Htemp <<= 1; //S循環結束num = 1000 0000Delay_ms(500); //延時500ms} for(i = 1; i < 8; i++) //循環7次{HC595_Cascade(Htemp, 0x00);Htemp >>= 1; //循環結束num = 0000 0001Delay_ms(500); //延時500ms}HC595_Cascade(Htemp, 0x00);Delay_ms(500); //延時500msfor(i = 1; i < 8; i++) //循環7次{HC595_Cascade(0x00, Ltemp);Ltemp >>= 1; //循環結束num = 0000 0001Delay_ms(500); //延時500ms}}
}
3.2、驅動8位數碼管
①H595_SEG8.c文件的代碼如下:
/***********************************/
/* 8位數碼管的底層驅動文件 */
/***********************************/#include "H595_Seg8.h"/*** 2片74HC595的級聯* PossData:位選數據* SegData:段碼數字據*/
void HC595_Cascade_Seg8(unsigned char PossData, unsigned char SegData)
{ unsigned char i = 0;SEG_ST = 0;/* 將高位字節的數據移位到第一個595里面 */for(i = 0; i < 8; i++){SEG_SH = 0;SEG_DS = (PossData & (0x80 >> i));//高位先行SEG_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} /* 將高位字節的數據移位到第二個595里面,低位字節的數據移到第一個595里面 */for(i = 0; i < 8; i++){SEG_SH = 0;SEG_DS = (SegData & (0x80 >> i));//高位先行SEG_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} SEG_ST = 1; //595的ST引腳來一個上升沿將移位寄存器的數據移到存儲寄存器SEG_OE = 0; //輸出使能
}/* 字符數據 */
static unsigned char code Data8[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, //共陽極顯示的數值0 ~ 90xBF,0x7F,0x8C //-,.P
};/* 顯示的數值緩存區 */
unsigned char SegNum8[] = {0,0,0,0,0,0,0,0};/*** 選擇哪個數碼管顯示數據的函數* Position:哪一個數碼管* Data:需要顯示的數據*/
void Seg8_Choice(unsigned char Position, unsigned char DisplayData)
{HC595_Cascade_Seg8(0x00,0x00); //讓8個數碼管先熄滅HC595_Cascade_Seg8((0x01 << (Position - 1)), Data8[SegNum8[DisplayData]]); //傳入段碼數據進行顯示
}
②H595_SEG8.h文件的代碼如下:
#ifndef __H595_Seg8_H
#define __H595_Seg8_H
#include <REGX52.H> //包含51頭文件,里面全是寄存器地址sbit SEG_SH = P0^0; //移位時鐘引腳
sbit SEG_DS = P0^1; //HC595輸入數據口
sbit SEG_ST = P0^2; //存儲時鐘引腳
sbit SEG_OE = P0^3; //輸出使能引腳extern unsigned char SegNum8[];void HC595_Cascade_Seg8(unsigned char PossData, unsigned char SegData);
void Seg8_Choice(unsigned char Position, unsigned char DisplayData);#endif
③User_SEG8.c文件的代碼如下:
/********************************************/
/* 使用74HC595驅動8位數碼管的應用層 */
/********************************************/
#include "User_Seg8.h"void Delay1ms() //@11.0592MHz
{unsigned char i, j;i = 2;j = 199;do{while (--j);} while (--i);
}/*** X的Y次方函數*/
unsigned int SEG8_Pow(unsigned char X,unsigned char Y)
{unsigned int Result = 1;while(Y--){Result *= X;}return Result;
}/*** 數碼管顯示正整數* Number:0~65535* Length:有效數值長度* Lie: 顯示的位置1~8*/
void SEG8_Show_Num(unsigned char Lie,unsigned short Number,unsigned char Length)
{/* 將整數進行拆分在通過數碼管顯示 */unsigned char i,Data;for(i = 0; i < Length; i++){Data = (Number / SEG8_Pow(10,Length - i -1)) % 10;//將整數進行拆分SegNum8[0] = Data;Seg8_Choice(i+Lie,0);//顯示Delay1ms();}
}/*** 數碼管顯示有符號整數* Number:-32768~32767* Length:有效數值長度* Lie: 顯示的位置1~8*/
void SEG8_Show_SignedNum(unsigned char Lie, short Number,unsigned char Length)
{/* 若為負數,先顯示負號 */if(Number < 0){Number = -Number;SegNum8[0] = 10;Seg8_Choice(Lie,0); //顯示"-"Lie++;}SEG8_Show_Num(Lie, Number, Length);
}/*** 數碼管顯示有符號小數* Number:小數數值* Floatcount:顯示幾位小數* Lie: 顯示的位置1~8* IntCount: 整數的個數* Floatcount:小數的個數*/
void SEG8_Show_FloatNum(unsigned char Lie, float Number, unsigned char IntCount, unsigned char Floatcount)
{short Num = 0; if(Number < 0){Number = -Number; //將負數轉換為正數,例如:3.14 = -(-3.14)SegNum8[0] = 10;Seg8_Choice(Lie,0); //顯示"-"Lie++;}/* 先提取整數部分 */Num = Number; //此時Num保存的是小數的整數部分,例如:Number = 3.14,Num = 3SEG8_Show_Num(Lie,Num,IntCount);/* 將小數換算為整數 */Number -= Num; //Number = Number - Num,Number = 3.14 - 3 = 0.14Num = (short)(Number * SEG8_Pow(10,Floatcount));//將小數將小數換算為整數,0.14 * 100 = 14SegNum8[0] = 11; //先添加數據的索引Seg8_Choice(Lie+IntCount-1,0); //顯示小數點/* 顯示小數部分 */SEG8_Show_Num(Lie+IntCount, Num, Floatcount);
}
④User_SEG8.h文件的代碼如下:
#ifndef __User_Seg8_H
#define __User_Seg8_H
#include "H595_Seg8.h"unsigned int SEG8_Pow(unsigned char X,unsigned char Y);
void SEG8_Show_Num(unsigned char Lie,unsigned short Number,unsigned char Length);
void SEG8_Show_SignedNum(unsigned char Lie, short Number,unsigned char Length);
void SEG8_Show_FloatNum(unsigned char Lie, float Number, unsigned char IntCount, unsigned char Floatcount);#endif
⑤main.c文件的代碼如下:
#include "User_Seg8.h"void main(void)
{ while(1){SEG8_Show_FloatNum(1,-200.123,3,3);}
}
3.3、驅動8x8點陣屏幕
如圖:點亮圖上的小亮點,則陰極引腳輸出的數據為:1011 1111(0xBF)選中第2列;陽引腳輸出的數據為:1000 0000(0x80)表示點亮選中的列的最上的LED
LED顯示字符的方法:
例如想要顯示如下圖是字符:
列掃描:從左到右依次從第一列進行掃描,即(共陰極的引腳數據依次為:0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE)。而共陽極字模數據Data[8] = {0x00,0x00,0xFF,0x08,0x08,0xFF,0x00,0x00};當進行第一列掃描時,共陽極引腳輸出Data[0]
①Dot_LED.c文件的代碼如下:
#include "Dot_LED.h"/*** 2片74HC595的級聯* LEDNode: 陽極數據,選擇選定的列中哪幾個LED點亮* LEDCathode: 陰極數據,選擇哪一列點亮*/
void HC595_Cascade_8x8LED(unsigned char LEDNode, unsigned char LEDCathode)
{ unsigned char i = 0;LED_ST = 0;/* 將高位字節的數據移位到第一個595里面 */for(i = 0; i < 8; i++){LED_SH = 0;LED_DS = (LEDNode & (0x80 >> i));//高位先行LED_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} /* 將高位字節的數據移位到第二個595里面,低位字節的數據移到第一個595里面 */for(i = 0; i < 8; i++){LED_SH = 0;LED_DS = (LEDCathode & (0x80 >> i));//高位先行LED_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} LED_ST = 1; //595的ST引腳來一個上升沿將移位寄存器的數據移到存儲寄存器LED_OE = 0; //輸出使能
}/*** 8x8點陣顯示函數(列掃描顯示)*/
void Show_8X8Dot_ColumnScan(unsigned char *Data)
{unsigned char i = 0;for(i = 0; i < 8; i++){HC595_Cascade_8x8LED(Data[i],~(0x80 >> i)); //依次選擇從左到右第1列行開始(行掃描顯示)}
}
②Dot_LED.h文件的代碼如下:
#ifndef __Dot_LED_H
#define __Dot_LED_H
#include <REGX52.H> //包含51頭文件,里面全是寄存器地址sbit LED_SH = P2^0;
sbit LED_DS = P2^1;
sbit LED_ST = P2^2;
sbit LED_OE = P2^3;void HC595_Cascade_8x8LED(unsigned char LEDNode, unsigned char LEDCathode);
void Show_8X8Dot_ColumnScan(unsigned char *Data);#endif
③main.c文件的代碼如下:
#include "Dot_LED.h"/* 顯示H */
static unsigned char H_Data[] = {0x00,0x00,0xFF,0x08,0x08,0xFF,0x00,0x00};//縱向,上為最高位(縱向取模)
void main(void)
{ while(1){Show_8X8Dot_ColumnScan(H_Data); //列掃描顯示}
}
3.4、8x8點陣屏幕滾動顯示
從左向右滾動顯示“HELLO”
滾動顯示的原理: 點陣屏幕一直顯示8個字節Buffer中的數據,我們只需要將HELLO的字模數據依次放入到Buffer中。如下圖所示:
取模軟件的使用:
①Dot_LED.c文件的代碼如下:
#include "Dot_LED.h"
#include "Timer.h"/*** 2片74HC595的級聯* LEDNode: 陽極數據,選擇選定的列中哪幾個LED點亮* LEDCathode: 陰極數據,選擇哪一列點亮*/
void HC595_Cascade_8x8LED(unsigned char LEDNode, unsigned char LEDCathode)
{ unsigned char i = 0;LED_ST = 0;/* 將高位字節的數據移位到第一個595里面 */for(i = 0; i < 8; i++){LED_SH = 0;LED_DS = (LEDNode & (0x80 >> i));//高位先行LED_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} /* 將高位字節的數據移位到第二個595里面,低位字節的數據移到第一個595里面 */for(i = 0; i < 8; i++){LED_SH = 0;LED_DS = (LEDCathode & (0x80 >> i));//高位先行LED_SH = 1; //595的SH引腳來一個上升沿將數據進行移位} LED_ST = 1; //595的ST引腳來一個上升沿將移位寄存器的數據移到存儲寄存器LED_OE = 0; //輸出使能
}/*** 8x8點陣顯示函數(列掃描顯示)*/
void Show_8X8Dot_ColumnScan(unsigned char *Data)
{unsigned char i = 0;for(i = 0; i < 8; i++){HC595_Cascade_8x8LED(0x00,~(0x80 >> i)); //向將掃描的一列的燈全部熄滅HC595_Cascade_8x8LED(Data[i],~(0x80 >> i)); //依次選擇從左到右第1列行開始(行掃描顯示)}
}/*** 8x8點陣數據滾動函數*/
unsigned char LEDBuffer[8] = {0x00,0x00,0xFF,0x08,0x08,0xFF,0x00,0x00};
void LEDData_Move(unsigned char *Data,unsigned char Len)
{static unsigned char j = 0;static unsigned char i = 0;static unsigned char Status = 1;static unsigned char TimeStatus = 1;static unsigned long GET_Time = 0;switch(TimeStatus){case 1:GET_Time = Get_TimeCount(); //獲取TimeCount的值TimeStatus = 2;case 2:if(Get_TimeCount() - GET_Time > 500) //每隔500ms進行向Buff里面放入數據{GET_Time = Get_TimeCount();for (j = 0; j < 7; j++) //先移動{LEDBuffer[j] = LEDBuffer[j+1];}switch(Status){case 1:LEDBuffer[7] = Data[i+8]; //第一輪放入從Data[8]開始取出放入if(i == Len - 8) {i = Len - 1;Status = 2;}break;case 2: //第二輪放入從Data[0]開始取出放入LEDBuffer[7] = Data[i]; break;}i = (i + 1) % Len; //循環遍歷 i:0~31}break;}
}
②Dot_LED.h文件的代碼如下:
#ifndef __Dot_LED_H
#define __Dot_LED_H
#include <REGX52.H> //包含51頭文件,里面全是寄存器地址sbit LED_SH = P2^0;
sbit LED_DS = P2^1;
sbit LED_ST = P2^2;
sbit LED_OE = P2^3;extern unsigned char LEDBuffer[8];void HC595_Cascade_8x8LED(unsigned char LEDNode, unsigned char LEDCathode);
void Show_8X8Dot_ColumnScan(unsigned char *Data);
void LEDData_Move(unsigned char *Data,unsigned char Len);#endif
③main.c文件的代碼如下:
#include "Dot_LED.h"
#include "Timer.h"/* 顯示HELLO */
static unsigned char HELLO_Data[] = {0x00,0x00,0xFF,0x08,0x08,0xFF,0x00,0x00,0xFF,0x89,0x89,0x89,0x00,0x00,0xFF,0x01,0x01,0x01,0x00,0x00,0xFF,0x01,0x01,0x01,0x00,0x00,0x7E,0x81,0x81,0x7E,0x00,0x00
};//縱向,上為最高位(縱向取模)void main(void)
{ Time0_Intrrupt_Init(); //啟動定時器中斷while(1){LEDData_Move(HELLO_Data,32);Show_8X8Dot_ColumnScan(LEDBuffer); //列掃描顯示}
}
QQ2025427-13511