十天学会嵌入式技术之51单片机—day-9

51单片机入门指南:10天学习路线与实战项目 单片机作为嵌入式系统的核心组件,通过GPIO、定时器、串口等基础外设实现硬件控制。其工作原理基于寄存器直接操作,相比现代ARM芯片的HAL库封装,51单片机架构精简透明,特别适合初学者理解计算机体系结构。在物联网和智能硬件领域,掌握单片机开发能快速实现传感器数据采集(如DS18B20温度传感器)、执行器控制(如PWM调光)等典型应用。本文以STC89C52为例,详细解析GPIO工作模式、定时器配置等核心知识,并提供智能路灯控制系统等实战项目代码,帮助开发者快速掌握51单片机开发技巧。 阅读详情

第 19 章 OLED 模块-I2C 协议


19.1 OLED 模块概述

19.1.1 OLED 简介

OLED(Organic Light-Emitting Diode,有机发光二极管)显示屏由许多微小的发光二
极管构成,每个发光二极管就对应着屏幕上的一个像素,通过控制二极管的亮灭就能在屏
幕上显示图像或文字。

按照驱动方式划分,OLED 显示屏分可分为两类,分别是 PMOLED(Passive Matrix,
被动矩阵)和 AMOLED(Active Matrix,主动矩阵)。

PMOLED 的驱动方式和前文的 LED 点阵类似,每次只能点亮一行或者一列,需要快
速的逐行或者逐列扫描来显示内容。

AMOLED 屏幕上的每个像素点都有一个单独的控制电路,可以独立进行控制。

本课程使用的是一块 PMOLED(Passive Matrix,被动矩阵)屏,其分辨率为 128x64。

19.1.2 驱动芯片

市面上的多数 OLED 显示屏都会带有驱动芯片,驱动芯片的核心作用是控制每个像素
点的亮灭以显示图像或文字,此外它还会提供数据接口(例如 I2C),用于接收屏幕上要显
示的数据。驱动芯片的存在使得我们可以通过简单的接口控制 OLED 显示屏,大大简化了
开发和控制流程。

本课程所使用的这块 OLED 屏的驱动芯片为 SSD1315,由于我们需要通过它来控制
OLED 显示的内容,所以需要重点学习它的用法。

19.1.2.1 基本工作原理

19.1.2.2 IIC 接口

虽然 SSD1315 的 MCU Interface 支持多种通信协议,但我们所选用的 OLED 显示模块
只暴露出了 IIC 接口。

由于 OLED 显示屏的作用是显示数据,它对于 MCU 来讲更多的是一个输出设备,因
此我们只需关注如何向 SSD1315 写入数据即可。下面是写数据的时序图:

19.1.2.3 GDDRAM

GDDRAM 的作用是存储显示数据,其容量是 128×64 bit,每个 bit 对应着屏幕上的一
个像素,该 bit 的值就能决定该像素的亮灭。

(1)内存组织结构

(2)内存寻址

在了解了内存组织结构之后,我们还需掌握内存的寻址方式,这样才能在我们指定的
位置写入指定的内容。

向 GDDRAM 写入数据时是以 byte 为单位的,按照上述的内存组织结构, 定位一个
byte,至少需要明确两点,分别是第几页(Page Address,页地址)和第几列(ColumnAddress,列地址)。因此 GDDRAM 内部设有两个指针, Page Address Pointer 和 ColumnAddress Pointer,分别指向当前要写入的页和列。为方便连续写入多个字节,每当成功写
入一个字节后,Page Address Pointer 或者 Column Address Pointer 会自动递增,指向下一
个要写入的位置。

根据指针递增逻辑的不同,GDFRAM 提供了三种不同的寻址方式,分别是页寻址,水
平寻址和垂直寻址,具体使用哪种模式,可以通过向 SSD1315 发送控制命令进行选择,具
体命令如下

下面逐一介绍三种寻址方式的工作原理。

(1)页寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令设置页地址(例如 Page1)和
列地址(例如 COL3),此时 Page Address Pointer 和 Column Address Pointer 就会指向对
应的位置。之后便可开始连续发送数据,每成功写入一个字节,Column Address Pointer
都会自动+1,而 Page Address Pointer 始终不变,如果写到当前页末尾,Column Address
Pointer 会回到当前页的第 1 列。

