7针0.96寸OLED_SPI的驱动代码 STM32CubeMX HAL库

请注意以下代码只适合硬件SPI
硬件SPISTM32cubeMX的配置方法!

其余的时钟等操作与其他一致
重点讲SPI的配置
SPI1/2都行,选一个,因为oled只能接受数据,不能发送所以选只做主机,(选双向也可以),下面选择硬件输出型号 连接oled的cs 接口,用于控制输出命令还是数据。
其他选项默认
在这里插入图片描述
然后博主oled为中景圆的7针SPI接口
所以还要再选两个IO口做res 和 dc
使用user label
在这里插入图片描述
在这里插入图片描述

就可以在main.h中看见
在这里插入图片描述
以下为oled.h头文件内容

#include "main.h"

// 常量定义
#define u8         unsigned char  // 将unsigned char 定义简写
#define MAX_LEN    128  // 列最多像素点
#define OLED_CMD   1  // 写命令
#define OLED_DATA  0  // 写数据

// 定义字体枚举,值为字体的高度
enum Font_Size {
    
    SMALL = 6 , MEDIA = 12 , BIG = 16};
// 定义数字枚举,值为数字的高度
enum Num_Size {
    
    SMALL_NUM = 24 , MEDIA_NUM = 32 , BIG_NUM = 40};
// 定义汉字的大小枚举,值为字体的高度
enum Zh_Size {
    
    ZH16 = 16 , ZH32 = 32};
// 滚动方向枚举
enum DIRECTION {
    
     LEFT = 0x27 , RIGHT = 0x26,UP=0x29,DAWN=0x2a};

// 端口高低操纵定义
#define OLED_RST_H HAL_GPIO_WritePin(OLED_RST_GPIO_Port,OLED_RST_Pin,GPIO_PIN_SET)    // 复位脚高
#define OLED_RST_L HAL_GPIO_WritePin(OLED_RST_GPIO_Port,OLED_RST_Pin,GPIO_PIN_RESET)  // 复位脚低

#define OLED_DC_H HAL_GPIO_WritePin(OLED_DC_GPIO_Port,OLED_DC_Pin,GPIO_PIN_SET)  			// 控制脚高
#define OLED_DC_L HAL_GPIO_WritePin(OLED_DC_GPIO_Port,OLED_DC_Pin,GPIO_PIN_RESET)  		// 控制脚低

// 函数定义
// OLED的基础操作函数
void OLED_Write_Byte(u8 data , u8 cmd);
void OLED_Init(void);
void OLED_On(void);
void OLED_Off(void);
void OLCD_Set_Pos(u8 x, u8 y);

void OLED_Ascii_Test(void);

// OLED的显示操作函数
void OLED_Clear(void);
void OLED_Show_Char(u8 x, u8 y , u8 chr , enum Font_Size size);
void OLED_Show_String(u8 x, u8 y , char *chr , enum Font_Size size);
void OLED_Show_Num(u8 x, u8 y , u8 num , enum Num_Size size);
void OLED_Show_Chinese(u8 x, u8 y , u8 index , enum Zh_Size size , u8 reverse);
void OLED_Show_Icon(u8 x, u8 y , u8 index);
void OLED_horizontalroll_Display(u8 start,u8 end,enum DIRECTION dirct);
void OLED_verticalroll_Display(void);
void OLED_obliqueroll_Display(u8 start,u8 end,enum DIRECTION dirct);
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void OLED_DrawDot(u8 x,u8 y,u8 t);
void OLED_Circle(uint8_t x,uint8_t y,uint8_t r);
void OLED_DrawSquare(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2);
void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2);
void OLED_fill_Circle(u8 x0,u8 y0,u8 r,u8 dot);
#endif

以下为oled.c文件中的内容

写命令或者数据的函数和初始化的函数

void OLED_Write_Byte( u8 data , u8 cmd )
{
    
    
                                           // 这里直接使用三目运算符,不使用if/else写法,看起来简洁些
    cmd ? OLED_DC_L : OLED_DC_H ; 				// 写命令DC输出低,写数据DC输出高
                                          // 硬件SPI数据传输
    HAL_SPI_Transmit(&hspi2,&data,sizeof(data),1000); // SPI写数据或者命令
    OLED_DC_H;														// 控制脚拉高,置成写数据状态
}


