前一章介绍了在ESP8266下搭建的天气预报机。
单片机—ESP8266模块开发
当时结果中含有中文的部分乱码了,今天尝试着解决一下这个问题。
这里涉及到的问题有以下几步:
- 首先要将utf-8的字符串,转化为gbk编码,
- 然后通过查找HZK字库,找到对应的点阵数据,
- 修改扫描模式,最后放到屏幕上显示。
- 优化多个字符一起显示
- 优化中英文一起显示
我们一步一步来尝试解决。
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。