今晚学了一些SPI的资料,但玩单片机毕竟不能只看而不实践,于是写了个利用两片AT89C51的GPIO接口软件模拟SPI实现双MCU通信的程序。
实现目标:
两片AT89C51均通过软件模拟SPI的方式建立通信,主机循环发送数值0~9,从机将接收到的数值显示在数码管上且将该数值返回给主机,主机也将从机返回的数值显示在数码管上。
主机源码:
#include<reg51.h>
#include<intrins.h>
sbit SCLK=P1^0;
sbit MOSI=P1^1;
sbit MISO=P1^2;
sbit SS=P1^3;
void Delay_ms() //延时一段时间
{
unsigned char i,j,k;
_nop_();
i=4;
j=129;
k=119;
do
{
do
{
while(--k);
}
while(--j);
}
while(--i);
}
void Delay1ms()
{
unsigned char i,j;
_nop_();
i=2;
j=199;
do
{
while(--j);
}
while(--i);
}
void SPI_M_Write(unsigned char dat) //主机发送数据
{
unsigned char i;
SS=0;
for(i=0;i<8;i++)
{
if(dat&0x80)
{
MOSI=1;
}
else
{
MOSI=0;
}
dat<<=1;
SCLK=1;
_nop_();
_nop_();
SCLK=0;
_nop_();
_nop_();
}
SS=1;
Delay1ms();
}
unsigned char SPI_M_Read() //主机接收数据
{
unsigned char i;
unsigned char dat=0;
SS=0;
for(i=0;i<8;i++)
{
dat<<=1;
dat|=MISO;
SCLK=1;
_nop_();
_nop_();
SCLK=0;
_nop_();
_nop_();
}
SS=1;
return dat;
}
void main()
{
unsigned char LEDS[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char i,temp;
SCLK=0;
P2=0x00;
while(1)
{
for(i=0;i<10;i++)
{
SPI_M_Write(i);
Delay_ms();
temp=SPI_M_Read();
P2=LEDS[temp];
Delay_ms();
}
}
}
从机源码:
#include<reg51.h>
#include<intrins.h>
sbit SCLK=P1^0;
sbit MOSI=P1^1;
sbit MISO=P1^2;
sbit SS=P1^3;
void Delay_ms() //延时一段时间
{
unsigned char i,j,k;
_nop_();
i=4;
j=129;
k=119;
do
{
do
{
while(--k);
}
while(--j);
}
while(--i);
}
void SPI_S_Write(unsigned char dat) //从机发送数据
{
unsigned char i;
while(SS==1);
for(i=0;i<8;i++)
{
while(SCLK==0);
while(SCLK==1);
dat<<=1;
if(dat&0x80)
{
MISO=1;
}
else
{
MISO=0;
}
}
while(SS==0);
}
unsigned char SPI_S_Read() //从机接收数据
{
unsigned char i;
unsigned char dat=0;
while(SS==1);
for(i=0;i<8;i++)
{
while(SCLK==0);
while(SCLK==1);
dat<<=1;
dat|=MOSI;
}
while(SS==0);
return dat;
}
void main()
{
unsigned char LEDS[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char i,temp;
P2=0x00;
while(1)
{
for(i=0;i<10;i++)
{
temp=SPI_S_Read();
P2=LEDS[temp];
Delay_ms();
SPI_S_Write(i);
Delay_ms();
}
}
}
原理图如下:
|