从昨天晚上到今天下午,一直在做STC12的SPI通信,终于有所收获。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
最初我阅读了STC公司的中文datasheet,初步了解了SPI通信的原理和STC12的SPI寄存器操作。STC公司在datasheet中给了一些例程,这对初学者来说有很大的帮助。在SPI通信中,单主机和单从机通信当然是最简单的的了。于是我决定从最简单的通信开始调。Datasheet中给了单机通信的汇编程序,51的汇编还是很简单的,虽然写得不熟,但看还是可以看懂的。为了通用性,我按照上面程序的思路用C语言来实现。
调试是51最大的缺陷,没有仿真芯片,就不知道你传输的是什么数据。所以就只有用串口送到上位机来显示。所以在做SPI之前,建议一定要熟悉串口的操作。
其实程序结构还是很清晰的。只是在调试的过程中,我发现了datasheet的几个错误。这些错误严重地影响了我的调试进度。最严重的错误就是SPI的中断使能位。
Datasheet上是这样说的:
;AUXR 特殊功能寄存器的 bit3 是 SPI 中断允许控制位 ESPI
;IE 特殊功能寄存器的 bit5 是ADC 和SPI 两个中断共享的总中断允许控制位 EADC_SPI
;要产生 SPI 中断, 需要 ESPI/EADC_SPI/EA 都为 1
所以我就写了AUXR = 0x08; EADC_SPI =1 ;EA =1;开启中断。
但是实验告诉我,这是不对的。我在始终无果的情况下,寻求了网络的支持。在网上看到有人这样使能中断:IE2 |=0x02;
于是我查看了IE2的寄存器定义,发现IE2.1是SPI的中断使能位。
啊!STC的datasheet这是误人子弟呀!
还有就是有个寄存器SPSTAT,bit7,bit6,对他们写1意味着清零。这个也太不方便了!大家用的时候要注意点。
在看datasheet时,感受最深的就是,这个datasheet写的太乱了!
哎!客观地说,这一点真不得不向人家国外的公司学学!
程序已调试通过:
一、主机程序
/* SPI主机程序,无中断串口接收并用SPI发送---------------------------------------
*硬件:STC12C5A60S2,晶振22.1184MHZ
*程序名称:main.c
*作者 :UESTC-35
*日期 :7/17/2011
连接方式 :三线连接
主单片机 I/O 口 I/O 口 从单片机
;
; +--------------+ MISO <-- 位流方向 MISO +--------------+
; | SPI |<<-----------------| SPI |
; |8 位移位寄存器 | |8 位移位寄存器 |
; | |---------------->> | | |
; +-------+------+ MOSI 位流方向 --> MOSI +-------^------+
; | | | |
; | | SCLK SCLK | |
; +---------------------------->>------------------------+
--------------------------------------------------------------------*/
#include "STC_NEW_8051.h"
#define SPIF ( SPSTAT & 0x80 ) //查询SPIF是否置位,SPIF不能进行位操作
/*通信端口设置-------------------------------------------------------*/
sbit SCLK = P1^7;
sbit MISO = P1^6;
sbit MOSI = P1^5;
sbit SS = P1^4;
unsigned char UART_SendData=0;
unsigned char UART_RecData=0;
unsigned char SPI_RecData=0;
void Init_System();
void Init_UART();
void Init_SPI();
unsigned char SPI_SendByte(unsigned char SPI_SendData);
void UART_SendByte(unsigned char UART_Send);
void main()
{
Init_System();
while(1)
{
/* 查询UART接收信号 ----------------------------------*/
while(!RI); //查看串口是否接收到数据
{
RI=0; //当接收到数据后,清除接收中断标志
UART_RecData=SBUF; //读入数据
UART_SendData=SPI_SendByte(UART_RecData);//将收到的数据由SPI发送出去,又接收回来
UART_SendByte(UART_SendData);
}
}
}
/*---------------------------------------------------------
*函数名:Init_System
*函数功能:系统初始化
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_System()
{
Init_UART();
Init_SPI();
}
/*---------------------------------------------------------
*函数名:Init_UART
*函数功能:串口初始化,无中断方式
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_UART()
{
TMOD=0x20;//设置定时器1为工作方式2
TH1=0xfa; //波特率为9600,晶振为22.1184MHz
TL1=0xfa;
TR1=1; //启动T1
REN=1; //串行允许位
// PCON=0x80; //PCON寄存器的SMOD位置一,波特率提高一倍
SM0=0;
SM1=1; //串行方式1
// ES=1; //中断接收则开串口中断,查询接收则关闭此句
}
/*---------------------------------------------------------
*函数名:Init_SPI
*函数功能:SPI初始化,SPI的工作方式,不使用SPI中断方式
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_SPI()
{
SPCTL = 0xfd;//CPU_CLK/16,时钟前沿为下降沿,后沿采样,主模式,最低位在前,SPI使能
SPSTAT = 0xc0;//SPDAT.7和SPDAT.6写11,可以将中断标志清零。注意是写1才清零
}
/*---------------------------------------------------------
*函数名:SPI_SendByte
*函数功能:SPI发射接收一体程序
*输入参数:SPI_SendData,经主机发给从机的数据
*返回参数:从机发给主机的数据
----------------------------------------------------------*/
unsigned char SPI_SendByte(unsigned char SPI_SendData)
{
SPDAT= SPI_SendData; //将串口接收的数据装入SPI数据寄存器
while(!SPIF);//等待发送完毕
SPSTAT = 0xc0; //清除中断标志,和写冲突标志,注意是对应位写1才能清零
SPI_RecData = SPDAT;
return SPI_RecData;
}
/*---------------------------------------------------------
*函数名:UART_SendByte
*函数功能:串口发送
*输入参数:UART_Send
*返回参数:无
----------------------------------------------------------*/
void UART_SendByte(unsigned char UART_Send)
{
TI = 0; //清除发送SBUF空标志
SBUF = UART_Send; //写入SBUF
while (!TI); //等待发送完毕
TI = 0; //清除发送SBUF空标志
}
二、从机程序
/* SPI从机程序,中断接收并发送---------------------------------------
*硬件:STC12C5A60S2,晶振22.1184MHZ
*程序名称:main.c
*作者 :UESTC-35
*日期 :7/17/2011
连接方式 :三线连接
主单片机 I/O 口 I/O 口 从单片机
;
; +--------------+ MISO <-- 位流方向 MISO +--------------+
; | SPI |<<-----------------| SPI |
; |8 位移位寄存器 | |8 位移位寄存器 |
; | |---------------->> | | |
; +-------+------+ MOSI 位流方向 --> MOSI +-------^------+
; | | | |
; | | SCLK SCLK | |
; +---------------------------->>------------------------+
--------------------------------------------------------------------*/
#include "STC_NEW_8051.h"
#define SPIF ( SPSTAT & 0x80 ) //查询SPIF是否置位,SPIF不能进行位操作
/*通信端口设置-------------------------------------------------------*/
sbit SCLK = P1^7;
sbit MISO = P1^6;
sbit MOSI = P1^5;
sbit SS = P1^4;
unsigned char SPI_Buffer=0;
void Init_SPI();
void main()
{
Init_SPI();
while(1);
}
/*---------------------------------------------------------
*函数名:Init_SPI
*函数功能:SPI初始化,SPI的工作方式,开中断
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_SPI()
{
SPCTL = 0xed;//CPU_CLK/16,时钟前沿为下降沿,后沿采样,从模式,最低位在前,SPI使能
SPSTAT = 0xc0;//SPDAT.7和SPDAT.6写11,可以将中断标志清零。注意是写1才清零
IE2 |= 0x02; //允许SPI中断
EA =1; //开总中断
}
/*---------------------------------------------------------
*函数名:SPI_Rec
*函数功能:SPI接收处理中断函数,将接收到的数发送出去
*输入参数:
*返回参数:
----------------------------------------------------------*/
void SPI_Rec() interrupt 9 //当SPIF = 1时,且EADC=1,AUXR = 0x08,EA=1时将进入此中断
{
SPSTAT = 0xc0; //清除中断标志,和写冲突标志,注意是对应位写1才能清零
SPI_Buffer = SPDAT;
SPDAT= SPI_Buffer;
}
724791548_274370249 2015-1-21 09:57
用户1370477 2014-11-17 23:32
用户377235 2014-8-3 22:08
还是有错误啊,发回来的数据不准确
用户377235 2014-5-3 23:00
用户920610 2012-12-16 13:23
用户310885 2011-7-20 10:43
飞言走笔 2011-7-19 11:25