STC15系列单片机SPI使用教程(二)

硬件SPI(中断方式)

以STC15W408AS单片机为例

一、硬件接线

STC15系列单片机SPI使用注意事项(一)



二、程序编写

1、和SPI中断相关的寄存器


① IE寄存器

在这里插入图片描述

② IE2寄存器

在这里插入图片描述

③ IP2寄存器

在这里插入图片描述

2、自定义寄存器,数据类型重定义

sfr P_SW1  = 0xA2;		//外设功能切换寄存器1
sfr SPSTAT = 0xCD;		//SPI状态寄存器
sfr SPCTL  = 0xCE;		//SPI控制寄存器
sfr SPDAT  = 0xCF;		//SPI数据寄存器

sfr IE2    = 0xAF;      //中断控制寄存器2

#ifndef uchar
	#define uchar unsigned char
#endif
#ifndef uint
	#define uint  unsigned int
#endif

typedef bit BOOL;

#define NULL            0
#define FALSE           0
#define TRUE            1

3、寄存器相关位宏定义, CS引脚定义

#define SPI_S0	0x04
#define SPI_S1	0x08

#define SPIF	0x80	//SPSTAT.7
#define WCOL	0x40	//SPSTAT.6

#define SSIG	0x80	//SPCTL.7
#define SPEN	0x40	//SPCTL.6
#define DORD	0x20	//SPCTL.5
#define MSTR	0x10	//SPCTL.4
#define CPOL	0x08	//SPCTL.3
#define CPHA	0x04	//SPCTL.2
#define SPDHH	0x00	//CPU_CLK/4
#define SPDH	0x01	//CPU_CLK/16
#define SPDL	0x02	//CPU_CLK/64
#define SPDLL	0x03	//CPU_CLK/128

#define ESPI	0x02	//IE2.1

sbit SS_1 = P1^2;		//SPI_1的SS脚

BOOL g_fSpiBusy;		//SPI的工作状态

4、SPI初始化代码

void InitSPI_1(void)
{
    
    
	uchar temp;
	temp = P_SW1;                                //切换到第一组SPI
	temp &= ~(SPI_S0 | SPI_S1);                  //SPI_S0=0 SPI_S1=0
	P_SW1 = temp;                                //(P1.2/SS, P1.3/MOSI, P1.4/MISO, P1.5/SCLK)

//	temp = P_SW1;                                //可用于测试U7,U7使用的是第二组SPI控制Flash
//	temp &= ~(SPI_S0 | SPI_S1);                  //SPI_S0=1 SPI_S1=0
//	temp |= SPI_S0;                              //(P2.4/SS_2, P2.3/MOSI_2, P2.2/MISO_2, P2.1/SCLK_2)
//	P_SW1 = temp;  

//	temp = P_SW1;                                //切换到第三组SPI
//	temp &= ~(SPI_S0 | SPI_S1);                  //SPI_S0=0 SPI_S1=1
//	temp |= SPI_S1;                              //(P5.4/SS_3, P4.0/MOSI_3, P4.1/MISO_3, P4.3/SCLK_3)
//	P_SW1 = temp;  
	
	
    SPDAT = 0;                  //初始化SPI数据
    SPSTAT = SPIF | WCOL;       //清除SPI状态位
    SPCTL = SPEN | MSTR | SSIG | SPDLL;        //主机模式
}

5、SPI中断服务程序

//SPI中断服务程序
void spi_isr() interrupt 9 using 1
{
    
    
    SPSTAT = SPIF | WCOL;					//清除SPI状态位
    g_fSpiBusy = FALSE;
}

6、SPI数据交换代码

/************************************************
使用SPI方式进行数据交换
入口参数:
    dat : 准备写入的数据
出口参数:
    从Flash中读出的数据
************************************************/
uchar SPIShift(uchar dat)
{
    
    
    g_fSpiBusy = TRUE;
    SPDAT = dat;						//触发SPI发送
    while(g_fSpiBusy);					//等待SPI数据传输完成
    
    return SPDAT;
}

7、GD25Q80BSIG读写例程

//GD25Q80BSIG相关宏定义
#define NOP							    0xFF	//空操作
#define Write_Enable					0x06	//写使能
#define Write_Disable					0x04	//写禁能
#define Read_Status_Register			0x05	//读前八位状态寄存(S7-S0)
#define Read_Status_Register_1			0x35	//读后八位状态寄存(S15-S8)
#define Read_Data						0x03	//读数据
#define Page_Program					0x02	//页面编程,256字节
#define Chip_Erase_1					0xC7	//芯片擦除命令1
#define Chip_Erase_2					0x60	//芯片擦除命令2
#define Read_Identification				0x9F	//读取标识命令允许读取8位制造商标识,然后是两个字节的设备标识。

sbit WP = P1^6;		//写保护,低电平有效

