关于STC12C5A60S2的SPI接口

2019-07-16 05:01发布

       大家好,我是一个单片机自学新人。没有导师,很多问题光靠百度是解决不了的。每个人遇到的问题都不一样。偶然看到电子发烧友网站。希望在这里可以得到大家的提点。
       这两天我在实验SPI通讯。
用了两片STC12C5A60S2(网上申请的样片),自带SPI硬件接口的。
本想达到的目的是。其中一个芯片做主机,另外一个做从机。
主机由UART串口发送一个数据,通过SPI串口发送到从机,
从机收到数据后用1602液晶显示出来,并且向主机返回接收到的数据,然后
在串口小助手里显示从机返回的值。
可是在主机发送程序端就出现了问题。
我通过几处添加串口小助手接收子程序UART_SendByte()
发现问题出在,向SPDAT写入数据时,无法写进数据。
SPDAT总是0XFF。
下面是主机程序。能帮我分析一下,为什么写不进去吗?还有那个CPU_CLK/16分频

file:///D:QQ消息保存位置605106547Imagem1)3]%rnby~d1b7jt0ny44w.jpg
有什么影响吗?这个MCU是1T的单片机,但是我没有开,用的是默认的12T的。

/* SPI主机程序,无中断串口接收并用SPI发送---------------------------------------


--------------------------------------------------------------------*/

#include <STC12C5A60S2.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=0xF3; //波特率为2400,晶振为12MHz

TL1=0xF3;

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 = 0xfc;//CPU_CLK/16,时钟前沿为下降沿,后沿采样,主模式,最低位在前,SPI使能 1111 1101

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数据寄存器

UART_SendByte(SPDAT);

while(!SPIF);//等待发送完毕

SPSTAT = 0xc0; //清除中断标志,和写冲突标志,注意是对应位写1才能清零

SPI_RecData = SPDAT;

