SPI写OLED(软硬件切换)

1、SPI读写原理

还是一样的,关于屏幕资料,这里有个比较好的网站方便我们进行查阅 0.96inch SPI OLED Module

打开就可以看到我们需要的屏幕资料了

在这里插入图片描述
引脚说明
在这里插入图片描述
查看数据手册
在这里插入图片描述
写数据说明
在这里插入图片描述
翻译过来就是

SDIN 在 SCLK 的每个上升沿按 D7、D6、… DO.D/C# 的顺序移入一个 8 位移位寄存器每 8个时钟采样一次,移位寄存器中的数据字节在同一时钟写入图形显示数据 RAM (GDDRAM) 或命令寄存器。

写数据时序图
在这里插入图片描述
好了,有了这些在借鉴下前人的代码,基本就可以了!!

2、模拟SPI驱动

配置模拟SPI需要的引脚
在这里插入图片描述

编写SPI写数据函数
在这里插入图片描述
初始化函数
在这里插入图片描述
下面是清屏函数和更新显存函数
在这里插入图片描述
这里我们试下全屏读写,可以看到数完全OK的,这基本就说明我们驱动写的没什么问题了
在这里插入图片描述

然后之后就是移植代码了,说的简单点就是抄!!!

函数部分我都写好用法了,大部分都是放到显存然后我们调用显存来刷新
在这里插入图片描述
用法例如
在这里插入图片描述
将程序下载到开发板,效果如下
在这里插入图片描述

3、硬件SPI驱动

使用CUBEMX配置SPI
在这里插入图片描述
配置辅助引脚
在这里插入图片描述
修改驱动函数,这里不就是修改个写数据的函数吗
在这里插入图片描述
下面我们测试下写一张图片
在这里插入图片描述
将程序下载到开发板,效果如下
在这里插入图片描述

4、源码

oled.c

#include "oled.h"
#include "oled_font.h"

#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据



#define OLED_RES_LOW HAL_GPIO_WritePin(SPI_RES_GPIO_Port,SPI_RES_Pin,GPIO_PIN_RESET)
#define OLED_RES_HIGH HAL_GPIO_WritePin(SPI_RES_GPIO_Port,SPI_RES_Pin,GPIO_PIN_SET)

#define OLED_DC_LOW HAL_GPIO_WritePin(SPI_DC_GPIO_Port,SPI_DC_Pin,GPIO_PIN_RESET)
#define OLED_DC_HIGH HAL_GPIO_WritePin(SPI_DC_GPIO_Port,SPI_DC_Pin,GPIO_PIN_SET)

#define OLED_CS_LOW HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET)
#define OLED_CS_HIGH HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET)

uint8_t OLED_GRAM[128][8];//oled显存缓冲区

extern SPI_HandleTypeDef hspi1;




