Skip to content

SPI 数据接口使用

SPI接口是一种用于数据传输的接口,通常用于多设备之间的数据传输。对于STC8G系列单片机,SPI接口可以配置为主机模式或从机模式,并且支持全双工或半双工数据传输。一般情况下,SPI会使用主机模式的全双工数据传输方式。

1.SPI引脚

SPI引脚功能备注
SCK时钟信号P32
MISO主入从出P33
MOSI主出从入P54
SS从设备选择P55

2.SPI(主机模式)初始化

c
// SPI初始化(主模式)
void SPI_Init(void) {
    // 配置SPI引脚模式
    P3M0 = (P3M0 & ~0x08) | 0x04; 
    P3M1 = (P3M1 & ~0x04) | 0x08; 
    P5M0 |= 0x30; 
    P5M1 &= ~0x30; 

    
    // SPI控制寄存器配置
    SPCTL = 0xDC; // 二进制 1101 1100
    /*
    bit7: SPEN=1  使能SPI
    bit6: SSIG=1  忽略SS引脚(使用GPIO控制片选)
    bit5: CPOL=1  时钟空闲高电平
    bit4: CPHA=1  数据在时钟第二个跳变沿采样
    bit3: MSTR=1  主模式
    bit2: DORD=0  MSB先传输
    bit1-0: SPR=00 时钟=Fsys/4 (12MHz@48MHz主频)
    */
    
    SPSTAT = 0xC0; // 清除传输完成标志
}

3.SPI(主模式)发送数据

c
// SPI发送并接收1字节
unsigned char SPI_TransferByte(unsigned char dat) {
    SPDAT = dat;                // 写入发送数据
    while (!(SPSTAT & 0x80));   // 等待SPIF标志置位
    SPSTAT = 0x80;              // 清除SPIF标志
    return SPDAT;               // 返回接收数据
}

4.SPI(主模式)完整代码

c
#include <STC8G.h>
#include <intrins.h>

// 引脚定义 (8pin封装)
#define CS   P55  // 片选引脚 
#define SCK  P32  // 时钟引脚
#define MOSI P54  // 主出从入
#define MISO P33  // 主入从出
#define LIS3DH_WHO_AM_I   0x0F

// SPI初始化(主模式)
void SPI_Init(void) {
    // 配置SPI引脚模式
    P3M0 = (P3M0 & ~0x08) | 0x04; 
    P3M1 = (P3M1 & ~0x04) | 0x08; 
    P5M0 |= 0x30; 
    P5M1 &= ~0x30; 

    
    // SPI控制寄存器配置
    SPCTL = 0xDC; // 二进制 1101 1100
    /*
    bit7: SPEN=1  使能SPI
    bit6: SSIG=1  忽略SS引脚(使用GPIO控制片选)
    bit5: CPOL=1  时钟空闲高电平
    bit4: CPHA=1  数据在时钟第二个跳变沿采样
    bit3: MSTR=1  主模式
    bit2: DORD=0  MSB先传输
    bit1-0: SPR=00 时钟=Fsys/4 (12MHz@48MHz主频)
    */
    
    SPSTAT = 0xC0; // 清除传输完成标志
}


void Uart1_Init(void)	//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xE0;			//设置定时初始值
	TH1 = 0xFE;			//设置定时初始值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
}

void UartSendByte(unsigned char dat) {
    SBUF = dat;            // 发送当前数据
    while(!(TI));          // 等待数据发送完成
    TI = 0;                // 清除发送完成标志
}


// SPI发送并接收1字节
unsigned char SPI_TransferByte(unsigned char dat) {
    SPDAT = dat;                // 写入发送数据
    while (!(SPSTAT & 0x80));   // 等待SPIF标志置位
    SPSTAT = 0x80;              // 清除SPIF标志
    return SPDAT;               // 返回接收数据
}

void Delay1000ms(void)	//@11.0592MHz
{
	// 声明三个无符号字符型变量i、j、k
    //在 unsigned char data i, j, k; 这种变量定义方式中,
    //data 是 Keil C 编译器中用于指定变量存储类型的修饰符,
    //用于告诉编译器该变量应存放在 内部 RAM 的低 128 字节(即 data 区域) 中。
	unsigned char data i, j, k;

	_nop_();	// 空操作,延时1个机器周期
	_nop_();	// 空操作,延时1个机器周期
	i = 43;		// 将变量i赋值为43
	j = 6;		// 将变量j赋值为6
	k = 203;	// 将变量k赋值为203
	do
	{
		do
		{
			while (--k);	// 当k大于0时,循环执行k减1操作
		} while (--j);	// 当j大于0时,循环执行j减1操作
	} while (--i);		// 当i大于0时,循环执行i减1操作
}


// 主函数
void main() {
	  unsigned char rx;
    // 系统时钟初始化(48MHz)
    Uart1_Init();
    
    SPI_Init();     // 初始化SPI
    CS = 1;         // 初始片选高电平
    
    while(1) {
        CS = 0;                     // 片选使能
        SPI_TransferByte(LIS3DH_WHO_AM_I | 0x80); // 发送并接收
        rx = SPI_TransferByte(0x00);
        UartSendByte(rx); // 发送接收到的数据到串口
        CS = 1;                     // 片选禁止
        
        // 此处可添加数据处理逻辑
        Delay1000ms();
    }
}