导航编程方法.docx

上传人:b****6 文档编号:3255284 上传时间:2022-11-21 格式:DOCX 页数:8 大小:21.31KB
下载 相关 举报
导航编程方法.docx_第1页
第1页 / 共8页
导航编程方法.docx_第2页
第2页 / 共8页
导航编程方法.docx_第3页
第3页 / 共8页
导航编程方法.docx_第4页
第4页 / 共8页
导航编程方法.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

导航编程方法.docx

《导航编程方法.docx》由会员分享,可在线阅读,更多相关《导航编程方法.docx(8页珍藏版)》请在冰豆网上搜索。

导航编程方法.docx

导航编程方法

导航编程方法

1.引言

我们中的大多数人通常编写运行在PC机上的软件,如数据库应用、图像处理、Internet应用等,而缺乏编写嵌入式软件的经验。

不幸(遗憾)的是,我们不得不编写运行在导航机上的程序。

在编写这样的程序之前,我们需要了解我们将要进行的工作和以往的工作有哪些不同,我们所习惯的编程方法哪些可以继续使用,哪些必须改变。

2.内存

PC机的一个最大的优势是我们可以认为有无限多的内存,大多数的PC机有64M的内存,而且Windows提供了虚拟内存机制,使编程者可以任意地使用内存,而在导航机上,我们一共只有4M或8M的内存可以使用,这要求我们必须认真地考虑在编码时如何节省内存,甚至会遇到为了节省内存而牺牲效率的情况。

●不要使用小块内存

使用小块内存会增加系统在管理、检查内存状态上的开销;同时,使用小块内存过多很容易出现内存碎块,尽管系统有内存碎块整理的功能,但还是会增大系统负担。

因此,我们强烈反对使用小块内存。

推荐的使用方法:

Ø当仅使用少量且事先知道大小的内存时,可以以变量或数组的形式申请。

Ø当时用内存量较大,使用的大小事先(编码时)不知道,必须动态申请的内存时,应该先申请一块较大内存块,使用时通过计算确定每一小块的内存地址。

●用数组实现链表

在程序中使用链表有时是必须的,也可以给编程带来很多方便。

但使用链表实施必要分配多块内存,在链表进行插入、删除等操作时还要进行内存的申请和释放操作,在导航系统这样一个资源非常有限的系统里,这样做会占用大量系统时间,给系统带来不必要的负担。

那么我们怎样才能既使用链表的优点,同时又避免给系统增加不必要的麻烦呢?

针对这个目的,我们认为:

用数组实现链表是一个比较好的方式。

实现方式:

结构体数组,在每个元素的结构体中保存Next/Previous节点的下标。

●不用的内存要及时释放或解锁

理由很简单:

导航系统的资源(尤其是内存)非常有限,占用不再需要的内存会导致其他任务无法取得所需的内存,影响导航系统的性能甚至功能的实现。

●不要保存(非固定)内存块的指针

导航系统中的内存属性有很多种,在OS的讲座中想必已经介绍了。

其中除了Fixed这种属性的内存块之外,其他内存块的指针(地址)并非在任何时候都是有效的。

如果保存了一个内存块的指针,而这个内存块再没有被这个指针的持有者意识到的情况下被移动或被删除了的话,再次企图使用这个指针来访问这个内存块是非常危险的,可能导致任何不可预期的后果(轻则数据不正常,重则整个系统会崩溃)。

●堆栈的使用

●内存泄漏(系统需要长时间运行)

●结构体定义

原则是从小到大的顺序定义结构体成员

structSample_A{

intiMember1;

charcMember2;

shortsiMember3;

intiMember4;

}

structSample_A{

charcMember2;

shortsiMember3;

intiMember4;

intiMember1;

}

*注意区别

●关于内存块的属性特征及其适用范围是否已在OS的讲座中介绍了?

有没有必要强调一下?

●介绍了RSM,及与其它普通内存池的区别,使用目的.