void OLED_WR_Byte(uint8_t data,uint8_t cmd)
{
    
    
	uint8_t *dat = &data;
	if(cmd)
		OLED_DC_HIGH;
	else
		OLED_DC_LOW;
  OLED_CS_LOW;
  HAL_SPI_Transmit(&hspi1, dat, sizeof(data), 1000);
  OLED_CS_HIGH;
  OLED_DC_HIGH;
}
//void OLED_WR_Byte(uint8_t data,uint8_t cmd)
//{
    
    
//	if(cmd)
//		OLED_DC_HIGH;
//	else
//		OLED_DC_LOW;
//
//	OLED_CS_LOW;
//
//	for(uint8_t i = 0;i<8;i++)
//	{
    
    
//		OLED_SCL_LOW;
//		if(data & 0x80)
//			OLED_SDA_HIGH;
//		else
//			OLED_SDA_LOW;
//		OLED_SCL_HIGH;
//		data <<= 1;
//	}
//	OLED_CS_HIGH;
//	OLED_DC_HIGH;
//}
//OLED的初始化
void OLED_Init(void)
{
    
    
	OLED_RES_LOW;
	HAL_Delay(200);
	OLED_RES_HIGH;

//	OLED_WR_Byte(0xAE, OLED_CMD);
//	OLED_WR_Byte(0x00, OLED_CMD);
//	OLED_WR_Byte(0x10, OLED_CMD);
//	OLED_WR_Byte(0x40, OLED_CMD);
//	OLED_WR_Byte(0x81, OLED_CMD);
//	OLED_WR_Byte(0xCF, OLED_CMD);
//	OLED_WR_Byte(0xA1, OLED_CMD);
//	OLED_WR_Byte(0xC8, OLED_CMD);
//	OLED_WR_Byte(0xA6, OLED_CMD);
//	OLED_WR_Byte(0xA8, OLED_CMD);
//	OLED_WR_Byte(0x3f, OLED_CMD);
//	OLED_WR_Byte(0xD3, OLED_CMD);
//	OLED_WR_Byte(0x00, OLED_CMD);
//	OLED_WR_Byte(0xd5, OLED_CMD);
//	OLED_WR_Byte(0x80, OLED_CMD);
//	OLED_WR_Byte(0xD9, OLED_CMD);
//	OLED_WR_Byte(0xF1, OLED_CMD);
//	OLED_WR_Byte(0xDA, OLED_CMD);
//	OLED_WR_Byte(0x12, OLED_CMD);
//	OLED_WR_Byte(0xDB, OLED_CMD);
//	OLED_WR_Byte(0x40, OLED_CMD);
//	OLED_WR_Byte(0x20, OLED_CMD);
//	OLED_WR_Byte(0x02, OLED_CMD);
//	OLED_WR_Byte(0x8D, OLED_CMD);
//	OLED_WR_Byte(0x14, OLED_CMD);
//	OLED_WR_Byte(0xA4, OLED_CMD);
//	OLED_WR_Byte(0xA6, OLED_CMD);
//	OLED_WR_Byte(0xAF, OLED_CMD);

	// 也可以用下面的写法
	const uint8_t oledcmd[]={
    
    0XAE,0X00,0X10,0X40,0X81,0XCF,0XA1,0XC8,0XA6,0XA8,0X3F,0XD3,0X00,0XD5,0X80,
							0XD9,0XF1,0XDA,0X12,0XDB,0X40,0X20,0X02,0X8D,0X14,0XA4,0XA6,0XAF,0XAF,0XAF};
	for(uint8_t i=0;i<sizeof(oledcmd);i++)
	{
    
    
		OLED_WR_Byte(oledcmd[i],OLED_CMD);
		HAL_Delay(1);
	}
	OLED_Clear();
}
//OLED反色显示
void OLED_ColorTurn(uint8_t i)
{
    
    
  if(i == 0)
  {
    
    
    OLED_WR_Byte(0xA6, OLED_CMD); //正常显示
  }
  if(i == 1)
  {
    
    
    OLED_WR_Byte(0xA7, OLED_CMD); //反色显示
  }
}
//OLED屏幕旋转180
void OLED_DisplayTurn(uint8_t i)
{
    
    
  if(i == 0)
  {
    
    
    OLED_WR_Byte(0xC8, OLED_CMD); //正常显示
    OLED_WR_Byte(0xA1, OLED_CMD);
  }
  if(i == 1)
  {
    
    
    OLED_WR_Byte(0xC0, OLED_CMD); //旋转180度显示
    OLED_WR_Byte(0xA0, OLED_CMD);
  }
}
//开启OLED显示
void OLED_DisPlay_On(void)
{
    
    
	OLED_WR_Byte(0x8D, OLED_CMD); //电荷泵使能
	OLED_WR_Byte(0x14, OLED_CMD); //开启电荷泵
	OLED_WR_Byte(0xAF, OLED_CMD); //点亮屏幕
}
//关闭OLED显示
void OLED_DisPlay_Off(void)
{
    
    
	OLED_WR_Byte(0x8D, OLED_CMD); //电荷泵使能
	OLED_WR_Byte(0x10, OLED_CMD); //关闭电荷泵
	OLED_WR_Byte(0xAF, OLED_CMD); //关闭屏幕
}
//更新显存到OLED
void OLED_Refresh(void)
{
    
    
	uint8_t i, n;
	for (i = 0; i < 8; i++)
	{
    
    
		OLED_WR_Byte(0xb0 + i, OLED_CMD); //设置行起始地址
		OLED_WR_Byte(0x00, OLED_CMD);	  //设置低列起始地址
		OLED_WR_Byte(0x10, OLED_CMD);	  //设置高列起始地址
		for (n = 0; n < 128; n++)
			OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
	}
}
//清屏函数
void OLED_Clear(void)
{
    
    
	uint8_t i, n;
	for (i = 0; i < 8; i++)
	{
    
    
		for (n = 0; n < 128; n++)
		{
    
    
			OLED_GRAM[n][i] = 0xff; //全屏点亮
			OLED_GRAM[n][i] = 0; //清除所有数据
		}
	}
	OLED_Refresh(); //更新显示
}
/*******************************
 * 函数名称 画点
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3
 * 返回值
 ******************************/