设置页地址的命令如下

设置列地址的命令如下。

(2)水平寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令,设置一个写入区域,具体来
讲就是分别指定页的起始地址和结束地址(例如 Page1~Page5)以及列的起始地址和结束
地址(例如 COL2~COL125)。此时 Page Address Pointer 和 Column Address Pointer 会指
向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Column Address
Pointer 会自动+1,当到达目标区域的右侧边界时,Page Address Pointer 便会自动+1。当写
到目标区域的右下角时,两个指针会再次回到左上角。如下图所示。

设置页地址范围的命令如下。

设置列地址范围的命令如下。

(3)垂直寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令,设置一个写入区域,具体来
讲就是分别指定页的起始地址和结束地址(例如 Page1~Page5)以及列的起始地址和结束
地址(例如 COL2~COL125)。此时 Page Address Pointer 和 Column Address Pointer 会指
向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Page Address
Pointer 会自动+1,当到达目标区域的底部边界时,Column Address Pointer 便会自动+1。当
写到目标区域的右下角时,两个指针会再次回到左上角。如下图所示。

3)内存 bit 与屏幕像素映射关系

GDDRAM 中的每个 bit 都对应着屏幕上的一个像素,但具体哪个 bit 对应着哪个像素,
目前仍是不明确的,最理想的方式当然是每个 bit 和每个像素的位置完全对应,但默认情况
下并非如此。
bit 和像素之间的对应关系受两个环节的影响,第一个环节是 GDDRAM 和 SSD1315 输
出引脚(64 个 COM 和 128 个 SEG)的对应关系,第二个环节是 SSD1315 的输出引脚和
OLED 屏幕的连线方式。下面逐一分析。

(1)GDDRAM 和 SSD1315 输出引脚对应关系

(2)SSD1315 输出引脚和 OLED 屏幕对应关系

根据前文的描述,若要保证 GDDRAM 中的 bit 与 OLED 屏幕中的像素位置完全对应,
那么 GDDRAM 和 SSD1315 输出引脚的对应关系,需要进行重映射。

设置 Segment 重映射的命令如下。

设置 Common 重映射的命令如下。

19.1.3 相关资料

(1)实物图

19.2 需求描述

在 OLED 屏指定位置显示 ASCII 表中的指定字符.

19.3 硬件设计

19.4 软件设计

19.4.1 需求分析

想要在指定位置显示 ASCII 表中的指定字符,首先需要为每个字符制作字模。至于显
示位置的控制,只需通过命令指定自模数据写入 GDDRAM 的位置即可实现。

19.4.2 字模制作

19.4.3 显示位置

19.4.4 完整代码

(1)Int_Oled.h

#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Util.h"
/**
* @brief Oled 初始化
*
*/
void Int_Oled_Init();
/**
* @brief 在指定位置(x,y)显示字符串
*
* @param x 横坐标
* @param y 纵坐标
* @param str 待展示字符串
*/
void Int_Oled_ShowStr(u8 x, u8 y, u8 *str);
/**
* @brief 在指定位置(x,y)显示数字
*
* @param x 横坐标
* @param y 纵坐标
* @param num 待展示数字
*/
void Int_Oled_ShowNum(u8 x, u8 y, long int num);
/**
* @brief 清屏
*
*/
void Int_Oled_Clear();
#endif /* __INT_OLED_H__ */

(2)Int_Oled.c

