8-OLED屏幕

OLED屏幕

同样的oled屏幕也连接在I2C1总线上。

屏幕驱动芯片用来操控屏幕上的8000个小灯的亮灭

常见的CH1116芯片和SSD1306芯片都可以驱动128X64的OLED屏幕

其工作原理:

将整块屏幕划分为了8个page,或者我们称其为页

在这里插入图片描述

比如芯片通过I2C通信,将第0页第3列设置为0xC1 (1100 0001)

在这里插入图片描述

则会按低位到高位依次点亮为1的像素,使其亮起

CH1116的I2C地址为0x7A即OLED_ADDRESS

1.指令

0x7A 0x00 0xXX (0xXX为要发送的指令)

如何设置页地址和列地址

​ 将页地址设置为0 ,指令最后一位为0xB0

​ 将页地址设置为7 ,指令最后一位为0xB7

设置列地址的指令则分为两次(列地址0-128)

​ 将列地址设置为90 ,即0x5A,则要发送指令0x0A将列地址低4位设置为A,然后发送指令0x15将列地址高4位设置为5

2.数据

0x7A 0x40 0xXX 0xXX (0xXX为任意数量的数据)即控制小灯的亮灭数据。

比如0x7A 0x40 0x01 0x02 0x03

发送

第一个数据为0x01 控制指令所设置的页地址和列地址上的小灯亮灭设置为00000001,即最低位亮起,并将列地址自动加1,接着读取第二个数据。

第二个数据为0x02 小灯亮灭设置为00000010 第2位上亮起并将列地址自动加1接着读取第3个数据

第三个数据为0x03 以此类推。

在这里插入图片描述

用指令设置第0页第0列,发送128个显示数据,就可以控制第一页

整页的像素设置。

接着将也地址递增,如此循环8次,就可以完成整个屏幕的像素设置。

控制OLED的步骤:

1.在这里插入图片描述

因为要发送控制屏幕亮灭的数据,需要设置I2C的速度模式改为Fast Mode。

在这里插入图片描述

I2C的速度从100k hz 提升到了 400K hz

同时可以使用开发板上额外准备的外部晶振给STM32提速。

在这里插入图片描述

在这里插入图片描述

确定后稍等片刻,cubeMX就自动将时钟源切换到了外部晶振。实现了72MHz的时钟频率(时钟树相关知识。)

在这里插入图片描述

为每个外设单独生成.c/.h 文件

接着,像AHT20一样为oled单独创建.c & .h文件并在oled.c中include “i2c.h”

1.点亮屏幕

oled.c中

#include"oled.h"

#define OLED_ADRESS 0x7A   //通信地址:0x7A


void OLED_SendCmd(uint8_t data){

	uint8_t sendBuffer[2] = {0x00,data};
	HAL_I2C_Master_Transmit(&hi2c1, OLED_ADRESS, sendBuffer, sizeof(sendBuffer), HAL_MAX_DELAY);
}


void OledInit(){
	 OLED_SendCmd(0xAE); /*关闭显示 display off*/

	  OLED_SendCmd(0x02); /*设置列起始地址 set lower column address*/
	  OLED_SendCmd(0x10); /*设置列结束地址 set higher column address*/

	  OLED_SendCmd(0x40); /*设置起始行 set display start line*/

	  OLED_SendCmd(0xB0); /*设置页地址 set page address*/

	  OLED_SendCmd(0x81); /*设置对比度 contract control*/
	  OLED_SendCmd(0xCF); /*128*/

	  OLED_SendCmd(0xA1); /*设置分段重映射 从右到左 set segment remap*/

	  OLED_SendCmd(0xA6); /*正向显示 normal / reverse*/

	  OLED_SendCmd(0xA8); /*多路复用率 multiplex ratio*/
	  OLED_SendCmd(0x3F); /*duty = 1/64*/

	  OLED_SendCmd(0xAD); /*设置启动电荷泵 set charge pump enable*/
	  OLED_SendCmd(0x8B); /*启动DC-DC */

	  OLED_SendCmd(0x33); /*设置泵电压 set VPP 10V */

	  OLED_SendCmd(0xC8); /*设置输出扫描方向 COM[N-1]到COM[0] Com scan direction*/

	  OLED_SendCmd(0xD3); /*设置显示偏移 set display offset*/
	  OLED_SendCmd(0x00); /* 0x00 */

	  OLED_SendCmd(0xD5); /*设置内部时钟频率 set osc frequency*/
	  OLED_SendCmd(0xC0);

	  OLED_SendCmd(0xD9); /*设置放电/预充电时间 set pre-charge period*/
	  OLED_SendCmd(0x1F); /*0x22*/

	  OLED_SendCmd(0xDA); /*设置引脚布局 set COM pins*/
	  OLED_SendCmd(0x12);

	  OLED_SendCmd(0xDB); /*设置电平 set vcomh*/
	  OLED_SendCmd(0x40);

//	  OLED_NewFrame();
//	  OLED_ShowFrame();

	  OLED_SendCmd(0xAF); /*开启显示 display ON*/

}

void Oled_Test(){
	OLED_SendCmd(0xB0);
	OLED_SendCmd(0x00);
	OLED_SendCmd(0x10);

	uint8_t sendBuffer[] = {0x40,0xAA};
	HAL_I2C_Master_Transmit(&hi2c1, OLED_ADRESS, sendBuffer, sizeof(sendBuffer), HAL_MAX_DELAY);

}