void OLED_DrawPoint(uint8_t x, uint8_t y)
{
    
    
	uint8_t i, m, n;
	i = y / 8;
	m = y % 8;
	n = 1 << m;
	OLED_GRAM[x][i] |= n;
}
/*******************************
 * 函数名称 清除点
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3
 * 返回值
 ******************************/
void OLED_ClearPoint(uint8_t x, uint8_t y)
{
    
    
	uint8_t i, m, n;
	i = y / 8;
	m = y % 8;
	n = 1 << m;
	OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
	OLED_GRAM[x][i] |= n;
	OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
}
/*******************************
 * 函数名称 画线
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3
 * 返回值
 ******************************/
void OLED_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
    
    
	uint8_t i, k, k1, k2;
	if (x1 == x2) //画竖线
	{
    
    
		for (i = 0; i < (y2 - y1); i++)
		{
    
    
			OLED_DrawPoint(x1, y1 + i);
		}
	}
	else if (y1 == y2) //画横线
	{
    
    
		for (i = 0; i < (x2 - x1); i++)
		{
    
    
			OLED_DrawPoint(x1 + i, y1);
		}
	}
	else //画斜线
	{
    
    
		k1 = y2 - y1;
		k2 = x2 - x1;
		k = k1 * 10 / k2;
		for (i = 0; i < (x2 - x1); i++)
		{
    
    
			OLED_DrawPoint(x1 + i, y1 + i * k / 10);
		}
	}
}
/*******************************
 * 函数名称 画圆
 * 参数1 圆心x坐标(0-128)
 * 参数2 圆心y坐标(0-63)
 * 参数3
 * 返回值
 ******************************/
void OLED_DrawCircle(uint8_t x, uint8_t y, uint8_t r)
{
    
    
	int a, b, num;
	a = 0;
	b = r;
	while (2 * b * b >= r * r)
	{
    
    
		OLED_DrawPoint(x + a, y - b);
		OLED_DrawPoint(x - a, y - b);
		OLED_DrawPoint(x - a, y + b);
		OLED_DrawPoint(x + a, y + b);

		OLED_DrawPoint(x + b, y + a);
		OLED_DrawPoint(x + b, y - a);
		OLED_DrawPoint(x - b, y - a);
		OLED_DrawPoint(x - b, y + a);
		a++;
		num = (a * a + b * b) - r * r; //计算画的点离圆心的距离
		if (num > 0)
		{
    
    
			b--;
			a--;
		}
	}
}
/*******************************
 * 函数名称 单个字符显示
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3 字符值
 * 参数4 字符大小 12/16/24
 * 返回值
 ******************************/
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size1)
{
    
    
	uint8_t i, m, temp, size2, chr1;
	uint8_t y0 = y;
	size2 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * (size1 / 2); //得到字体一个字符对应点阵集所占的字节数
	chr1 = chr - ' ';										   //计算偏移后的值
	for (i = 0; i < size2; i++)
	{
    
    
		if (size1 == 12)
		{
    
    
			temp = asc2_1206[chr1][i]; //调用1206字体
		}
		else if (size1 == 16)
		{
    
    
			temp = asc2_1608[chr1][i]; //调用1608字体
		}
		else if (size1 == 24)
		{
    
    
			temp = asc2_2412[chr1][i]; //调用2412字体
		}
		else
			return;
		for (m = 0; m < 8; m++) //写入数据
		{
    
    
			if (temp & 0x80)
				OLED_DrawPoint(x, y);
			else
				OLED_ClearPoint(x, y);
			temp <<= 1;
			y++;
			if ((y - y0) == size1)
			{
    
    
				y = y0;
				x++;
				break;
			}
		}
	}
}
/*******************************
 * 函数名称 字符串显示
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3 字符大小 12/16/24
 * 返回值
 ******************************/
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t size1)
{
    
    
	while ((*chr >= ' ') && (*chr <= '~')) //判断是不是非法字符!
	{
    
    
		OLED_ShowChar(x, y, *chr, size1);
		x += size1 / 2;
		if (x > 128 - size1) //换行
		{
    
    
			x = 0;
			y += 2;
		}
		chr++;
	}
}
/*******************************
 * 函数名称 次方函数(c语言没有专门的次方函数)
 * 参数1
 * 返回值
 ******************************/