/*******************
** OLED初始化
********************/
void OLED_Init(void)
{
    
    
    // 制造一个先低后高的电平变换,达到复位的效果
    OLED_RST_L;
    HAL_Delay(500);
    OLED_RST_H;

    OLED_Write_Byte(0xAE,OLED_CMD);//--turn off oled panel
    OLED_Write_Byte(0x02,OLED_CMD);//---set low column address
    OLED_Write_Byte(0x10,OLED_CMD);//---set high column address
    OLED_Write_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_Write_Byte(0x81,OLED_CMD);//--set contrast control register
    OLED_Write_Byte(0xff,OLED_CMD);// Set SEG Output Current Brightness
    OLED_Write_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_Write_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_Write_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    OLED_Write_Byte(0x3f,OLED_CMD);//--1/64 duty
    OLED_Write_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    OLED_Write_Byte(0x00,OLED_CMD);//-not offset
    OLED_Write_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
    OLED_Write_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_Write_Byte(0xD9,OLED_CMD);//--set pre-charge period
    OLED_Write_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_Write_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
    OLED_Write_Byte(0x12,OLED_CMD);
    OLED_Write_Byte(0xDB,OLED_CMD);//--set vcomh
    OLED_Write_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
    OLED_Write_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_Write_Byte(0x02,OLED_CMD);//
    OLED_Write_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
    OLED_Write_Byte(0x14,OLED_CMD);//--set(0x10) disable
    OLED_Write_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
    OLED_Write_Byte(0xA6,OLED_CMD);// 开启正常显示 (0xA6 = 正常 / 0xA7 = 反显)
    OLED_Write_Byte(0xAF,OLED_CMD);//--turn on oled panel

    OLED_Clear(); // 清屏
}

接下来使一些开启,关闭,清屏,设置光标的位置的函数

void OLED_On(void)
{
    
    
    OLED_Write_Byte(0X8D,OLED_CMD);  //SET DCDC命令
    OLED_Write_Byte(0X14,OLED_CMD);  //DCDC ON
    OLED_Write_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}

/******************
**  关闭OLED显示
*******************/
void OLED_Off(void)
{
    
    
    OLED_Write_Byte(0X8D,OLED_CMD);  //SET DCDC命令
    OLED_Write_Byte(0X10,OLED_CMD);  //DCDC OFF
    OLED_Write_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}


/****************************
** 设置坐标点
** x: 行坐标 0~127
** y: 页坐标 0~7
*****************************/
void OLCD_Set_Pos(u8 x, u8 y)
{
    
    
    OLED_Write_Byte(0xb0+y,OLED_CMD);
    OLED_Write_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
    OLED_Write_Byte((x&0x0f)|0x01,OLED_CMD);
}

/********************
** OLED清屏操作
*********************/
void OLED_Clear(void)
{
    
    
    u8 i,n;
    for(i=0; i<8; i++)
    {
    
    
        OLED_Write_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
        OLED_Write_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
        OLED_Write_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
        for(n=0; n<128; n++)OLED_Write_Byte(0,OLED_DATA); // 每一列都置零
    }
}

下面使一些关于字符,图片,中文,数字,字符串展示的函数
关于图片,汉字的取模可以看我的另外一篇文章
oled汉字和图片取模教程

void OLED_Ascii_Test()
{
    
    
    u8 i,j;
    for(j=0; j<160; j++) {
    
    
        OLCD_Set_Pos(j*6%120,j/20); // 设置显示位置
        for(i=0; i<6; i++)
        {
    
    
            OLED_Write_Byte(F6x8[j%90][i],OLED_DATA);
        }
    }

}