在oled.h中注册

#ifndef INC_OLED_H_
#define INC_OLED_H_
#include "i2c.h";

void OLED_SendCmd(uint8_t data);
void OledInit();
void Oled_Test();
#endif /* INC_OLED_H_ */

在main.c中使用

/* USER CODE BEGIN 2 */
    OledInit();

    Oled_Test();
  /* USER CODE END 2 */

启动后,可以看到第一页中第一列并不是我们设想的那样,其原因是屏幕驱动芯片的第一列地址是从0x02开始的

因此需要将Oled_Test()函数改成

void Oled_Test(){
	OLED_SendCmd(0xB0);
	OLED_SendCmd(0x02);  //低地址2
	OLED_SendCmd(0x10);	 //高地址0

	uint8_t sendBuffer[] = {0x40,0x00};
	HAL_I2C_Master_Transmit(&hi2c1, OLED_ADRESS, sendBuffer, sizeof(sendBuffer), HAL_MAX_DELAY);

}

此时运行程序可以看到屏幕花屏且第一排像素全部熄灭

这是因为未对其他像素进行初始化的操作,于是就随机控制像素的亮灭,就造成了花屏的现象。

我们在oled.c中编写以下代码:

uint8_t GRAM[8][128];

void OLED_NewFrame(){
	memset(GRAM,0,sizeof(GRAM));
	//清空屏幕
}
 
void OLED_ShowFrame(){
	uint8_t sendBuffer[129] ;
	sendBuffer[0] = 0x40;
	for (uint8_t i = 0;  i < 8; ++ i) {
		for (uint8_t j = 0;  j < 128; ++j) {
			sendBuffer[j+1] = GRAM[i][j];
		}
		OLED_SendCmd(0xB0+i);
		OLED_SendCmd(0x02);
		OLED_SendCmd(0x10);
		HAL_I2C_Master_Transmit(&hi2c1, OLED_ADRESS, sendBuffer, sizeof(sendBuffer), HAL_MAX_DELAY);
	}
	
}

接着在oled.h中声明

在main.c中使用:

  /* USER CODE BEGIN 2 */
    OledInit();
    OLED_NewFrame();
    OLED_ShowFrame();
    Oled_Test();
  /* USER CODE END 2 */

运行后可以看到就是我们想要的前几排亮起

其实控制屏幕就是控制GRAM [ 8 ] [ 128 ] 这个数组,并将其数据发送给屏幕驱动芯片就能控制屏幕了。

在oled.c中

void OLED_SetPixel(uint8_t x, uint8_t y){
    if(x >= 128 || y >= 64)  return ;
    GRAM[y/8][x] |= 0x01 << (y % 8);   
}

接着在oled.h中声明

在main.c中使用:

 while (1)
  {
    /* USER CODE END WHILE */
	  	 for (int i = 0; i < 64; ++ i) {
	  		 OLED_NewFrame();
			OLED_SetPixel(2*i, i);
			OLED_ShowFrame();
		}
    /* USER CODE BEGIN 3 */
  }

就可以看到变化了

以上就是oled显示的基本原理、但是,在真正使用的时候,并不需要这样自己造轮子,而是直接使用已经写好的代码,只需要会自己调用。

使用方法:

https://led.baud-dance.com/

去下载在对应oled的驱动

将对应的font.c和oled.c复制覆盖到Src文件夹中

将对应的font.h和oled.h复制覆盖到Inc文件夹中

接着直接在main.c中include一下

 /* USER CODE BEGIN 2 */
    OLED_Init();
    OLED_NewFrame();
    OLED_ShowFrame();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  for (int i = 0; i < 64; ++ i) {
	 	  		OLED_NewFrame();
	 			OLED_DrawCircle(64, 32, i,OLED_COLOR_NORMAL );
	 			OLED_DrawCircle(64, 32, i*2,OLED_COLOR_NORMAL );
	 			OLED_DrawCircle(64, 32, i*3,OLED_COLOR_NORMAL );

	 			OLED_ShowFrame();
	 		}
	  for (int i = 64; i > 0;-- i) {
		  OLED_NewFrame();
	 	  		OLED_DrawCircle(64, 32, 64-i,OLED_COLOR_NORMAL );
				OLED_DrawCircle(64, 32, 64-i*2,OLED_COLOR_NORMAL );
				OLED_DrawCircle(64, 32, 64-i*3,OLED_COLOR_NORMAL );

	 			OLED_ShowFrame();
	 		}

    /* USER CODE BEGIN 3 */

就可以直接使用oled.c中写好的函数了。

扩展,如果想绘制图片或复杂的字符则可以用网站上 提供的取模工具实现

如我想在显示屏上

在这里插入图片描述

显示这种图片组合则可以

在这里插入图片描述

复制到font.c中 接着在font.h中进行extern 就可以在main.c中使用

 OLED_PrintString(70, 30,"基尼台妹", &font15x15, OLED_COLOR_NORMAL);

即可显示文字

图片则用

在这里插入图片描述

选择合适的参数后复制与文字操作类似复制到font.c中 接着在font.h中进行extern 就可以在main.c中使用

OLED_DrawImage(0, 0, &giegieImg, *OLED_COLOR_NORMAL*);

即可显示图片。

至此整个OLED驱动讲解完毕,试着在屏幕上打印温湿度信息吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值