【正点原子探索者STM32F407开发板例程连载+教学】第54章 T9拼音输入法实验

2019-07-21 04:20发布

第五十四章 T9拼音输入法实验

  [mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板 2.软件平台:MDK5.1 3.固件库版本:V1.4.0[/mw_shl_code]
上一章,我们在ALIENTEK探索者STM32F4开发板上实现了手写识别输入,但是该方法只能输入数字或者字母,不能输入汉字。本章,我们将给大家介绍如何在ALIENTEK探索者STM32F4开发板上实现一个简单的T9中文拼音输入法。本章分为如下几个部: 54.1 拼音输入法简介 54.2 硬件设计 54.3 软件设计 54.4 下载验证  

54.1 拼音输入法简介  

在计算机上汉字的输入法有很多种,比如拼音输入法、五笔输入法、笔画输入法、区位输入法等。其中,又以拼音输入法用的最多。拼音输入法又可以分为很多类,比如全拼输入、双拼输入等。 而在手机上,用的最多的应该算是T9拼音输入法了,T9输入法全名为智能输入法,字库容量九千多字,支持十多种语言。T9输入法是由美国特捷通讯(Tegic Communications)软件公司开发的,该输入法解决了小型掌上设备的文字输入问题,已经成为全球手机文字输入的标准之一。 一般,手机拼音输入键盘如图54.1.1所示:
 54.1.1 手机拼音输入键盘 在这个键盘上,我们对比下传统的输入法和T9输入法,输入“中国”两个字需要的按键次数。传统的方法,先按49,输入字母z,再按24,输入字母h,再按36,输入字母o,再按26,输入字母n,最后按14,输入字母g。这样,输入“中”字,要按键12次,接着同样的方法,输入“国”字,需要按6次,总共就是18次按键。 如果是T9,我们输入“中”字,只需要输入:94664,即可实现输入“中”字,在选择中字之后,T9会联想出一系列同中字组合的词,如:文、国、断、山等。这样输入“国”字,我们直接选择即可,所以输入“国”字按键0次,这样T9总共只需要5次按键。 这就是T9智能输入法的优越之处。正因为T9输入法高效便捷的输入方式得到了众多手机厂商的采用,以至于T9成为了使用频率最高知名度最大的手机输入法。 本章,我们实现的T9拼音输入法,没有真正的T9那么强大,我们这里仅实现输入部分,不支持词组联想。 本章,我们主要通过一个和数字串对应的拼音索引表来实现T9拼音输入,我们先将汉语拼音所有可能的组合全部列出来,如下所示: const u8 PY_mb_space []={""}; const u8 PY_mb_a     []={"啊阿腌吖锕厑嗄錒呵腌"}; const u8 PY_mb_ai    []={"爱埃挨哎唉哀皑癌蔼矮艾碍隘捱嗳嗌嫒瑷暧砹锿霭"}; const u8 PY_mb_an    []={"安俺按暗岸案鞍氨谙胺埯揞犴庵桉铵鹌黯"}; ……此处省略N多组合 const u8 PY_mb_zu    []={"足租祖诅阻组卒族俎菹镞"}; const u8 PY_mb_zuan  []={"钻攥纂缵躜"}; const u8 PY_mb_zui   []={"最罪嘴醉蕞觜"}; const u8 PY_mb_zun   []={"尊遵樽鳟撙"}; const u8 PY_mb_zuo   []={"左佐做作坐座昨撮唑柞阼琢嘬怍胙祚砟酢"};        这里我们只列出了部分组合,我们将这些组合称之为码表,然后将这些码表和其对应的数字串对应起来,组成一个拼音索引表,如下所示: const py_index py_index3[]= { {"" ,"",(u8*)PY_mb_space}, {"2","a",(u8*)PY_mb_a}, {"3","e",(u8*)PY_mb_e}, {"6","o",(u8*)PY_mb_o}, {"24","ai",(u8*)PY_mb_ai}, {"26","an",(u8*)PY_mb_an}, ……此处省略N多组合 {"94664","zhong",(u8*)PY_mb_zhong}, {"94824","zhuai",(u8*)PY_mb_zhuai}, {"94826","zhuan",(u8*)PY_mb_zhuan}, {"248264","chuang",(u8*)PY_mb_chuang}, {"748264","shuang",(u8*)PY_mb_shuang}, {"948264","zhuang",(u8*)PY_mb_zhuang}, }        其中py_index是一个结构体,定义如下: typedef struct {   u8 *py_input;     //输入的字符串   u8 *py;            //对应的拼音   u8 *pymb;       //码表 }py_index; 其中py_input,即与拼音对应的数字串,比如“94824”。py,即与py_input数字串对应的拼音,如果py_input=94824”,那么py就是“zhuai”。最后pymb,就是我们前面说到的码表。注意,一个数字串可以对应多个拼音,也可以对应多个码表。 在有了这个拼音索引表(py_index3)之后,我们只需要将输入的数字串和py_index3索引表里面所有成员的py_input对比,将所有完全匹配的情况记录下来,用户要输入的汉字就被确定了,然后由用户选择可能的拼音组成(假设有多个匹配的项目),再选择对应的汉字,即完成一次汉字输入。 当然还可能是找遍了索引表,也没有发现一个完全符合要求的成员,那么我们会统计匹配数最多的情况,作为最佳结果,反馈给用户。比如,用户输入“323”,找不到完全匹配的情况,那么我们就将能和“32”匹配的结果返回给用户。这样,用户还是可以得到输入结果,同时还可以知道输入有问题,提示用户需要检查输入是否正确。 以上,就是我们的T9拼音输入法原理,关于拼音输入法,我们就介绍到这里。 最后,我们看看一个完整的T9拼音输入步骤(过程): 1) 输入拼音数字串 本章,我们用到的T9拼音输入法的核心思想就是对比用户输入的拼音数字串,所以必须先由用户输入拼音数字串。 2) 在拼音索引表里面查找和输入字符串匹配的项,并记录 在得到用户输入的拼音数字串之后,在拼音索引表里面查找所有匹配的项目,如果有完全匹配的项目,就全部记录下来,如果没有完全匹配的项目,则记录匹配情况最好的一个项目。 3) 显示匹配清单里面所有可能的汉字,供用户选择. 将匹配项目的拼音和对应的汉字显示出来,供用户选择。如果有多个匹配项(一个数字串对应多个拼音的情况),则用户还可以选择拼音。 4) 用户选择匹配项,并选择对应的汉字. 用户对匹配的拼音和汉字进行选择,选中其真正想输入的拼音和汉字,实现一次拼音输入。  以上4个步骤,就可以实现一个简单的T9汉字拼音输入法。

54.2 硬件设计

本章实验功能简介:开机的时候先检测字库,然后显示提示信息和绘制拼音输入表,之后进入等待输入状态。此时用户可以通过屏幕上的拼音输入表输入拼音数字串(通过DEL可以实现退格),然后程序自动检测与之对应的拼音和汉字,并显示在屏幕上(同时输出到串口)。如果有多个匹配的拼音,则通过KEY_UP和KEY1进行选择。按键KEY0用于清除一次输入,按键KEY2用于触摸屏校准。 本实验用到的资源如下: 1)  指示灯DS0 2)  四个按键(KEY0/KEY1/KEY2/KEY_UP 3)  串口 4)  TFTLCD模块(含触摸屏) 5)  SPI FLASH 这些用到的硬件,我们在之前都已经介绍过,这里就不再介绍了。