#include "Int_Oled.h"
#include "Dri_IIC.h"
#define OLED_ADDR 0x78
#define DATA_MODE 0x40
#define CMD_MODE 0x00
code const u8 Int_Oled_Font[][16] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
    0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
    0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
    0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00,
    0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
    0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00,
    0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
    0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00,
    0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
    0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00,
    0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
    0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
    0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00,
    0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
    0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
    0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00,
    0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
    0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//- 13
    0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
    0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04,
    0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
    0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
    0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
    0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00,
    0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
    0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00,
    0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
    0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00,
    0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
    0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00,
    0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
    0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00,
    0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
    0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
    0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
    0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00,
    0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
    0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
    0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
    0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
    0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00,
    0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
    0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00,
    0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
    0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
    0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00,
    0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
    0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00,
    0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
    0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
    0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
    0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
    0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
    0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
    0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
    0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00,
    0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
    0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
    0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
    0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00,
    0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
    0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00,
    0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
    0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00,
    0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
    0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08,
    0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
    0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
    0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00,
    0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
    0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
    0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
    0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00,
    0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
    0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00,
    0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
    0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08,
    0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
    0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00,
    0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
    0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08,
    0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
    0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00,
    0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
    0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
    0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
    0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00,
    0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
    0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
    0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
    0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
    0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
    0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
    0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
    0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
    0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,   
    0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
    0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
    0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00,
    0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
    0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
    0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
    0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
    0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
    0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
    0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
    0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
    0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
    0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
    0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
    0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80,
    0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
    0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
    0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
    0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
    0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
    0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
    0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
    0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
    0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
/**
* @brief 写显示数据
*
* @param bytes 字节数组
* @param length 数组长度
*/
void Int_Oled_WriteData(u8 bytes[], u8 length)
{
    u8 i;
    // 发送起始信号
    Dri_IIC_Start();

    // 发送设备地址
    Dri_IIC_SendByte(OLED_ADDR);
    Dri_IIC_ReceiveAck();

    // 发送控制字节
    Dri_IIC_SendByte(DATA_MODE);
    Dri_IIC_ReceiveAck();

    // 发送数据
    for (i = 0; i < length; i++) {
        Dri_IIC_SendByte(bytes[i]);
        Dri_IIC_ReceiveAck();
    }
    Dri_IIC_Stop();
}
/**
* @brief 写控制命令
*
* @param bytes 字节数组
* @param length 数组长度
*/
void Int_Oled_WriteCmd(u8 bytes[], u8 length)
{
    u8 i;
    // 发送起始信号
    Dri_IIC_Start();
    // 发送设备地址
    Dri_IIC_SendByte(OLED_ADDR);
    Dri_IIC_ReceiveAck();
    // 发送控制字节
    Dri_IIC_SendByte(CMD_MODE);
    Dri_IIC_ReceiveAck();
    // 发送数据
    for (i = 0; i < length; i++) {
        Dri_IIC_SendByte(bytes[i]);
        Dri_IIC_ReceiveAck();
    }
    Dri_IIC_Stop();
}
void Int_Oled_Init()
{
    u8 bytes[6];
    // 关闭屏幕
    bytes[0] = 0xAE;
    // Segment 重映射
    bytes[1] = 0xA1;
    // Common 重映射
    bytes[2] = 0xC8;
    // 启动内置电荷泵(用于升压)
    bytes[3] = 0x8D;
    bytes[4] = 0x14;
    // 开启屏幕
    bytes[5] = 0xAF;
    Int_Oled_WriteCmd(bytes, 6);
}

/**
* @brief 设置页地址和列地址
*
* @param page 页地址
* @param column 列地址
*/
void Int_Oled_SetPointer(u8 page, u8 column)
{
    u8 bytes[3];
    bytes[0] = 0xB0 | (page & 0x07);
    bytes[1] = 0x00 | (column & 0x0F);
    bytes[2] = 0x10 | ((column >> 4) & 0x07);
    Int_Oled_WriteCmd(bytes, 3);
}

void Int_Oled_Clear()
{
    u8 i;
    u8 j;
    for (i = 0; i < 8; i++) {
        Int_Oled_SetPointer(i, 0);
        for (j = 0; j < 8; j++) {
            Int_Oled_WriteData(Int_Oled_Font[0], 16);
        }
    }
}

void Int_Oled_ShowStr(u8 x, u8 y, u8 *str)
{
    u8 i;
    // 上半部分
    // 设置页地址和列地址
    Int_Oled_SetPointer(2 * y, 8 * x);
    // 发送数据
    for (i = 0; i < 16 - x && str[i]; i++) {
        Int_Oled_WriteData(Int_Oled_Font[str[i] - 32], 8);
    }
    // 下半部分
    // 设置页地址和列地址
    Int_Oled_SetPointer(2 * y + 1, 8 * x);
    // 发送数据
    for (i = 0; i < 16 - x && str[i]; i++) {
        Int_Oled_WriteData(Int_Oled_Font[str[i] - 32] + 8, 8);
    }
}

