六、stm32-OLED
目录
- 一、固件库模板
- 二、准备资料
- 三、OLED简介
- 1. OLED引脚
- 2. OLED屏幕像素与GDDRAM (Graphic Display Data RAM)
- 3. OLED屏幕原理
- 4. OLED屏幕指令
- 5. 字模软件的使用(软件链接)
- 四、OLED显示实验(模拟IIC、硬件IIC)
- 1.硬件设计
- 2.软件设计
- 2.1 复制工程 ([stm32f103c8t6新建固件库模板(可自取)](https://blog.csdn.net/weixin_55999942/article/details/126022602?spm=1001.2014.3001.5502))
- 2.2 新建oled文件(打开工程)
- 2.3 编写代码
- oled.c(模拟IIC)
- oled.h(模拟IIC)
- oledfont.h
- oled(硬件IIC)
- main.c
- 3. 编译
- 4. 选择烧录工具并配置MDK
- 5. 成品
- 工程链接
一、固件库模板
见博客:stm32f103c8t6新建固件库模板(可自取)
二、准备资料
- 固件库模板
- MDK5开发环境
- IIC协议
- OLED 数据手册及实物
- 字模软件
实验程序已经发布到百度网盘,本文末有链接可以自取
IIC协议查看这篇博客IIC协议
数据手册查看SSD1306Z
字模链接 链接:https://pan.baidu.com/s/1k_ay03xnAdGChirlTpTIVA
提取码:OLED
三、OLED简介
OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术。
OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。
常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为128*64,所以我们称为0.96oled屏或者12864屏。

这类屏幕大部分是由SSD1306来驱动的,查看数据手册在这:SSD1306Z
1. OLED引脚
| 标号 | PIN | 引脚说明 |
|---|---|---|
| 1 | GND | OLED显示模块电源地 |
| 2 | VCC | OLED显示模块电源正 |
| 3 | SCL | OLED显示模块I2C总线时钟信号 |
| 4 | SDA | OLED显示模块I2C总线数据信号 |
2. OLED屏幕像素与GDDRAM (Graphic Display Data RAM)
屏幕有128列(Column ),64行(Row),共128*64像素点,每8行为1页(PAGE),共有8页

3. OLED屏幕原理
STM32内部建立一个缓存(共128*8个字节),每次修改的时候,只是修改STM32上的缓存(静态随机存储器 SRAM),修改完后一次性把STM32上的缓存数据写入到OLED的GRAM。
这个方法也有坏处,对于SRAM很小的单片机(51系列)就比较麻烦。
4. OLED屏幕指令
这个写的很详细,建议看看
https://wlink.blog.csdn.net/article/details/81329770
5. 字模软件的使用(软件链接)
OLED点阵的点亮方式,举个显示”P”的例子,最左边位最高位P7。
这个图画错了从下到上应该是8个点,他画了9个点。从下至上第2个点开始。

-
可以看出,要想显示”P”,首先写入0x1f,则显示一个竖杠,之后控制器自动水平移动到下一列。
-
再写入0X05,则出现两个小横杆,这个两个横杆就是0X05中0000 0101中两个1所处的位置,写完第二列后,控制器自动跳到第三列.
-
再写入0X07,第四列写入0X00后,P就显示出来了。这也说明,即使你只想再一列的最上端显示一个小点,即写入0X01。
-
即你不能一次性控制一个点阵,只能一次性控制八位点阵,即一列点阵。这也决定了字模选择的取模方式为“列行式”。
链接:https://pan.baidu.com/s/1k_ay03xnAdGChirlTpTIVA
提取码:OLED


四、OLED显示实验(模拟IIC、硬件IIC)
1.硬件设计
GND接GND
VCC接3.3
OLED的SCL接stm32的B8(模拟IIC)
OLED的SDA接stm32的B9(模拟IIC)
硬件IIC请查看IIC协议
2.软件设计
-
配置通讯使用的目标引脚为开漏模式;
-
使能 I2C 外设的时钟;
-
配置 I2C 外设的模式、地址、速率等参数并使能 I2C 外设;
-
编写向OLED写入函数;
-
编写OLED初始化指令
2.1 复制工程 (stm32f103c8t6新建固件库模板(可自取))
2.2 新建oled文件(打开工程)



2.3 编写代码
oled.c(模拟IIC)
切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"//起始信号
void I2C_Start(void)
{OLED_SDIN_Set();OLED_SCLK_Set();OLED_SDIN_Clr();OLED_SCLK_Clr();
}//结束信号
void I2C_Stop(void)
{OLED_SCLK_Set();OLED_SDIN_Clr();OLED_SDIN_Set();
}//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{OLED_SCLK_Set();OLED_SCLK_Clr();
}//写入一个字节
void Send_Byte(u8 dat)
{u8 i;for(i = 0; i < 8; i++){OLED_SCLK_Clr();//将时钟信号设置为低电平if(dat & 0x80) //将dat的8位从最高位依次写入{OLED_SDIN_Set();}else{OLED_SDIN_Clr();}OLED_SCLK_Set();//将时钟信号设置为高电平OLED_SCLK_Clr();//将时钟信号设置为低电平dat <<= 1;}
}//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat, u8 mode)
{I2C_Start();Send_Byte(0x78);I2C_WaitAck();if(mode){Send_Byte(0x40);}else{Send_Byte(0x00);}I2C_WaitAck();Send_Byte(dat);I2C_WaitAck();I2C_Stop();
}uint8_t CMD_Data[] =
{0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,0xD8, 0x30, 0x8D, 0x14, 0xAF
}; //初始化命令/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:15
* @brief: 写入初始化命令
* @return: None
********************************************************************************/
void Write_Cmd(void)
{int i;for (i = 0; i < 27; i++){OLED_WR_Byte(CMD_Data[i], OLED_CMD); //SET DCDC命令}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:19
* @brief: 向设备写控制命令
* @param: cmd
* @return: None
********************************************************************************/
void OLED_WR_CMD(uint8_t cmd)
{OLED_WR_Byte(cmd, OLED_CMD); //SET DCDC命令
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:35
* @brief: 写数据
* @param: data
* @return: None
********************************************************************************/
void OLED_WR_DATA(uint8_t data)
{OLED_WR_Byte(data, OLED_DATA); //SET DCDC命令
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:32
* @brief: 清屏
* @param: None
* @return: None
********************************************************************************/
void OLED_Clear(void)
{uint8_t i, n;for (i = 0; i < 27; i++){OLED_WR_CMD(0xb0 + i);OLED_WR_CMD(0x00);OLED_WR_CMD(0x10);for (n = 0; n < 128; n++){OLED_WR_DATA(0);}}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:59
* @brief: 开启OLed显示
* @param: None
* @return: None
********************************************************************************/
void OLED_Display_On(void)
{OLED_WR_CMD(0x8D); //SET DCDC设置电荷泵OLED_WR_CMD(0x14); //DCDC ON 开启电荷泵OLED_WR_CMD(0xAF); //DISPlay ON开启显示
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 16:36
* @brief: 关闭OLED显示
* @param:
* @return:
********************************************************************************/
void OLED_Display_Off(void)
{OLED_WR_CMD(0x8D); //SET DCDC设置电荷泵OLED_WR_CMD(0x10); //DCDC OFF 开启电荷泵OLED_WR_CMD(0xAE); //DISPlay OFF开启显示
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 16:33
* @brief: 设置起始点坐标
* @param: x,y
* @return: None
********************************************************************************/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{OLED_WR_CMD(0xb0 + y);OLED_WR_CMD(((x & 0xf0) >> 4) | 0x10);OLED_WR_CMD(x & 0x0f);
}void OLED_On(void)
{uint8_t i, n;for (i = 0; i < 8; i++){OLED_WR_CMD(0xb0 + i); //设置页地址OLED_WR_CMD(0x00); //设置显示位置-列低地址OLED_WR_CMD(0x10); //设置显示位置-列高地址for (n = 0; n < 128; n++){OLED_WR_DATA(1);}//刷新显示}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-03 15:35
* @brief: n为循环次数,得到值为m的n+1次方
* @param m
* @param n
* @return result
********************************************************************************/
unsigned int oled_pow(uint8_t m, uint8_t n)
{unsigned int result = 1;while (n--)result *= m;return result;
}//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x, uint8_t y, unsigned int num, uint8_t len, uint8_t size2)
{uint8_t t, temp;uint8_t enshow = 0;for (t = 0; t < len; t++){temp = (num / oled_pow(10, len - t - 1)) % 10;if (enshow == 0 && t < (len - 1)){if (temp == 0){OLED_ShowChar(x + (size2 / 2) * t, y, ' ', size2);continue;}else enshow = 1;}OLED_ShowChar(x + (size2 / 2) * t, y, temp + '0', size2);}
}//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
{unsigned char c = 0, i = 0;c = chr - ' ';//得到偏移后的值if (x > 128 - 1){x = 0;y = y + 2;}if (Char_Size == 16){OLED_Set_Pos(x, y);for (i = 0; i < 8; i++)OLED_WR_DATA(F8X16[c * 16 + i]);OLED_Set_Pos(x, y + 1);for (i = 0; i < 8; i++)OLED_WR_DATA(F8X16[c * 16 + i + 8]);}else{OLED_Set_Pos(x, y);for (i = 0; i < 6; i++)OLED_WR_DATA(F6x8[c][i]);}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-03 15:02
* @brief: 显示一个字符号串
* @param x
* @param y
* @param chr
* @param Char_Size
* @return: None
********************************************************************************/
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size)
{unsigned char j = 0;while (chr[j] != '\0'){OLED_ShowChar(x, y, chr[j], Char_Size);x += 8;//如果--行显示的数字大于16就将行清零,y+2变成下一行if (x > 120){x = 0;y += 2;}j++;}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-03 14:46
* @brief: 显示汉字 hzk 用取模软件得出的数组
* @param x,设置起始点x坐标
* @param y,设置起始点y坐标
* @param no,显示数组的第n个字
* @return:
********************************************************************************/
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no)
{uint8_t t, adder = 0;OLED_Set_Pos(x, y);//显示上面一部分for (t = 0; t < 16; t++){//Hzk[第几个数组][第几个值]OLED_WR_DATA(Hzk[2 * no][t]);adder += 1;}//显示下面一部分OLED_Set_Pos(x, y + 1);for (t = 0; t < 16; t++){OLED_WR_DATA(Hzk[2 * no + 1][t]);adder += 1;}
}/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:38
* @brief: 初始化oled屏幕
* @param: None
* @return: None
********************************************************************************/
void OLED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( OLED_CLK, ENABLE );GPIO_InitStructure.GPIO_Pin = OLED_SCLK_Pin | OLED_SDIN_Pin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(OLED_PORT, &GPIO_InitStructure);Delay_ms(100);Write_Cmd();OLED_Clear();
}
oled.h(模拟IIC)
/************************************ Copyright ************************************ (C) Copyright 2022-2022 xxx,China.** All Rights Reserved.*********************************************************************************--------------------------------------------------------------------------**** @FileName : oled.h** @Description : None**--------------------------------------------------------------------------**** @Author : Luo Chen** @Version : v1.0** @Creat Date : 2022-07-16**--------------------------------------------------------------------------**** @Modfier : None** @Version : None** @Modify Date : None** @Description : None**--------------------------------------------------------------------------**** @Function List : None**--------------------------------------------------------------------------**** @Attention : None**--------------------------------------------------------------------------***********************************************************************************//* Define to prevent recursive inclusion -------------------------------------*/#ifndef __OLED_H_
#define __OLED_H_#include "stm32f10x.h"#include "sys.h"
#include "stdlib.h"
////-----------------OLED端口定义----------------#define OLED_SCLK_Pin GPIO_Pin_8
#define OLED_SDIN_Pin GPIO_Pin_9
#define OLED_CLK RCC_APB2Periph_GPIOB
#define OLED_PORT GPIOB#define OLED_SCLK_Clr() GPIO_ResetBits(OLED_PORT,OLED_SCLK_Pin)
#define OLED_SCLK_Set() GPIO_SetBits(OLED_PORT,OLED_SCLK_Pin)//SCL#define OLED_SDIN_Clr() GPIO_ResetBits(OLED_PORT,OLED_SDIN_Pin)//DIN
#define OLED_SDIN_Set() GPIO_SetBits(OLED_PORT,OLED_SDIN_Pin)#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据void I2C_Start(void);
void I2C_Stop(void);
void I2C_WaitAck(void);
void Send_Byte(u8 dat);
void OLED_WR_Byte(u8 dat, u8 mode);
void Write_Cmd(void);
void OLED_WR_CMD(uint8_t cmd);
void OLED_WR_DATA(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_On(void);
void OLED_ShowNum(uint8_t x, uint8_t y, unsigned int num, uint8_t len, uint8_t size2);
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size);
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size);
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no);#endif/******************************** END OF FILE *********************************/
oledfont.h
{0x04,0x24,0x44,0x84,0x64,0x9C,0x40,0x30,0x0F,0xC8,0x08,0x08,0x28,0x18,0x00,0x00},
{0x10,0x08,0x06,0x01,0x82,0x4C,0x20,0x18,0x06,0x01,0x06,0x18,0x20,0x40,0x80,0x00},/*"欢",0*/{0x40,0x40,0x42,0xCC,0x00,0x00,0xFC,0x04,0x02,0x00,0xFC,0x04,0x04,0xFC,0x00,0x00},
{0x00,0x40,0x20,0x1F,0x20,0x40,0x4F,0x44,0x42,0x40,0x7F,0x42,0x44,0x43,0x40,0x00},/*"迎",1*/{0x00,0x08,0x08,0x28,0xC8,0x08,0x08,0xFF,0x08,0x08,0x88,0x68,0x08,0x08,0x00,0x00},
{0x21,0x21,0x11,0x11,0x09,0x05,0x03,0xFF,0x03,0x05,0x09,0x11,0x11,0x21,0x21,0x00},/*"来",2*/{0x42,0x62,0x52,0x4A,0xC6,0x42,0x52,0x62,0xC2,0x00,0xF8,0x00,0x00,0xFF,0x00,0x00},
{0x40,0xC4,0x44,0x44,0x7F,0x24,0x24,0x24,0x20,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00},/*"到",3*/{0x10,0x60,0x02,0x8C,0x00,0x10,0x08,0x14,0xA7,0x44,0xA4,0x14,0x0C,0x00,0x00,0x00},
{0x04,0x04,0x7E,0x01,0x02,0x02,0xFD,0x45,0x44,0x44,0x44,0x45,0xFD,0x02,0x02,0x00},/*"洛",4*/{0x00,0x40,0x20,0x10,0x0C,0x00,0x00,0x7F,0x00,0x00,0x04,0x08,0x10,0x60,0x00,0x00},
{0x40,0x40,0x44,0x44,0x44,0x44,0x44,0x7F,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00},/*"尘",5*/{0x00,0xF8,0x0C,0x0B,0x08,0x08,0xF8,0x40,0x30,0x8F,0x08,0x08,0x08,0xF8,0x00,0x00},
{0x00,0x7F,0x21,0x21,0x21,0x21,0x7F,0x00,0x00,0x00,0x43,0x80,0x40,0x3F,0x00,0x00},/*"的",6*/{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},/*"C",7*/{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},/*"S",8*/{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},/*"D",9*/{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},/*"N",10*/
oled(硬件IIC)
oled.c已经写好(可能会有小问题哦),现在可以给自己一个小难度,自己整合main.c,实现显示
链接:https://pan.baidu.com/s/152-9TrB_QuYDivIrDiCwTA
提取码:0000
main.c
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "stm32f10x.h"
#include "oled.h"int main()
{/********************************************************************************* Delay_init(); //本实验使用的是SysTick时钟* CPU_TS_TmrInit(); //已经使能宏,不需要初始化* uart1_init(115200); //串口初始化为115200,需要在usart.h中使能* uart3_init(115200); //串口初始化为115200********************************************************************************//* 初始化 */OLED_Init();OLED_Clear();OLED_ShowString(30, 0, "OLED", 16); //输出字符OLED_ShowCHinese(0, 4, 0); //欢OLED_ShowCHinese(16, 4, 1); //迎OLED_ShowCHinese(32, 4, 2); //来OLED_ShowCHinese(48, 4, 3); //到OLED_ShowCHinese(64, 4, 4); //洛OLED_ShowCHinese(80, 4, 5); //尘OLED_ShowCHinese(96, 4, 6); //的OLED_ShowString (0, 6,"CSDN",16);while(1){}
}
3. 编译
编译成功

4. 选择烧录工具并配置MDK
本文选择的是ST_Link烧录工具


如果没有ID号看博客:ST-Link V2烧录问题(已解决)


5. 成品

工程链接
链接:https://pan.baidu.com/s/103fBiqMb3REZwn1tGnOgMA 提取码:OLED
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
