Single chip microcomputer -- oled Chinese display in ESP8266

The previous chapter introduced the weather forecast machine built under ESP8266. At that time, the results contained some Chinese garbled codes. Today, I try to solve this problem.
The problems involved here include the following steps:

  1. First, convert the string of utf-8 into gbk encoding,
  2. Then find the corresponding lattice data by looking up the HZK font,
  3. Modify the scanning mode and finally display it on the screen.
  4. Optimize the display of multiple characters together

Let's try to solve it step by step.

utf to gbk coding

Our development environment is the development board of ESP8266. freeRTOS system is used. Compared with the iconv method under conventional linux, we do not have this library. If we transplant it, it will be more troublesome (actually lazy)

Here is a version of look-up table method.
Code download
c language version utf-8 to gbk look-up table method

The following interface is used

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

Do a test first.

We can compile the two files first to test the conversion effect

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

You can see it in the print

By comparing gbk coding table

Found no problem. So smooth?

Find font

Continue, gbk convert font. HZK font library is used here. Download link
HZK font
This word library is a file, but on our single chip microcomputer, there is no more suitable way to import this file directly into the device, because there is no ready-made file system in it. Therefore, here, flash is used to directly burn the file to a fixed position, and then the corresponding data can be obtained by directly reading the content in flash.

First, burn the HZK file
Our is 8Mflash, and we don't know how much we used earlier, so I used the last 1M location to store the HZK file. The HZK file is about 200 K, which is enough

Then we test the read-write flash interface again. Interface is used

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;
}

Test the file we just burned in. Just check the two to see if they are consistent.

Read function

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

test result

No problem.

Character display

Then we start to search HZK, find the lattice data of the test character "I", and use the previous data to test

	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");
    }

Then you can see my picture

But if you want to display it on the oled screen, another step is to change the scanning mode. HZK uses progressive scanning and oled is determinant scanning. It needs to be transformed.

A function is used here, referring to a function of the boss, but a compilation error is slightly modified.

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;
}

Then an interface for displaying Chinese characters is encapsulated

void OLED_ShowHZK(unsigned char x,unsigned char y,unsigned char* data)
{      			    
	unsigned char t; //Define variables

	OLED_Set_Pos(x,y);	//Start with X and Y and start with the first page
    for(t=0;t<16;t++) //Cycle 16 times and draw 16 columns on the first page
	{
		OLED_WR_Byte(data[t],OLED_DATA);//Draw no the point in column 16 on the first page of the array position
 	}	
	OLED_Set_Pos(x,y+1); //Draw the second page
    for(t=16;t<32;t++)//Cycle 16 times and draw 16 columns on the second page
	{	
		OLED_WR_Byte(data[t],OLED_DATA);//Draw no the point in column 16 on the second page of the array position
    }					
}

Finally, test

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

Test results, successful!

optimization

After optimization, it can display multiple Chinese characters.

void get_hzk(unsigned char* gbkdata,int len ,unsigned char* modedata,int* modes)
{
	//If it's Chinese characters
	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 bytes to 2 bytes, length change
	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("Hello, brother");
}

effect

reference resources

Blog of a great God
Chinese character dot matrix description

end

Yesterday's article was on the hot list. Don't you all know our boss's actions.

Intel started to be a demon again these two days and made rubbish remarks. It really doesn't pay attention to the world's largest market. However, it's really uncomfortable here. If we want to follow our temper, we won't tm need it, but there's really no way. Use AMD? Also beautiful

No choice is the most sad place. Therefore, we should study hard. As a programmer, we should have our own value to society and feel useful things, or share them with everyone as much as possible. Therefore, we often update articles these days, hoping to have some useful things, help others walk less, and have a deeper understanding.

I hope our computers can use their own CPU in our lifetime.

Keywords: Single-Chip Microcomputer ESP8266 OLED

Added by mynameisbob on Mon, 27 Dec 2021 10:17:41 +0200