您的位置:首页 > 其它

硬件SPI实现

2017-10-19 18:53 134 查看
emmmm,,,,话说这个硬件SPI,,,做成了,再回过头来看,也特么真的没啥,,,,,但是做不成,哪都是问题。。。。

借此仅分享下我的经验,希望您可以少走弯路。。。

嗯,,,,其实在这之前我做单片机的SPI通信没有成功,于是就先做了SPI的W25Q16的读写,,,,可以参考这里

单主单从(忽略片选)

22.1184M 9600

话补多少,上最终代码。。。

实验手札:

问题大概想了一下,只要有三个

1、具体到各个寄存器的使用,当时没弄太懂,太过心急。。。磨刀不误砍柴工,,,切记切记啊。。。

2、用李基佬的15的最小系统,特么谁知道背面有个自锁开关,,,我一不小心就按关了,,,导致调试的时候好几次情况都很意外。。。

3、关于单片机的封装没仔细看清,以及要不要用到复用引脚AUXR/AUXR1切换。。。

嗯,大概就是这样,咱们看代码!!!

主机

#include "stc15.h"       // 注意宏定义后面没分号
bit SPI_Receive;            // SPI 端口收到数据标志位
unsigned char SPI_buffer;   // 保存SPI端口收到的数据
/**************************************************************************
- 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器
**************************************************************************/
void UART_init(void)       // 9600bps@22.1184MHz
{
// 下面代码设置定时器1
TMOD |= 0x20;   // 0010 0000 定时器1工作于方式2(8位自动重装方式)
TH1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TL1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TR1  = 1;
// 下面代码设置定串口
AUXR = 0x00;             // 很关键,使用定时器1作为波特率发生器,S1ST2=0
SCON = 0x50;    // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受)
}

void port_mode()            // 端口模式
{
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
}

void main(void)
4000

{
unsigned char tmpdata,SPI_status;
port_mode();      // 所有IO口设为准双向弱上拉方式。
UART_init();      // 初始化串口,9600bps@22.1184MHz
SPCTL=0xF0;       // 主机 (或SPCTL=0xFC; )
while(1)              // 主循环
{
if(RI)                      // 判串口是否收到数据
{
tmpdata=SBUF;           // 读取串口中收到的数据
RI=0;
P35=!P35;               // 串口接收数据指示灯,调试时观察串口工作是否正常
// 将数据发送到从机SPI
SPDAT=tmpdata;          // SPI 发送数据
SPI_status=0;
while(SPI_status==0)
{
SPI_status=SPSTAT;   // 等待SPIF=1即等待SPI发送完毕
SPI_status=SPI_status&0x80;
}
SPSTAT=0xC0;             // 清0标志位SPIF和WCOL
SPI_buffer=SPDAT;        // 保存收到的数据
SBUF=SPI_buffer;  // 将接收到的数据从串口发送到计算机
while(TI==0);     // 等待发送完毕
TI=0;             // 清零串口发送中断标志
}
}
}


从机

#include "stc15.h"       // 注意宏定义后面没分号
bit SPI_Receive;            // SPI 端口收到数据标志位
unsigned char SPI_buffer;   // 保存SPI端口收到的数据
void port_mode()            // 端口模式
{
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
}

void main(void)
{
port_mode();          // 所有IO口设为准双向弱上拉方式。
SPCTL=0xE0;           // 从机  (或SPCTL=0xEC; )
IE2=IE2|0x02;         // ESPI(IE2.1)=1,允许SPIF产生中断
EA=1;                 // 开总中断
SPI_Receive=0;        // 清标志字
while(1)              // 主循环
{
if (SPI_Receive)      // 判收是否收到主机SPI发来的数据
{
SPI_Receive=0;    // 清0主单片机SPI端口收到数据标志位
SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回
}
}
}
void SPI(void) interrupt 9
{
SPSTAT=0xC0;             // 清0标志位SPIF和WCOL
SPI_buffer=SPDAT;        // 保存收到的数据
SPI_Receive=1;           // 设置SPI端口收到数据标志
}


为了更方便一点,把主机从机做到了一个程序里面。

只需要下载的时候主机define上master,而从机注释掉即可

手札:

1、注意自己连的是复用后的IO口,还是原装的,要不要进行端口转换。

2、注意两块SPI进行通信的时候,要MOSI、MISO、SCK、对应连接。

3、要共VCC、共GND。

看程序吧。。。

#include "STC15W4K.H"       // 注意宏定义后面没分号
#define MASTER 1            // 作为从机程序时,将该行注释掉,其余都不用修改。

bit SPI_Receive;            // SPI 端口收到数据标志位
unsigned char SPI_buffer;   // 保存SPI端口收到的数据
/**************************************************************************
- 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器
**************************************************************************/
void UART_init(void)       // 9600bps@22.1184MHz
{
// 下面代码设置定时器1
TMOD |= 0x20;   // 0010 0000 定时器1工作于方式2(8位自动重装方式)
TH1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TL1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TR1  = 1;
// 下面代码设置定串口
AUXR = 0x00;             // 很关键,使用定时器1作为波特率发生器,S1ST2=0
SCON = 0x50;    // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受)
}
void Switch_port() // 根据硬件切换端口
{
//  AUXR1&=0XF3;    //1111 0011
//    AUXR1|=0X04;    //0000 0100
}
void port_mode()            // 端口模式
{
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
}