/**************************************
** 显示一个字符
** x: 列坐标位置
** y: 页坐标位置
** chr: 待显示的字符
***************************************/
void OLED_Show_Char(u8 x, u8 y , u8 chr , enum Font_Size size)
{
    
    
    u8 i=0  ,c=0;
    c = chr - ' '; // 从空字符串算起,得到偏移后的值

    switch(size)
    {
    
    
    case SMALL:
        OLCD_Set_Pos(x,y); // 设置显示位置
        for(i=0; i< size ; i++)
            OLED_Write_Byte(F6x8[c][i],OLED_DATA);
        break;
    case MEDIA:
        OLCD_Set_Pos(x,y); // 设置显示位置
        for(i=0; i< 6 ; i++)
            OLED_Write_Byte(F12X6[c][i],OLED_DATA);
        OLCD_Set_Pos(x,y+1); // 设置显示位置
        for(i=6; i< 12 ; i++)
            OLED_Write_Byte(F12X6[c][i],OLED_DATA);
        break;
    case BIG:
        OLCD_Set_Pos(x,y); // 设置显示位置
        for(i=0; i< 8 ; i++)
            OLED_Write_Byte(F16x8[c][i],OLED_DATA);
        OLCD_Set_Pos(x,y+1); // 设置显示位置
        for(i=8; i< 16 ; i++)
            OLED_Write_Byte(F16x8[c][i],OLED_DATA);
        break;
    }
}

/****************************************
** 显示字符串
** x: 起始列坐标
** y: 起始页
** chr: 待显示的字符串
*****************************************/
void OLED_Show_String(u8 x, u8 y , char *chr , enum Font_Size size)
{
    
    
    u8 i = 0;
    u8 page =  (size>8 ? size >> 3 : 1 );  // 字体大小决定翻几页
    u8 len = (size>8 ? size >>1 : size ) ;   // 字体宽度,最后结果对应了字体表中的每行长度索引
    u8 limit = MAX_LEN/len - 1 ;
    while(chr[i] != '\0') {
    
    
        OLED_Show_Char(x,y,chr[i],size);
        x+=len; // 字体宽高 6*8
        if(x>(len*limit-1))    // 如果大于了极限值 128
        {
    
    
            x = 0 ;  //  列从零开始
            y += page;  //  另起一页
        }
        i ++ ;    // 循环继续,直到字符串都写完了为止
    }
}

/*********************************************************
** 自定义数字显示函数
** x: 列起始位置 0~(127-len) 取值从0到最后一个字符的起始位置
** y: 页起始位置 0~7
** num: 待显示的数字 0~9
** size: 字体大小枚举值
*********************************************************/
void OLED_Show_Num(u8 x, u8 y , u8 num , enum Num_Size size)
{
    
    
    u8 i,j ;
    u8 len = size >> 1 ;  // 字体宽度,这里直接处以2,因为字体宽度正好是高度的一半
    u8 page = size >> 3 ; // 这里处以8直接用移位操作,高度大于8就要翻页

    for(i = 0 ; i < page ; i ++)
    {
    
    
        OLCD_Set_Pos(x,y+i); // 设置显示位置
        switch(size)
        {
    
    
        case SMALL_NUM:
            for(j=0; j<len; j++)
                OLED_Write_Byte(N24x12[num*page + i][j],OLED_DATA);  // 写数据
            break;
        case MEDIA_NUM:
            for(j=0; j<len; j++)
                OLED_Write_Byte(N32x16[num*page + i][j],OLED_DATA);  // 写数据
            break;
        case BIG_NUM:
            for(j=0; j<len; j++)
                OLED_Write_Byte(N40x20[num*page + i][j],OLED_DATA);  // 写数据
            break;
        }
    }
}

/*********************************************************
** 自定义汉字显示函数
** x: 列起始位置 0~(127-len) 取值从0到最后一个字符的起始位置
** y: 页起始位置 0~7
** index: 待显示的汉字序号
** size: 字体大小枚举值
** reverse: 是否反显 1=是,0=否
*********************************************************/
void OLED_Show_Chinese(u8 x, u8 y , u8 index , enum Zh_Size size , u8 reverse)
{
    
    
    u8 i,j ;
    u8 len = size  ;  // 字体宽度,等于字体高度
    u8 page = size >> 3 ; // 这里处以8直接用移位操作,高度大于8就要翻页

    for(i = 0 ; i < page ; i ++)
    {
    
    
        OLCD_Set_Pos(x,y+i); // 设置显示位置
        switch(size)
        {
    
    
        case ZH16:
            for(j=0; j<len; j++)
                reverse?OLED_Write_Byte(~ZH16x16[index*page + i][j],OLED_DATA):OLED_Write_Byte(ZH16x16[index*page + i][j],OLED_DATA);  // 写数据
            break;
        case ZH32:
            for(j=0; j<len; j++)
                reverse?OLED_Write_Byte(~ZH32x32[index*page + i][j],OLED_DATA):OLED_Write_Byte(ZH32x32[index*page + i][j],OLED_DATA);  // 写数据
            break;
        }
    }
}

