还是一样的,关于屏幕资料,这里有个比较好的网站方便我们进行查阅 0.96inch SPI OLED Module
打开就可以看到我们需要的屏幕资料了
SDIN 在 SCLK 的每个上升沿按 D7、D6、… DO.D/C# 的顺序移入一个 8 位移位寄存器每 8个时钟采样一次,移位寄存器中的数据字节在同一时钟写入图形显示数据 RAM (GDDRAM) 或命令寄存器。
写数据时序图
好了,有了这些在借鉴下前人的代码,基本就可以了!!
编写SPI写数据函数
初始化函数
下面是清屏函数和更新显存函数
这里我们试下全屏读写,可以看到数完全OK的,这基本就说明我们驱动写的没什么问题了
然后之后就是移植代码了,说的简单点就是抄!!!
函数部分我都写好用法了,大部分都是放到显存然后我们调用显存来刷新
用法例如
将程序下载到开发板,效果如下
使用CUBEMX配置SPI
配置辅助引脚
修改驱动函数,这里不就是修改个写数据的函数吗
下面我们测试下写一张图片
将程序下载到开发板,效果如下
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);