void Int_Oled_ShowNum(u8 x, u8 y, long int num)
{
    u8 str[17];
    u8 i = 0;
    u8 j = 0;
    u8 tmp;
    if (num == 0) {
        str[0] = '0';
    } else {
        if (num < 0) {
            str[i++] = '-';
            num = -num;
            j = 1;
        }
        // 转换字符串
        while (num) {
            str[i++] = num % 10 + '0';
            num = num / 10;
        }
        // 字符串终止
        str[i] = 0;
        i--;
        // 反转整个数字
        while (i > j) {
            tmp = str[i];
            str[i] = str[j];
            str[j] = tmp;
            i--;
            j++;
        }
    }    
    Int_Oled_ShowStr(x, y, str);
}

(3)main.c

#include "Int_Oled.h"
void main()
{
    Int_Oled_Init();
    Int_Oled_Clear();
    Int_Oled_ShowStr(0, 0, "Hello world!");
    Int_Oled_ShowNum(0, 1, 123456);
    while (1) {
    }
}

嵌入式硬件工程师成长之路·2026(2):电阻与电容选型实战清单——常温能过、高温就漂的 6 个参数 常温测试全绿,45℃ 老化 8 小时就有 3 台采样点漂了 300mV?先别换料。本文按排查顺序拆解:热风枪定位、TCR 误差预算算出温漂只占 22mV,真凶是 X5R 电容的直流偏压衰减。附电阻封装、电容介质、降额系数三张对照表和 5 条避坑清单,单台 9 分钱修完。 阅读详情

相关推荐

[Vue][面试]谈谈你对MVC、MVP和MVVM的理解

谈谈你对MVC、MVP和MVVM的理解 答题思路:此题涉及知识点很多,很难说清楚,说透彻,因为MVC,MVP这些我们前端程序员自己甚至都没用过。但是恰恰反映了前端这些年从无到有, 从有到优的变迁过程,因此沿此思路回答将十分清除。 Web1.0时代 在web1.0时代,并没有前端的概念。开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常由多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、C#/Java/PHP代码, 系统整体架构可能如下图所

你好,欢迎光临! 723

十天学会嵌入式技术之51单片机—day-10

手把手入行嵌入式之10天学会51单片机day-10

2301_80748708的博客 2477

jaka+realsense+aruco+手眼标定(python)

第二次重建了项目的手眼标定部分……有很多第一次记录遗漏的地方,在此补充。

drivenzyw的博客 2122

10天学会嵌入式技术之51单片机-day-7

手把手入行嵌入式之10天学会51单片机day-7

2301_80748708的博客 1339

基于PLC的立体车库控制系统设计

本文介绍了基于西门子S7-1511-1PN PLC和KTP700 Basic PN HMI的立体堆垛式停车场自动化控制系统。系统通过PLC逻辑控制滑台运动,配合传感器实现车辆存取自动化,包含初始化、入库、出库和安全保护程序。程序采用模块化设计,分为安全互锁、动画显示、模式切换等六个功能模块,运用边沿触发、定时器和多级联锁确保安全。HMI界面提供模式切换、车位选择、状态显示和手动控制功能。该系统具有模块化、安全性和可扩展性特点,可应用于多车位立体停车场场景。

sxs3030787796的博客 1265

手把手教你用STM32CubeIDE移植Vector CCP驱动,实现与INCA的标定通信(附避坑指南)

本文详细介绍了如何在STM32CubeIDE环境下移植Vector CCP驱动,实现与INCA的标定通信。从开发环境准备、CAN外设配置到CCP协议栈移植和A2L文件生成,提供了完整的操作流程和常见问题解决方案,帮助工程师快速掌握基于CAN总线的标定技术。

weixin_28685287的博客 138

10天学会嵌入式技术之51单片机-day-2

