TI OMAPL处理器介绍(二)

无意间收集到这篇有关OMAP技术介绍文章,感觉出作者的行文幽默,和深厚的技术功底,特分享给大家。

以SEED-DIM138/1808-Kit上的LED灯D1为例讲述如何进行相关开发(一)

本文档的使用许可证:

本文档遵循GPLv2发布,因此任何人引用或修改本文档均需要在发起引用的文章的显要位置(开头或结束处)原样引入本段文字(互联网及电子文档为斜体蓝色,)及所引用版本的下一段的文档编辑人员的列表及工作内容。

适用器件:操作适用于基于TI OMAP-Lx8 C6748 AM18xx处理器的SEED-DIM138/1808-kit,方法适用于TI Sitara、DaVinci、OMAP、Integra、C67xx等系列的绝大多数处理器。 原理适用于所有嵌入式处理器上的产品开发。

嵌入式的开发与PC程序不同,通常需要与定制的开发板或是产品打交道,这就意味着与PC那样的标准架构不同,所有的东西你不能依靠猜来进行。因此我们的工作要从实际硬件出发。那么本文中我们将以SEED-DIM138/1808-Kit上的LED灯D1为例讲述如何进行相关开发,也就是嵌入式的软件开发人员如何从软件的角度看硬件。

看原理图

看原理图,是为一款嵌入式产品开发软件(纯应用层软件工程师除外)的必备技能之一。具体如何看原理图,今天我们不在这里讲述。我们看SEED-DIM138底板的原理图,知道灯D1是连接到GP6[13]的,所图1所示。

图1 SEED-DIM138-Kit套件中底板用户LED原理图

由这个图可以看出要想让灯D2发光,必须置GP6_13为高电平。

查相关器件手册,了解如何进行配置

从软件工程师的角度,所有的外设都是通过地址来进行访问或配置的。

查一下TI的芯片手册,我们发现Datasheet SPRS586x中第3章是Device Overview,其中会有一节讲述Pin Assignments,那么在这边手册中是3.7节。如图 2 所示的 R 行 17 列是GP6[13] 所在的引脚,该引脚是一个 GP6[13] 及PRU0_R30[31]等功能的一个复用引脚。(我们知道TI提供的产品功能都比较强大,因此引脚的复用程度都比较大)。

因此我们首先要解决的是软件的管脚复用问题。我们发现芯片手册SPRS586x中的第3.7节是讲述Pin Multiplexing Control的。"Device level pin multiplexing is controlled by registers PINMUX0 - PINMUX19 in the SYSCFG module."

根据这句话,我们可以在文档里搜索PINMUX或SYSCFG的其它章节,发现本文档中并无进一步详细信息。

因此我们需要进一步看文档 SPRUGM7x ,也就是《 OMAP-L138 Applications Processor System Reference Guide》这篇文档。 SPRUGM7x的第11章是专门讲述SYSCFG(System ConFiG)。其子节11.5.10是详细讲述PINMUX的。我们在里面找到关于GP6[13]的配置说明如图3所示。

意思是说PINMUX13寄存器的11_8位设为8h即可以令该引脚工作为GPIO的GP6[13]. 那么从软件工程师的角度就是需要知道PINMUX13寄存器的地址。

而同样这11.5节的刚开始就是重点介绍SYSCFG寄存器的,在这节的表里面我们发瑞PINMUX13寄存器对应的地址为01c1 4154h.

现在这个引脚已经是GPIO了。

然后我们就应该读具体外设的手册,那么本外设为GPIO,从TI网站OMAPL138 产品信息页面查找并 下载到 GPIO 的用户手册 SPRUF18x 《TMS320C674x/OMAP-L1xProcessor General-Purpose Input/Output 》,根据这篇文档我们知道要使用这个GPIO引脚我们需要将该GPIO引脚的具体功能设为输出,并向该引脚输出高电平,灯D1才会亮。

而GP6对应的输入还是输出是由DIR67寄存器的GP6P13位也是本寄存的比特13控制的。

