【正点原子STM32连载】第五十八章 T9拼音输入法实验摘自【正点原子】STM32F103 战舰开发指南V1.2

本文主要是介绍【正点原子STM32连载】第五十八章 T9拼音输入法实验摘自【正点原子】STM32F103 战舰开发指南V1.2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html#

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

本章,我们将介绍如何在STM32板子上实现一个简单的T9中文拼音输入法。本章分为如下几个小节:
58.1 拼音输入法简介
58.2 硬件设计
58.3 程序设计
58.4 下载验证

58.1 拼音输入法简介
在计算机上汉字的输入法有很多种,比如拼音输入法、五笔输入法、笔画输入法、区位输入法等。其中,又以拼音输入法用的最多。拼音输入法又可以分为很多类,比如全拼输入、双拼输入等。
而在手机上,用的最多的应该算是T9拼音输入法了,T9输入法全名为智能输入法,字库容量九千多字,支持十多种语言。T9输入法是由美国特捷通讯(Tegic Communications)软件公司开发的,该输入法解决了小型掌上设备的文字输入问题,已经成为全球手机文字输入的标准之一。
一般情况下,手机拼音输入键盘如图58.1.1所示:
在这里插入图片描述

图58.1.1 手机拼音输入键盘
在这个键盘上,我们对比下传统的输入法和 T9 输入法,输入“中国”两个字需要的按键次数。传统的方法,先按4次9,输入字母z,再按2次4,输入字母 h,再按3次6,输入字母o,再按2次6,输入字母n,最后按1次4,输入字母g。这样,输入“中”字,要按键12 次,接着同样的方法,输入“国”字,需要按6次,总共就是18次按键。
如果是T9,我们输入“中”字,只需要输入:9、4、6、6、4,即可实现输入“中”字,在选择“中”字之后,T9会联想出一系列同“中”字组合的词,如:文、国、断、山等。这样输入“国”字,我们直接选择即可,所以输入“国”字按键0次,这样使用T9输入法总共只需要5次按键。
这就是T9智能输入法的优越之处。正因为T9输入法高效便捷的输入方式得到了众多手机厂商的采用,以至于T9成为了使用频率最高知名度最大的手机输入法。
在本实验中,我们实现的T9拼音输入法,没有真正的T9那么强大,我们这里仅实现输入部分,不支持词组联想。
58.2 硬件设计

  1. 例程功能
    开机的时候先检测字库,然后显示提示信息和绘制拼音输入表,之后进入等待输入状态。此时用户可以通过屏幕上的拼音输入表输入拼音数字串(通过DEL可以实现退格),然后程序自动检测与之对应的拼音和汉字,并显示在屏幕上(同时输出到串口)。如果有多个匹配的拼音,则通过KEY_UP和KEY1进行选择。按键KEY0用于清除一次输入,按键KEY2用于触摸屏校准。LED0闪烁用于提示程序正在运行。
  2. 硬件资源
    1)LED灯
    LED0 – PB5
    2)独立按键
    KEY0 – PE4
    KEY1 – PE3
    WK_UP – PA0
    3)串口1
    4)正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
    5)NOR FLASH,通过SPI2驱动,我们需要里面的汉字库
    58.3 程序设计
    58.3.1 程序流程图
    在这里插入图片描述

图58.3.1.1 T9拼音输入法实验程序流程图
我们通过LCD的绘制算法生成一个9宫格输入法,采集到对应的合法输入点后,我们把这些信息传给解码库进行解码,识别出对应的拼音,并调用汉字库显示对应的匹配汉字。
58.3.2 程序解析
1.T9拼音输入法代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码,T9拼音输入法的驱动源码包括pyinput.c、pyinput.h和pymb.h三个文件。
首先我们先介绍一下定义在pymb.h中的拼音索引。先介绍一下汉字排列表,该表将汉字拼音所有可能的组合都列出来了,如下所示:
/* 汉字排列表 */

const uint8_t PY_mb_space 	[]={""};
const uint8_t PY_mb_a     	[]={"啊阿腌吖锕厑嗄錒呵腌"};
const uint8_t PY_mb_ai    	[]={"爱埃挨哎唉哀皑癌蔼矮艾碍隘捱嗳嗌嫒瑷暧砹锿霭"};
…………此处省略N多个组合…………
const uint8_t PY_mb_zu    	[]={"足组卒族租祖诅阻俎菹镞"};
const uint8_t PY_mb_zuan  	[]={"钻攥纂缵躜"};
const uint8_t PY_mb_zui   	[]={"最罪嘴醉蕞觜"};
const uint8_t PY_mb_zun   	[]={"尊遵樽鳟撙"};
const uint8_t PY_mb_zuo   	[]={"左佐做作坐座昨撮唑柞阼琢嘬怍胙祚砟酢"};

