当前位置: 首页 > news >正文

OLED中英文混合显示

 前情提要

        内容主要包含OLED显示中英文混合的代码逻辑。

OLED屏幕介绍

        

四针脚 OLED 显示屏是一种常见的显示模块,包括一个 OLED 显示屏和 4 个引脚,常用于嵌入式系统、小型电子设备,如智能手表、健康追踪器等3。

引脚功能3

  • VCC:电源引脚,一般提供 3.3V 或 5V 电源,为模块供电。
  • GND:地引脚,用于提供模块接地。
  • SCL:时钟引脚,传输数据时提供时钟信号,需连接到主控芯片时钟引脚。
  • SDA:数据引脚,用于传输数据,使用 I2C 接口时也称为串行数据线。

特点

  • 接口简单:主要使用 I2C 接口,线路连接少,通信协议简单,降低硬件设计复杂度和成本,也便于软件开发1。
  • 显示效果出色:具有高对比度,能呈现清晰锐利的图像;响应速度快,适合显示动态内容;视角宽广,从各个角度观看画面失真小5。
  • 低功耗:显示黑色时几乎不耗电,在电池供电设备中能有效延长续航时间5。
  • 尺寸小:屏幕尺寸通常较小,如 0.96 英寸等,适用于空间有限的小型设备3。

工作原理

  • OLED 发光原理:通过电场驱动,有机半导体材料和发光材料经载流子注入和复合后实现发光,每个像素点可独立控制发光,无需背光源4。
  • 数据传输与控制:通过 I2C 或 SPI 通信协议,主控芯片向 OLED 显示屏的控制器发送命令和数据,控制器内部的帧缓冲区存储像素状态,根据接收到的指令和数据更新显示内容。

OLED显示基础(重要)

        我单独拿出这个来是因为,写逻辑的时候需要计算显示位置,这张图可以很好的表现出oled屏幕的空间,我们可以将OLED屏幕想象成一个64行128列的表格。

        中文一般是16*16,英文类符号一般是8*16(高*长),也就是说一个汉字在oled屏幕上显示需要花费16行16列,英文同理。中英文在行上占格子的不同,就需要设计一个合理的逻辑方便他们可以一起显示。还需要说明,按照以上论述可以得到中文是最多有4行8列,英文则是4行16列。

        

OLED核心代码逻辑介绍

第一个核心设计是,如何解决通过中文索引取字符点阵?

我设计了一个结构体,构建结构体数组,将汉字作为索引的角色,来取字符点阵,结构体设计如下;Index存储的是3个字节,这里的编码结构是gbk的,所以一个中文是两个字节,然后加上\0构成一个char数组,来作为结构体数组的索引。

typedef struct
{
	const char Index[3];
	uint8_t data[32];
		
}Myoled;

取输入,采用循环,每两个字符,为一个中文,将输入的字符串切割成单个中文(SigleChinese),将切割好的单个汉字与Myoled结构体构成的数组中的每一个元素比较,当中文匹配成功,取出中文进行显示。

char SigleChinese[3] = {Chinese[i], Chinese[i + 1], '\0'};
            uint8_t pIndex;
            for (pIndex = 0; strcmp(expe[pIndex].Index, "") != 0; pIndex++) 
			{
                if (strcmp(expe[pIndex].Index, SigleChinese) == 0) 
				{
                     break;
                }
            }

   第二个核心设计是,如何中英文混合显示?

这就涉及到我上面提到的位置计算(列位置的计算),初始位置+中文输出次数*16+英文输出次数*8。

offsetcol = Column + 16 * ccount + 8 * ecount;

OLED中英文显示核心代码

//显示实验,名字,日期
void OLED_ShowChar1(uint8_t Line, uint8_t Column, char Char, uint8_t ccount, uint8_t ecount)
{      	
	uint8_t i;
	uint8_t offsetcol=0;
	
	offsetcol = Column + 16 * ccount + 8 * ecount;
	
	OLED_SetCursor((Line - 1) * 2, offsetcol);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, offsetcol);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