UART_SendByte(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空标志

}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
lstcspring
1楼-- · 2019-07-16 10:40
UART_SendByte(SPI_SendData);改成这样试一下,看数据到底正常不,然后看一下接线正常不
zzw17hao
2楼-- · 2019-07-16 10:40
这是我自己写的关于SPI模块的程序,你参考参考吧
//SPI从机程序
#include <STC12C5A60S2.H>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
/************对SPCTL寄存器的设置位宏定义*************/
#define SSIG    0x80  //SS引脚忽略
#define SPEN    0x40  //SPI使能位
#define DORD    0x20  //SPI数据发送LSB最先发送
#define MSTR    0x10  //主从模式选择
#define CPOL    0x08  //SPICLK空闲时为高电平
#define CPHA    0x04  //数据在SPICLK的前时钟沿驱动,并在后时钟沿采样
#define SP_CLK0 0x00  //SPI时钟频率为CPU_CLK/4
#define SP_CLK1 0x01  //SPI时钟频率为CPU_CLK/16
#define SP_CLK2 0x02  //SPI时钟频率为CPU_CLK/64
#define SP_CLK3 0x03  //SPI时钟频率为CPU_CLK/128
/************对SPSTAT寄存器的设置位宏定义************/
#define SPIF    0x80  //传输完成标志
#define WCOL    0x40  //SPI写冲突标志               
/************SPI口切换宏定义***************/
#define SPI_P4  0x20   //SPI从P1口切换到P4口
/************波特率选择********************/
#define BTL 9600   //若要更改波特率直接更改此处,当波特率大于9600时需修改相应的接收程序,
//可选波特率有以下:    否则有可能出现乱码
//波特率为2400     //波特率为28800
//波特率为4800     //波特率为38400
//波特率为9600     //波特率为57600
//波特率为14400    //波特率为115200
//波特率为19200
void UART_init(void);
uchar Receive(void);
void Printf( uchar *p );
void Init_SPI(void);
void Send_byte( uchar byte );
//****************************************//
//                 串口初始化                  //                        
//****************************************//
void UART_init(void)
{
//    SM0  = 0;      //选择串口为方式1工作
//    SM1  = 1;     //8位数据波特率可变
//    REN  = 1;     //允许串口接收
    SCON = 0x50;
#if( BTL == 2400 )
    BRT  = 0x70; //波特率设置为9600
#elif( BTL == 4800 )
    BRT  = 0xB8;
#elif( BTL == 9600 )
    BRT     = 0xDC;
#elif( BTL == 14400 )
    BRT     = 0xE8;
#elif( BTL == 19200 )
    BRT  = 0xEE;
#elif( BTL == 28800 )
    BRT  = 0xF4;
#elif( BTL == 38400 )
    BRT  = 0xF7;
#elif( BTL == 57600 )
    BRT  = 0xFA;
#elif( BTL == 115200 )
    BRT  = 0xFD;
#endif
    AUXR = 0x15; //选择独立波特率发生器为串行
                 //口的波特率发生器,模式为1T
//    ES     = 1;     //允许串口中断
//    IPH  = 0X10; //PSH = 1;
//    IP     = 0X10; //PS  = 1;串口1中断为最高优先级中断
//    EA      = 1;     //开总中断
}
//************************************************//
//                    发送一个字节数据              //
//************************************************//
void Send_byte( uchar byte )
{
    SBUF         = byte;
    while(!TI);
    TI            = 0;
}
//************************************************//
//                  打印字符                          //
//************************************************//
void Printf( uchar *p )
{
    while( *p != '' )
    {
        Send_byte(*p);
        p++;
    }
   
}
//************************************************//
//                   接收函数                     //
//************************************************//
uchar Receive( void )
{
    uchar byte;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    if( RI == 1 )
    {
         RI = 0;
        byte = SBUF;
        
    }            
    return byte;
}
//***********************************//
//* 名称:Init_SPI()
//* 功能: 对SPI进行初始化
//* 输入:无
//* 输出:无
//***********************************//
void Init_SPI(void)
{
    SPDAT  = 0;         //清空数据寄存器
    SPSTAT = SPIF|WCOL; //清空SPI状态寄存器
    SPCTL  =SPEN;       //SPI设置为从机模式
    IE2    = 0x02;      //允许SPI中断
}
//***********************************//
//* 名称:main
//* 功能:
//* 输入:无
//* 输出:无
//***********************************//
void main()
{
    uchar flag = 0;
    UART_init();
    Init_SPI();
    EA  = 1;        //开总中断
    while(1)
    {       
        flag = Receive();
        if(flag)            //当PC端有给从机发送数据时把从机当前的SPDAT值发送出来
            {
            Send_byte(SPDAT);
            flag = 0;
        }                               
    }
}
//***********************************//
//* 名称:SPI_ISR()
//* 功能: SPI中断服务
//* 输入:无
//* 输出:无
//***********************************//
void SPI_ISR(void) interrupt 9 using 1  //使用工作寄存器组1
{
    SPSTAT = SPIF|WCOL;     //清标志
    Printf("Receive_Data:");
    P2 = P2+1;              //LED灯表示接收的次数
    Send_byte(SPDAT);       //读出主机发送过来的数据
    SPDAT  = SPDAT;         //把上一次接收到的值传回主机
    Send_byte(' ');
}
//SPI主机程序
#include <STC12C5A60S2.H>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
/************对SPCTL寄存器的设置位宏定义*************/
#define SSIG    0x80  //SS引脚忽略
#define SPEN    0x40  //SPI使能位
#define DORD    0x20  //SPI数据发送LSB最先发送
#define MSTR    0x10  //主从模式选择
#define CPOL    0x08  //SPICLK空闲时为高电平
#define CPHA    0x04  //数据在SPICLK的前时钟沿驱动,并在后时钟沿采样
#define SP_CLK0 0x00  //SPI时钟频率为CPU_CLK/4
#define SP_CLK1 0x01  //SPI时钟频率为CPU_CLK/16
#define SP_CLK2 0x02  //SPI时钟频率为CPU_CLK/64
#define SP_CLK3 0x03  //SPI时钟频率为CPU_CLK/128
/************对SPSTAT寄存器的设置位宏定义************/
#define SPIF    0x80  //传输完成标志
#define WCOL    0x40  //SPI写冲突标志               
/************SPI口切换宏定义***************/
#define SPI_P4  0x20   //SPI从P1口切换到P4口

