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

    科技2022-07-10  126

    硬件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使用注意事项(一)

    Processed: 0.058, SQL: 8