RSM的内存是属于RX830操作系统后增加的一部分,主要的目的是为系统提供某些时候(偶尔),较少时间需要使用大量内存的机制.主要用于具有Cache属性的内存使用方式.

RSM内存池并不是一个完整的(或者说连续的)内存,生成时只是在系统中进行登记,分配内存块时的机制是从全部的用户内存池(1号内存池)中分配.

●介绍了内存的属性,相应的区别,使用目的.

在本节介绍时,由于大家对lock,unlock使用不是很清楚,因此强调一遍.

分为固定,可移动,可抛弃三种属性.

固定属性的内存一般在系统初始化时进行分配,因为如果在以后的运行中随机分配会导致内存碎片,所以要求在运行中分配的固定的内存一定要第一时间释放.处于Unlock时(如果不释放(Release))它的handle有效和地址全局有效.

可移动的内存处于Unlock时(如果不释放(Release))它的handle有效,但是地址无效.

可抛弃的内存处于Unlock时(如果不释放(Release))它的地址无效,handle状态不明,需要先进行Refer.主要用于Cache.

内存块同时可以Lock多次,也就是说可以多个任务同时使用一个内存块,因此要特别注意使用的任务不要发生write和read两种操作,只能有一种.另外,要严格保证Lock和Unlock得成对使用,否则会发生无法正常释放及地址非法的现象.

●SCL(SequenceableCollectionLight)数组

详细的使用方法请向刘超(电话:

64047,E-mail:

liuchao@neu-)咨询。

3.多任务

准确地说这并不是PC机和导航机编程的区别,因为在PC机上也经常会编写多线程、多进程的软件,但我们中的大多数人没有做过这样的工作,因此在这里列举了一些多任务编程的注意事项。

●保护公用的数据

在多任务系统中,经常会出现多个任务需要访问同一个数据的情况,这时我们就必须对这些数据进行保护,通常的方法是用Semaphore来实现。

例如:

intiCount;

HandleSemaphore_iCount;

TaskA_Main()

{

os_iWaitSemaphore(Semaphore_iCount,…);

iCount++;

os_iSignalSemaphore(Semaphore_iCount,…);

}

TaskB_Main()

{

os_iWaitSemaphore(Semaphore_iCount,…);

iCount--;

os_iSignalSemaphore(Semaphore_iCount,…);

}

以上是从严格意义上来说,但是有时候为了系统的要求(例如性能),如果确信对全局变量进行操作的任务不会有冲突,也可以不使用保护机制.

例如:

他们使用了禁止中断的形式.

另外也会有其他的形式,但暂时想的还不是很清楚.

●时刻意识到有其他任务在运行(例子)

●Mail和EventFlag

任务间通信有EventFlag和Mail两种方式,其主要区别是Mail可以携带数据。

一般来说,每个任务组有一个处理事件的任务,等待事件并做简单处理或分发给其他任务,没有事件发生时这个任务要进入Wait状态。

为保证信息不发生堵塞,这个任务对一个事件的处理必须简单。

由于任务必须主动取Mail,因此发送Mail的同时要设置EventFlag来通知受信方。

(由受信方来轮巡也可以)

注意点:

1)Mail的Size定义

2)Mail中可以采取查询的方式.

另外注意Ossimulator和Rx830的区别:

在后者中evnet,semaphore,mail都允许使用查询方式,在前者中不允许.

●PlugIn机制

有两个任务A和B,任务B要求任务A在某种条件下通知任务B,这时可以采用PlugIn机制。

为实现PlugIn,任务A要维护一张表,并提供可以将一个Event插入表中的函数。

任务B在需要等待任务A的通知时,创建Event,并通过调用任务A提供的函数将此Event插入到表中,然后等待任务A来SetFlag。

一般地说,任务A可以为一种事件创建一个表,不同的任务(B、C、D)都需要等待同一事件时,它们向表中登录不同的Event(或同一Event的不同Flag)。

这样,当的事件发生时,任务A只需要Set表中的所有Flag就可以了。