/*********************************************************
** 自定义图标显示
** x: 列起始位置 0~(127-len) 取值从0到最后一个字符的起始位置
** y: 页起始位置 0~7
** index: 待显示的图标序号,图标大小为16*16
*********************************************************/
void OLED_Show_Icon(u8 x, u8 y , u8 index)
{
    
    
    u8 i,j ;
    u8 len = 16  ;
    u8 page = 2 ;

    for(i = 0 ; i < page ; i ++)
    {
    
    
        OLCD_Set_Pos(x,y+i); // 设置显示位置
        for(j=0; j<len; j++)
            OLED_Write_Byte(ICON16[index*page + i][j],OLED_DATA);  // 写数据
    }
}
/*展示图片*/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
    
     	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
    
    
		OLCD_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	    {
    
          
	    	OLED_Write_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 

空心圆,实心圆,点,线,矩形的绘制

/*********************************************************************
**画点
x,y为坐标
t=1为亮,0为灭
pos为页
*********************************************************************/
void OLED_DrawDot(u8 x,u8 y,u8 t)
{
    
    
	    u8 pos,bx,temp=0;
		if(x>127||y>63) return;
	
		pos=(y)/8;
		bx=y%8;
		temp=1<<(bx);
	
		
	if(t){
    
    
		OLED_date[x][pos]|=temp;}
	else{
    
    
	OLED_date[x][pos]&=~temp;}
	OLCD_Set_Pos(x,pos);
	OLED_Write_Byte(OLED_date[x][pos],OLED_DATA);
	
}


void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2)
{
    
    
	uint16_t i,k,k1,k2;
	if((x2>128)||(y2>64)||(x1>x2)||(y1>y2))return;
	if(x1==x2)    //画竖线
	{
    
    
			for(i=0;i<(y2-y1);i++)
			{
    
    
				OLED_DrawDot(x1,y1+i,1);
			}
  }
	else if(y1==y2)   //画横线
	{
    
    
			for(i=0;i<(x2-x1);i++)
			{
    
    
				OLED_DrawDot(x1+i,y1,1);
			}
  }
	else      //画斜线
	{
    
    
		k1=y2-y1;
		k2=x2-x1;
		k=(uint16_t)k1*100/k2;
		for(i=0;i<(x2-x1);i++)
			{
    
    
			  OLED_DrawDot(x1+i,y1+i*k/1000,1);
			}
	}
}
//画方形;x:0~127 y:0~63
//x1,y1,左上角坐标;x2,y2,右下角坐标
void OLED_DrawSquare(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2)
{
    
    
	OLED_DrawLine(x1,y1,x2,y1);
	OLED_DrawLine(x1,y2,x2,y2);
	OLED_DrawLine(x1,y1,x1,y2);
	OLED_DrawLine(x2,y1,x2,y2);
}
/**********************************************************
date :1.26
author:  zs
优化,使圆能够连在一起
x,y:圆心坐标
r:圆的半径
***************************************************************/
//x,y:圆心坐标
//r:圆的半径
void OLED_Circle(uint8_t x,uint8_t y,uint8_t r)
{
    
    
	int a, b;
    a = 0;
    b = r;
    while(b>=0)      
    {
    
    
      OLED_DrawDot(x + a, y - b,1);
        OLED_DrawDot(x - a, y - b,1);
        OLED_DrawDot(x - a, y + b,1);
        OLED_DrawDot(x + a, y + b,1);
       
 			 OLED_DrawDot(x - b, y + a,1);
        OLED_DrawDot(x - b, y - a,1);
        OLED_DrawDot(x + b, y + a,1);
        OLED_DrawDot(x + b, y - a,1);
       
			if((a*a+b*b)>r*r)
			{
    
     b--;
			a--;
			}			
    a++;
       
    }
}

