功率监测与控制系统DIY——实现OLED屏幕显示信息
1 任务目标
实现OLED 屏幕显示信息
2 OLED介绍
此款OLED是Seeed Studio 出品的Grove 接口的0.96英寸OLED 显示屏,驱动IC 为SSD1315.
OLEDDisplay 0.96” SSSD1315 V1.1分辨率为128×64。
供电为3.3 V 或者5 V,通信接口为I2C。
考虑到电流表INA219也是I2C通信接口,在STM32开发板上使用同一组I2C 硬件,OLED和INA219配置不同的器件地址,就可以一个I2C控制器驱动两个I2C器件。
此开发板有Arduino接口,恰好把Seeed Base Shield扩展板接上。
3 STM32 I2C配置
3.1 选用I2C1
Nucleo-F411RE管脚分配
3.2 STM32CubeMX工程配置
● 在Connecity 中选择I2C1
● 在右侧使能i2c
● 配置I2C 参数为Standard Mode,速率100 KHz,地址为7 比特,主要的从器件地址为0×78
3.3 PB8配置为SCL
3.4 PB9配置为SDA
4 PCtoLCD汉字取模软件
此次任务在OLED 上展示中文字符如下:
电子产品世界
得捷
你好
功率检测
系统控制
电压电流
所有取模的文字:
电子产品世界得捷你好功率监测系统控制电压流
PCtoLCD2002软件配置如下:
● 点阵格式:阴码
● 取模方式:列行式
● 取模走向:逆向(低位在前)
● 自定义格式:C51 格式,且行前缀、行后缀都为空。
在输入框输入文字后点击“生成字模”,拷贝到工程中即可。
5 流程图
6 关键代码
6.1 主函数
● HAL库初始化
● 时钟初始化
● 硬件初始化,如GPIO,TIM,UART,I2C 等
● OLED 初始化,清屏
● 显示界面,界面切换,死循环
view plaincopy to clipboardprint?
1. int main(void)
2. {
3. /* USER CODE BEGIN 1 */
4.
5. /* USER CODE END 1 */
6.
7. /* MCU Configuration--------------------------
------------------------------*/
8.
9. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
10. HAL_Init();
11.
12. /* USER CODE BEGIN Init */
13.
14. /* USER CODE END Init */
15.
16. /* Configure the system clock */
17. SystemClock_Config();
18.
19. /* USER CODE BEGIN SysInit */
20.
21. /* USER CODE END SysInit */
22.
23. /* Initialize all configured peripherals */
24. MX_GPIO_Init();
25. MX_USART2_UART_Init();
26. MX_TIM1_Init();
27. MX_I2C1_Init();
28.
29. /* USER CODE BEGIN 2 */
30.
31. printf(“rn”);
32. printf(“tt EEPW_2025_DIY1_Task2_
OLED rn”);
33. printf(“tt Build: %s %s rn”, __DATE
__, __TIME__);
34. printf(“rn”);
35.
36. HAL_TIM_Base_Start_IT(&htim1);
37.
38. OLED_Init();
39.
40. /* USER CODE END 2 */
41.
42. /* Infinite loop */
43. /* USER CODE BEGIN WHILE */
44. while (1) {
45. screen_00_welcome();
46. HAL_Delay(1000 * 3);
47. screen_01_welcome();
48. HAL_Delay(1000 * 3);
49. screen_02_diy_power_monitor();
50. HAL_Delay(1000 * 5);
51. /* USER CODE END WHILE */
52.
53. /* USER CODE BEGIN 3 */
54. // HAL_Delay(2000);
55. }
56. /* USER CODE END 3 */
57. }
6.2 I2C 初始化
这里的初始化代码是STM32CubeMX生成的,初始化参数来自界面配置的参数。
● 函数MX_I2C1_Init() 先保存I2C 参数到hi2c1 结构体上,调用HAL_I2C_Init() 初始化硬件
● 函数HAL_I2C_MspInit() 由HAL_I2C_Init() 函数调用,初始化I2C1 管脚,配置为复用功能
view plaincopy to clipboardprint?
1. void MX_I2C1_Init(void)
2. {
3.
4. /* USER CODE BEGIN I2C1_Init 0 */
5.
6. /* USER CODE END I2C1_Init 0 */
7.
8. /* USER CODE BEGIN I2C1_Init 1 */
9.
10. /* USER CODE END I2C1_Init 1 */
11. hi2c1.Instance = I2C1;
12. hi2c1.Init.ClockSpeed = 100000;
13. hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
14. hi2c1.Init.OwnAddress1 = 240;
15. hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
16. hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
17. hi2c1.Init.OwnAddress2 = 0;
18. hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
19. hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
20. if (HAL_I2C_Init(&hi2c1) != HAL_OK)
21. {
22. Error_Handler();
23. }
24. /* USER CODE BEGIN I2C1_Init 2 */
25.
26. /* USER CODE END I2C1_Init 2 */
27.
28. }
29.
30. void HAL_I2C_MspInit(I2C_HandleTypeDef*i2cHandle)
31. {
32.
33. GPIO_InitTypeDef GPIO_InitStruct = {0};
34. if(i2cHandle->Instance==I2C1)
35. {
36. /* USER CODE BEGIN I2C1_MspInit 0 */
37.
38. /* USER CODE END I2C1_MspInit 0 */
39.
40. __HAL_RCC_GPIOB_CLK_ENABLE();
41. /**I2C1 GPIO Configuration
42. PB8 ------> I2C1_SCL
43. PB9 ------> I2C1_SDA
44. */
45. GPIO_InitStruct.Pin = OLED_SCL_Pin|OLED_SDA_Pin;
46. GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
47. GPIO_InitStruct.Pull = GPIO_NOPULL;
48. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
49. GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
50. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
51.
52. /* I2C1 clock enable */
53. __HAL_RCC_I2C1_CLK_ENABLE();
54. /* USER CODE BEGIN I2C1_MspInit 1 */
55.
56. /* USER CODE END I2C1_MspInit 1 */
57. }
58. }
6.3 OLED接口函数
OLED 接口层,主要实现两个函数,其他的OLED
API 都是依赖这两个函数
● Oled_Write_Data() 发送数据到OLED IC
● Oled_Write_Cmd() 发送命令到OLED I
6.3.1 Oled_Write_Data() 实现
这里直接调用HAL API 往OLED 发送数据
view plaincopy to clipboardprint?
1. void Oled_Write_Data(uint8_t data)
2. {
3. HAL_I2C_Mem_Write(&HI2CX, OLED_ID,
OLED_WR_DATA, I2C_MEMADD_SIZE_8BIT,
&data, 1, 0×100);
4. }
6.3.2 Oled_Write_Cmd() 实现
这里直接调用HAL API 往OLED 发送命令
view plaincopy to clipboardprint?
1. void Oled_Write_Cmd(uint8_t cmd)
2. {
3. HAL_I2C_Mem_Write(&HI2CX, OLED_ID,
OLED_WR_CMD, I2C_MEMADD_SIZE_8BIT,
&cmd, 1, 0×100);
4. }
6.4 OLED API
这里仅列举几个常用的API 实现。
6.4.1 OLED_Init()初始化
OLED 上电后需要发送命令配置参数
view plaincopy to clipboardprint?
1.void OLED_Init(void)
2.{
3./*设置显示打开/ 关闭
4.*AE--->显示打开
5.*AF--->显示关闭( 休眠模式)
6.*/
7.Oled_Write_Cmd(0xAE);
8.
9./*==========基本命令表==========*/
10./*设置对比度
11.*0~255:数值越大 亮度越亮
12.*/
13.Oled_Write_Cmd(0×81);
14.Oled_Write_Cmd(0×FF);
15.
16./*使能全屏显示
17.*A4--->恢复到RAM 内容显示
18.*A5--->忽略RAM 内容显示
19.*/
20.Oled_Write_Cmd(0×A4);
21.
22./*设置显示模式
23.*A6--->正常显示:0 灭1 亮
24.*A7--->逆显示:1灭0亮
25.*/
26.Oled_Write_Cmd(0×A6);
27.
28./*==========滚动命令表==========*/
29./*滚动使能/ 失能
30.*2E--->失能
31.* 2F--->使能
32.*/
33.Oled_Write_Cmd(0×2E);
34.
35./*七字节命令: 连续水平滚动设置 */
36.
37./*左/ 右水平滚动设置
38.*26---> 右水平滚动
39.*27---> 左水平滚动
40.*/
41.Oled_Write_Cmd(0×26);
42./*虚拟字节*/
43.Oled_Write_Cmd(0×00);
44./*设置滚动起始页地址*/
45.Oled_Write_Cmd(0×00);
46./*设置滚动间隔*/
47.Oled_Write_Cmd(0×03);
48./*设置滚动结束地址 */
49.Oled_Write_Cmd(0×07);
50./*虚拟字节*/
51.Oled_Write_Cmd(0×00);
52.Oled_Write_Cmd(0×FF);
53.
54./*==========寻址设置命令表==========*/
55.
56./*双字节命令: 寄存器寻址模式 */
57.Oled_Write_Cmd(0×20);
58.
59./* 10:页寻址模式
60.* 01:垂直寻址模式
61.* 00:水平寻址模式
62.*/
63.Oled_Write_Cmd(0×10);
64./*单字节命令: 设置页寻址的起始页地址 */
65.Oled_Write_Cmd(0×B0);
66./* 单字节命令: 设置页寻址的起始列地址低位 */
67.Oled_Write_Cmd(0×00);
68. /* 单字节命令: 设置页寻址的起始列地址高位 */
69.Oled_Write_Cmd(0×10);
70.
71./*========== 硬件配置命令表 ==========*/
72.
73./*设置显示开始线
74.*0×40~0×7F 对应0~63
75.*/
76.Oled_Write_Cmd(0×40);
77.
78./*设置列重映射
79.*A0:addressX--->segX
80.*A1:addressX--->seg(127-X)
81.*/
82.Oled_Write_Cmd(0×A1);
83.
84./*设置多路复用比 */
85.Oled_Write_Cmd(0×A8);
86.Oled_Write_Cmd(0×3F);
87.
88./*设置COM 输出扫描方向
89.*C0:COM0--->COM63( 从上往下扫描)
90.*C8:COM63--->COM0( 从下往上扫描)
91.*/
92.Oled_Write_Cmd(0×C8);
93.
94./*双字节命令:设置COM 显示偏移量 */
95.Oled_Write_Cmd(0×D3);
96.Oled_Write_Cmd(0×00); /* COM 不偏移 */
97.
98./*双字节命令:配置COM 重映射 */
99.Oled_Write_Cmd(0×DA);
100.Oled_Write_Cmd(0×12);
101.
102./*双字节命令:设置预充期 */
103.Oled_Write_Cmd(0×D9);
104.Oled_Write_Cmd(0×22); /* 阶段一2 个无效DCLK 时钟/ 阶段二2 个无效DCLK 时钟 */
105.
106./*设置VCOMH 取消选择电平
107.*00:0.65xVcc
108.*20:0.77xVcc
109.*30:0.83xVcc
110.*/
111.Oled_Write_Cmd(0×DB);
112.Oled_Write_Cmd(0×20);
113.
114./*双字节命令:设置电荷泵 */
115.Oled_Write_Cmd(0×8d);
116.Oled_Write_Cmd(0×14);
117.
118.Oled_Write_Cmd(0×AF);
119.}
6.4.2 OLED_Fill()刷屏
m表示page地址,数值0~7,n 表示列地址,数值0~127。
填充的数据fill_data,设置为0,则屏幕为黑色;设置为1,则屏幕白色;设置为其他值,屏幕显示条纹。
view plaincopy to clipboardprint?
1.void OLED_Fill(uint8_t fill_data) // 全屏填充
2.{
3.unsigned char m, n;
4.for (m = 0; m < 8; m++) {
5.Oled_Write_Cmd(0×b0 + m); // page0-page1
6.Oled_Write_Cmd(0×00); // low column st art address
7.Oled_Write_Cmd(0×10); // high column s tart address
8.for (n = 0; n < 128; n++) {
9.Oled_Write_Data(fill_data);
10.}
11.}
12.}
6.4.3 OLED_ShowStr()
这里支持两种字体大小,分别是6×8 和8×16 大小。
view plaincopy to clipboardprint?
1./**
2.*@brief 显示 ASCII 字符,有 6×8 和 8×16 字体大小可以选择
3.*
4.*@param x起始点坐标x[0, 127]
5.*@param y 起始点坐标 y [0, 7]
6.*@param ch 要显示的字符串
7.*@param textsize 1 表示字体大小 6×8; 2 表示字体大小 8×16
8.*/
9.void OLED_ShowStr(uint16_t x, uint16_t y,uint8_t ch[], ascii_font_e font)
10. {
11.uint8_t c = 0, i = 0, j = 0;
12.switch (font) {
13.case ASCII_FONT_6×8: {
14.while (ch[j] != ‘ ’) {
15.c=ch[j] - 32;
16.if (x > 126) {
17.x = 0;
18.y++;
19.}
20.OLED_SetPos(x, y);
21.for (i = 0; i < 6; i++)
22.Oled_Write_Data(FONT_ASCII_6×8[c][i]);
23.x= 6;
24.j++;
25.}
26.break;
27.}
28.
29.case ASCII_FONT_8×16: {
30.while (ch[j] != ‘ ’) {
31.c=ch[j] - 32;
32.if (x > 120) {
33.x=0;
34.y++;
35.}
36.OLED_SetPos(x, y);
37.for (i = 0; i < 8; i++)
38.Oled_Write_Data(FONT_ASCII_8×16[c * 16 + i]);
39.OLED_SetPos(x, y + 1);
40.for (i = 0; i < 8; i++)
41.Oled_Write_Data(FONT_ASCII_8×16[c * 16 + i + 8]);
42.x=8;
43.j++;
44. }
45.break;
46.}
47.
48.default:
49.break;
50. }
51. }
6.4.4 OLED_ShowCN()
这里只支持一种中文字体大小,16×16。
/**
*@brief显示oled_codetab.h中的汉字,16×16点阵
*
*@param x起始坐标x[0, 127]
*@param y起始坐标y[0, 7]
*@param n汉字在16×16点阵中的索引,下标从0开始
*/
void OLED_ShowCN(uint16_t x, uint16_t y, uint16_t index)
{
unsigned char wm=0;
unsigned int adder = 32 * index;
OLED_SetPos(x, y);
for (wm = 0; wm < 16; wm++) {Oled_Write_Data(FONT_CN_16×16[adder]);
adder += 1;
}
OLED_SetPos(x, y + 1);
for (wm = 0; wm < 16; wm++) {Oled_Write_Data(FONT_CN_16×16[adder]);
adder += 1;
}
}
7 实操演示
显示中文欢迎界面
显示英文欢迎界面
显示功率检测界面,其中的电压、电流和功率数值是预设值,并非实际测量的。
(本文来源于《EEPW》202507)
评论