任务A还应该提供PlugOut函数,让其他任务取消其登录的事件,这样当事件发生时任务A就不用通知相应的任务了。

典型应用:

MM用的Postman。

任务A为Postman,任务B为Map,Map进入Navi方式时,向Postman登录最新自车位置的请求。

当Postman产生新的自车位置时,通知Map并把新位置发给Map。

当Map进入Scroll方式时,不再需要最新自车位置,可以撤消请求。

今后,会有其他任务(如RG)也要求得到最新的自车位置,它可以登录另一个事件。

●轮巡和等待(中断)

在导航系统中的通信主要有两种方式:

轮巡和等待。

轮巡是接收者主动去查询是否有请求/数据;而等待是接收者在有请求/数据时被发送者发送的EventFlag等的同步对象激活。

(关于轮巡和等待的优缺点和适用的范围请补充)

这里只补充他们的区别:

等待的主要使用的目的时达到同步,是真正意义的事件驱动,只有事件发生时才会有下一步的动作.

Polling指的是每隔一定时间就要做一个(或一些)动作.(例如中断)

或者在等待某个事件时,一定时间没有满足所需要的接续动作.(例如TimeOut处理).

4.指针

在PC机上,Windows有良好的内存保护机制,如果一段代码向非法的地址写入数据,马上会引发异常,并且能定位到错误的代码行,使编程者顺利地找出错误的原因。

而在导航机上,异常的产生可能会滞后,以至于发生异常时已经无法判断真正的原因,因此需要对指针操作格外小心。

●初始化

●合法性判断

5.调试代码

导航机的调试效率比较低,原因有以下几个方面:

调试工具不够强大;多任务给调试带来困难;修改-编译-链接-加载-调试的过程繁琐而耗时;导航机内存少(又是内存!

),以至于不能把所有的代码加上调试信息——这是一个致命的弱点。

●使用Assert

在导航系统中,可以象在VC++中一样,使用ASSERT来检查数据的有效性,但使用时请注意:

不要在ASSERT语句中写有效代码!

这是因为ASSERT语句,包括写在括号中的任何内容,在实际生成Release版本后是不执行的,这样导致的后果不言自明。

例如:

如下代码:

ASSERT(iGetDataBlk(……)==TE_OK);在程序Release后与NULL;是等价的。

如果要检查函数运行的结果,应该用如下方式:

iRet=iGetDataBlk(……);

ASSERT(iRet==TE_OK);

●检查参数

●对指针或地址的参数要进行参数检查,而且,如不改变,最好加const

●返回错误码

在导航程序中,大量的函数都以错误码作为返回值,这样可以向使用者告知本函数处理的状态:

是正常结束、没有内存还是出现了未知的错误等。

通过检查返回值可以决定下一步的处理:

是继续运行、整理内存还是挂起系统等。

对我们即使的发现错误和解决问题,保证导航系统的正常动作是有帮助的。

注意:

调用有返回值的函数后一定要检查其返回值是否正常以决定今后的处理,在实际开发中,曾经出现过这样的错误:

被调函数返回错误“没有数据”,这时内存中的信息为一随机值,但调用者没有判断就使用了该数据,导致功能无法正常完成。

●加打印信息

导航系统的调试相信大家都已经有了一定的认识,目前的导航系统没有非常好的实机调试环境,而添加调试信息需要重新编译,且不能加得太多(会导致.out文件过大无法加载),这就要求我们在调试的过程中学会使用打印信息,将一些认为可疑的变量的值、函数的返回值等通过打印语句(ptprintf)输出到Partner调试器中显示,作为程序调试的一个参考。

但使用打印信息时请注意:

尽量避免在执行频率非常高的地方加入打印信息,否则可能会导致导航机CPU负载过大,Partner出现“TargetCPUHang-UP”的错误,影响调试。

6.其他问题

●关于const变量

●变量定义的位置

其实这是一个标准C的规则:

但是我们在经常使用VC等支持C++的编译器之后

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1