使用SPI接口控制74HC595 LED顯示
SPI接口的全稱是"Serial Peripheral Interface",意為串行外圍接口。SPI接口主要應(yīng)用在EEPROM,F(xiàn)LASH,實時時鐘,AD轉(zhuǎn)換器,還有數(shù)字信號處理器和數(shù)字信號解碼器之間。
SPI接口是在CPU和外圍低速器件之間進行同步串行數(shù)據(jù)傳輸,在主器件的移位脈沖下,數(shù)據(jù)按位傳輸,為全雙工通信,數(shù)據(jù)傳輸速度總體來說比I2C總線要快,速度可達到幾Mbps。
SPI接口是以主從方式工作的,這種模式通常有一個主器件和一個或多個從器件,其接口包括以下四種信號:
(1)MOSI – 主器件數(shù)據(jù)輸出,從器件數(shù)據(jù)輸入
(2)MISO – 主器件數(shù)據(jù)輸入,從器件數(shù)據(jù)輸出
(3)SCLK – 時鐘信號,由主器件產(chǎn)生
(4)/SS – 從器件使能信號,由主器件控制
在BASCOM中,提供了軟件實現(xiàn)的SPI接口的語句,同樣BASCOM也有支持硬件SPI的語句。
下面將使用三個例子來說明如何在BASCOM中使用SPI接口。
在介紹例子之前,我們先了解一下硬件連接圖,連接如圖1所示。
圖中共使用三片74HC595芯片,分別控制三個數(shù)碼管,三片74HC595通過Q7’引腳進行級聯(lián)。第一片74HC595的DS引腳連接到了ATmega88的MOSI引腳,而SH_CP引腳連接到了ATmega88的SCK引腳,ST_CP引腳連接到了ATmega88的PB1引腳。
一、使用硬件SPI接口控制74HC595
'------------------------------------------------------------------------
'使用芯片: ATmega88,
'晶振: 內(nèi)部8MHz晶振
'email: support@avrbascom.com
'軟件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片為ATmega88
$crystal = 8000000 '8M晶振頻率
$hwstack = 32 '設(shè)置堆棧大小
$swstack = 10
$framesize = 40
Dim I As Byte
Dim A(3) As Byte
Latch Alias Portb.1
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes ,
Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
'定義使用單片機自帶的硬件SPI,SPI中斷未使能,數(shù)據(jù)發(fā)送時,高位先發(fā)送。
'設(shè)為SPI主設(shè)備,時鐘4分頻
Spiinit 'SPI初始化
Restore Segtab '獲取要顯示數(shù)據(jù)的內(nèi)容
For I = 1 To 3
Read A(i)
Next I
Spiout A(1) , 3 '輸出要顯示的內(nèi)容給74HC595,分別輸出A(1),A(2),A(3)
Latch = 1? '使能顯示
Waitus 10
Latch = 0
Do
Loop
End
'*******************************************************************************
'--------------------------專用字形表------------------------------------------
Segtab:
Data &H77 , &H14 , &HE6 , &HB6 , &H95 , &HB3 , &HF3 , &H16 , &HF7 , &HB7
'0 1 2 3 4 5 6 7 8 9
二、使用軟件SPI接口控制74HC595
'------------------------------------------------------------------------
'使用芯片: ATmega88,
'晶振: 內(nèi)部8MHz晶振
'email: support@avrbascom.com
'軟件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片為ATmega88
$crystal = 8000000 '8M晶振頻率
$hwstack = 32 '設(shè)置堆棧大小
$swstack = 10
$framesize = 40
Const On = 1
Const Off = 0
Dim I As Byte
Dim A(3) As Byte
Latch Alias Portb.1
Config Spi = Soft , Dout = Portb.3 , Ss = None , Clock = Portb.5
'定義使用軟件SPI,pb3作為數(shù)據(jù)輸出口,pb5作為時鐘引腳
Spiinit 'SPI初始化
Restore Segtab '獲取要顯示數(shù)據(jù)的內(nèi)容
For I = 1 To 3
Read A(i)
Next I
Spiout A(1) ,3
'輸出要顯示的內(nèi)容給74HC595,分別輸出A(1),A(2),A(3)
Latch = Off '使能顯示
Waitus 10
Latch = On
Do
Loop
End
'********************************************************************
'--------------------------專用字形表------------------------------------------
Segtab:
Data &H77 , &H14 , &HE6 , &HB6 , &H95 , &HB3 , &HF3 , &H16 , &HF7 , &HB7
'0 1 2 3 4 5 6 7 8 9
三、使用軟件SPI接口控制74HC595
'------------------------------------------------------------------------
'使用芯片: ATmega88,
'晶振: 內(nèi)部8MHz晶振
'email: support@avrbascom.com
'軟件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片為ATmega88
$crystal = 8000000 '8M晶振頻率
$hwstack = 32 '設(shè)置堆棧大小
$swstack = 10
$framesize = 40
Const On = 1
Const Off = 0
Ledata Alias Portb.3 '數(shù)據(jù)輸出口
Ledclk Alias Portb.5 '時鐘輸出口
Latch Alias Portb.1
Dim I As Byte
Dim A(3) As Byte
Restore Segtab '獲取要顯示數(shù)據(jù)的內(nèi)容
For I = 1 To 3
Read A(i)
Next I
For I = 3 To 1 Step -1
Shiftout Ledata , Ledclk , A(i) , 1
'輸出要顯示的內(nèi)容給74HC595
Next I
Latch = Off '使能顯示
Waitus 10
Latch = On
Do
Loop
End
'********************************************************************
'--------------------------專用字形表------------------------------------------
Segtab:
Data &H77 , &H14 , &HE6 , &HB6 , &H95 , &HB3 , &HF3 , &H16 , &HF7 , &HB7
'0 1 2 3 4 5 6 7 8 9
//*******************************************
// 74HC595/165驅(qū)動程序
// (165,595均為兩片)
//*******************************************
unsigned int LED;
unsigned int KEY_DATA;
void Driver_595(unsigned char Bit,unsigned char State)
{
if(State)
LED|=(0x00001<<Bit);
else
LED&=~(0x00001<<Bit);
SPI_W_R((int)(LED>>8));
set_bit(1,0);
clr_bit(1,0);
SPI_W_R((int)LED);
set_bit(1,0);
clr_bit(1,0);
}
void Port_Init(void)
{
DDRB=0xff;
PORTB=0x00;
}
//****************************************************************
void Driver_165(void) //Bite所取位0~15,State為改位的狀態(tài)0,1
{
unsigned char a1;
unsigned char a2;
clr_bit(1,3);
set_bit(1,3);
a1=SPI_W_R(0x00); //74HC165輸入使能
a2=SPI_W_R(0x00); //讀出鍵值
KEY_DATA=a1;
KEY_DATA<<=8;
KEY_DATA+=a2;
return;
}
//*******************************************************************
void set_bit(unsigned char port,unsigned char n)//port為端口號分別用0~3表示A~D,n該端口的引腳號0~7
{
switch(port)
{
case 0x00:
PORTA|=(0x01<<n);
break;
case 0x01:
PORTB|=(0x01<<n);
break;
case 0x02:
PORTC|=(0x01<<n);
break;
case 0x03:
PORTD|=(0x01<<n);
break;
}
}
//****************OK**********************
//**************************************
void clr_bit(unsigned char port,unsigned char n)//port為端口號分別用0~3表示A~D,n該端口的引腳號0~7
{
switch(port)
{
case 0x00:
PORTA&=~(0x01<<n);
break;
case 0x01:
PORTB&=~(0x01<<n);
break;
case 0x02:
PORTC&=~(0x01<<n);
break;
case 0x03:
PORTD&=~(0x01<<n);
break;
}
}
//***************OK***********************************************
unsigned char SPI_W_R(unsigned char data)
{
SPCR=0x50; //SPI為查詢方式,系統(tǒng)時鐘四分頻
SPDR=data; //寫入數(shù)據(jù)
while((SPSR>>7)==0x00); //等待數(shù)據(jù)發(fā)送完畢
return SPDR; //返回收到的數(shù)據(jù)
}
//*********************OK*****************************************
總結(jié):以上是AVR單片機使用SPI接口控制74HC595的例子,這些例子經(jīng)過簡單的修改就可以應(yīng)用到其它具有SPI即可的芯片上,如SPI接口的Flash存儲芯片AT45DB系列、SPI接口的時鐘芯片DS1302、SPI接口的AD或DA芯片等等。
對于AVR mega系列單片機一般都具有硬件SPI接口,建議客戶使用硬件SPI接口,這樣可以占用更少的硬件和軟件資源。但軟件實現(xiàn)SPI接口,也有一定的優(yōu)勢,如它使用的IO口不是固定的,可以根據(jù)需要來指定,它一次發(fā)送的數(shù)據(jù)可以不是8位,而是可以根據(jù)需要來指定。
Shiftout VS Spiout
這兩個語句都是SPI輸出語句,與它們對應(yīng)的分別是shiftin和spiin
shiftout語句可以使用在硬件spi或軟件spi接口,通過config語句來確定:
Config Spi = Hard/soft
Shiftout語句使用在軟件spi接口。
