STC8H系列—12. 寄存器方式硬件SPI驱动OLED屏教程

一、概述:

   STC8H自带一组硬件SPI接口,SPI接口具有高速传输数据的能力已经是众所周知了,曾经有做一个案例,通过传统的C51通过软件模拟SPI的方式传输数据至W25Q16,采用硬件方式SPI方式传输数据尚无涉及。本次在学习测试STC8H系列的过程中,找到一块SPI接口的OLED屏,有意想通过硬SPI方式驱动此屏,经过大半天时间的捉弄把玩,终于测试成功,出于本人知识域的局限,如下的介绍出于个人的理解。

      硬SPI的传输和软SPI的传输相类似,首先是工作模式设置,通过设置CPOL与CPHA确定SPI的四种工作方式,其次是设置SPI的传输传输速率,自然硬SPI的传输速率是软SPI远不能比的通常是Sysclk/2n 。接收与发送共用一个SPDAT寄存器,像串口一样和简单,直接赋值就可,传输是否完成可以通过标志位来判定,当然有查询和中断两种方式。

   SSD1306 OLED屏网上的资料很多,但涉及硬SPI的传输的资料不是很详,OLED屏的控制只需单向传输就行,所以采用查询方式传输数据,其中DC脚需要单独定义,用于区会发送是命令还是数据,在测试过程中RST脚容易忽略,虽然不参与控制但使用过程中必须给定一个高电平。

二、知识链接:

   1、SPI状态寄存器(SPSTAT):

SPIF和WCOL置1时标志位清零

   2、SPI控制寄存器(SPCTL):

这里必须结合OLED屏的控制时序给定参数

  SPCTL参数设置(以下设置针对SSD1306 4线硬SPI传输)

        B7:SSIG=0  SS脚功能

        B6:SPEN=1  使能硬SPI

        B5:DORD=0  MSB方式传输,高位优先

        B4:MSRT=1  设置成主机模式

         B3与B2:CPOL=1 CPHA=0  方式2传输,经测试方式0、方式1、方式2、方式3都行

       B1与B0:SPR=10  SPI传输频率=sysclk/16,SPR=00SPI传输频率=sysclk/4也行

三、实验平台搭建:

   1、MCU:STC-打狗棒系列核心实验板 V2.3

   2、实验板平台:德飞莱LY-51s

   3、显示:SSD1306 1.3寸白色OLED屏(7脚SPI接口)

   4、硬件连接表:

      1.3寸7脚OLED接线图硬SPI接线表

         CS------>P20

         DC------>P21

         RST----->P26[此脚未参与控制,但必须给个高电平]

         DI(MOSI)----->P23

         CLK---------->P25

         VCC---------->+5V

         GND---------->GND

四、测试源代码:

#include <STC8H.h>

#include "intrins.h"

#include "oledfont.h"

#define uint8_t unsigned char

#define u8 unsigned char

#define u16  unsigned int

#define uint32_t unsigned long

#define SIZE 16

#define XLevelL     0x00

#define XLevelH     0x10

#define Max_Column  128

#define Max_Row     64

#define Brightness 0xFF

#define X_WIDTH 128

#define Y_WIDTH 64

          

#define OLED_CMD  0 //写命令

#define OLED_DATA 1 //写数据

/*********************************

  1.3寸7脚OLED接线图硬SPI接线表

   CS------>P20

   DC------>P21

   RST----->P26[此脚未参与控制,但必须给个高电平]

   DI(MOSI)----->P23

   CLK---------->P25

   VCC---------->+5V

   GND---------->GND

***********************************/

sbit DC=P2^1;//定义数据和命令端

sbit CS=P2^0;//片选信号

void init_IO();//初始化IO

//硬件SPI

void init_SPI();//初始化硬SPI

void SPI_Write(unsigned char dat);//查询方式硬SPI写数据

//OLED控制用函数

void OLED_Init(void);

void OLED_WR_Byte(unsigned char dat,unsigned char cmd);

void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr);

void OLED_ShowString(uint8_t x,uint8_t y, uint8_t *p); 

void OLED_Set_Pos(unsigned char x, unsigned char y);

void OLED_Clear(void);

void main()

{

      P_SW2 |= 0x80;  //扩展寄存器XFR访问使能

      init_IO(); //初始化IO

    init_SPI();//初始化硬SPI

     OLED_Init();//初始化OLED

     OLED_ShowString(0,1," MG LeiYang!");

     OLED_ShowString(0,5," by lizhipeng!");

     OLED_ShowString(0,3," OLED SPI Test!");

   while(1); 

}