手把手入行嵌入式之10天学会51单片机day-2

2301_80748708的博客 705

华为OD新系统机试真题 - 操作历史管理器的撤销/重做能力

华为OD机试新系统真题【操作历史管理器的撤销/重做能力】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【操作历史管理器的撤销/重做能力】

qq_45776114的博客 865

【学习笔记】51单片机 按键控制LED流水灯模式&定时器时钟

在下面去给他写中断子函数,他会在main中去到Timer0这个子函数当中去,再接着跳转回来。再TMOD上,这个是不可位寻址的,必须八位同时复制,如果同时使用定时器1和定时器0,先配置定时器1再去配置定时器0会把 之前前定时器1的更新掉,我们去给他让他只去执行一部分。现在我们要去做中断了,改正之后的是这样,但其实是还有缺陷在的。寄存器是连接软硬件的媒介,我们现在写一个关于这个的代码。这样得到的和我们预期的一样。TMOD的寄存模式,M1和M0是来决定工作模式的。我们要看的是关于以下的寄存器。

2601_96469072的博客 235

扫地机器人行业 企业篇-产业总部地理分布

中国扫地机器人产业呈现区域集聚特征,广东省以13家企业领跑全国,其中深圳独占9家(如大疆、云鲸智能等),佛山、广州、东莞各有分布。江苏省6家企业主要集中在苏州(科沃斯、追觅科技等)。北京聚集了石头科技、小米等4家品牌。浙江、山东、湖南等地也有代表性企业分布。国际品牌方面,美国iRobot、韩国三星/LG、日本松下等均在各自国家设立总部,而戴森、飞利浦等欧洲品牌则将中国运营中心设在上海或苏州。值得注意的是,部分品牌如由利、宝家丽虽为外资起源,但主要运营实体已落户中国。

智能硬件研发,欢迎交流 363

Lumerical 教程目录,说明及个人感悟(共计138篇,持续更新中)

Lumerical---教程说明及个人感悟

u011699626的博客 1万+

51单片机:流水灯

复位后单片机会:PC归零(从0000H重新执行)、各SFR恢复默认值、端口输出高电平(P0~P3默认全1)。所以复位期间LED通常全灭(共阳极接法下输出1即灭),复位结束后程序从头跑起。正常工作时RST应保持低电平(接近0V),复位时则需把它拉高。:当RST引脚上的电压高于某个阈值(通常约1.5V~2.5V,具体随芯片型号和电源电压变化)并持续。,视觉上像水流一样移动。以8个LED接P1口、共阳极接法为例:要让最低位LED亮,P1应输出。的值,每个值点亮不同的LED组合,配合延时,人眼就看到"流动"效果。

橘为己有的博客 199

使用STM32实现简单的语音识别

此外,还需要将计算机的音频输出连接到外部音频放大器上,以便将测试语音播放到MAX9814麦克风模块。运行STM32代码后,系统将开始采集语音数据,并在采集完成后调用Python脚本进行MFCC特征提取。在本案例中,我们将使用STM32F4开发板、MAX9814麦克风模块和MFCC特征提取算法来实现语音识别。通过这个案例,我们可以了解到如何结合STM32开发板和Python实现语音识别,并可以根据需要进行相关扩展和优化。现在,我们可以编译和烧录STM32代码到开发板中,并准备好测试语音文件。

吃不胖. 1473

【学习笔记】51单片机 定时器

定时器子单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当技术单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数执行。注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的。注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的终端资源,例如中断源个数不同、中断优先级个数不同等。

2601_96469072的博客 259

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

51单片机:STC89C52RC片内硬件结构

8051 兼容内核 + 8KB Flash + 512B SRAM + 4KB EEPROM + 3 个定时器 + 8 个中断源 + 1 个 UART + 看门狗,相比经典 8051/89C52,主要增强了 RAM 容量、EEPROM、定时器数量和中断优先级层级,同时保留了串口直接下载的便利性。

橘为己有的博客 283

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

(done) 嵌入式硬件电路图 (5) 重要的元器件特性之二极管三极管

TODO: here。

shimly123456的博客 176

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