而且,写0表示输出。

而往该引脚输出高电平可以通过OUT_DATA67的GP6P13即比特13完成。

表7 GPIO寄存的偏移地址分配表

因此现在的情况是我们需要知道DIR67及OUT_DATA67的地址。而文档SPRUF18x给出的GPIO寄存器地址对DIR67及OUT_DATA67的分配如图

表8 OMAPL1x8器件的Memory Map

而这里的值是相对值,需要对照芯片的SPRS586x SPRS586x关于Memory Map的分配,发现GPIO地址起始为01e2 6000h.

[总结一下],看文档的顺序,Datasheet->System Reference Guide->专项手册。 这也是看TI文档的基本套路。

[总结一下],点亮SEED-DIM138/1808-Kit上灯D1的工作流程为:

1 设PINMUX13_11_8 为08h

2 设GPIO DIR67的GP6P13位为0,配置管脚为输出

3 设GPIO OUT_DATA67的GP6P13位为1

下几节我们将实际通过操作CCS而不编程、裸机程序、Linux程序三种手段来以上面介绍的方法来实际点亮这个灯。

CCS下简单几步操作点亮灯D1

打开CCS(3.3.82或更新版本,CCSv4.x或后续其它CCS产品), 具体仿真器的配置情况,这里我们不再描述。推荐使用XDS560系列仿真器,如我们合众达的SEED-XDS560Plus因为它确实能让你非常畅地完成我下面要进行的操作。

打开CCS后,选择连接器件的ARM端(DIM138/1808适用)或是DSP端(DIM138/6748适用)。注:需要用到相应的GEL文件。

在View菜单里选择Expressions,这是一个我们通过CCS调试程序时监测变量的一个窗口。如图3所示。

点击其中的”Add new expresion”并输入*0x01c14154作为Expression,然后在Value处入0x8<<8。然后再分别加入:

Expression: *0x01e26088 Value: 0xfffffff&(~(0x1<<13))

Expression: *0x01e2608c Value: 0x0|(0x1<<13)

最后输入完的CCS Expressions窗口如图4所示。

到这一步为止,你会发现板子上的LED D1已经亮了。当然在CCS下还可以使用

Memory窗口来完成同样的工作。但我个人觉得Expressions窗口最好用。

裸机编程的方法点亮LED D1

程序代码如下:

#define PINMUX_BASE _ADDR 0x01c14120
#define PINMUX_4_LED_D1 13
#define PINMUX_START_BIT_4_LED_D1 8
#define PINMUX_SET_4_LED_D1 0x8
#define GPIO_BASE_ADDR 0x01e26000
#define GP_BANK_LED1_D1 6
#define GP_PIN_4_LED1_D1 13
typedef enum {PIN_OUTPUT, PIN_INPUT} gpio_DIR;
typedef struct ledStruct
{
unsigned char pinmuxGroup;
unsigned char pinmuxStartBit;
unsigned char pinmuxSet;
unsigned char gpioBank;
unsigned char gpioPin;
bool state; // On or Off
};
bool pinmux(unsigned short pinMuxGroupNum, unsigned short
pinMuxStartBit, unsigned char pinMuxCmd)
{
unsigned int *pinmux = (unsigned int*)( PINMUX_BASE _ADDR +
pinMuxGroupNum *4);
*pinmux = (*pinmux & ~(0xf << pinMuxStartBit)) | (pinMuxCmd <<
pinMuxStartBit);
if(*pinmux & (0xf << pinMuxStartBit )) != (pinMuxCmd <<
pinMuxStartBit)
return false;
else
return true;
}
bool gpioSetDir(unsigned short gpioBank, unsigned char
gpioBankPinNum, gpio_DIR gpioDir )
{
unsigned int *gpioGroup = (unsigned int*) (GPIO_BASE_ADDR +
(gpioBank/2)*4 );
*gpioGroup = ( *gpioGroup & ~(0x1<
( gpioDir << gpioBankPinNum);
if ( *gpioGroup & (0x1<<<
gpioBankPinNum)
return false;
else
return true;
}
bool led_init(ledStruct led)
{
if (!pinmux(led.pinmuxGroup, led.pinmuxStartBit, led.pinmuxSet ))
return false;
if (!gpioSetDir(led.gpioBank, led.gpioPin, PIN_OUTPUT))
return false;
return true;
}
bool led_on(ledStruct led)
{
//TODO: Left for you to implement this function;
}
bool led_off(ledStruct led)
{
//TODO: Left for you to implement this function;
}
!
!
int!main(int!*argc,!char!**argv)!
{!
! //TODO:!Code!to!turn!on!and!swich!off!the!LED!is!left!for!you.!
}!
!

请自行建立 CCS 工程编译本程序,或使用 arm-linux-gcc 来编译本代码。区别是ccs 编译出来的程序可以通过 CCS 来下载执行,arm-linux-gcc 编译出来的版本,可能需要 uboot或是其它手段才能装载执行。不过 TI 未来推出的 CCS 版本应该会支持 arm-linux-gcc 编译出来的代码(我已经在测试版本 CCS 中见到这一功能)。!

Linux下,访问 LED(D1)

Linux下,地址空间分为三种,分别是

用户空间:应用程序代码所能直接访问的地址空间;

内核空间:操作系统内核及驱动程序所能直接访问的地址空间;

物理空间:器件及系统上各种实际的物理地址空间。

从前面的介绍我们知道,从嵌入式开发工程师的角度,各种外设是需要通过物理地址来进行访问的,因此说代码需要跟物理地址发生关系。 而按照 Linux 对地址空间的三种划分,应用程序甚至驱动程序都是不能直接访问的。那么怎么样才能访问物理地址空间呢?Linux 的做法是通过几个桥梁函数架设了驱动程序访问物理地址及应用程序访问物理地址的桥梁。

这些函数分别是: ioremap 函数家族及 remap_pfn_range 函数家族。最后形成的关系如图 5所示。注意:这两个函数家族均需要在内核空间执行,只是执行后,内核空间及用户空间便可以通过相应的指针来映身到指定的物理地址上,从而实现对物理空间访问。

从前面的介绍我们知道,从嵌入式开发工程师的角度,各种外设是需要通过物理地址来进行访问的,因此说代码需要跟物理地址发生关系。 而按照 Linux 对地址空间的三种划分,应用程序甚至驱动程序都是不能直接访问的。那么怎么样才能访问物理地址空间呢?Linux 的做法是通过几个桥梁函数架设了驱动程序访问物理地址及应用程序访问物理地址的桥梁。

这些函数分别是: ioremap 函数家族及 remap_pfn_range 函数家族。最后形成的关系如图 5所示。注意:这两个函数家族均需要在内核空间执行,只是执行后,内核空间及用户空间便可以通过相应的指针来映身到指定的物理地址上,从而实现对物理空间访问。

对于单个寄存器,还可以使用 phys_to_virt 函数来获得物理地址对应的内核空间地址,但对于连续空间的访问不建议使用这种方法。因为这不能保证你获得一个连续的内核空间地址区,甚至当你用指针进行操作时,有可能出现内存越界。比如说,内核中地址A及B是连续的两个地址,a 和 b 为连续的两个物理地址,如果你用 phys_to_virt 得到 a 对应的虚拟地址 A,当你需要访问 b 时,你会很自然的使用指针
A+1 也就是B来访问。但这里不幸地是B事先已经被对应用到物理地址X了,而对 X 的野蛮操作引发的灾难,没有人知道。

而内核空间与用户空间要拷贝数据,有函数 copy_from_user 及copy_to_user 可用。

那么仅剩下的问题就是如何写一个字符型的设备驱动程序,以及如何在应用程序里访问驱动程序。

关于如果写字符型设备驱动程序,这里我就不在缀述,几乎每一本讲述Linux 驱动程序的书中都有长篇大论的阐述。(我会在后续给出一个实作的代码,有需要的可以给我写邮件,但由于近阶段一直较忙,白天忙工作,晚上有时要加班,还要给孩子讲故事,这个实作代码可能会比较晚才给出来。写本文时一夜未眠,请见谅。)

用常规的CCS开发方式建立一个完整的LED项目

大家好,我是Even,北京合众达电子的产品FAE。对于OMAP-L138这个平台我也是刚接触不久,略懂皮毛。有说的不对的地方还请大家多多指教,一起学习。

之前David已经为大家介绍了CCSV4的使用方法和调试技巧。并通过阅读相关DATASHEET实现用配置寄存器的方式点亮板卡上的LED灯。下面我将用常规的CCS开发方式建立一个完整的LED项目。

对于开发的认识,软件工程师和硬件工程师会有不同的看法。硬件工程师乐于用直接控制硬件的方式来实现系统的功能,如控制相关寄存器的值。这样做的好处是节省系统资源,运行速度快,但需要对各种硬件的寄存器有相当的了解。缺点是遇到大型系统构建时会有些力不从心。软件工程师更乐于基于操作系统进行开发,通过系统调用的方式控制硬件。好处是可以尽量少的接触底层硬件,专心软件的设计。缺点是如果遇到驱动不完善或者有BUG的情况下,就会有些束手无策。精通软硬件是每个嵌入式工程师的最高追求,不过由于专业不同就会有所偏好,找到一个适合自身的开发模式还是十分必要的。

之前说了不少闲话,现在我们言归正题。

OMAP-L138是一个双核的芯片,无论是ARM核还是DSP核,都有相当数量的寄存器需要配置,如果从头开始逐一定义和设置,需要消耗大量的时间,但这又是不得不做的事。庆幸的是TI的第三方已经为我们写好芯片的寄存器定义,并把初始化和功能实现通过C函数的方式集成起来,这样我们只需要调用相关的函数,就可以实现对指定外设初始化工作和使用。

这些文件的集合体被称作BSL(Board Support Library)。它大大减少了开发初期的工作量,注释也全面,容易理解。

下面通过调用BSL的方式,建立一个ARM端点亮LED的项目,

void main()
{
#if NO_GEL
EVMOMAPL138_init(); //初始化芯片,PLL等
EVMOMAPL138_initRAM(); //初始化RAM,DDR
EVMOMAPL138_enableDsp(); //使能DSP
#endif
USTIMER_init(); //初始化CPU定时器
// EVMOMAPL138_pinmuxConfig(PINMUX_GPIO613_REG, PINMUX_GPIO613_MASK, PINMUX_GPIO613_VAL); //设置管脚复用,作为GPIO
EVMOMAPL138_pinmuxConfig(PINMUX_GPIO810_REG, PINMUX_GPIO810_MASK, PINMUX_GPIO810_VAL); //设置管脚复用,作为GPIO
// GPIO_setDir(GPIO_BANK6, GPIO_PIN13, GPIO_OUTPUT); //设置GPIO为输出模式
GPIO_setDir(GPIO_BANK8, GPIO_PIN10, GPIO_OUTPUT); //设置GPIO为输出模式
printf("\r\n\r\n********** OMAP-L138 LED TEST **********\r\n\r\n"); //输出打印信息
while(1)
{
// GPIO_setOutput(GPIO_BANK6, GPIO_PIN13, OUTPUT_LOW);
// USTIMER_delay(500000);
// GPIO_setOutput(GPIO_BANK6, GPIO_PIN13, OUTPUT_HIGH);
// USTIMER_delay(500000);
GPIO_setOutput(GPIO_BANK8, GPIO_PIN10, OUTPUT_LOW); //设置GPIO输出低电平
USTIMER_delay(500000); //延时500ms
GPIO_setOutput(GPIO_BANK8, GPIO_PIN10, OUTPUT_HIGH); //设置GPIO输出高电平
USTIMER_delay(500000); //延时500ms
}
}

上面的代码就是主函数的内容,简洁明了,一看注释就能明白函数的作用。整体思路也是完全按照芯片手册中对外设配置的步骤进行操作的。

1. 开启外设时钟。

2. 设置芯片管脚复用,用为GPIO。

3. 设置GPIO为输出模式。

4. 设置GPIO输出值,高电平或者低电平。

其中第一步是通过EVMOMAPL138_init()这个函数实现的,具体原理可以参考BSL相关的源码注释,此时已经开启了芯片上所有外设时钟,当然也包括了GPIO的。

第二步是由EVMOMAPL138_pinmuxConfig()函数实现的,其内部源码也是对寄存器的操作。

第三部是通过GPIO_setDir()函数实现,可以配置为输入或者输出。当作为输入时,配置会更复杂一些,因为会涉及到中断等内容。

第四步通过GPIO_setOutput()函数实现,给指定的GPIO管脚赋值,输出高电平或者低电平。

由此可见,BSL中大部分函数功能都可以通过名称知道,内部代码注释也很全面,容易理解。这个程序的源码已经打包,在CCSV4中直接导入项目就可以运行。运行结果就是LED灯不停闪烁,亮0.5秒,灭0.5秒。

或许有人会问,为什么除main.c之外,还有很多看上去没用的源文件。这是因为模块的相关性导致的,调用一个模块的功能函数的时候,或许会用到其它模块的函数,因此在编译的时候必须要将其包含进来,否则编译会出错。

无论接触哪种新的硬件平台,点亮LED一般会是工程师第一个要做的实验,就像编写软件HelloWorld一样经典。虽然程序很短小,但集成了系统设计中大部分操作。是新手入门,老手熟悉平台的绝佳选择。

DIM138 nand AIS文件烧写说明

各位好,由于最近工作比较忙,很久才更新这次调试笔记,先说声抱歉了。

另外声明一下,下面这篇关于NANDFLASH烧写的文档是我们研发工程师的功劳,我代他发到论坛上来,可不想抢别人的功劳,哈。同时感谢他白忙之中配合此次论坛活动。他调试的时候使用的是SEED-DIM138最新的GB底板,LED的地址可能不太一样,各位需要稍稍留意一下。

下面进入正题:

1. 首先在下载安装.net framework 2.0,然后安装。然后下载安装AISgen,因为AISgen运行依赖于.net framework。

下载地址:

.net framework 2.0 :http://www.crsky.com/soft/4818.html

AISgen : http://www-s.ti.com/sc/techlit/sprab41.zip

2. 打开CCS4,打开LED工程。修改lind.cmd内容如下

-e _boot
IRAMStart = 0x80000000;
IRAMSize = 0x00020000;
DDRStart = 0xc0000000;
DDRSize = 0x02000000;
DRAMStart = 0x80000000;
_DRAMSize = 0x00020000;
STACKStart = IRAMStart + IRAMSize;
_NAND_EMIFStart = 0x62000000;
_NOR_EMIFStart = 0x60000000;
MEMORY
{
ARM_INTERNAL_RAM (RWXI): origin = 0x80000000 length = 0x00010000
SDRAM (RWXI): org=0xc0000000 length = 0x02000000
}
SECTIONS
{
.boot: load = ARM_INTERNAL_RAM
.text: load > ARM_INTERNAL_RAM
.data: load > ARM_INTERNAL_RAM
.bss: load > ARM_INTERNAL_RAM
}

3. 在evmomapl138.c文件中添加函数

void boot(void)
{
asm(" .global STACKStart");
asm(" .global _stack");
asm(" .global main");
asm(" NOP");
asm(" MRS r0, cpsr");
asm(" BIC r0, r0, #0x1F"); // CLEAR MODES
asm(" ORR r0, r0, #0x13"); // SET SUPERVISOR mode
asm(" ORR r0, r0, #0xC0"); // Disable FIQ and IRQ
asm(" MSR cpsr, r0");
asm(" NOP");

// Set the IVT to low memory, leave MMU & caches disabled
asm(" MRC p15,#0,r0,c1,c0,#0");
asm(" BIC r0,r0,#0x00002300");
asm(" BIC r0,r0,#0x00000087");
asm(" ORR r0,r0,#0x00000002");
asm(" ORR r0,r0,#0x00001000");
asm(" MCR p15,#0,r0,c1,c0,#0");
asm(" NOP");

// Setup the stack pointer
asm(" LDR sp,_stack");
asm(" SUB sp,sp,#4");
asm(" BIC sp, sp, #7");

// Call to main entry point
main();

asm("_stack:");
asm(" .word STACKStart");
}

在evmomapl138.h中添加:

void boot(void);

保存后,编译生成led.out文件。

4. 打开AISgen工具,点击File菜单,选择Load Configuration,选择文件SEED138_AIS_CONFIG.cfg。出现以下界面:

在ARM Application File中选择CCS4生成led.out文件

在AIS Out File中填入led.bin文件的路径。

然后点击 Genrate AIS 生成.bin文件。

5.打开CCS4,连接仿真器,加载GEL文件然后连接板卡

然后运行程序nand-writer_ccs33.out 用来烧写 AIS文件。

烧写完成后,断开仿真器,重启开发板,即可看见两个LED灯交替闪烁。

看了上面的说明,有些经验的工程师可能会问,看主函数基本上都是用操作寄存器的方式进行LED控制,那为什么还采用TI的BSL库呢?

原因主要是文中的例程是根据我之前的LED控制加以修改的,整体上尽可能少变动进行固化工作。有些寄存器定义采用了TI的BSL库中的定义,需要进行调用,因此会感觉程序比较大一些。如果各位觉得繁琐的话,完全可以摒弃这些,自己进行精简工作,整体的固化流程是一样的。

到此,各位应该对DIM138的开发有了一个整体上的认识。从芯片认识,新项目建立,开发和调试,最后进行脱机固化有了一个完整的了解,为以后的深入研究打下基础。

在这里我和合众达的所有同事们祝各位工作顺利,项目早日完成。

时间: 2024-11-05 22:32:33

TI OMAPL处理器介绍(二)的相关文章

TI OMAPL处理器介绍(一)

无意间收集到这篇有关OMAP技术介绍文章,感觉出作者的行文幽默,和深厚的技术功底,特分享给大家. 曾经,会单片机的工程师牛得一塌糊涂.想十年前一个会单片机的工程师几乎就是嵌入式工程师的代名词. 若干年前,ARM开始暂露头角,看到单片机工程师的牛气,ARM工程师笑了.而从包括合众达在内的中国DSP三巨头开始在中国推广DSP时,所有开始使用DSP的工程师笑了.他们有理由笑,他们有资格笑.因为在那时,DSP就代表着高高在上,收入高.职位高.声誉高,典型的三高.而经过若干年的推广,DSP已经脱下了神的外

TI OMAPL处理器介绍(三)

个人认为,学TI的OMAP也好,学Samsung的arm也好,学MIPS也好.最好的上手的方法就是忘了他是什么.(对于应用开发人员用操作系统下的驱动开发人员适用) 只要有操作系统, 不管他是什么处理器,其本质都只是处理器的核 + 一堆外设 那么对于做应用的人来说,没有任何本质的区别. 对于做驱动的人来说,只是在不同的器件上pinmux设置等东西有所不同.但本质都是为某一个操作系统写驱动. 真正需要去理解硬件内核的架构的人是做编译器的人,大部分工作需要量写汇编代码的人. 对于像OMAPL这样的主流

TI AM335X处理器介绍

AM335X是美国TI(德州仪器)公司基于 ARM Cortex-A8内核的AM335X微处理器,在图像.图形处理.外设方面进行了增强,并全面支持诸如 EtherCAT 和 PROFIBUS等工业接口.AM335X的优点有如下几个: 第一:该器件是最实惠的Cortex A8 处理芯片,这个对中国市场至关重要 ,甚至是决定性的因素.第二: TI 史上公开资料最全的一个芯片.第三: 产品定位最清晰的一个工业控制MCU第四 : 唯一一个集成2个MAC的 MCU.第五: 目前唯一支持Androd 4.0

linux程序分析工具介绍(二)—-ldd,nm

本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具.ldd是用来分析程序运行时需要依赖的动态库的工具:nm是用来查看指定程序中的符号表相关内容的工具.下面通过例子,分别来介绍一下这两个工具: 1. ldd, 先看下面的例子, 用ldd查看cs程序所依赖的动态库: [email protected]:~/Public$ ldd cs linux-gate.so.1 => (0xffffe000) libz.so.1 => /lib/libz.so.1 (0xb7f8c000)

Avaya Exrience Portal(AEP)基础介绍 二(四大组件总结)

什么是Avaya Exrience Portal(AEP)? 1:提供语音(或者多媒体)自动化用户体验的软件平台:  2:基于标准的VXML(定义了如何使用语音识别.语音合成.互联网访问.数据库访问.语音文件播放.DTMF输入等功能开发一个完整的语音应用系统.)和CCXML(它基于XML定义了一系列开放标准的呼叫控制API)的应用:  3:支持多媒体处理:  4:完全基于Web架构:  5:支持TTS文语转换和语音识别技术:     2)AEP包含的组件   EPM:AEP集成的管理,报表,监控

Lucene.Net 2.3.1开发介绍 —— 二、分词(五)

原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(五) 2.1.3 二元分词 上一节通过变换查询表达式满足了需求,但是在实际应用中,如果那样查询,会出现另外一个问题,因为,那样搜索,是只要出现这个字,不管它出现在什么位置.这就产生了上一小节开头讲的,对准确性产生了极大干扰.比如,如果有一段这样的话:“这是一个英雄!他有无法用词汇形容的孤单,但是他并没有用言语来表达.”这句话包含了“英 语 单 词”这四个字,但是却和“英语单词”一点关系都没有.首先想到的解决方法,就是把句子按词来划分

Lucene.Net 2.3.1开发介绍 —— 二、分词(四)

原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(四) 2.1.2 可以使用的内置分词 简单的分词方式并不能满足需求.前文说过Lucene.Net内置分词中StandardAnalyzer分词还算比较实用(见1.1.2小节).StandardAnalyzer为什么能满足我们的部分需求,而它又有哪些不足呢?看分词的好坏还是要从效果说起.简单的说,在中英文混合的情况下,StandardAnalyzer会把英文按空格拆,而中文则按单字拆.因为中文是按单字拆,所以对分词的准确性起到了干扰,

Lucene.Net 2.3.1开发介绍 —— 二、分词(三)

原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(三) 1.3 分词器结构 1.3.1 分词器整体结构 从1.2节的分析,终于做到了管中窥豹,现在在Lucene.Net项目中添加一个类关系图,把TokenStream和他的儿孙们统统拉上去,就能比较好的把握他们之间的关系. 图 1.3.1.1 如图1.3.1.1 就是他们的类关系图.看出如果要做一个分词器,最短的路,就是继承第二代,成为第三代.然后再写一个Analyzer的子类,专门用来做新分词器的适配器就好了.转换器.  呵呵,写

红黑树详细介绍二

删除 RB-TRANSPLANT(T,u,v)函数是将u子树用v来代替,在替换的时候分为了三种情况,如果u就是root结点则直接替换u,如果树里面还包含有其它结点,则将u的左右子树转移到v的左右子树上面. RB-TRANSPLANT(T,u,v) if u.p == T.nil T.root = v else if u == u.p.left u.p.left = v else u.p.right = v v.p = u.p 删除代码 RB-DELETE(T,z) y = z y-origina