SPI写OLED(软硬件切换)

文章目录

    • 1、SPI读写原理
    • 2、模拟SPI驱动
    • 3、硬件SPI驱动
    • 4、源码

1、SPI读写原理

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

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

SPI写OLED(软硬件切换)_第1张图片
引脚说明
SPI写OLED(软硬件切换)_第2张图片
查看数据手册
SPI写OLED(软硬件切换)_第3张图片
写数据说明
在这里插入图片描述
翻译过来就是

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

写数据时序图
SPI写OLED(软硬件切换)_第4张图片
好了,有了这些在借鉴下前人的代码,基本就可以了!!

2、模拟SPI驱动

配置模拟SPI需要的引脚
SPI写OLED(软硬件切换)_第5张图片

编写SPI写数据函数
SPI写OLED(软硬件切换)_第6张图片
初始化函数
SPI写OLED(软硬件切换)_第7张图片
下面是清屏函数和更新显存函数
SPI写OLED(软硬件切换)_第8张图片
这里我们试下全屏读写,可以看到数完全OK的,这基本就说明我们驱动写的没什么问题了
SPI写OLED(软硬件切换)_第9张图片

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

函数部分我都写好用法了,大部分都是放到显存然后我们调用显存来刷新
SPI写OLED(软硬件切换)_第10张图片
用法例如
SPI写OLED(软硬件切换)_第11张图片
将程序下载到开发板,效果如下
SPI写OLED(软硬件切换)_第12张图片

3、硬件SPI驱动

使用CUBEMX配置SPI
SPI写OLED(软硬件切换)_第13张图片
配置辅助引脚
SPI写OLED(软硬件切换)_第14张图片
修改驱动函数,这里不就是修改个写数据的函数吗
SPI写OLED(软硬件切换)_第15张图片
下面我们测试下写一张图片
SPI写OLED(软硬件切换)_第16张图片
将程序下载到开发板,效果如下
SPI写OLED(软硬件切换)_第17张图片

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);

你可能感兴趣的:(单片机学习记录,stm32,单片机,arm,c语言,嵌入式硬件)