(done) 嵌入式硬件电路图 (1) 看图的脉络依据

TODO: here。

shimly123456的博客 43

(done) 嵌入式硬件电路图 (3) 重要的元器件特性之电阻

TODO: here。

shimly123456的博客 23

(done) 嵌入式硬件电路图 (4) 重要的元器件特性之电容

TODO: here。

shimly123456的博客 168

(done) 嵌入式硬件电路图 (2) 熟悉常用元器件

常见电阻分为 贴片电阻 和 色环电阻。

shimly123456的博客 44

嵌入式硬件选型|EY406-2131D1 双路互补脉冲长按复位 IC 方案解析

在锂电供电的嵌入式项目开发中,带无线模组的复合系统经常遇到复位不同步问题。主控完成复位,蓝牙、WiFi 射频模块未同步复位,模块状态不一致,出现配网失败、链路锁死等现象。软件长按复位方案在主控跑飞后直接失效,RC 延时电路受温漂、器件离散性影响,量产时序一致性较差。EY406-2131D1 是 SOT23-6 封装纯硬件逻辑复位芯片,依靠硬件计时实现长按识别与双路脉冲输出,可以作为这类场景的备选方案。

ELITECHIPLJW的博客 156

基本定时器(TIM6/TIM7)

基本定时器最简单,就干一件事:到点了触发中断。定时器本质就是计数器,每个时钟脉冲加1,数到ARR就溢出、产生中断、清0重来。三个核心寄存器:PSC(预分频器):对输入时钟分频CNT(计数器):从0往上数ARR(自动重装载值):数到这个值就溢出,CNT清0,产生更新中断公式:  定时周期 = (PSC+1) × (ARR+1) / 定时器时钟  更新事件频率 = 定时器时钟 / ((PSC+1) × (ARR+1)) 例:TIM6时钟84MHz,要定时0.5秒(2

2401_89890233的博客 244

串口实验-11

① 显示串口0接收到的数据② 串口0每隔3秒发送“waitting for serial data”信息COM30IDE 右上角 …三个点打开 串口监视器,选择波特率 115200在串口监视器 消息 位置 输入:hello esp32s3,会打印输出使用串口1来实现 串口数据回显功能方便大家后面用到串口接口的模块时,能知道使用方法COM26。

智能机器人产学研基地 25

TMS320F28335 学习笔记(二):系统时钟、PLL 与看门狗

本文系统介绍F28335的时钟架构与看门狗应用,涵盖外部晶振、PLL倍频生成系统时钟(SYSCLKOUT)、高速/低速外设时钟分频配置,以及看门狗的启用、关闭与喂狗机制。强调时钟配置准确性对延时、PWM、通信等外设的重要性,指出常见错误如晶振不匹配、未等待PLL锁定、随意修改PLL或喂狗周期过长等问题,并提供初始化框架与验证方法,帮助开发者正确配置时钟系统,确保程序稳定运行。

2403_83044722的博客 350

MCU 启动流程解析:从 SRAM 到 DDR

MCU 的性能瓶颈通常不在 DDR 带宽,而在访问延迟与确定性。因此,关键代码、中断向量、栈以及功能安全数据应放在片内 SRAM;大块传感器数据缓冲、堆和冷数据则放在 DDR。启动流程的核心可以概括为三步:Boot ROM 搬运、Remap 切换、SRAM 执行。

Where there is life, there is hope. 283

MCU的ADC采样怎么配

一块采集板,室温下读电池电压挺准,一上高低温箱就差出0.3V。软件反复查了三遍,没改一行代码,最后发现是参考电压选错了——电源纹波直接灌进了测量基准。ADC这东西,代码就那么几行,坑全在配置里。这篇拿ATmega16当例子,把采样链路从头讲清:参考电压怎么选、时钟为什么卡在50到200kHz、结果为什么要讲究读取顺序。这些规则不只对AVR成立,换成车规MCU,思路一样。

qq_43241255的博客 194
上一篇: 10天学会嵌入式技术之51单片机-day-8
下一篇: 十天学会嵌入式技术之51单片机—day-10
昊昊昊昊昊明
博客等级 码龄3年 285粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值