sbit SPISS = P0^0;     //用来选择从机
/************串口波特率设定*************************/
#define BTL 9600    //若要更改波特率直接更改此处,当波特率大于9600时需修改相应的接收程序,
//可选波特率有以下:    否则有可能出现乱码
//波特率为2400     //波特率为28800
//波特率为4800     //波特率为38400
//波特率为9600     //波特率为57600
//波特率为14400    //波特率为115200
//波特率为19200
void UART_init(void);
uchar Receive(void);
void Printf( uchar *p );
void Init_SPI(void);
void Send_byte( uchar byte );
//****************************************//
//                 串口初始化                  //                        
//****************************************//
void UART_init(void)
{
//    SM0  = 0;      //选择串口为方式1工作
//    SM1  = 1;     //8位数据波特率可变
//    REN  = 1;     //允许串口接收
    SCON = 0x50;
#if( BTL == 2400 )
    BRT  = 0x70; //波特率设置为9600
#elif( BTL == 4800 )
    BRT  = 0xB8;
#elif( BTL == 9600 )
    BRT     = 0xDC;
#elif( BTL == 14400 )
    BRT     = 0xE8;
#elif( BTL == 19200 )
    BRT  = 0xEE;
#elif( BTL == 28800 )
    BRT  = 0xF4;
#elif( BTL == 38400 )
    BRT  = 0xF7;
#elif( BTL == 57600 )
    BRT  = 0xFA;
#elif( BTL == 115200 )
    BRT  = 0xFD;
#endif
    AUXR = 0x15; //选择独立波特率发生器为串行
                 //口的波特率发生器,模式为1T
//    ES     = 1;     //允许串口中断
//    IPH  = 0X10; //PSH = 1;
//    IP     = 0X10; //PS  = 1;串口1中断为最高优先级中断
//    EA      = 1;     //开总中断
}
//************************************************//
//                    发送一个字节数据              //
//************************************************//
void Send_byte( uchar byte )
{
    SBUF         = byte;
    while(!TI);
    TI            = 0;
}
//************************************************//
//                  打印字符                          //
//************************************************//
void Printf( uchar *p )
{
    while( *p != '' )
    {
        Send_byte(*p);
        p++;
    }
}
//************************************************//
//                   接收函数                     //
//************************************************//
uchar Receive( void )
{
    uchar byte;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    if( RI == 1 )
    {
         RI = 0;
        byte = SBUF;
        
    }            
    return byte;
}
//***********************************//
//* 名称:Init_SPI()
//* 功能: 对SPI进行初始化
//* 输入:无
//* 输出:无
//***********************************//
void Init_SPI(void)
{
    SPDAT  = 0;         //清空数据寄存器
    SPSTAT = SPIF|WCOL; //清空SPI状态寄存器
    SPCTL  = SPEN|MSTR; //SPI设置为主机模式
    IE2    = 0x02;      //允许SPI中断
}
//***********************************//
//* 名称:main
//* 功能:
//* 输入:无
//* 输出:无
//***********************************//
void main()
{
    uchar flag = 0;
    UART_init();
    Init_SPI();
    EA  = 1;        //开总中断
    while(1)
    {
        flag = Receive();                 
        if(flag)                 //当PC端有发送数据时才进行SPI传输数据
            {
            SPISS = 0;
            SPDAT = flag;
            flag  = 0;               
            }
                           
    }
}
//***********************************//
//* 名称:SPI_ISR()
//* 功能: SPI中断服务
//* 输入:无
//* 输出:无
//***********************************//
void SPI_ISR(void) interrupt 9 using 1  //使用工作寄存器组1
{          
    SPSTAT = SPIF|WCOL;     //清标志
    Printf("Send_Data:");
    Send_byte(SPDAT);      //从从机中把主机上一次发送的值读回来
    Send_byte(' ');
    SPISS  = 1;
}
dongzhiwei
3楼-- · 2019-07-16 10:48
学习啊
junjun19860722
4楼-- · 2019-07-16 13:22
 精彩回答 2  元偷偷看……
fafactx
5楼-- · 2019-07-16 16:02
相互学习何来自己写的??
hushenghua668
6楼-- · 2019-07-16 20:23
不错,后生可畏

一周热门 更多>