STM32:OLED原理

目录

一.OLED原理

二.CubeMX

三.代码:

[1. oled.c:](#1. oled.c:)

2.注意声明oled.h

3.main.c


一.OLED原理

OLED屏幕由许多的小灯组成,有选择点亮一部分小灯,可以得到我们想要的图案。

屏幕上小灯排列的数目,称为分辨率。比如128*64分辨率:128列64行小灯。

stm32不会像之前控制RGB小灯一样使用一个IO口控制一个小灯,因为需要占用很多个引脚。因此,stm32通过屏幕驱动芯片:使用IIC或SPI等通信协议与屏幕驱动芯片进行通信就可以操控很多个小灯的亮灭。以128*64分辨率的oled屏幕为例:将其64行分为8页,每页有8行,保证可以用一个字节的数据来表示其中一页的某一列8个像素的亮灭。例如,我们通过IIC通信告诉屏幕驱动芯片,将第0页的第三列设置为0xC1,即1100 0001。那么,我们如何通过IIC通信操作屏幕驱动芯片呢?

1.屏幕驱动芯片CH1116的IIC地址为0x7A

操控oled屏幕的通信分为两类:

(1)第一类为指令(给哪个从机发送,在从机具体哪个位置):0x7A(IIC地址,即给哪个从机发地址),0x00(固定开头指令),0xXX(一字节指令:在具体哪一页哪一列开始发送指令)

其中一字节指令:

设置页地址,page0:0xB0;fff page7:0xB7

设置列地址,设置90(0x5A):0x0A(列地址低四位设置为A),0x15(列地址高四位设置为5)

(2)第二类为数据(发送具体数据):

0x7A(IIC地址),0x40(开头),发送任意数量的数据

发送任意数量数据的规则:比如0x01,0x02.......屏幕驱动芯片根据当前页地址与列地址,将这些数据代表的像素亮灭表现在屏幕上,CH1116芯片设置完一字节的8个像素后,列地址会自动+1。

因此,我们只需将指令中的页地址设置为0x7A,0x00,0xB0,设置列地址:0x7A,0x00,0x00&0x7A,0x00,0x10,然后发送128字节(数据)直接完成一页屏幕的像素设置,然后将页地址递增,循环8次,即可完成整个屏幕的像素设置。

二.CubeMX

1.与CH1116通信的I2C1打开,设置I2C1模式

2.为了提速,使用外部晶振

改为72MHz时钟频率

3.为每个外设生成单独的.c与.h文件

(1)再建立oled.h文件

(2)再建立oled.c文件

三.代码:

实现在oled屏幕显示一个移动的小点

1. oled.c:

(1)发送指令函数

cpp 复制代码
//发送指令函数
void OLED_SendCmd(uint8_t cmd)//参数为发送的一字节指令
{
	uint8_t sendBuffer[2];
	sendBuffer[0] = 0x00;
	sendBuffer[1] = cmd;
	HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, sendBuffer, 2, HAL_MAX_DELAY);//发送到CH1116芯片
}

(2)oled初始化

cpp 复制代码
void OLED_Init()
{
	//由厂商提供:
	 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*/
}

(3)"显存"清空为0函数:

cpp 复制代码
//"显存":

uint8_t GRAM[8][128];

//调用此函数后,开始画新的一帧屏幕,作用将显存清空为0,防止"花屏"
//启动"刷新":
void OLED_NewFrame()
{
	//法一:双层for循环
//	for(uint8_t i = 0; i < 8; i++)
//	{
//		for(uint8_t j = 0; j< 128; j++)
//		{
//			GRAM[i][j] = 0;
//		}
//	}

//法二:memset函数
	memset(GRAM, 0, sizeof(GRAM));//头文件string.h
}

(4)设置某个像素亮起的函数::

cpp 复制代码
//设置某个像素亮起的函数:
//将(x,y)位置的像素设置为1
//设置像素点亮起:
void OLED_SetPixel(uint8_t x, uint8_t y)
{
	if(x >= 128 || y>= 64)//防止数组越界
	{
		return;
	}
	GRAM[y/8][x] |= 0X01 << (y % 8);

}

(5)将显存显示到屏幕上的函数:

cpp 复制代码
//将显存显示到屏幕上的函数:
//"展示":
void OLED_ShowFrame()
{
	uint8_t sendBuffer[129];//存储要发送的数据
	sendBuffer[0] = 0x40;//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);//注意+i
		OLED_SendCmd(0x02);
		OLED_SendCmd(0x10);
		HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, sendBuffer, sizeof(sendBuffer), HAL_MAX_DELAY);//发送给oled屏幕
	}
}

2.注意声明oled.h

cpp 复制代码
/*
 * oled.h
 *
 *  Created on: Jun 9, 2026
 *      Author: 25306
 */

#ifndef INC_OLED_H_
#define INC_OLED_H_

#include"i2c.h"
//在oled.c文件中定义好的函数都要在oled.h文件中声明
void OLED_Init();
void OLED_Test();

void OLED_NewFrame();
void OLED_ShowFrame();
void OLED_SetPixel(uint8_t x, uint8_t y);

#endif /* INC_OLED_H_ */

3.main.c

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include"oled.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
   HAL_Delay(20);//OLED启动比stm32慢20ms
   OLED_Init();//要初始化
//  OLED_NewFrame();//清空显存
//  OLED_ShowFrame();//显存刷新到屏幕上
//  OLED_Test();//让第0页前几个像素间隔亮起
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  for(uint8_t i = 0; i < 64; i++)
	  {
	  	OLED_NewFrame();

	  	OLED_SetPixel(2*i , i);

	  	OLED_ShowFrame();
	  }
  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
相关推荐
清风66666611 小时前
基于单片机与DAC0832的双路波形信号发生系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
azwsm13 小时前
电路元器件和GPIO控制器
单片机·嵌入式硬件
kebidaixu16 小时前
FreeRTOS 移植到 STM32F407VETX 记录(一)
stm32·单片机·嵌入式硬件
CSDN官方博客16 小时前
「谁说嵌入式只是调包和焊板子?」—— 2026嵌入式全栈技术征锋令
嵌入式硬件·物联网·embedding
半条-咸鱼16 小时前
【INACCESSIBLE_BOOT_DEVICE】安装 Config Tool 后 Windows 蓝屏,最终通过 VMware 虚拟机解决
windows·stm32·vmware·芯片
点灯小铭17 小时前
基于单片机的数码管定时插座设计与定时开关功能实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
云栖梦泽17 小时前
玩转RK3506SDK
linux·嵌入式硬件
数智工坊19 小时前
机器人四大主控板系统分层选型指南:树莓派、ESP32、STM32与Arduino的能力边界与实战定位
stm32·嵌入式硬件·机器人
某林21219 小时前
跨越底层与AI的鸿沟:ROS2+多模态大模型(Qwen-VL)机器人全链路排障实录
人工智能·stm32·机器人·人机交互·ros2·技术复盘