使用SPI接口控制74HC595 LED显示
SPI接口的全称是"Serial Peripheral Interface",意为串行外围接口。SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,为全双工通信,数据传输速度总体来说比I2C总线要快,速度可达到几Mbps。
SPI接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从器件,其接口包括以下四种信号:
(1)MOSI – 主器件数据输出,从器件数据输入
(2)MISO – 主器件数据输入,从器件数据输出
(3)SCLK – 时钟信号,由主器件产生
(4)/SS – 从器件使能信号,由主器件控制
在BASCOM中,提供了软件实现的SPI接口的语句,同样BASCOM也有支持硬件SPI的语句。
下面将使用三个例子来说明如何在BASCOM中使用SPI接口。
在介绍例子之前,我们先了解一下硬件连接图,连接如图1所示。
图中共使用三片74HC595芯片,分别控制三个数码管,三片74HC595通过Q7’引脚进行级联。第一片74HC595的DS引脚连接到了ATmega88的MOSI引脚,而SH_CP引脚连接到了ATmega88的SCK引脚,ST_CP引脚连接到了ATmega88的PB1引脚。
一、使用硬件SPI接口控制74HC595
'------------------------------------------------------------------------
'使用芯片: ATmega88,
'晶振: 内部8MHz晶振
'email: support@avrbascom.com
'软件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片为ATmega88
$crystal = 8000000 '8M晶振频率
$hwstack = 32 '设置堆栈大小
$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中断未使能,数据发送时,高位先发送。
'设为SPI主设备,时钟4分频
Spiinit 'SPI初始化
Restore Segtab '获取要显示数据的内容
For I = 1 To 3
Read A(i)
Next I
Spiout A(1) , 3 '输出要显示的内容给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,
'晶振: 内部8MHz晶振
'email: support@avrbascom.com
'软件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片为ATmega88
$crystal = 8000000 '8M晶振频率
$hwstack = 32 '设置堆栈大小
$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作为数据输出口,pb5作为时钟引脚
Spiinit 'SPI初始化
Restore Segtab '获取要显示数据的内容
For I = 1 To 3
Read A(i)
Next I
Spiout A(1) ,3
'输出要显示的内容给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,
'晶振: 内部8MHz晶振
'email: support@avrbascom.com
'软件版本: Bascom-AVR 1.11.8.3 Full version
'------------------------------------------------------------------------
$regfile = "m88def.dat" '芯片为ATmega88
$crystal = 8000000 '8M晶振频率
$hwstack = 32 '设置堆栈大小
$swstack = 10
$framesize = 40
Const On = 1
Const Off = 0
Ledata Alias Portb.3 '数据输出口
Ledclk Alias Portb.5 '时钟输出口
Latch Alias Portb.1
Dim I As Byte
Dim A(3) As Byte
Restore Segtab '获取要显示数据的内容
For I = 1 To 3
Read A(i)
Next I
For I = 3 To 1 Step -1
Shiftout Ledata , Ledclk , A(i) , 1
'输出要显示的内容给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驱动程序
// (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为改位的状态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为查询方式,系统时钟四分频
SPDR=data; //写入数据
while((SPSR>>7)==0x00); //等待数据发送完毕
return SPDR; //返回收到的数据
}
//*********************OK*****************************************
总结:以上是AVR单片机使用SPI接口控制74HC595的例子,这些例子经过简单的修改就可以应用到其它具有SPI即可的芯片上,如SPI接口的Flash存储芯片AT45DB系列、SPI接口的时钟芯片DS1302、SPI接口的AD或DA芯片等等。
对于AVR mega系列单片机一般都具有硬件SPI接口,建议客户使用硬件SPI接口,这样可以占用更少的硬件和软件资源。但软件实现SPI接口,也有一定的优势,如它使用的IO口不是固定的,可以根据需要来指定,它一次发送的数据可以不是8位,而是可以根据需要来指定。
Shiftout VS Spiout
这两个语句都是SPI输出语句,与它们对应的分别是shiftin和spiin
shiftout语句可以使用在硬件spi或软件spi接口,通过config语句来确定:
Config Spi = Hard/soft
Shiftout语句使用在软件spi接口。