这里我们只列出了部分组合,我们将这些组合称之为码表,然后将这些码表和其对应的数字串对应起来,组成一个拼音索引表,如下所示:
/* 拼音索引表 */

const py_index py_index3[]=
{
{"" ,"",(uint8_t*)PY_mb_space},
{"2","a",(uint8_t*)PY_mb_a},
{"3","e",(uint8_t*)PY_mb_e},
{"6","o",(uint8_t*)PY_mb_o},
{"24","ai",(uint8_t*)PY_mb_ai},
…………此处省略N多个组合…………
{"94664","zhong",(uint8_t*)PY_mb_zhong},
{"94824","zhuai",(uint8_t*)PY_mb_zhuai},
{"94826","zhuan",(uint8_t*)PY_mb_zhuan},
{"248264","chuang",(uint8_t*)PY_mb_chuang},
{"748264","shuang",(uint8_t*)PY_mb_shuang},
{"948264","zhuang",(uint8_t*)PY_mb_zhuang},
};
其中py_index是一个结构体,定义如下:
/* 拼音码表与拼音的对应表 */
typedef struct
{uint8_t *py_input;    	/* 输入的字符串 */uint8_t *py;          	/* 对应的拼音 */uint8_t *pymb;        	/* 码表 */
}py_index;

其中py_input,即与拼音对应的数字串,比如“94824”。py,即与py_input数字串对应的拼音,如果py_input = “94824”,那么py就是“zhuai”。最后pymb就是我们前面说到的码表。注意,一个数字串可以对应多个拼音,也可以对应多个码表。
有了这个拼音索引表(py_index3)之后,我们只需要将输入的数字串和py_index3索引表里面所有成员的py_input对比,将所有完全匹配的情况记录下来,用户要输入的汉字就被确定了,然后由用户选择可能的拼音组成(假设有多个匹配的项目),再选择对应的汉字,即完成一次汉字输入。
当然还可能是找遍了索引表,也没有发现一个完全符合要求的成员,那么我们会统计匹配数最多的情况,作为最佳结果,反馈给用户。比如,用户输入“323”,找不到完全匹配的情况,那么我们就将能和“32”匹配的结果返回给用户。这样,用户还是可以得到输入结果,同时还可以知道输入有问题,提示用户需要检查输入是否正确。
我们归纳一下一个完整的T9拼音输入步骤:
1)输入拼音数字串
我们用到的T9拼音输入法的核心思想就是对比用户输入的拼音数字串,所以必须先由用户输入拼音数字串。
2)在拼音索引表里面查找和输入字符串匹配的项,并记录
在得到用户输入的拼音数字串之后,在拼音索引表里面查找所有匹配的项目,如果有完全匹配的项目,就全部记录下来,如果没有完全匹配的项目,则记录匹配情况最好的一个项目。
3)显示匹配清单里面所有可能的文字,供用户选择
将匹配项目的拼音和对应的汉字显示出来,供用户选择。如果有多个匹配项(一个数字串对应多个拼音的情况),则用户还需要选择拼音。
4)用户选择匹配项,并选择对应的汉字
用户对匹配的拼音和汉字进行选择,选中其真正想输入的拼音和汉字,实现一次拼音输入。
下面介绍一下pyinput.c中比较核心的函数get_matched_pymb,代码如下:

/*** @brief       获取匹配的拼音码表* @param       strin     : 输入的字符串,形如:"726"* @param       matchlist : 输出的匹配表* @retval      匹配状态*              [7]  , 0,表示完全匹配;1,表示部分匹配(仅在没有完全匹配的时候才会出现)*              [6:0], 完全匹配的时候,表示完全匹配的拼音个数*                     部分匹配的时候,表示有效匹配的位数*/
uint8_t get_matched_pymb(uint8_t *strin, py_index **matchlist)
{py_index *bestmatch = 0;    								/* 最佳匹配 */uint16_t pyindex_len = 0;uint16_t i = 0;uint8_t 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, (uint8_t *)py_index3[i].py_input);if (temp){if (temp == 0XFF){matchlist[mcnt++] = (py_index *)&py_index3[i];}else if (temp > bmcnt)  						/* 找最佳匹配 */{bmcnt = temp;bestmatch = (py_index *)&py_index3[i];  	/* 最好的匹配 */}}}if (mcnt == 0 && bmcnt)     	/* 没有完全匹配的结果,但是有部分匹配的结果 */{matchlist[0] = bestmatch;mcnt = bmcnt | 0X80;    	/* 返回部分匹配的有效位数 */}return mcnt;    				/* 返回匹配的个数 */
}