void main(void)
{
unsigned char tmpdata,SPI_status;
port_mode();     // 所有IO口设为准双向弱上拉方式。
#ifdef MASTER
UART_init();      // 初始化串口,9600bps@22.1184MHz
SPCTL=0xF0;       // 主机 (或SPCTL=0xFC; )
Switch_port();    // 端口切换
#else
SPCTL=0xE0;       // 从机  (或SPCTL=0xEC; )
#endif
SPSTAT=0xc0;          // 清0标志位SPIF和WCOL
IE2=IE2|0x02;         // ESPI(IE2.1)=1,允许SPIF产生中断
EA=1;                 // 开总中断
SPI_Receive=0;        // 清标志字
while(1)              // 主循环
{
#ifdef MASTER
if(RI)                      // 判串口是否收到数据
{
tmpdata=SBUF;           // 读取串口中收到的数据
RI=0;
P35=!P35;               // 串口接收数据指示灯,调试时观察串口工作是否正常
// 将数据发送到从机SPI
IE2&=0xfd;              // ESPI(IE2.1)=0,禁止SPIF产生中断
SPDAT=tmpdata;          // SPI 发送数据
SPI_status=0;
while(SPI_status==0)
{
SPI_status=SPSTAT;   // 等待SPIF=1即等待SPI发送完毕
SPI_status=SPI_status&0x80;
}
IE2|=0x02;               // ESPI(IE2.1)=1,允许SPIF产生中断
continue;                // 跳转到循环体最后结尾“}” 处执行程序
}
if (SPI_Receive)      // 判断是否接收到从SPI发回数据
{
SPI_Receive=0;    // 清0主单片机SPI端口收到从机数据标志位
TI=0;             // 清零串口发送中断标志
SBUF=SPI_buffer;  // 将接收到的数据从串口发送到计算机
while(TI==0);     // 等待发送完毕
TI=0;             // 清零串口发送中断标志
}
#else
if (SPI_Receive)      // 判收是否收到主机SPI发来的数据
{
SPI_Receive=0;    // 清0主单片机SPI端口收到数据标志位
SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回
}
#endif
}
}
void SPI(void) interrupt 9
{
SPSTAT=0xC0;             // 清0标志位SPIF和WCOL
SPI_buffer=SPDAT;        // 保存收到的数据
SPI_Receive=1;           // 设置SPI端口收到数据标志
}


单主单从(加入片选)

22.1184M 9600

#include "STC15W4K.H"   // 注意宏定义后面没分号
#define MASTER 1            // 作为从机程序时,将该行注释掉,其余都不用修改。

bit SPI_Receive;            // SPI 端口收到数据标志位
unsigned char SPI_buffer;   // 保存SPI端口收到的数据
sbit P2_4=P2^4;

/**************************************************************************
- 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器
**************************************************************************/
void UART_init(void)       // 9600bps@22.1184MHz
{
// 下面代码设置定时器1
TMOD |= 0x20;   // 0010 0000 定时器1工作于方式2(8位自动重装方式)
TH1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TL1  = 0xFA;    // 波特率:9600 /22.1184MHZ
TR1  = 1;
// 下面代码设置定串口
AUXR = 0x00;             // 很关键,使用定时器1作为波特率发生器,S1ST2=0
SCON = 0x50;    // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受)
}
void Switch_port() // 根据硬件切换端口
{
//  AUXR1&=0XF3;    //1111 0011
//    AUXR1|=0X04;    //0000 0100
}
void port_mode()            // 端口模式
{
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
}
void main(void)
{
unsigned char tmpdata,SPI_status;
port_mode();     // 所有IO口设为准双向弱上拉方式。
#ifdef MASTER
UART_init();      // 初始化串口,9600bps@22.1184MHz
SPCTL=0xF3;       // 主机 (或SPCTL=0xFC; )
Switch_port();    // 端口切换
#else
SPCTL=0x63;       // 从机  (或SPCTL=0xEC; )
#endif
SPSTAT=0xc0;          // 清0标志位SPIF和WCOL
IE2=IE2|0x02;         // ESPI(IE2.1)=1,允许SPIF产生中断
EA=1;                 // 开总中断
SPI_Receive=0;        // 清标志字
while(1)              // 主循环
{
#ifdef MASTER
if(RI)                      // 判串口是否收到数据
{
tmpdata=SBUF;           // 读取串口中收到的数据
RI=0;
P35=!P35;               // 串口接收数据指示灯,调试时观察串口工作是否正常
// 将数据发送到从机SPI
IE2&=0xfd;              // ESPI(IE2.1)=0,禁止SPIF产生中断
P2_4=0;                 // 打开从机片选
SPDAT=tmpdata;          // SPI 发送数据
SPI_status=0;
while(SPI_status==0)
{
SPI_status=SPSTAT;   // 等待SPIF=1即等待SPI发送完毕
SPI_status=SPI_status&0x80;
}
P2_4=1;                  // 关闭从机片选
IE2|=0x02;               // ESPI(IE2.1)=1,允许SPIF产生中断
continue;                // 跳转到循环体最后结尾“}” 处执行程序
}
if (SPI_Receive)      // 判断是否接收到从SPI发回数据
{
SPI_Receive=0;    // 清0主单片机SPI端口收到从机数据标志位
TI=0;             // 清零串口发送中断标志
SBUF=SPI_buffer;  // 将接收到的数据从串口发送到计算机
while(TI==0);     // 等待发送完毕
TI=0;             // 清零串口发送中断标志
}
#else
if (SPI_Receive)      // 判收是否收到主机SPI发来的数据
{
SPI_Receive=0;    // 清0主单片机SPI端口收到数据标志位
SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回
}
#endif
}
}
void SPI_ISR(void) interrupt 9
{
SPSTAT=0xC0;             // 清0标志位SPIF和WCOL
SPI_buffer=SPDAT;        // 保存收到的数据
SPI_Receive=1;           // 设置SPI端口收到数据标志
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: