OpenHarmony开源社区
直播中

cszzlsw

9年用户 202经验值
擅长:嵌入式技术
私信 关注
[经验]

【小凌派RK2206开发板试用体验】测评第三帖:手势操作菜单

小凌派手势操作菜单

1.前言:
接上篇,https://bbs.elecfans.com/jishu_2278344_1_1.html
当手势传感器案例可以和OLED运行之后,我们就可以想办法更好玩一些了,想要好玩一些的话当然就是用手势操作菜单了.具体的效果可以看帖子上面的视频来感受.


2.制作中文字体
如果要实现手势菜单.就不能使用以前的方式来操作中文了,除非你能记住所有的中文字的位置,那这种情况下要如果进行呢,请看法宝:
  1. typedef struct  Chinese_Font_data{
  2.     char text[3];
  3.     uint8_t data[32];

  4. }Chinese_Font_data;

  5. typedef struct ChineseFont{
  6.    
  7.     uint8_t font_size;
  8.     uint8_t font_data_len;
  9.     // uint8_t keep;
  10.     Chinese_Font_data *font_data;

  11. }ChineseFont;
这里创建两个结构体,结构体里面就是存的字体信息和字体数据,那内容是啥样的呢,这里举几个例子:

  1. Chinese_Font_data xingkai_data_16[]={

  2. /*---------------子----------------*/
  3. {"子",
  4. {0x00,0x00,0x00,0x00,0x01,0xF0,0x0F,0x70,0x00,0x60,0x01,0xC0,0x01,0xFE,0x3F,0xFE,
  5. 0x78,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x07,0xC0,0x03,0x80,0x01,0x00}},

  6. /*---------------菜----------------*/
  7. {"菜",
  8. {0x00,0x00,0x06,0x70,0x06,0x7C,0x3F,0xFC,0x12,0xC0,0x03,0xC0,0x07,0x30,0x0D,0xE0,
  9. 0x05,0x70,0x3F,0xF8,0x17,0xC0,0x0D,0x60,0x19,0x38,0x71,0x1F,0x03,0x00,0x01,0x00}},

  10. /*---------------单----------------*/
  11. {"单",
  12. {0x00,0x00,0x06,0x70,0x07,0x60,0x02,0x70,0x0F,0xF8,0x0D,0xF8,0x0F,0xF0,0x07,0xF0,
  13. 0x07,0xA0,0x01,0xFE,0x7F,0xFC,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80}},

  14. /*---------------选----------------*/
  15. {"选",
  16. {0x00,0x00,0x00,0x60,0x00,0x60,0x19,0xE0,0x09,0xF8,0x01,0xF0,0x02,0x7C,0x3F,0xF8,
  17. 0x3A,0xA0,0x19,0xA0,0x19,0x24,0x0A,0x3E,0x7F,0x1C,0x01,0xFF,0x00,0x3C,0x00,0x00}},

  18. /*---------------项----------------*/
  19. {"项",
  20. {0x00,0x00,0x00,0x00,0x00,0x1E,0x01,0xFC,0x0E,0x60,0x3C,0xFC,0x0C,0x8C,0x0C,0xAC,
  21. 0x0E,0xAC,0x3F,0xAC,0x71,0xEC,0x01,0xFC,0x00,0xDC,0x01,0x8C,0x02,0x04,0x00,0x00}},
  22. }

3.中文字体的显示
处理完这个之后,就可以编写中文显示的方法了:

  1. void ssd1306_DrawChinese(char *ch, ChineseFont *font,SSD1306_COLOR color)
  2. {
  3.     // printf("%d %dn",sizeof(xingkai_16),(sizeof(xingkai_16[0])));
  4.     // printf("%d,, draw chinese:%sn",xingkai_16_font_len,ch);
  5.     if(font == &xingkai_16){

  6.         for(int ch_idx=0;ch_idx
  7.             // printf("%d === %sn",i,font[i].text);
  8.             Chinese_Font_data *font_data =&font->font_data[ch_idx];
  9.             if(strncmp(ch,font_data->text,sizeof(font_data->text))==0){
  10.   
  11.                 {
  12.                     int x=SSD1306.CurrentX,y=SSD1306.CurrentY;
  13.                     int w=font->font_size,h=font->font_size;
  14.                     int stride = 0;
  15.                     if (x + w > SSD1306_WIDTH || y + h > SSD1306_HEIGHT || w * h == 0) {
  16.                         printf("%dx%d @ %d,%d out of range or invalid!rn", w, h, x, y);
  17.                         return;
  18.                     }

  19.                     w = (w <= SSD1306_WIDTH ? w : SSD1306_WIDTH);
  20.                     h = (h <= SSD1306_HEIGHT ? h : SSD1306_HEIGHT);
  21.                     stride = (stride == 0 ? w : stride);

  22.                     uint8_t rows = font->font_data_len * 8 / stride;
  23.                     for (uint8_t i = 0; i < rows; i++) {
  24.                         uint32_t base = i * stride / 8;
  25.                         for (uint8_t j = 0; j < w; j++) {
  26.                             uint32_t idx = base + (j / 8);
  27.                             uint8_t byte = idx < font->font_data_len ? font_data->data[idx] : 0;
  28.                             uint8_t bit  = byte & (0x80 >> (j % 8));
  29.                             ssd1306_DrawPixel(x + j, y + i, bit ? !color : color);
  30.                         }
  31.                     }
  32.                 }

  33.                 // ssd1306_DrawRegion(SSD1306.CurrentX,SSD1306.CurrentY,font->font_size,
  34.                 // font->font_size, font_data->data,font->font_data_len,0);
  35.                 SSD1306.CurrentX += font->font_size;

  36.                 break;
  37.             }
  38.         }

  39.     }

  40.    
  41. }

  42. void ssd1306_Text(char *string,uint8_t string_len,uint8_t font_size,uint8_t mode)
  43. {
  44.     int i=0;

  45.     // printf("Text:%x %x %x %x %x %x %d %d %dn",string[0],string[1],string[2],string[3],string[4],string[5],
  46.     //                             string[3],string[4],string[5]);
  47.    printf("ssd1306_Text %d:%sn",string_len,string);
  48.     while(i
  49.         if(string[i] < 0)
  50.         {
  51.             // printf("[%d ]%d %x for chinesen",i,string[i],string[i]);
  52.             ssd1306_DrawChinese(&string[i],&xingkai_16,mode);
  53.             
  54.             
  55.             i+=3;
  56.         }
  57.         else
  58.         {
  59.             // printf("[%d ]%d %x for charn",i,string[i],string[i]);
  60.             ssd1306_DrawChar(string[i],Font_7x10,!mode);
  61.             i+=1;
  62.         }
  63.     }
  64. }

这里面的一个逻辑就是判断字符是中文还是英文,如果是中文的话char值是小于0的,但是不是一个字符能表示,中文使用UTF-8,最多会使用3个字符表示一个中文字,所以当出现中文的时候,char数组里长度需要增加3,如果是英文字的话就只需要1个字符了.
这工作完成之后就可以测试中文和英文数字等的的显示了,随便写几个中文字,调用接口显示:
  1. ssd1306_Text("1.你好 2.Hello",strlen("你好世界"),16,0);
可以观察显示,不得不提一句,这地方花费了大量的时间在编译上,因为编译系统不完善.不能支持增量编译,希望厂家团队尽快解决.

4.制作菜单框架
其实这里演示的菜单框架比较简单,因为菜单会有子菜单项,所以需要用多叉树的结构来表现,请看法宝:
  1. typedef struct Menu{
  2.     // char name[8];
  3.     char text[14];
  4.     char state;
  5.     void *param;
  6.     uint8_t sub_len;
  7.     struct Menu **subMenu;
  8.     void (*enterFunc)(struct Menu *menu);
  9.     void (*exitFunc)(struct Menu *menu);

  10. }Menu;
