单片机---ESP8266中oled中文显示(完美方案)

前一章介绍了在ESP8266下搭建的天气预报机。
单片机—ESP8266模块开发

当时结果中含有中文的部分乱码了,今天尝试着解决一下这个问题。
这里涉及到的问题有以下几步:

  1. 首先要将utf-8的字符串,转化为gbk编码,
  2. 然后通过查找HZK字库,找到对应的点阵数据,
  3. 修改扫描模式,最后放到屏幕上显示。
  4. 优化多个字符一起显示
  5. 优化中英文一起显示

我们一步一步来尝试解决。
在这里插入图片描述

utf转gbk编码

我们的开发环境是ESP8266的开发板,用了的freeRTOS系统,对比常规linux下面的iconv方式,我们并没有这个库,移植的话,比较麻烦(其实就是懒)
在这里插入图片描述

这里介绍了一个查表法的版本。
代码下载
c语言版本utf-8转gbk查表法

使用方式就是下面的接口

int SwitchToGbk(const unsigned char* pszBufIn, int nBufInLen, unsigned char* pszBufOut, int* pnBufOutLen)

做个测试先。在这里插入图片描述

我们可以先将两个文件编译进去,测试一下转化效果

	unsigned char out[8]={0};
	int lenout=0;
	unsigned char falsh[8]={0};
	ESP_ERROR_CHECK( nvs_flash_init() );
	SwitchToGbk((unsigned char*)"我",3, out, &lenout);
	printf("lenout:%d 0x%02x 0x%02x\n",lenout,out[0],out[1]);

打印中可以看到
在这里插入图片描述
通过对照gbk编码表
在这里插入图片描述
发现没有问题。这么顺利?
在这里插入图片描述

查找字库

继续,gbk转化字模。这里用到了HZK字库,下载链接
HZK字库
这个字库是一个文件,但是我们的单片机上,并没有办法比较合适的将这个文件直接导入到设备中,因为并没有现成的文件系统在里面,所以,这里用flash方式,直接将文件烧录到固定的位置上,到时候直接读取flash中的内容就可以获得相应的数据了。
在这里插入图片描述

首先烧写HZK文件
我们的是8Mflash,也具体不太清楚前面用到了多少,所以我用了最后1M的位置来存储这个HZK文件,HZK文件大概两百多K,足够了
在这里插入图片描述
然后我们再次测试读写flash接口。使用的是接口

esp_err_t spi_flash_read(size_t src_addr, void *des_addr, size_t size)
{
    if (!s_emulator) {
        return ESP_ERR_FLASH_OP_TIMEOUT;
    }

    if (!s_emulator->read(reinterpret_cast<uint32_t*>(des_addr), src_addr, size)) {
        return ESP_ERR_FLASH_OP_FAIL;
    }

    return ESP_OK;
}

测试一下我们刚才烧写进去的文件,就检查这两位,看看一致不一致。
在这里插入图片描述
读取函数

	spi_flash_read(0x700000+0x70, falsh, 2);
	printf("falsh: 0x%02x 0x%02x\n",falsh[0],falsh[1]);

测试结果
在这里插入图片描述
没毛病。

字符显示

然后我们就开始查找HZK,找到测试字符“我”的点阵数据,利用前面的数据,我们接着测试

	offset = (94*(unsigned int)(out[0]-0xa0-1)+(out[1]-0xa0-1))*32;
	spi_flash_read(0x700000+offset, falsh, 32);
    for(k=0; k<16; k++)
	{
        for(j=0; j<2; j++)
		{
            for(i=0; i<8; i++)
			{
				unsigned char flag=0;
                flag = falsh[k*2+j]&key[i];
                printf("%s", flag?"●":"○");
            }
        }
        printf("\n");
    }

然后就能看到我的图片了
在这里插入图片描述
但是如果要在oled屏幕上显示,还有一步,就是转化一下扫描方式。HZK用的是逐行扫描,oled是行列式扫描,需要转化一下。
在这里插入图片描述
这里用了一个函数,参考了大佬的一个函数,不过稍微修改了一个编译error。

int change_arrangement_mode(unsigned char *pc_buf, unsigned char *oled_buf, int len)
{
    int i, j, k;
    if (len % 32)
    {
        printf("len is not multiple of 32 \n");
        return -1;
    }
    k = 0;
    do 
	{
		for (i = 0; i < 8; i++)
		{
			for (j = 0; j < 8; j++)
			{
				oled_buf[i   ]|=(((pc_buf[j*2] 			& (0x1<<(7-(i%8))))>>(7-(i% 8))) << j );
				oled_buf[i+ 8]|=(((pc_buf[j*2+1] 		& (0x1<<(7-(i%8))))>>(7-(i% 8))) << j );
				oled_buf[i+16]|=(((pc_buf[j*2+16] 		& (0x1<<(7-(i%8))))>>(7-(i% 8))) << j );
				oled_buf[i+24]|=(((pc_buf[j*2+1+16]		& (0x1<<(7-(i%8))))>>(7-(i% 8))) << j 	);
			}
		}
		k += 32;
		pc_buf += 32;
		oled_buf += 32;
	}while(k < len);
    pc_buf -= k;
    oled_buf -= k;
	return 0;
}

然后封装了一个显示汉字的接口

void OLED_ShowHZK(unsigned char x,unsigned char y,unsigned char* data)
{      			    
	unsigned char t; //定义变量

	OLED_Set_Pos(x,y);	//从 x y 开始画点,先画第一页
    for(t=0;t<16;t++) //循环16次,画第一页的16列
	{
		OLED_WR_Byte(data[t],OLED_DATA);//画no在数组位置的第一页16列的点
 	}	
	OLED_Set_Pos(x,y+1); //画第二页
    for(t=16;t<32;t++)//循环16次,画第二页的16列
	{	
		OLED_WR_Byte(data[t],OLED_DATA);//画no在数组位置的第二页16列的点
    }					
}

最后进行测试

change_arrangement_mode(falsh,oled,32);
OLED_ShowHZK(16,0,oled);

测试结果,成功!
在这里插入图片描述

优化1

然后经过了优化,能够显示多个汉字。

void get_hzk(unsigned char* gbkdata,int len ,unsigned char* modedata,int* modes)
{
	//如果是汉字
	int i=0;
	int tmpmods=0;
	while(i<len)
	{
		if((gbkdata[i]>=0x81)&&(gbkdata[i]<0xFE))
		{
			unsigned char tmpmod[32]={0};
			unsigned int offset=0;
			
			offset = (94*(unsigned int)(gbkdata[i]-0xa0-1)+(gbkdata[i+1]-0xa0-1))*32;
			spi_flash_read(0x700000+offset, tmpmod, 32);
			memcpy(modedata+tmpmods*32,tmpmod,32);
			tmpmods++;
			i=i+2;
		}
	}
	*modes=tmpmods;
}

void show_chinese(char* instring)
{
	unsigned char* gbks=NULL;
	int gbks_len=0;
	
	unsigned char* mods=NULL;
	int mods_count=0;
	
	unsigned char* oleds=NULL;
	int oleds_len=0;
	
	gbks=malloc(strlen(instring)+1);
	memset(gbks, 0, strlen(instring)+1);

	//3字节转2字节,长度变化
	SwitchToGbk((unsigned char*)instring,strlen(instring), gbks, &gbks_len);

	mods=malloc((gbks_len+1)*32);
	memset(mods, 0, (gbks_len+1)*32);
	
	get_hzk(gbks,gbks_len,mods,&mods_count);
	oleds_len=mods_count*32;
	oleds=malloc(oleds_len);
	memset(oleds, 0, oleds_len);
	
	printf("oleds_len:%d\n",oleds_len);
	change_arrangement_mode(mods,oleds,oleds_len);

	//OLED_ShowHZK(16,0,oleds);
	
	OLED_ShowHZKS(16,0,oleds,mods_count);
	free(gbks);
	free(mods);
	free(oleds);
}
void app_main()
{
    ESP_ERROR_CHECK( nvs_flash_init() );
	OLED_Init();
	OLED_Clear();
	show_chinese("你好兄弟");
}

效果
在这里插入图片描述

优化2

必须要让字符串和英文字符,共同显示,那才专业
在这里插入图片描述
上代码

void show_chinese(char* instring)
{
	//如果是汉字
	int x=0;
	int y=0;
	
	int i=0;
	int tmpmods=0;
	
	unsigned char* gbks=NULL;
	int gbks_len=0;

	
	unsigned char* mods=NULL;
	int mods_count=0;
	
	unsigned char* oleds=NULL;
	int oleds_len=0;
	
	gbks=malloc(strlen(instring)+1);
	memset(gbks, 0, strlen(instring)+1);

	//3字节转2字节,长度变化
	SwitchToGbk((unsigned char*)instring,strlen(instring), gbks, &gbks_len);
	
	while(i<gbks_len)
	{
		if((gbks[i]>=0x81)&&(gbks[i]<0xFE))
		{
			unsigned char tmpmod[32]={0};
			unsigned int offset=0;
			unsigned char oledmod[32]={0};
			
			offset = (94*(unsigned int)(gbks[i]-0xa0-1)+(gbks[i+1]-0xa0-1))*32;
			spi_flash_read(0x700000+offset, tmpmod, 32);
			change_arrangement_mode(tmpmod,oledmod,32);
			
			OLED_ShowHZK(x,y,oledmod);
			
			x=x+16;
			i=i+2;
		}
		else
		{
			OLED_ShowChar(x,y,gbks[i]);
			i=i+1;
			x=x+8;
		}
	}
}

效果杠杠的
在这里插入图片描述

参考

一位大神的博客
汉字点阵说明

结束

昨天的文章上了热榜,那岂不是都知道了我们老板的举动了。
在这里插入图片描述
Intel这两天又开始作妖,发表的垃圾言论,真是不把全球最大市场放在眼里啊,不过这里还真是有些难受,要按照咱们的脾气,就tm不用了,可是这可就真没办法了,用AMD?也是美丽的……

没得选择才是最可悲的地方,所以说,还是要努力学习,作为程序员,要有自身对于社会的价值,感觉有用的东西,还是尽量分享给大家,所以这些天经常更新文章,就是希望能有一些有用的东西,能帮他人少走些,自己也能够有更深刻的认知。

希望有生之年,我们的电脑,能用上自己的CPU。
在这里插入图片描述

  • 16
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值