54.3 软件设计

打开本章实验工程可以看到,我们在根目录文件夹下新建了一个T9INPUT的文件夹。在该文件夹下面新建了pyinput.cpyinput.hpymb.h三个文件,然后在工程里面新建一个T9INPUT的组,将pyinput.c加入到该组下面。最后,将T9INPUT文件夹加入头文件包含路径。     打开pyinput.c,代码如下:  //拼音输入法 pyinput t9= {        get_pymb,     0, }; //比较两个字符串的匹配情况 //返回值:0xff,表示完全匹配. //            其他,匹配的字符数 u8 str_match(u8*str1,u8*str2) {        u8 i=0;        while(1)        {               if(*str1!=*str2)break;             //部分匹配               if(*str1==''){i=0XFF;break;}//完全匹配               i++; str1++; str2++;        }        return i;//两个字符串相等 } //获取匹配的拼音码表 //*strin,输入的字符串,形如:"726" //**matchlist,输出的匹配表. //返回值:[7],0,表示完全匹配;1,表示部分匹配(仅在没有完全匹配的时候才会出现) //            [6:0],完全匹配的时候,表示完全匹配的拼音个数 //                      部分匹配的时候,表示有效匹配的位数                                       u8 get_matched_pymb(u8 *strin,py_index **matchlist) {        py_index *bestmatch=0;//最佳匹配        u16 pyindex_len=0;        u16 i=0;        u8 temp,mcnt=0,bmcnt=0;        bestmatch=(py_index*)&py_index3[0];//默认为a的匹配        pyindex_len=sizeof(py_index3)/sizeof(py_index3[0]);//得到py索引表的大小.        for(i=0;i<pyindex_len;i++)        {               temp=str_match(strin,(u8*)py_index3.py_input);               if(temp)               {                      if(temp==0XFF)matchlist[mcnt++]=(py_index*)&py_index3;                      else if(temp>bmcnt)//找最佳匹配                      {                             bmcnt=temp;                          bestmatch=(py_index*)&py_index3;//最好的匹配.                      }               }        }        if(mcnt==0&&bmcnt)//没有完全匹配的结果,但是有部分匹配的结果        {               matchlist[0]=bestmatch;               mcnt=bmcnt|0X80;        //返回部分匹配的有效位数        }        return mcnt;//返回匹配的个数 } //得到拼音码表. //str:输入字符串 //返回值:匹配个数. u8 get_pymb(u8* str) {        return get_matched_pymb(str,t9.pymb); } //串口测试用 void test_py(u8 *inputstr) {        ……代码省略 }        这里总共就4个函数,其中get_matched_pymb,是核心,该函数实现将用户输入拼音数字串同拼音索引表里面的各个项对比,找出匹配结果,并将完全匹配的项目存放在matchlist里面,同时记录匹配数。对于那些没有完全匹配的输入串,则查找与其最佳匹配的项目,并将匹配的长度返回。函数test_py(代码省略)用于给usmart调用,实现串口测试,该函数可有可无,只是在串口测试的时候才用到,如果不使用的话,可以去掉,本章,我们将其加入usmart控制,大家可以通过该函数实现串口调试拼音输入法。        其他两个函数,也比较简单了,我们这里就不细说了,保存pyinput.c,打开pyinput.h,代码如下: #ifndef __PYINPUT_H #define __PYINPUT_H #include "sys.h" //拼音码表与拼音的对应表 typedef struct {   u8 *py_input;//输入的字符串   u8 *py;          //对应的拼音   u8 *pymb;     //码表 }py_index; #define MAX_MATCH_PYMB    10    //最大匹配数 //拼音输入法 typedef struct {   u8(*getpymb)(u8 *instr);                 //字符串到码表获取函数   py_index *pymb[MAX_MATCH_PYMB];      //码表存放位置 }pyinput; extern pyinput t9; u8 str_match(u8*str1,u8*str2); u8 get_matched_pymb(u8 *strin,py_index **matchlist); u8 get_pymb(u8* str); void test_py(u8 *inputstr); #endif        保存pyinput.hpymb.h里面完全就是我们前面介绍的拼音码表,该文件很大,里面存储了所有我们可以输入的汉字,此部分代码就不贴出来了,请大家参考光盘本例程的源码。        最后,我们看看主函数代码: const u8* kbd_tbl[9]={"","2","3","4","5","6","7","8","9",};//数字表 const u8* kbs_tbl[9]={"DEL","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz",};//字符表 u16 kbdxsize;  //虚拟键盘按键宽度 u16 kbdysize;  //虚拟键盘按键高度 //加载键盘界面 //x,y:界面起始坐标 void py_load_ui(u16 x,u16 y) {        u16 i;        POINT_COLOR=RED;        LCD_DrawRectangle(x,y,x+kbdxsize*3,y+kbdysize*3);                                                  LCD_DrawRectangle(x+kbdxsize,y,x+kbdxsize*2,y+kbdysize*3);                                           LCD_DrawRectangle(x,y+kbdysize,x+kbdxsize*3,y+kbdysize*2);        POINT_COLOR=BLUE;        for(i=0;i<9;i++)        {               Show_Str_Mid(x+(i%3)*kbdxsize,y+4+kbdysize*(i/3),(u8*)kbd_tbl,16,kbdxsize);     Show_Str_Mid(x+(i%3)*kbdxsize,y+kbdysize/2+kbdysize*(i/3),(u8*)kbs_tbl, 16,kbdxsize);                     }                                                 } //按键状态设置 //x,y:键盘坐标 //key:键值(0~8 //sta:状态,0,松开;1,按下; void py_key_staset(u16 x,u16 y,u8 keyx,u8 sta) {                     u16 i=keyx/3,j=keyx%3;        if(keyx>8)return;        if(sta)LCD_Fill(x+j*kbdxsize+1,y+i*kbdysize+1,x+j*kbdxsize+kbdxsize-1,y+i*kbdysize+ kbdysize-1,GREEN);        else LCD_Fill(x+j*kbdxsize+1,y+i*kbdysize+1,x+j*kbdxsize+kbdxsize-1,y+i*kbdysize +kbdysize-1,WHITE);        Show_Str_Mid(x+j*kbdxsize,y+4+kbdysize*i,(u8*)kbd_tbl[keyx],16,kbdxsize);                   Show_Str_Mid(x+j*kbdxsize,y+kbdysize/2+kbdysize*i,(u8*)kbs_tbl[keyx],16,kbdxsize); } //得到触摸屏的输入 //x,y:键盘坐标 //返回值:按键键值(1~9有效;0,无效) u8 py_get_keynum(u16 x,u16 y) {        u16 i,j; u8 key=0;        static u8 key_x=0;//0,没有任何按键按下;1~91~9号按键按下        tp_dev.scan(0);                      if(tp_dev.sta&TP_PRES_DOWN)               //触摸屏被按下        {                   for(i=0;i<3;i++)               {                      for(j=0;j<3;j++)                      {                            if(tp_dev.x[0]<(x+j*kbdxsize+kbdxsize)&&tp_dev.x[0]>(x+j*kbdxsize)&& tp_dev.y[0]<(y+i*kbdysize+kbdysize)&&tp_dev.y[0]>(y+i*kbdysize))                             {key=i*3+j+1; break;}                      }                      if(key)                      {                                    if(key_x==key)key=0;                             else                             {                                    py_key_staset(x,y,key_x-1,0);                                    key_x=key;                                    py_key_staset(x,y,key_x-1,1);                             }                             break;                      }               }         }else if(key_x){ py_key_staset(x,y,key_x-1,0); key_x=0;}        return key; }                                                  //显示结果. //index:0,表示没有一个匹配的结果.清空之前的显示 //   其他,索引号  void py_show_result(u8 index) {       LCD_ShowNum(30+144,125,index,1,16);         //显示当前的索引        LCD_Fill(30+40,125,30+40+48,130+16,WHITE);     //清除之前的显示       LCD_Fill(30+40,145,lcddev.width,145+48,WHITE);//清除之前的显示           if(index)        {              Show_Str(30+40,125,200,16,t9.pymb[index-1]->py,16,0);       //显示拼音               Show_Str(30+40,145,lcddev.width-70,48,t9.pymb[index-1]->pymb,16,0);//显示汉字               printf(" 拼音:%s ",t9.pymb[index-1]->py);       //串口输出拼音               printf("结果:%s ",t9.pymb[index-1]->pymb); //串口输出结果        } }     int main(void) {              u8 i=0; u8 key; u8 cur_index;       u8 result_num;        u8 inputstr[7];        //最大输入6个字符+结束符        u8 inputlen;           //输入长度            NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2        delay_init(168);  //初始化延时函数        uart_init(115200);         //初始化串口波特率为115200        LED_Init();                         //初始化LED        usmart_dev.init(84);             //初始化USMART       LCD_Init();                         //LCD初始化        KEY_Init();                         //按键初始化       W25QXX_Init();                  //初始化W25Q128        tp_dev.init();                        //初始化触摸屏        my_mem_init(SRAMIN);     //初始化内部内存池        my_mem_init(SRAMCCM);  //初始化CCM内存池 RESTART:        POINT_COLOR=RED;            while(font_init())                //检查字库        {                        LCD_ShowString(60,50,200,16,16,"Font Error!"); delay_ms(200);                                        LCD_Fill(60,50,240,66,WHITE);//清除显示                  }       Show_Str(30,5,200,16,"探索者STM32F407开发板",16,0);                                              Show_Str(30,25,200,16,"拼音输入法实验",16,0);                                              Show_Str(30,45,200,16,"正点原子@ALIENTEK",16,0);                                          Show_Str(30,65,200,16,"  KEY2:校准  KEY0:清除",16,0);         Show_Str(30,85,200,16,"KEY_UP:上翻  KEY1:下翻",16,0);         Show_Str(30,105,200,16,"输入:        匹配:  ",16,0);       Show_Str(30,125,200,16,"拼音:        当前:  ",16,0);       Show_Str(30,145,210,32,"结果:",16,0);        if(lcddev.id==0X5310){kbdxsize=86;kbdysize=43;}//根据LCD分辨率设置按键大小        else if(lcddev.id==0X5510){kbdxsize=140;kbdysize=70;}        else {kbdxsize=60;kbdysize=40;}        py_load_ui(30,195);        memset(inputstr,0,7);     //全部清零        inputlen=0;                   //输入长度为0        result_num=0;               //总匹配数清零        cur_index=0;                       while(1)        {               i++;               delay_ms(10);               key=py_get_keynum(30,195);               if(key)               {                      if(key==1)//删除                      {                             if(inputlen)inputlen--;                             inputstr[inputlen]='';//添加结束符                      }else                      {                             inputstr[inputlen]=key+'0';//输入字符                             if(inputlen<7)inputlen++;                      }                      if(inputstr[0]!=NULL)                      {                             key=t9.getpymb(inputstr);     //得到匹配的结果数                             if(key)//有部分匹配/完全匹配的结果                             {                                    result_num=key&0X7F; //总匹配结果                                    cur_index=1;                //当前为第一个索引                                    if(key&0X80)             //是部分匹配                                    {                                           inputlen=key&0X7F;//有效匹配位数                                           inputstr[inputlen]='';//不匹配的位数去掉                                           if(inputlen>1)result_num=t9.getpymb(inputstr);//重新获取                                    }                              }else //没有任何匹配                             {                                                                  inputlen--;                                    inputstr[inputlen]='';                             }                      }else{ cur_index=0; result_num=0; }                      LCD_Fill(30+40,105,30+40+48,110+16,WHITE);//清除之前的显示                      LCD_ShowNum(30+144,105,result_num,1,16);        //显示匹配的结果数                      Show_Str(30+40,105,200,16,inputstr,16,0); //显示有效的数字串                                py_show_result(cur_index);                        //显示第cur_index的匹配结果               }                   key=KEY_Scan(0);               if(key==KEY2_PRES&&tp_dev.touchtype==0)//KEY2按下,且是电阻屏               {                      tp_dev.adjust();                      LCD_Clear(WHITE);                      goto RESTART;               }               if(result_num) //存在匹配的结果                {                          switch(key)                      {                             case WKUP_PRES://上翻                                    if(cur_index<result_num)cur_index++;                                    else cur_index=1;                                    py_show_result(cur_index);   //显示第cur_index的匹配结果                                    break;                            case KEY1_PRES://下翻                                  if(cur_index>1)cur_index--;                                    else cur_index=result_num;                                    py_show_result(cur_index);   //显示第cur_index的匹配结果                                    break;                             case KEY0_PRES://清除输入                                   LCD_Fill(30+40,145,lcddev.width,145+48,WHITE);//清除之前的显示                                       goto RESTART;                                                              }                          }               if(i==30) { i=0; LED0=!LED0; }        }                                                                                                   }     此部分代码除main函数外还有4个函数。首先,py_load_ui,该函数用于加载输入键盘,在LCD上面显示我们输入拼音数字串的虚拟键盘。py_key_staset,该函数用与设置虚拟键盘某个按键的状态(按下/松开)。py_get_keynum,该函数用于得到触摸屏当前按下的按键键值,通过该函数实现拼音数字串的获取。最后,py_show_result,该函数用于显示输入串的匹配结果,并将结果打印到串口。main函数里面,实现了我们在54.2节所说的功能,这里我们并没有实现汉字选择功能,但是有本例程作为基础,再实现汉字选择功能就比较简单了,大家自行实现即可。注意:kbdxsizekbdysize代表虚拟键盘按键宽度和高度,程序根据LCD分辨率不同而自动设置这两个参数,以达到较好的输入效果。 最后,我们将test_py函数加入USMART控制,以便大家串口调试。 至此,本实验的软件设计部分结束。

54.4 下载验证

在代码编译成功之后,我们下载代码到ALIENTEK探索者STM32F4开发板上,得到,如图54.4.1所示: 说明: 说明: C:UsersAdministratorDesktopF407教程文档资料例程图片T9输入法启动界面.jpg54.4.1 汉字输入法界面 此时,我们在虚拟键盘上输入拼音数字串,即可实现拼音输入,如图54.4.2所示: 说明: 说明: C:UsersAdministratorDesktopF407教程文档资料例程图片T9输入法.jpg54.4.2 实现拼音输入 如果发现输入错了,可以通过屏幕上的DEL按钮,来退格。如果有多个匹配的情况(匹配值大于1),则可以通过KEY_UPKEY1来选择拼音。通过按下KEY0,可以清楚当前输入,通过按下KEY2,可以实现触摸屏校准。  我们还可以通过USMART调用test_py来实现输入法调试,如图54.4.3所示:  54.4.3 USMART调试T9拼音输入法
  实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm  正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779
  
0条回答

一周热门 更多>