void OLED_fill_Circle(u8 x0,u8 y0,u8 r,u8 dot)//写画实心圆心(x0,y0),半径r
{
    
    	
		u8 x = 0,y = 0,R = 0;
		for(x = x0-r;x <= x0+r;x++){
    
    
			for(y = y0-r; y <= y0+r ;y++ ){
    
    
				R = sqrt(pow(r,2)-pow(x-x0,2))+y0; //圆方程  x,y反置		
				if( (y >= y0 && y <= R) || (y < y0 && y >= 2*y0-R )|| dot == 0 ) {
    
      //点限制在 圆方程内	
					OLED_DrawDot(x,y,dot);
				}	
			}
		}
}

最后是是显示界面滚动,通过写命令操作ssd1306驱动芯片

/************************************************************
** 滚动显示某一页
** start: 开始页 0 - 7
** end  : 结束页 0 - 7
** dirct:方向枚举,left向左,right向右
**************************************************************/
void OLED_horizontalroll_Display(u8 start,u8 end,enum DIRECTION dirct)
{
    
    
    if(start > 7 || end > 7) return; // 页码超出
    OLED_Write_Byte(0x2E ,OLED_CMD); // 关闭滚动
    OLED_Write_Byte(dirct,OLED_CMD); // 向左/右滚动
    OLED_Write_Byte(0x00 ,OLED_CMD); // 空制令
    OLED_Write_Byte(start,OLED_CMD); // 起始页
    OLED_Write_Byte(0x0F ,OLED_CMD); // 滚动间隔,0=不滚动,值越大,滚动越快
    OLED_Write_Byte(end  ,OLED_CMD); // 结束页
    OLED_Write_Byte(0x00 ,OLED_CMD); // 空指令
    OLED_Write_Byte(0xFF ,OLED_CMD); // 空指令,加两条空指令,不然不会生效
    OLED_Write_Byte(0x2F ,OLED_CMD); // 开启滚动
}
/*倾斜滚动,可以改角度,和速度,当倒数第二个命令改为0x00时,即角度为0,相当于只有左右滚动*/
void OLED_obliqueroll_Display(u8 start,u8 end,enum DIRECTION dirct){
    
    
				if(start >7 || end > 7) return;       
	      OLED_Write_Byte(0x2e,OLED_CMD);        //关闭滚动
        OLED_Write_Byte(dirct,OLED_CMD);        //水平垂直和水平滚动左右 29/2a
        OLED_Write_Byte(0x00,OLED_CMD);        //虚拟字节
        OLED_Write_Byte(start,OLED_CMD);        //起始页 0
        OLED_Write_Byte(0x07,OLED_CMD);        //滚动间隔,0=不滚动,值越大,滚动越快
        OLED_Write_Byte(end,OLED_CMD);        //终止页 1
        OLED_Write_Byte(0x01,OLED_CMD);        //垂直滚动偏移量(可修改角度)
        OLED_Write_Byte(0x2F,OLED_CMD);        //开启滚动
}
/*垂直滚动,因为没有直接的连续滚动,博主将滚动页设成了9页(超范围了),就可以为单一的垂直滚动*/
void OLED_verticalroll_Display(){
    
          
	      OLED_Write_Byte(0x2e,OLED_CMD);        //关闭滚动
        OLED_Write_Byte(0x2a,OLED_CMD);        //水平垂直和水平滚动左右 29/2a
        OLED_Write_Byte(0x00,OLED_CMD);        //虚拟字节
        OLED_Write_Byte(0x00,OLED_CMD);        //起始页 0
        OLED_Write_Byte(0x07,OLED_CMD);        //滚动时间间隔
        OLED_Write_Byte(0x08,OLED_CMD);        //终止页 1
        OLED_Write_Byte(0x01,OLED_CMD);        //滚动间隔,0=不滚动,值越大,滚动越快
        OLED_Write_Byte(0x2F,OLED_CMD);        //开启滚动
}

以上内容,经博主整理,改写和拓展,属实耗费了一些时间
如果看到这里觉得满意,请点赞,收藏。

一些字库,图库,太多,请下载下方工程
如还有不懂,可直接下载工程,对照
以下是工程链接
oled_spi显示

猜你喜欢

转载自blog.csdn.net/m0_52521883/article/details/113208833
今日推荐