void OLED_ShowChinses_oneexpe(uint8_t Line, uint8_t Column,const uint8_t *t, uint8_t ccount, uint8_t ecount)
{      	
	uint8_t i;
	uint8_t offsetcol=0;
	
	offsetcol = Column + 16 * ccount + 8 * ecount;
	
	OLED_SetCursor((Line - 1) * 2, offsetcol);		//设置光标位置在上半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(t[i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, offsetcol);	//设置光标位置在下半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(t[i+16]);		//显示下半部分内容
	} 
}




void OLED_ShowChinses_exep1(uint8_t Line, uint8_t Column, char *Chinese) 
{
    //uint8_t currentColumn = Column;
    uint8_t i = 0;
	uint8_t j = 1;
	uint8_t ccount = 0;
	uint8_t ecount = 0;
    while (Chinese[i] != '\0') 
	{ 
		
		if (j == 1)
		{
			if ((Chinese[1] & 0x80) == 0)
			{
				Column = (Column - 1) * 8;
			}
			else
			{
				Column = (Column - 1) * 16;
			}
			j = 0;
		}
		
        if ((Chinese[i] & 0x80) == 0) 
		{  // 单字节字符(英文)
			OLED_ShowChar1(Line, Column, Chinese[i], ccount, ecount);
            //currentColumn += 1;  
            i++;
			ecount++;
        } 
		else 
		{  // 双字节字符(中文)
            char SigleChinese[3] = {Chinese[i], Chinese[i + 1], '\0'};
            uint8_t pIndex;
            for (pIndex = 0; strcmp(expe[pIndex].Index, "") != 0; pIndex++) 
			{
                if (strcmp(expe[pIndex].Index, SigleChinese) == 0) 
				{
                     break;
                }
            }
            
			OLED_ShowChinses_oneexpe(Line, Column, expe[pIndex].data, ccount, ecount);
            //currentColumn += 1; 
            i += 2;  // 跳过中文的第二个字节
			ccount++;
        }
    }
}

总结

        我认为我在做这个实验的时候遇到的最大的问题不是核心代码的逻辑设计,反而是一个编码问题,就是我的字库文件是utf8的,但是我的编译器是gpk的,这样在汉字匹配的时候就会出现汉字无法正确匹配的问题,我也是在进行调试后才发现,从字模库中取出的汉字并不是我所要的,因为utf8是3字节,然后我的逻辑只取两字节,就会出问题。然后还有一个问题就是,位置的计算,我一开始没反应过来,为啥显示内容没问题,显示位置异常,然后就研究了一下上面的坐标图,就推出了我想的那个公式。总之,遇到过程还是要多调试去发现它中间经历了什么,然后才方便解决,调试真是个好东西。

相关文章:

  • 如何设计一个处理物联网设备数据流的后端系统。
  • SpringMVC 配置详解
  • 《深度剖析:DevEco Studio 如何实现人工智能模型的高效可视化开发》
  • 交换机(access端口)
  • Vue中的状态管理器Vuex被Pinia所替代-上手使用指南
  • 数据预处理习题
  • EtherCAT转CANopen配置CANopen侧的PDO映射
  • JavaScript性能优化实战手册:从V8引擎到React的毫秒级性能革命
  • 大数据平台各组件功能与协同作用全解析
  • Python Excel表格数据对比工具
  • Spring MVC配置详解:从历史到实战
  • 多路径PKL文件读取与合并
  • 云服务器怎么设置端口禁用呢?
  • Python 迭代器与生成器:深入理解与实践
  • 资源分配图(RAG)检测死锁算法实现
  • 【数据库】sql错题详解
  • Android 16开发实战指南|锁屏交互+Vulkan优化全解析
  • QuectPython 网络协议之TCP/UDP协议最祥解析
  • drizzleDumper:基于内存搜索的Android脱壳工具
  • 计算机视觉算法实战——相机标定技术
  • 美国第一季度经济环比萎缩0.3%
  • 两部门预拨4000万元支持山西、广西、陕西做好抗旱救灾工作
  • 济南高新区一季度GDP增长8.5%,第二产业增加值同比增长14.4%
  • 80后共青团云南省委副书记许思思已任迪庆州委副书记
  • 力箭二号火箭成功进行满载起竖试验,计划今年首飞发射轻舟飞船
  • 马上评丨又见酒店坐地起价,“老毛病”不能惯着