//写使能
void Write_Enable_Cmd(void)
{
    
    
	SS_1 = 0;
	SPIShift(Write_Enable);
	SS_1 = 1;
}
//写禁能
void Write_Disable_Cmd(void)
{
    
    
	SS_1 = 0;
	SPIShift(Write_Disable);
	SS_1 = 1;
}
//读状态寄存器前八位
uchar Read_Status_Register_Sta(void)
{
    
    
	uchar sta;
	SS_1 = 0;
	SPIShift(Read_Status_Register);
	sta = SPIShift(NOP);
	SS_1 = 1;
	return sta;
}
//读数据
void Read_Data_Cmd(uchar ad1, uchar ad2, uchar ad3, uchar *dat, uint len)
{
    
    
	uchar i, cmd[4];
	cmd[0] = Read_Data;
	cmd[1] = ad1;
	cmd[2] = ad2;
	cmd[3] = ad3;
	SS_1 = 0;
	for(i = 0; i < 4; i++){
    
    
		SPIShift(cmd[i]);
	}
	for(i = 0; i < len; i++){
    
    
		*dat++ = SPIShift(NOP);
	}
	SS_1 = 1;
}

//页编程,输入24位起始地址
void Page_Program_Cmd(uchar ad1, uchar ad2, uchar ad3, uchar *dat, uint len)
{
    
    
	uchar i, cmd[4];
	uint count = 0, temp = 0;
	long address = 0;	//24位地址
	
	address = (ad1 << 16) | (ad2 << 8) | ad3;
	
	cmd[0] = Page_Program;
	cmd[1] = ad1;
	cmd[2] = ad2;
	cmd[3] = ad3;
	temp = 256 - ad3;
	Write_Enable_Cmd();
	SS_1 = 0;
	for(i = 0; i < 4; i++){
    
    
		SPIShift(cmd[i]);
	}
	for(i = 0; i < temp; i++){
    
    
		SPIShift(*dat++);
	}
	SS_1 = 1;
	while(Read_Status_Register_Sta() & 0x01);
	if(len > temp){
    
    
		cmd[0] = Page_Program;
		cmd[1] = ad1;
		cmd[2] = ad2 + 1;
		cmd[3] = 0;
		temp = len - temp;
		Write_Enable_Cmd();
		SS_1 = 0;
		for(i = 0; i < 4; i++){
    
    
			SPIShift(cmd[i]);
		}
		for(i = 0; i < temp; i++){
    
    
			SPIShift(*dat++);
		}
		SS_1 = 1;
		while(Read_Status_Register_Sta() & 0x01);
	}
}
//擦除芯片
void Chip_Erase_1_Cmd(void)
{
    
    
	Write_Enable_Cmd();
	SS_1 = 0;
	SPIShift(Chip_Erase_2);
	SS_1 = 1;
	while(Read_Status_Register_Sta() & 0x01);
}
//读id
void Read_Identification_Sta(uchar *rdid)
{
    
    
	uchar i;
	SS_1 = 0;
	SPIShift(Read_Identification);
	for(i = 0; i < 3; i++){
    
    
		*rdid++ = SPIShift(NOP);
	}
	SS_1 = 1;
}
//16进制转字符串输出
void HexToAscii(uchar *pHex, uchar *pAscii, uchar nLen)
{
    
    
    uchar Nibble[2];
    uint i,j;
    for (i = 0; i < nLen; i++){
    
    
        Nibble[0] = (pHex[i] & 0xF0) >> 4;
        Nibble[1] = pHex[i] & 0x0F;
        for (j = 0; j < 2; j++){
    
    
            if (Nibble[j] < 10){
    
    
                Nibble[j] += 0x30;
            }
            else{
    
    
                if (Nibble[j] < 16)
                    Nibble[j] = Nibble[j] - 10 + 'A';
            }
            *pAscii++ = Nibble[j];
        }               // for (int j = ...)
    }           // for (int i = ...)
    *pAscii++ = '\0';
}
//主函数
void main(void)
{
    
    
	uchar sta, dis[2], rdid[3];
	uchar write[10] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 11}, read[10] = {
    
    0x00};
	uchar play[20] = {
    
    0x00};
	
	Init_Uart();
	InitSPI_1();
	IE2 |= ESPI;		//使能SPI传输中断
    EA = 1;
	
	g_fSpiBusy = FALSE;	
	
	Read_Identification_Sta(rdid);	//切换SPI后,需要多读几次,等待SPI稳定
	Read_Identification_Sta(rdid);
	Read_Identification_Sta(rdid);
	HexToAscii(&rdid[0], dis, 1);
	SendString("Manufacturer ID: 0x");
	SendString(dis);
	SendString("\r\n");
	
	HexToAscii(&rdid[1], dis, 1);
	SendString("Memory Type: 0x");
	SendString(dis);
	SendString("\r\n");
	HexToAscii(&rdid[2], dis, 1);
	SendString("Capacity: 0x");
	SendString(dis);
	SendString("\r\n");

	sta = Read_Status_Register_Sta();
	HexToAscii(&sta, dis, 1);
	SendString("GD25Q80BSIG Status Register: 0x");
	SendString(dis);
	SendString("\r\n");

	Chip_Erase_1_Cmd();	//写数据之前要先擦除数据
	Page_Program_Cmd(0x00, 0x01, 0xFA, write, 10);//写数据
	Read_Data_Cmd(0x00, 0x01, 0xFA, read, 10);//读数据
	HexToAscii(read, play, 10);
	SendString("Read Address 0x0001FA: ");
	SendString(play);
	SendString("\r\n");
	
	while(1);
}

8、串口代码

STC15系列单片机SPI使用注意事项(一)

猜你喜欢

转载自blog.csdn.net/baidu_25117757/article/details/108910080