void init_IO()

{

   RSTCFG=0x50;  //开启RST键进入ISP模式

   P0M1 = 0x00;   P0M0 = 0x00;   //设置P0口为准双向口

   P2M1 = 0x00;   P2M0 = 0x00;   //设置P1口为准双向口

   P3M1 = 0x00;   P3M0 = 0x00;   //设置P3口为准双向口

}

void init_SPI()//初始化硬SPI

{

      CS=0;//打开片选信号,使能OLED屏

     P_SW1|=0x04;//P2.2-P2.5

     /************************

     SPCTL参数设置(以下设置针对SSD1306 4线硬SPI传输)

        D7:SSIG=0  SS脚功能

        D6:SPEN=1  使能硬SPI

        D5:DORD=0  MSB方式传输,高位优先

        D4:MSRT=1  设置成主机模式

       D3与D2:CPOL=1 CPHA=0  方式2传输,经测试方式0、方式1、方式2、方式3都行

       D1与D0:SPR=10  SPI传输频率=sysclk/16,SPR=00SPI传输频率=sysclk/4也行

  

     *******************************/

     SPCTL=0x5A; //控制位设置,传输方式参数设置与使能SPI

     SPSTAT=0xC0;//清空标志位

}

//cmd:数据/命令标志 0,表示命令;1,表示数据;

void OLED_WR_Byte(unsigned char dat,unsigned char cmd)

{  

    DC=cmd;//写命令或写数据

     SPI_Write(dat);//硬SPI写数据

}

//硬SPI写数据

void SPI_Write(unsigned char dat)

{

    SPSTAT=0xC0;//清空标志位

     SPDAT=dat;//写入数据

     while(!(SPSTAT&0x80));//等待传输完成    

     SPSTAT=0xC0;//再次清空标志位

}

/***********************以下部分借鉴与网络*****************************/

//设置显示坐标位置

void OLED_Set_Pos(unsigned char x, unsigned char y)

{

   OLED_WR_Byte(0xb0+y,OLED_CMD);

   OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);

   OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);

}       

                

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!    

void OLED_Clear(void) 

   u8 i,n;       

   for(i=0;i<8;i++) 

   { 

      OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)

      OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址

      OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址  

      for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);

   } //更新显示

}

//在指定位置显示一个字符,包括部分字符

//x:0~127

//y:0~63

//mode:0,反白显示;1,正常显示        

//size:选择字体 16/12

void OLED_ShowChar(u8 x,u8 y,u8 chr)

{       

   unsigned char c=0,i=0;

      c=chr-' ';//得到偏移后的值       

      if(x>Max_Column-1){x=0;y=y+2;}

      if(SIZE ==16)

        {

        OLED_Set_Pos(x,y); 

        for(i=0;i<8;i++)

        OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);

        OLED_Set_Pos(x,y+1);

        for(i=0;i<8;i++)

        OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);

        }

        else { 

           OLED_Set_Pos(x,y+1);

           for(i=0;i<6;i++)

           OLED_WR_Byte(F6x8[c][i],OLED_DATA);

          

        }

}

//显示一个字符号串

void OLED_ShowString(u8 x,u8 y,u8 *chr)

{

   unsigned char j=0;

   while (chr[j]!='\0')

   {     OLED_ShowChar(x,y,chr[j]);

        x+=8;

      if(x>120){x=0;y+=2;}

        j++;

   }

}

//初始化SSD1306                

void OLED_Init(void)

{

   OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel

   OLED_WR_Byte(0x00,OLED_CMD);//---set low column address

   OLED_WR_Byte(0x10,OLED_CMD);//---set high column address

   OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)

   OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register

   OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness

   OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

   OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

   OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display

   OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)

   OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty

   OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)

   OLED_WR_Byte(0x00,OLED_CMD);//-not offset

   OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency

   OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec

   OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period

   OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock

   OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration

   OLED_WR_Byte(0x12,OLED_CMD);

   OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh

   OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level

   OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)

   OLED_WR_Byte(0x02,OLED_CMD);//

   OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable

   OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable

   OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)

   OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)

   OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

  

   OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/

   OLED_Clear();

   OLED_Set_Pos(0,0);

猜你喜欢

转载自blog.csdn.net/qq_21082985/article/details/132171237