该函数实现的是将用户输入拼音数字串同拼音索引表里面的各个项对比,找出匹配结果,并将完全匹配的项目存放在matchlist里面,同时记录匹配数。对于那些没有完全匹配的输入串,则查找与其最佳匹配的项目,并将匹配的长度返回。
其中该文件还有一个函数test_py,提供给usmart调用,实现串口测试,在串口测试的时候才能用到,如果不使用的话,可以去掉。本实验也是加入usmart控制,大家可以通过该函数实现串口调试拼音输入法。
其他两个函数比较简单,这里就不细说了。
前面提及的matchlist,其定义在pyinput.h中,代码如下:

/* 拼音输入法 */
typedef struct
{uint8_t(*getpymb)(uint8_t *instr);	/* 字符串到码表获取函数 */py_index *pymb[MAX_MATCH_PYMB];		/* 码表存放位置 */
}pyinput;

该结构体提供了两个成员,一个成员就是字符串到码表获取函数,另外一个成员也就是码表的存放位置。另外一个结构体py_index,已经在前面讲解了,这里就不作展开。
2. main.c代码
在main.c文件下,除了main函数之外,还有py_load_ui、py_key_staset、py_get_keynum和py_show_result函数。其中,py_load_ui函数是用于加载输入键盘,在LCD上显示我们输入拼音数字串的虚拟键盘。py_key_staset函数用于与设置虚拟键盘某个按键的状态(按下/松开)。py_get_keynum函数用于得到触摸屏当前按下的按键键值,通过该函数实现拼音数字串的获取。py_show_result函数用于显示输入串的匹配结果,并将结果打印到串口。这部分代码就不列出来了,大家可以自行理解。
下面看一下main主函数的代码:

int main(void)
{uint8_t i = 0;uint8_t result_num;uint8_t cur_index;uint8_t key;uint8_t temp;uint8_t inputstr[7];					/* 最大输入6个字符+结束符 */uint8_t inputlen;                           /* 输入长度 */HAL_Init();                                 	/* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);		/* 设置时钟, 72Mhz */delay_init(72);                        		/* 延时初始化 */usart_init(115200);                  		/* 串口初始化为115200 */usmart_dev.init(72);                		/* 初始化USMART */led_init();                                 	/* 初始化LED */lcd_init();                                 	/* 初始化LCD */key_init();                                 	/* 初始化按键 */tp_dev.init();                              	/* 初始化触摸屏 */sram_init();                                	/* SRAM初始化 */norflash_init();                            	/* 初始化NORFLASH */my_mem_init(SRAMIN);                       /* 初始化内部SRAM内存池 */my_mem_init(SRAMEX);                       	/* 初始化外部SRAM内存池 */exfuns_init();                             	/* 为fatfs相关变量申请内存 */f_mount(fs[0], "0:", 1);                 	/* 挂载SD卡 */f_mount(fs[1], "1:", 1);                 	/* 挂载FLASH */
RESTART:while (fonts_init())                      	/* 检查字库 */{lcd_show_string(60, 50, 200, 16, 16, "Font Error!", RED);delay_ms(200);lcd_fill(60, 50, 240, 66, WHITE);   	/* 清除显示 */delay_ms(200);}text_show_string(30, 5, 200, 16, "正点原子STM32开发板", 16, 0, RED);text_show_string(30, 25, 200, 16, "拼音输入法实验", 16, 0, RED);text_show_string(30, 45, 200, 16, "正点原子@ALIENTEK", 16, 0, RED);text_show_string(30, 65, 200, 16, "KEY_UP:校准", 16, 0, RED);text_show_string(30, 85, 200, 16, "KEY0:翻页  KEY1:清除", 16, 0, RED);text_show_string(30, 105, 200, 16, "输入:        匹配:  ", 16, 0, RED);text_show_string(30, 125, 200, 16, "拼音:        当前:  ", 16, 0, RED);text_show_string(30, 145, 210, 32, "结果:", 16, 0, RED);/* 根据LCD分辨率设置按键大小 */if (lcddev.id == 0X5310){kbdxsize = 86;    kbdysize = 43;}else if (lcddev.id == 0X5510){kbdxsize = 140;kbdysize = 70;}else{kbdxsize = 60;kbdysize = 40;}py_load_ui(30, 195);my_mem_set(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] = '\0';      /* 添加结束符 */}else{inputstr[inputlen] = key + '0'; /* 输入字符 */if (inputlen < 7)inputlen++;}if (inputstr[0] != NULL){temp = t9.getpymb(inputstr);     	/* 得到匹配的结果数 */if (temp)   						/* 有部分匹配/完全匹配的结果 */{result_num = temp & 0X7F;   	/* 总匹配结果 */cur_index = 1;              		/* 当前为第一个索引 */if (temp & 0X80)            		/* 是部分匹配 */{inputlen = temp & 0X7F; 	/* 有效匹配位数 */inputstr[inputlen] = '\0';  /* 不匹配的位数去掉 */if (inputlen > 1){temp = t9.getpymb(inputstr);    /* 重新获取完全匹配字符数 */
/* 如果还是部分匹配, 直接匹配数为0, 否则表示匹配数量 */result_num = (temp & 0X80)? 0 : (temp & 0X7F); }}}else    /* 没有任何匹配 */{inputlen--;inputstr[inputlen] = '\0';}}else{cur_index = 0;result_num = 0;}lcd_fill(30 + 40, 105,30 + 40 + 48,110 + 16, WHITE);/* 清除之前的显示 */lcd_show_num(30 + 144, 105, result_num, 1, 16,BLUE);/*显示匹配的结果数*/
/* 显示有效的数字串 */text_show_string(30 + 40, 105, 200, 16, (char *)inputstr, 16,0,BLUE);py_show_result(cur_index);  /* 显示第cur_index的匹配结果 */}key = key_scan(0);if (key == WKUP_PRES && tp_dev.touchtype == 0)  /* KEYUP按下,且是电阻屏 */{tp_dev.adjust();lcd_clear(WHITE);goto RESTART;}switch (key){
case KEY0_PRES: /* 下翻 */if (result_num) /* 存在匹配的结果 */{if (cur_index < result_num)cur_index++;else cur_index = 1;
/* 显示第cur_index的匹配结果 */                                     py_show_result(cur_index);  }break;case KEY1_PRES: /* 清除输入 */
/* 清除之前的显示 */lcd_fill(30 + 40, 145, lcddev.width - 1, 145 + 48, WHITE); goto RESTART;}if (i == 30){i = 0;LED0_TOGGLE();}}
}

在main函数里,实现了我们在58.2.1小节所说的功能,也是按照它表述的逻辑进行实现。在这里我们并没有实现汉字选择功能,但是由本例程作为基础,再实现汉字选择功能就比较简单了,大家自行实现即可。注意:kbdxsize和kbdysize代表虚拟键盘按键宽度和高度,程序根据LCD分辨率不同而自动设置这两个参数,以达到较好的输入效果。
58.4 下载验证
将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。LCD显示的内容如图58.4.1所示:
在这里插入图片描述

图58.4.1 汉字输入法界面图
此时,我们在虚拟键盘上输入拼音数字串,即可实现拼音输入,如图58.4.2所示:
在这里插入图片描述

图58.4.2 实现拼音输入
如果发现输入错误了,可以通过屏幕上的DEL按键,来退格。如果有多个匹配的情况(匹配值大于1),则可以通过KEY_UP和KEY1来选择拼音。通过按下KEY0,可以KEY_UP和KEY1来选择拼音。通过按下KEY0,可以清除当前输入,通过按下KEY2,可以实现触摸屏校准(仅限电阻屏,电容屏无需校准)。
触摸输入的匹配项可以通过串口调试助手打印出来:
在这里插入图片描述

图58.4.2 拼音输入有匹配结果时打印
本章,我们还可以借助USMART调用test_py来实现输入法调试,如图58.4.3所示:
在这里插入图片描述

图58.4.2 USMART测试T9拼音输入法图

这篇关于【正点原子STM32连载】第五十八章 T9拼音输入法实验摘自【正点原子】STM32F103 战舰开发指南V1.2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/163918

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