网站备案号密码,wordpress 中型网站,网站建设策划书心得,合同备案号查询系统本文介绍了使用STM32 HAL库通过I2C协议驱动0.96寸OLED显示屏的方法。首先概述了OLED的基本特性和应用#xff0c;然后详细讲解了汉字点阵生成的方法#xff0c;并提供了完整的代码示例#xff0c;包括初始化、清屏、字符串显示和自定义汉字显示函数。这些代码实现了在STM32F…本文介绍了使用STM32 HAL库通过I2C协议驱动0.96寸OLED显示屏的方法。首先概述了OLED的基本特性和应用然后详细讲解了汉字点阵生成的方法并提供了完整的代码示例包括初始化、清屏、字符串显示和自定义汉字显示函数。这些代码实现了在STM32F103ZET6开发板上显示特定内容的功能如英文句子和中文字符“慢慢变好”。
目录 二、0.96 寸 OLED
三、生成汉字点阵
三、代码示例
1.初始化
2清屏函数
3.字符串显示函数
4.自定义汉字字模显示函数
5.完整示例代码,附件是源码
五、运行结果
六、总结 零、屏幕显示的本质
屏幕显示的核心其实非常简单归根结底就是“点灯”。每一个分辨率单位对应一个像素点也就是一盏可以单独控制的灯,屏幕放大后就是一个一个的小方块灯。 在屏幕上显示内容时实际上就是在指定坐标(x, y)上点亮或熄灭相应的像素点。 屏幕显示坐标(x,y)内容 对于分辨率为128x64的显示屏来说意味着它有64行、每行128个像素点总共包含8192个独立可控制的灯即像素。要控制这个128x64的显示屏本质上就是要对这8192个像素进行精确的点亮和熄灭操作。 在实际应用中我们并不会一个个地去控制这些像素点因为这样的效率太低了。我们会按照字节8位来操作显存每个字节控制8个连续的像素点。 一、开发环境 硬件正点原子精英 V2 STM32F103开发板
单片机STM32F103ZET6
Keil版本5.32
STM32CubeMX版本6.9.2
STM32Cube MCU Packges版本STM32F1xx_DFP.2.4.1 串口USART1(PA9,PA10)
I2C2:PB10(SCL),PB11(SDA)
屏幕0.96 寸 OLED 显示液晶屏模128 * 64 SSD1306屏幕的SCL、SDA接到STM32的PB10(SCL),PB11(SDA)
二、0.96 寸 OLED
0.96 寸 OLED 显示液晶屏模块是一种体积小巧但功能强大的显示设备在众多小型电子项目中广泛应用。它具有 128 * 64 的分辨率采用 SSD1306 驱动芯片支持 SPI 和 I2C 两种通信接口. 三、生成汉字点阵
显示汉字需要自行生成字库调用,运行“PCtoLCD2002”软件点击菜单“选项”进行设置如下图所示 比如显示慢慢变好.输入慢慢变好.点击生产字模把字模复制到chinese_font.c 四、代码示例
底层驱动已经实现好,只是调用函数.
1.初始化
************** 7. 初始化函数 **************/
/** 函数名OLED_Init* 功能描述初始化OLED* 输入参数无* 输出参数无* 返回值无*/
void OLED_Init(void)
{ /** 前提: 已经初始化的I2C通道* 本工程里已经: * 使用MX_I2C1_Init初始化I2C通道* 使用HAL_I2C_MspInit初始化I2C引脚*/OLED_SetMemAddrMode(PAGE_ADDR_MODE); // 0. 设置地址模式OLED_SetMuxRatio(0x3F); // 1. 设置多路复用率OLED_SetDispOffset(0x00); // 2. 设置显示的偏移值OLED_SetDispStartLine(0x00); // 3. 设置起始行OLED_SEG_REMAP(); // 4. 行翻转OLED_SCAN_REMAP(); // 5. 正常扫描OLED_SetComConfig(COM_PIN_SEQ, COM_NOREMAP); // 6. COM 引脚设置OLED_SetContrastValue(0x7F); // 7. 设置对比度ENTIRE_DISP_OFF(); // 8. 全屏点亮/熄灭DISP_NORMAL(); // 9. 显示模式OLED_SetDCLK_Freq(0x00, 0x08); // 10. 设置分频系数和频率增值OLED_SetChargePump(PUMP_ENABLE); // 11. 使能电荷碰撞OLED_SetComConfig(COM_PIN_ALT, COM_NOREMAP);DISP_ON();
}2.清屏函数
清屏函数的核心思路是通过循环遍历屏幕的每一页将每一页的所有像素点都置为 0从而实现清屏的效果。buf 数组用于存储要写入屏幕的数据所有元素初始化为 0。OLED_SetPosition 函数用于设置当前操作的页和列位置。OLED_WriteNBytes 函数用于将指定数量的数据写入屏幕。
通过这种方式可以确保整个屏幕的显示内容被清空显示为全黑。
/** 函数名OLED_Clear* 功能描述清屏函数用于将0.96寸OLED显示液晶屏的显示内容清空使屏幕显示为全黑。* 输入参数无* 输出参数无* 返回值无* 实现原理* 该OLED屏幕采用页寻址模式整个屏幕被划分为8页每页有128列。* 清屏的过程就是将每一页的128个像素点都置为0即不发光。* 首先创建一个长度为128的缓冲区所有元素初始化为0代表一列的像素数据都为0。* 然后通过循环遍历每一页设置当前操作的页和列位置将缓冲区的数据写入该页从而清空该页的显示内容。
*/
void OLED_Clear(void)
{// 定义一个循环变量i用于遍历屏幕的每一页uint8_t i 0;// 定义一个长度为128的缓冲区buf用于存储要写入屏幕的数据// 所有元素初始化为0代表一列的像素数据都为0即不发光uint8_t buf[128] {0};// 循环遍历屏幕的8页for(i 0; i 8; i){// 调用OLED_SetPosition函数设置当前操作的页和列位置// i表示当前页号0 - 70表示列号从第0列开始OLED_SetPosition(i, 0);// 调用OLED_WriteNBytes函数将缓冲区buf中的128个字节数据写入当前页// 由于buf中的数据都为0所以写入后该页的所有像素点都不发光实现了清屏效果OLED_WriteNBytes(buf[0], 128);}
}
3.字符串显示函数
此函数的主要逻辑是遍历传入的字符串使用 OLED_PutChar 函数逐个显示字符。每显示一个字符x 坐标右移一位。当 x 坐标超出范围大于 15时x 坐标重置为 0y 坐标下移 2 页。最后返回成功显示的字符数量.
/** 函数名OLED_PrintString* 功能描述在0.96寸OLED显示液晶屏上显示一个字符串。该函数会将传入的字符串按字符逐个显示在指定的起始坐标位置。* 输入参数* x -- x坐标(0~15)表示字符串起始显示位置的列坐标取值范围为0到15每一个单位对应屏幕上一定的列位置。* y -- y坐标(0~7)表示字符串起始显示位置的页坐标取值范围为0到7每一页对应屏幕垂直方向上的一部分区域。* str -- 显示的字符串是一个以\0结尾的字符数组。* 输出参数无* 返回值打印了多少个字符即成功显示在屏幕上的字符数量。*/
int OLED_PrintString(uint8_t x, uint8_t y, const char *str)
{ // 定义一个整型变量i用于记录当前处理的字符在字符串中的索引位置同时也用于统计打印的字符数量int i 0;// 进入循环只要字符串还未结束即当前字符不为字符串结束符\0就继续处理while (str[i]){// 调用OLED_PutChar函数将当前字符显示在指定的x、y坐标位置OLED_PutChar(x, y, str[i]);// 显示完一个字符后将x坐标加1以便在下一列显示下一个字符x;// 判断x坐标是否超出了最大允许值即是否超过了15if(x 15){// 如果x坐标超出范围将x坐标重置为0以便从下一行的起始位置开始显示x 0;// 同时将y坐标增加2因为通常每显示一行字符后需要移动到下一页继续显示y 2;}// 索引位置i加1指向下一个字符i;}// 循环结束后返回打印的字符数量return i;
}
4.自定义汉字字模显示函数
此函数 OLED_PrintChinese1 用于在 OLED 屏幕指定位置显示预定义的中文字符。它通过外部数组 g_chinese_fonts1 存储中文字符的字模数据按顺序将每个中文字符的上半部分和下半部分数据依次写入 OLED 屏幕并更新列位置以显示下一个字符。在写入前会检查输入坐标是否有效无效则不进行显示操作
/*** brief 在OLED屏幕上显示预定义的中文字符。* * 该函数用于在OLED屏幕的指定位置显示一系列预定义的中文字符。中文字符的字模数据存储在外部数组g_chinese_fonts1中。* * param x 中文字符起始显示位置的列索引范围0 - 15每个单位对应8列。* param y 中文字符起始显示位置的页索引范围0 - 7表示垂直位置。* * return 无*/
void OLED_PrintChinese1(uint8_t x, uint8_t y)
{ // 声明外部数组g_chinese_fonts1该数组存储了中文字符的字模数据。// 数组的每个元素代表一个中文字符每个中文字符由32字节的数据组成上半部分16字节下半部分16字节。extern uint8_t g_chinese_fonts1[4][32];// 保存起始页位置用于后续操作。uint8_t page y;// 计算起始列位置由于每个中文字符宽度为16列而x是按8列单位计数的所以乘以8。uint8_t col x * 8;// 检查输入的坐标是否超出OLED屏幕的有效范围。// 如果y超过7页索引范围为0 - 7或者x超过15列索引范围为0 - 15则直接返回不进行显示操作。if (y 7 || x 15)return;// 循环变量用于遍历中文字符数组。int i;// 遍历g_chinese_fonts1数组中的每个中文字符。// sizeof(g_chinese_fonts1)返回整个数组的字节数sizeof(g_chinese_fonts1[0])返回一个中文字符数据的字节数// 两者相除得到数组中中文字符的数量。for (i 0; i sizeof(g_chinese_fonts1) / sizeof(g_chinese_fonts1[0]); i){// 设置OLED屏幕的当前显示位置为当前页和当前列。// 这是为了准备写入当前中文字符的上半部分数据。OLED_SetPosition(page, col);// 向OLED屏幕发送当前中文字符的上半部分数据前16字节。// g_chinese_fonts1[i][0]是当前中文字符上半部分数据的起始地址16表示要发送的字节数。OLED_WriteNBytes((uint8_t*)g_chinese_fonts1[i][0], 16);// 设置OLED屏幕的当前显示位置为下一页page 1和当前列。// 这是为了准备写入当前中文字符的下半部分数据。OLED_SetPosition(page 1, col);// 向OLED屏幕发送当前中文字符的下半部分数据后16字节。// g_chinese_fonts1[i][16]是当前中文字符下半部分数据的起始地址16表示要发送的字节数。OLED_WriteNBytes((uint8_t*)g_chinese_fonts1[i][16], 16);// 更新列位置为显示下一个中文字符做准备。// 每个中文字符宽度为16列所以将列位置增加16。col 16;}
}
5.完整示例代码,附件是源码
/* USER CODE BEGIN Header */
/********************************************************************************* file : main.c* brief : Main program body******************************************************************************* attention** Copyright (c) 2025 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 usart.h
#include gpio.h/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include string.h
#include driver_oled.h
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern UART_HandleTypeDef huart1;
extern I2C_HandleTypeDef hi2c2;
/* 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 */
//char *str I2C FUNCTIONS\r\n;
//char c;/* 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_USART1_UART_Init();MX_I2C2_Init();/* USER CODE BEGIN 2 */OLED_Init();OLED_Clear();OLED_PrintString(0, 0, I love Aissa);OLED_PrintChinese1(3, 3);OLED_PrintChinese2(3, 6);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* 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 */五、运行结果
屏幕显示如下内容 六、总结
本文介绍了使用STM32 HAL库通过I2C协议驱动0.96寸OLED显示屏的方法仅供参考有任何问题欢迎在评论区留言讨论