1.前言:
接上篇,
https://bbs.elecfans.com/jishu_2278344_1_1.html
当手势传感器案例可以和OLED运行之后,我们就可以想办法更好玩一些了,想要好玩一些的话当然就是用手势操作菜单了.具体的效果可以看帖子上面的视频来感受.
2.制作中文字体
如果要实现手势菜单.就不能使用以前的方式来操作中文了,除非你能记住所有的中文字的位置,那这种情况下要如果进行呢,请看法宝:
- typedef struct Chinese_Font_data{
- char text[3];
- uint8_t data[32];
- }Chinese_Font_data;
- typedef struct ChineseFont{
-
- uint8_t font_size;
- uint8_t font_data_len;
- // uint8_t keep;
- Chinese_Font_data *font_data;
- }ChineseFont;
这里创建两个结构体,结构体里面就是存的字体信息和字体数据,那内容是啥样的呢,这里举几个例子:
- Chinese_Font_data xingkai_data_16[]={
- /*---------------子----------------*/
- {"子",
- {0x00,0x00,0x00,0x00,0x01,0xF0,0x0F,0x70,0x00,0x60,0x01,0xC0,0x01,0xFE,0x3F,0xFE,
- 0x78,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x07,0xC0,0x03,0x80,0x01,0x00}},
- /*---------------菜----------------*/
- {"菜",
- {0x00,0x00,0x06,0x70,0x06,0x7C,0x3F,0xFC,0x12,0xC0,0x03,0xC0,0x07,0x30,0x0D,0xE0,
- 0x05,0x70,0x3F,0xF8,0x17,0xC0,0x0D,0x60,0x19,0x38,0x71,0x1F,0x03,0x00,0x01,0x00}},
- /*---------------单----------------*/
- {"单",
- {0x00,0x00,0x06,0x70,0x07,0x60,0x02,0x70,0x0F,0xF8,0x0D,0xF8,0x0F,0xF0,0x07,0xF0,
- 0x07,0xA0,0x01,0xFE,0x7F,0xFC,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80}},
- /*---------------选----------------*/
- {"选",
- {0x00,0x00,0x00,0x60,0x00,0x60,0x19,0xE0,0x09,0xF8,0x01,0xF0,0x02,0x7C,0x3F,0xF8,
- 0x3A,0xA0,0x19,0xA0,0x19,0x24,0x0A,0x3E,0x7F,0x1C,0x01,0xFF,0x00,0x3C,0x00,0x00}},
- /*---------------项----------------*/
- {"项",
- {0x00,0x00,0x00,0x00,0x00,0x1E,0x01,0xFC,0x0E,0x60,0x3C,0xFC,0x0C,0x8C,0x0C,0xAC,
- 0x0E,0xAC,0x3F,0xAC,0x71,0xEC,0x01,0xFC,0x00,0xDC,0x01,0x8C,0x02,0x04,0x00,0x00}},
- }
3.中文字体的显示
处理完这个之后,就可以编写中文显示的方法了:
- void ssd1306_DrawChinese(char *ch, ChineseFont *font,SSD1306_COLOR color)
- {
- // printf("%d %dn",sizeof(xingkai_16),(sizeof(xingkai_16[0])));
- // printf("%d,, draw chinese:%sn",xingkai_16_font_len,ch);
- if(font == &xingkai_16){
- for(int ch_idx=0;ch_idx
- // printf("%d === %sn",i,font[i].text);
- Chinese_Font_data *font_data =&font->font_data[ch_idx];
- if(strncmp(ch,font_data->text,sizeof(font_data->text))==0){
-
- {
- int x=SSD1306.CurrentX,y=SSD1306.CurrentY;
- int w=font->font_size,h=font->font_size;
- int stride = 0;
- if (x + w > SSD1306_WIDTH || y + h > SSD1306_HEIGHT || w * h == 0) {
- printf("%dx%d @ %d,%d out of range or invalid!rn", w, h, x, y);
- return;
- }
- w = (w <= SSD1306_WIDTH ? w : SSD1306_WIDTH);
- h = (h <= SSD1306_HEIGHT ? h : SSD1306_HEIGHT);
- stride = (stride == 0 ? w : stride);
- uint8_t rows = font->font_data_len * 8 / stride;
- for (uint8_t i = 0; i < rows; i++) {
- uint32_t base = i * stride / 8;
- for (uint8_t j = 0; j < w; j++) {
- uint32_t idx = base + (j / 8);
- uint8_t byte = idx < font->font_data_len ? font_data->data[idx] : 0;
- uint8_t bit = byte & (0x80 >> (j % 8));
- ssd1306_DrawPixel(x + j, y + i, bit ? !color : color);
- }
- }
- }
- // ssd1306_DrawRegion(SSD1306.CurrentX,SSD1306.CurrentY,font->font_size,
- // font->font_size, font_data->data,font->font_data_len,0);
- SSD1306.CurrentX += font->font_size;
- break;
- }
- }
- }
-
- }
- void ssd1306_Text(char *string,uint8_t string_len,uint8_t font_size,uint8_t mode)
- {
- int i=0;
- // printf("Text:%x %x %x %x %x %x %d %d %dn",string[0],string[1],string[2],string[3],string[4],string[5],
- // string[3],string[4],string[5]);
- printf("ssd1306_Text %d:%sn",string_len,string);
- while(i
- if(string[i] < 0)
- {
- // printf("[%d ]%d %x for chinesen",i,string[i],string[i]);
- ssd1306_DrawChinese(&string[i],&xingkai_16,mode);
-
-
- i+=3;
- }
- else
- {
- // printf("[%d ]%d %x for charn",i,string[i],string[i]);
- ssd1306_DrawChar(string[i],Font_7x10,!mode);
- i+=1;
- }
- }
- }
这里面的一个逻辑就是判断字符是中文还是英文,如果是中文的话char值是小于0的,但是不是一个字符能表示,中文使用UTF-8,最多会使用3个字符表示一个中文字,所以当出现中文的时候,char数组里长度需要增加3,如果是英文字的话就只需要1个字符了.
这工作完成之后就可以测试中文和英文数字等的的显示了,随便写几个中文字,调用接口显示:
- ssd1306_Text("1.你好 2.Hello",strlen("你好世界"),16,0);
可以观察显示,不得不提一句,这地方花费了大量的时间在编译上,因为编译系统不完善.不能支持增量编译,希望厂家团队尽快解决.
4.制作菜单框架
其实这里演示的菜单框架比较简单,因为菜单会有子菜单项,所以需要用多叉树的结构来表现,请看法宝:
- typedef struct Menu{
- // char name[8];
- char text[14];
- char state;
- void *param;
- uint8_t sub_len;
- struct Menu **subMenu;
- void (*enterFunc)(struct Menu *menu);
- void (*exitFunc)(struct Menu *menu);
- }Menu;
,然后就制作菜单的数据,这里举例:
- #include "menu.h"
- #include
- Menu hoguo={
- .text="火锅",
- };
- Menu BBQ={
- .text="BBQ",
- };
- Menu western={
- .text="西餐",
- };
- extern Menu mainMenu;
- Menu *eating_subs[]={&mainMenu,&hoguo,&BBQ,&western};
- Menu eating={
- .text="聚餐",
- .sub_len = 3,
- .subMenu=eating_subs
- };
- Menu comedy={
- .text="喜剧片",
- .sub_len=0,
- };
- Menu Thriller={
- .text="惊悚片"
- };
- extern Menu movie;
- Menu *movie_subs[]={&mainMenu, &comedy,
- &Thriller};
- Menu movie={
- .text="看电影",
- .sub_len = 3,
- .subMenu=movie_subs
- };
- Menu yunnan={
- .text="云南",
- .sub_len=0,
- };
- Menu beijing={
- .text="北京"
- };
- Menu xizang={
- .text="西藏"
- };
- extern Menu trip;
- Menu *trip_subs[]={&mainMenu,&yunnan, &beijing,
- &xizang};
- Menu trip={
- .text="旅游",
- .sub_len = 4,
- .subMenu=trip_subs
- };
- Menu kge={
- .text="唱K",
- .sub_len=0,
- };
- Menu anmo={
- .text="按摩"
- };
- Menu xizao={
- .text="洗澡"
- };
- extern Menu relex;
- Menu *releax_subs[]={&mainMenu,&kge, &anmo,
- &xizao};
- Menu relax={
- .text="放松",
- .sub_len = 4,
- .subMenu=releax_subs
- };
- Menu *mainMenu_subs[5]={NULL,&eating,&trip,&movie,&relax};
- Menu mainMenu={
-
- .text = "娱乐活动",
- .sub_len = 5,
- .subMenu=mainMenu_subs
-
- };
菜单项制作好了之后,可以放到UI里去渲染
5.UI线程渲染菜单
- ssd1306_SetCursor(32, 0);
- ssd1306_Text(currentMenu->text,strlen(currentMenu->text),16,0);
- int show_idx=1;
- if(select_idx > max_sub){
- show_idx+=(select_idx-max_sub);
- // continue;
- }
- int cursor=1;
- for(int i=show_idx;isub_len;i++)
- {
-
-
- ssd1306_SetCursor(0, 16*(cursor++));
- Menu *currentSub=currentMenu->subMenu[i];
- if(currentSub){
- char text[24]={0};
- sprintf(text,"%d.%s",i,currentSub->text);
- printf("text = %sn",text);
- ssd1306_Text(text,strlen(text),16,select_idx==i);
- }
-
- }
- ssd1306_UpdateScreen();
这里的逻辑就是把菜单标题和子菜单都显示出来
6.结合手势传感器传的数据
把手势传感器的数据接收到,然后做相应的逻辑处理,这里有一个问题,就是目前菜单因为屏幕的原因,只能显示3个菜单,所以需要做一个机制,当选择的菜单超过当前长度的时候往下滑一格,
代码如下:
- static void *OLedTask(const char *arg)
- {
- (void)arg;
- uint32_t ret=0;
-
- ssd1306_Init();
- printf("OLedTask queueId=%dn",queueId);
- //ssd1306_DrawString("Hello HARMonyOS!", Font_7x10, White);
- int text_area_width = 64;
- int text_area_height = 64;
- int text_per_line_num = text_area_height / font_width;
- int mod = hope_num % text_per_line_num;
- int text_line_num = hope_num / text_per_line_num;
- if (mod)
- {
- text_line_num += 1;
- }
- printf("title_addr=%p,dir_addr=%pn", title_arr,dir_arr);
- int text_alredy_show = 0;
- int x = 0;
- int y = 0;
- int select_idx = 1;
- ssd1306_Fill(Black);
- ssd1306_SetCursor(0, 0);
- Menu *currentMenu = &mainMenu;
- int max_sub=3;
- int start=0;
-
- while(1){
- uint32_t flag = 0;
- uint32_t rLen =4;
- if(start){
-
- ret = LOS_QueueReadCopy(queueId,
- &flag,
- &rLen,
- LOS_WAIT_FOREVER);
- // LOS_Msleep(OLED_INTERVAL_TIME_US);
- printf("READ ret = %d,FLAG =%02xn",ret,flag);
- }
- start =1;
- ssd1306_Fill(Black);
- ssd1306_SetCursor(0, 0);
-
- int idx=0;
- for(;idx<9;idx++){
- if(flag&(1<
- break;
- }
- }
- printf("idx=%d,select_idx=%dn",idx,select_idx);
- switch(idx){
- case 0:
- if(select_idx > 1){
- select_idx--;
- }
- break;
- case 1:
- if(select_idx < currentMenu->sub_len-1){
- select_idx++;
- }
- break;
- case 2:
- {
- Menu *currentSub=currentMenu->subMenu[0];
- if(currentSub){
- currentMenu=currentSub;
- select_idx = 1;
- start = 0;
- continue;
- }
- }break;
- case 3:
- {
- Menu *currentSub=currentMenu->subMenu[select_idx];
- if(currentSub){
- currentMenu=currentSub;
- select_idx = 1;
- start = 0;
- continue;
- }
- }break;
-
- break;
- }
- printf(">>idx=%d,select_idx=%dn",idx,select_idx);
-
- ssd1306_SetCursor(32, 0);
- ssd1306_Text(currentMenu->text,strlen(currentMenu->text),16,0);
- int show_idx=1;
- if(select_idx > max_sub){
- show_idx+=(select_idx-max_sub);
- // continue;
- }
- int cursor=1;
- for(int i=show_idx;isub_len;i++)
- {
-
-
- ssd1306_SetCursor(0, 16*(cursor++));
- Menu *currentSub=currentMenu->subMenu[i];
- if(currentSub){
- char text[24]={0};
- sprintf(text,"%d.%s",i,currentSub->text);
- printf("text = %sn",text);
- ssd1306_Text(text,strlen(text),16,select_idx==i);
- }
-
- }
- ssd1306_UpdateScreen();
- }
这里需要一个currentMenu的指针来指示当前显示的是哪个菜单.
7.总结
到这里手势传感器的评测就完结了,感谢
电子发烧友和小凌派厂家,有机会使用到最新的
开发板和新潮的手势传感器,可以实现自己的想法.
希望大家都能完成自己的作品.
后续有创意会跟大家分享.