,然后就制作菜单的数据,这里举例:
  1. #include "menu.h"
  2. #include

  3. Menu hoguo={
  4.     .text="火锅",

  5. };

  6. Menu BBQ={
  7.     .text="BBQ",
  8. };

  9. Menu western={
  10.     .text="西餐",
  11. };

  12. extern Menu mainMenu;
  13. Menu *eating_subs[]={&mainMenu,&hoguo,&BBQ,&western};


  14. Menu eating={
  15.     .text="聚餐",
  16.     .sub_len = 3,
  17.     .subMenu=eating_subs
  18. };

  19. Menu comedy={
  20.     .text="喜剧片",
  21.     .sub_len=0,
  22. };

  23. Menu Thriller={
  24.     .text="惊悚片"
  25. };

  26. extern Menu movie;

  27. Menu *movie_subs[]={&mainMenu, &comedy,
  28.         &Thriller};

  29. Menu movie={
  30.     .text="看电影",
  31.     .sub_len = 3,
  32.     .subMenu=movie_subs
  33. };


  34. Menu yunnan={
  35.     .text="云南",
  36.     .sub_len=0,
  37. };

  38. Menu beijing={
  39.     .text="北京"
  40. };
  41. Menu xizang={
  42.     .text="西藏"
  43. };
  44. extern Menu trip;

  45. Menu *trip_subs[]={&mainMenu,&yunnan, &beijing,
  46.         &xizang};


  47. Menu trip={
  48.     .text="旅游",
  49.     .sub_len = 4,
  50.     .subMenu=trip_subs


  51. };

  52. Menu kge={
  53.     .text="唱K",
  54.     .sub_len=0,
  55. };

  56. Menu anmo={
  57.     .text="按摩"
  58. };
  59. Menu xizao={
  60.     .text="洗澡"
  61. };
  62. extern Menu relex;

  63. Menu *releax_subs[]={&mainMenu,&kge, &anmo,
  64.         &xizao};
  65. Menu relax={
  66.     .text="放松",
  67.     .sub_len = 4,
  68.     .subMenu=releax_subs


  69. };

  70. Menu *mainMenu_subs[5]={NULL,&eating,&trip,&movie,&relax};

  71. Menu mainMenu={
  72.    
  73.         .text = "娱乐活动",
  74.         .sub_len = 5,
  75.         .subMenu=mainMenu_subs
  76.    
  77. };
菜单项制作好了之后,可以放到UI里去渲染

5.UI线程渲染菜单


  1.                 ssd1306_SetCursor(32, 0);

  2.                 ssd1306_Text(currentMenu->text,strlen(currentMenu->text),16,0);



  3.                 int show_idx=1;

  4.                 if(select_idx > max_sub){

  5.                         show_idx+=(select_idx-max_sub);

  6.                         // continue;

  7.                 }

  8.                 int cursor=1;

  9.                 for(int i=show_idx;isub_len;i++)

  10.                 {

  11.                        

  12.                        

  13.                         ssd1306_SetCursor(0, 16*(cursor++));

  14.                         Menu *currentSub=currentMenu->subMenu[i];

  15.                         if(currentSub){



  16.                                 char text[24]={0};

  17.                                 sprintf(text,"%d.%s",i,currentSub->text);

  18.                                 printf("text = %sn",text);

  19.                                 ssd1306_Text(text,strlen(text),16,select_idx==i);

  20.                         }

  21.                        

  22.                 }



  23.                 ssd1306_UpdateScreen();       
这里的逻辑就是把菜单标题和子菜单都显示出来