uint32_t OLED_Pow(uint8_t m, uint8_t n)
{
    
    
	uint32_t result = 1;
	while (n--)
	{
    
    
		result *= m;
	}
	return result;
}
/*******************************
 * 函数名称 数字显示
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3 数值
 * 参数4 数字长度
 * 参数5 数字大小 12/16/24
 * 返回值
 ******************************/
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size1)
{
    
    
	uint8_t t, temp;
	for (t = 0; t < len; t++)
	{
    
    
		temp = (num / OLED_Pow(10, len - t - 1)) % 10;
		if (temp == 0)
		{
    
    
			OLED_ShowChar(x + (size1 / 2) * t, y, '0', size1);
		}
		else
		{
    
    
			OLED_ShowChar(x + (size1 / 2) * t, y, temp + '0', size1);
		}
	}
}
/*******************************
 * 函数名称 汉字显示
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-63)
 * 参数3 汉字对应的序号
 * 参数4 汉字大小
 * 返回值
 ******************************/
void OLED_ShowChinese(uint8_t x, uint8_t y, uint8_t num, uint8_t size1)
{
    
    
	uint8_t i, m, n = 0, temp, chr1;
	uint8_t x0 = x, y0 = y;
	uint8_t size3 = size1 / 8;
	while (size3--)
	{
    
    
		chr1 = num * size1 / 8 + n;
		n++;
		for (i = 0; i < size1; i++)
		{
    
    
			if (size1 == 16)
			{
    
    
				temp = Hzk1[chr1][i]; //调用16*16字体
			}
			else if (size1 == 24)
			{
    
    
				temp = Hzk2[chr1][i]; //调用24*24字体
			}
			else if (size1 == 32)
			{
    
    
				temp = Hzk3[chr1][i]; //调用32*32字体
			}
			else if (size1 == 64)
			{
    
    
				temp = Hzk4[chr1][i]; //调用64*64字体
			}
			else
				return;

			for (m = 0; m < 8; m++)
			{
    
    
				if (temp & 0x01)
					OLED_DrawPoint(x, y);
				else
					OLED_ClearPoint(x, y);
				temp >>= 1;
				y++;
			}
			x++;
			if ((x - x0) == size1)
			{
    
    
				x = x0;
				y0 = y0 + 8;
			}
			y = y0;
		}
	}
}
void OLED_WR_BP(uint8_t x, uint8_t y)
{
    
    
	OLED_WR_Byte(0xb0 + y, OLED_CMD); //设置行起始地址
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
	OLED_WR_Byte((x & 0x0f), OLED_CMD);
}
/*******************************
 * 函数名称 写入图片
 * 参数1 x坐标(0-128)
 * 参数2 y坐标(0-8)
 * 参数3 x坐标(0-128)
 * 参数4 y坐标(0-8)
 * 返回值
 ******************************/
void OLED_ShowPicture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[])
{
    
    
	uint32_t j = 0;
	uint8_t x = 0, y = 0;
	if (y % 8 == 0)
		y = 0;
	else
		y += 1;
	for (y = y0; y < y1; y++)
	{
    
    
		OLED_WR_BP(x0, y);
		for (x = x0; x < x1; x++)
		{
    
    
			OLED_WR_Byte(BMP[j], OLED_DATA);
			j++;
		}
	}
}

oled.h

#ifndef OLED_H_
#define OLED_H_

#include "main.h"

void OLED_ColorTurn(uint8_t i);
void OLED_DisplayTurn(uint8_t i);
void OLED_ClearPoint(uint8_t x,uint8_t y);
void OLED_WR_Byte(uint8_t dat,uint8_t cmd);
void OLED_DisPlay_On(void);
void OLED_DisPlay_Off(void);
void OLED_Refresh(void);
void OLED_Clear(void);
void OLED_DrawPoint(uint8_t x,uint8_t y);
void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2);
void OLED_DrawCircle(uint8_t x,uint8_t y,uint8_t r);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1);
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1);
void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t num,uint8_t size1);
void OLED_WR_BP(uint8_t x,uint8_t y);
void OLED_ShowPicture(uint8_t x0,uint8_t y0,uint8_t x1,uint8_t y1,uint8_t BMP[]);
void OLED_Init(void);

猜你喜欢

转载自blog.csdn.net/m0_51220742/article/details/123564015
今日推荐