6.结合手势传感器传的数据
把手势传感器的数据接收到,然后做相应的逻辑处理,这里有一个问题,就是目前菜单因为屏幕的原因,只能显示3个菜单,所以需要做一个机制,当选择的菜单超过当前长度的时候往下滑一格,
代码如下:


  1. static void *OLedTask(const char *arg)

  2. {

  3.         (void)arg;

  4.         uint32_t ret=0;

  5.        

  6.         ssd1306_Init();

  7.         printf("OLedTask queueId=%dn",queueId);



  8.         //ssd1306_DrawString("Hello HARMonyOS!", Font_7x10, White);



  9.         int text_area_width = 64;

  10.         int text_area_height = 64;



  11.         int text_per_line_num = text_area_height / font_width;



  12.         int mod = hope_num % text_per_line_num;

  13.         int text_line_num = hope_num / text_per_line_num;

  14.         if (mod)

  15.         {

  16.                 text_line_num += 1;

  17.         }

  18.         printf("title_addr=%p,dir_addr=%pn", title_arr,dir_arr);

  19.         int text_alredy_show = 0;



  20.         int x = 0;

  21.         int y = 0;

  22.         int select_idx = 1;



  23.         ssd1306_Fill(Black);

  24.         ssd1306_SetCursor(0, 0);



  25.         Menu *currentMenu = &mainMenu;

  26.         int max_sub=3;

  27.         int start=0;

  28.        

  29.         while(1){

  30.                 uint32_t flag = 0;

  31.                 uint32_t rLen =4;

  32.                 if(start){

  33.                                

  34.                         ret = LOS_QueueReadCopy(queueId,

  35.                                                                         &flag,

  36.                                                                         &rLen,

  37.                                                                         LOS_WAIT_FOREVER);

  38.                         // LOS_Msleep(OLED_INTERVAL_TIME_US);

  39.                         printf("READ ret = %d,FLAG =%02xn",ret,flag);

  40.                 }

  41.                 start =1;



  42.                 ssd1306_Fill(Black);

  43.                 ssd1306_SetCursor(0, 0);

  44.                

  45.                 int idx=0;

  46.                 for(;idx<9;idx++){

  47.                         if(flag&(1<

  48.                                 break;

  49.                         }

  50.                 }

  51.                 printf("idx=%d,select_idx=%dn",idx,select_idx);



  52.                 switch(idx){

  53.                         case 0:

  54.                         if(select_idx > 1){

  55.                                 select_idx--;

  56.                         }

  57.                         break;

  58.                         case 1:

  59.                         if(select_idx < currentMenu->sub_len-1){

  60.                                 select_idx++;

  61.                         }

  62.                         break;

  63.                         case 2:

  64.                         {

  65.                                 Menu *currentSub=currentMenu->subMenu[0];

  66.                                 if(currentSub){

  67.                                         currentMenu=currentSub;

  68.                                         select_idx = 1;

  69.                                         start = 0;

  70.                                         continue;

  71.                                 }



  72.                         }break;

  73.                         case 3:

  74.                         {

  75.                                         Menu *currentSub=currentMenu->subMenu[select_idx];

  76.                                         if(currentSub){

  77.                                                 currentMenu=currentSub;

  78.                                                 select_idx = 1;

  79.                                                 start = 0;

  80.                                                 continue;

  81.                                         }



  82.                         }break;

  83.                        

  84.                         break;



  85.                 }

  86.                 printf(">>idx=%d,select_idx=%dn",idx,select_idx);

  87.                

  88.                 ssd1306_SetCursor(32, 0);

  89.                 ssd1306_Text(currentMenu->text,strlen(currentMenu->text),16,0);



  90.                 int show_idx=1;

  91.                 if(select_idx > max_sub){

  92.                         show_idx+=(select_idx-max_sub);

  93.                         // continue;

  94.                 }

  95.                 int cursor=1;

  96.                 for(int i=show_idx;isub_len;i++)

  97.                 {

  98.                        

  99.                        

  100.                         ssd1306_SetCursor(0, 16*(cursor++));

  101.                         Menu *currentSub=currentMenu->subMenu[i];

  102.                         if(currentSub){



  103.                                 char text[24]={0};

  104.                                 sprintf(text,"%d.%s",i,currentSub->text);

  105.                                 printf("text = %sn",text);

  106.                                 ssd1306_Text(text,strlen(text),16,select_idx==i);

  107.                         }

  108.                        

  109.                 }



  110.                 ssd1306_UpdateScreen();       

  111.         }

这里需要一个currentMenu的指针来指示当前显示的是哪个菜单.

7.总结
到这里手势传感器的评测就完结了,感谢电子发烧友和小凌派厂家,有机会使用到最新的开发板和新潮的手势传感器,可以实现自己的想法.
希望大家都能完成自己的作品.
后续有创意会跟大家分享.

更多回帖

发帖
×
20
完善资料,
赚取积分