hxqhit

    1. 顶一个,下了试试~ 谢谢分享~
    2. 找工作很受用的一段程序 5/2960 嵌入式系统 2010-03-27
      程序清单 6  V0.5版程序 void * MyMemMove(void *dst,const void *src,int count) {      void *ret=dst; #ifdef DEBUG     if (NULL==dst||NULL ==src)     {          return dst;     } #endif     while (count--)     {           *(char *)dst = *(char *)src;           dst = (char *)dst + 1;           src = (char *)src + 1;      }      return ret; }     如果在调试时我们加入“#define DEBUG”语句,增强程序的健壮性,那么在调试通过后我们再改为“#undef DEBUG”语句,提高程序的性能。事实上在标准库里已经存在类似功能的宏:assert,而且更加好用,它还可以在定义DEBUG时指出代码在那一行检查失败,而在没有定义DEBUG时完全可以把它当作不存在。assert(_Expression)的使用非常简单,当_Expression为0时,调试器就可以出现一个调试错误,有了这个好东西代码就容易多了。 程序清单 7  V0.6版程序 void * MyMemMove(void *dst,const void *src,int count) {     assert(dst);     assert(src);     void *ret=dst;     while (count--)     {         *(char *)dst = *(char *)src;         dst = (char *)dst + 1;         src = (char *)src + 1;      }      return ret; }     一旦调用者的两个指针参数其中一个为零,就会出现如图1所示的错误,而且指示了哪一行非常容易查错。                                      图 1  assert(NULL)时,显示错误     到目前为止,在语言层面上,我们的程序基本上没有什么问题了,那么是否真的就没有问题了呢?这就要求程序员从逻辑上考虑了,这也是优秀程序员必须具备的素质,那就是思维的严谨性,否则程序就会有非常隐藏的bug,就这个例子来说,如果用户用下面的代码来调用你的程序。 程序清单 8  重叠的内存测试 void Test() {     char p [256]= "hello,world!";     MyMemMove(p+1,p,strlen(p)+1);     printf("%s\n",p); }     如果你身边有电脑,你可以试一下,你会发现输出并不是我们期待的“hhello,world!”(在“hello world!”前加个h),而是“hhhhhhhhhhhhhh”,这是什么原因呢?原因出在源地址区间和目的地址区间有重叠的地方,V0.6版的程序无意之中将源地址区间的内容修改了!有些反映快的同学马上会说我从高地址开始拷贝。粗略地看,似乎能解决这个问题,虽然区间是重叠了,但是在修改以前已经拷贝了,所以不影响结果。但是仔细一想,这其实是犯了和上面一样的思维不严谨的错误,因为用户这样调用还是会出错:     MyMemMove( p, p+1, strlen(p)+1);     所以最完美的解决方案还是判断源地址和目的地址的大小,才决定到底是从高地址开始拷贝还是低地址开始拷贝,所以V0.7顺利成章地出来了。 程序清单 9  V0.7版程序 void * MyMemMove(void *dst,const void *src,int count) {      assert(dst);      assert(src);      void * ret = dst;      if (dst = ((char *)src + count)) {                   while (count--) {              *(char *)dst = *(char *)src;              dst = (char *)dst + 1;              src = (char *)src + 1;          }       }       else {                     dst = (char *)dst + count - 1;           src = (char *)src + count - 1;           while (count--) {           *(char *)dst = *(char *)src;           dst = (char *)dst - 1;           src = (char *)src - 1;        }     }     return(ret); }     经过以上7个版本的修改,我们的程序终于可以算是“工业级”了。回头再来看看前面的测试用例,就会发现那根本就算不上是测试用例,因为它只调用了最正常的一种情况,根本达不到测试的目的。有了上面的经历,测试用例也就相应地出现了,我们不妨用字符数组来模拟内存。 程序清单 10  相对全面的测试用例 void Test() {     char p1[256] = "hello,world!";     char p2[256] = {0};     MyMemMove(p2,p1,strlen(p1)+1);     printf("%s\n",p2);     MyMemMove(NULL,p1,strlen(p1)+1);     MyMemMove(p2,NULL,strlen(p1)+1);     MyMemMove(p1+1,p1,strlen(p1)+1);     printf("%s\n",p1);     MyMemMove(p1,p1+1,strlen(p1)+1);     printf("%s\n",p1); }     初写代码的时候,往往考虑的是程序正常工作的情况该怎么处理。当你有了几年经验,写了几万行代码后就会发现,处理异常部分的分支代码有时比正常的主干线代码还要多,而这也正是高质量程序和一般程序拉开差距的地方。如果把软件产品当作一台机器,那么这样一个个细小的函数和类就是零部件,只有当这些零部件质量都很高时,整个软件产品的质量才会高,不然就会像前几年的国产轿车一样,今天这个零件罢工明天那个零件休息。而作为检验这些零部件的测试用例,一定要模拟各种恶劣的环境,将零部件隐藏的缺陷暴露出来,从这意义上说,编写测试用例的程序员要比软件设计的程序员思维要更严谨才行。
    3. 找工作很受用的一段程序 5/2960 嵌入式系统 2010-03-27
      //以后是原文,希望对大家有所帮助。 编者按:我们知道,优秀的运动员除了自身的天赋和努力之外,出色的教练必不可少。一个成功的企业除了拥有出类拔萃的员工之外,同样需要一位出色的教练,那就是企业的CEO。由此可见,如果我们要想成为一位优秀的程序员,毫无疑问卓越的教练是致关重要的。无数事实告诉我们,成功者之所以成功,是因为成功地选择导师的缘故。     周立功公司之所以在一定程度上取得了一些成功,绝对不是运气所为,除了不断努力选拔优秀人才之外,且不惜代价投入人力和资本培训员工,更重要的是有效的方法,从而保证了初学者的投入与产出的最佳效果,让具备一定潜质的应届大学生脱颖而出。     优秀与平庸全在一念之间,关键在于你的首次择业而非就业,良好的习惯与平和的心态跟人们的第一份工作和第一位导师有很大的关系。当下的利益固然重要,但从某种程度上来看,机会、环境、远景比眼前利益更重要,因为机会、环境和远景等因素会最大限度地将你锻造成为一个在未来有绝对竞争力的人才。同样是赚钱,你是否参与了公司由默默无闻迈向卓越的过程?你是否收获了更多的快乐?你是否找到了前所未有的成就感?而很多人仅仅赚到了一些钱,幸福而不快乐。     你将希望成为哪一类人,何去何从?最初的选择尤其重要。     本文是我们训练程序员的系列文章之一,仅供参考!       这几年在全国巡回招聘应届毕业生的过程中,经常会遇到这样的现象:有些同学对自己的笔试比较满意,可是最后却得不到面试的机会,心里大为不解,颇有“死不瞑目”的味道。那么问题到底出现在哪里呢?让我们来看一个例子,这是我们招聘过程中一道常见的题目。       写一个函数,完成内存移动,并为其写一个简单的测试用例来进行测试。       够简单的吧?有的同学很快就写出了答案,详见程序清单1与程序清单2。          程序清单 1   V0.1版程序 void MyMemMove(char *dst,char *src,int count) {     while(count--)     {         *dst++ = *src++;     } } 程序清单 2   测试用例 void Test() {     char p1[256] = ”hello,world!”;     char p2[256] = {0};     MyMemMove(p2,p1,strlen(p1));     printf(“%s”,p2); }     客观地讲,相比那些交白卷或者函数声明都不会写的同学来说,能够写出这段代码的同学已经非常不错了,至少在C语言这门课程上已经达到了现行高校的教育目标,但是离企业的用人要求还有一定的距离。我们不妨将上面的程序称为V0.1版本,看看还有没有什么地方可以改进。     首先我们看看函数声明是否合理,V0.1版的程序将源地址和目的地址都用char *来表示,这样当然也没有什么问题,但是让其他人使用起来却很不方便,假如现在要将count个连续的结构体对象移动到另外一个地方去,如果要使用v0.1的程序的话,正确的写法如下:      MyMemMove((char *)dst,(char *)src,sizeof(TheStruct)*count)     也就是说我们需要将结构体指针强制转换成char * 才能够正常工作,这样除了字符串以外其它的类型都不可避免地要进行指针强制转换,否则编译器就会呱呱叫,比如在VC++2008下就会出现这样的错误:     error C2664: 'MyMemMove' : cannot convert parameter 1 from 'TheStruct *' to 'char *'     那么如何解决这个问题呢?其实很简单,我们知道有一种特别的指针,任何类型的指针都可以对它赋值,那就是void *,所以应该将源地址和目的地址都用void*来表示。当然函数体的内容也要作相应的改变,这样我们就得到了V0.2版的程序。 程序清单 3   V0.2版程序 void MyMemMove(void *dst,void *src,int count) {      while (count--)      {         *(char *)dst = *(char *)src;         dst = (char *)dst + 1;         src = (char *)src + 1;       } }     有的同学可能会问,这里面不是还有指针强制转换吗?只不过是换了地方。没错,强制指针转换确实是从使用者的代码转移到了库的代码里,但我们可以将MyMemMove理解为库,而将Test理解为使用者,事实上通过调整之后的效果却有天壤之别,V0.1是一逸永劳,而V0.2是一劳永逸!     还有几个细节需要注意,为了实现链式表达式,我们应该将返回值也改为void *。此外,如果我们不小心将“*(char *)dst = *(char *)src;”写反了,写成“*(char *)src = *(char *)dst;”编译照样通过,而为了找出这个错误又得花费不少时间。注意到src所指向的内容在这个函数内不应该被改变,所有对src所指的内容赋值都应该被禁止,所以这个参数应该用const修饰,如果有类似的错误在编译时就能够被发现:     error C3892: 'src' : you cannot assign to a variable that is const     作为程序员犯错误在所难免,但是我们可以利用相对难犯错误的机器,也就是编译器来降低犯错误的概率,这样我们就得到了V0.3版的程序。 程序清单 4  V0.3版程序 void * MyMemMove(void *dst,const void *src,int count) {     void *ret=dst;     while (count--)     {         *(char *)dst = *(char *)src;         dst = (char *)dst + 1;         src = (char *)src + 1;      }      return ret; }     现在再来考虑这样一种情况,有使用者这样调用库:MyMemMove(NULL,src, count),这是完全可能的,因为一般来说这些地址都是程序计算出来的,那就难免会算错,出现零地址或者其它的非法地址也不足为奇。可以预料的是,如果出现这种情况的话,则程序马上就会down掉,更糟糕的是你不知道错误出在哪里,于是不得不投入大量的精力在浩瀚的代码中寻找bug。解决这类问题的通用办法是对输入参数作合法性检查,也就是V0.4版程序。 程序清单 5  V0.4版程序 void * MyMemMove(void *dst,const void *src,int count) {     void *ret=dst;     if (NULL==dst||NULL ==src)     {         return dst;     }     while (count--)     {         *(char *)dst = *(char *)src;         dst = (char *)dst + 1;         src = (char *)src + 1;      }      return ret; }     上面之所以写成“if (NULL==dst||NULL ==src)”而不是写成“if (dst == NULL || src == NULL)”,也是为了降低犯错误的概率。我们知道,在C语言里面“==”和“=”都是合法的运算符,如果我们不小心写成了“if (dst = NULL || src = NULL)”还是可以编译通过,而意思却完全不一样了,但是如果写成“if (NULL=dst||NULL =src)”,则编译的时候就通不过了,所以我们要养成良好的程序设计习惯:常量与变量作条件判断时应该把常量写在前面。     V0.4版的代码首先对参数进行合法性检查,如果不合法就直接返回,这样虽然程序dwon掉的可能性降低了,但是性能却大打折扣了,因为每次调用都会进行一次判断,特别是频繁的调用和性能要求比较高的场合,它在性能上的损失就不可小觑。     如果通过长期的严格测试,能够保证使用者不会使用零地址作为参数调用MyMemMove函数,则希望有简单的方法关掉参数合法性检查。我们知道宏就有这种开关的作用,所以V0.5版程序也就出来了。
    4. MSP430常见问题与解答 7/5750 微控制器 MCU 2010-03-19
      15-问:在何处可以找到 BSDL 文件来构建 JTAG 链? 答: 所有 MSP430 均具有仅用于程序开发与快闪编程的 JTAG 接口。但这个 JTAG 接口并不 完全与 IEEE 1149.1 兼容。例如,任何 MSP430 均没有边界扫描单元 (Boundary Scan Cell)。我们仅支持所需的命令 BYPASS,但不支持其它所需的命令:EXTEST 与 SAMPLE/PRELOAD。 结论: 任何 MSP430 器件都没有 BSDL 文件。 您不能 将 MSP430 与其它器件一起放入 JTAG 链中。 16-问:在除 32.768kHz 以外的其它晶振频率下运行 MSP430   答: MSP430x3xx 器件经过专门设计,可以使用 32kHz 钟表晶振,然后从独立、内部数字控制振荡器 (DCO) 生成内部高速主时钟 (MCLK)。MCLK 通过使用内部锁频环 (FLL) 电路,可以根据用户设定的值在 MSP430x3xx 器件中自动趋于稳定。 MSP430x1xx 与 MSP430x4xx 器件具有一个可接受 32kHz 或高速晶振的晶体振荡器。某些MSP430x1xx 与 MSP430x4xx 另外还有一个仅可接受高速晶振的晶体振荡器。这可以同时连接一个或两个晶振,并且每个晶振仅在必要时使用。 MSP430x1xx 与 MSP430x4xx 器件还具有可产生高速时钟(与任何晶振无关)的可编程内部 DCO。在 MSP430x4xx 器件中,FLL 还可根据类似于 MSP430x3xx 器件的许多外部 32kHz 晶振使 DCO 趋于稳定。如欲了解不同时钟电路与器件的具体特性及功能,敬请参阅数据表及用户指南。 17-问:如何处理未使用的 I/O 引脚?   答: 导致耗流量高于预期值的一个问题是打开输入。为了防止打开输入,请对未使用的 I/O 引脚使用以下解决方案之一: 将未使用的 I/O 切换到输出模式 将未使用的输入连接到 VCC 或 VSS 通过电阻器将未使用的输入连接到 VCC 或 VSS 提示: 将未使用的引脚 Test/Vpp 连接到 VSS (GND) 是一种很好的设计实践。如果将引脚 Test/Vpp 路由到 JTAG 连接器以进行调试,则外部下拉电阻器将提高 EMI/EMC 性能。 18-问:系统内快闪编程或用作EEPROM   答: MSP430 能够对闪存内任何位置、系统内任何单个位、字节或字进行编程。即使从快闪执行代码,并且即使程序正从已编程的数据段中执行代码,快闪仍可进行系统内编程。在编程之前不必擦除数据段,但 1s 只能通过编程转换成 0s。在完整的数据段上执行擦除操作,并且将所有数据段中的 bits 擦除为 1s。在从快闪执行代码时,可以进行系统内闪存编程或擦除,在执行操作的过程中,程序计数器将在器件数据表中指定的持续时间内自动停止。或者,也可以将程序计数器移到 RAM 中,并在快闪进行系统内编程或擦除期间执行应用程序 - 在这种情况下,代码将继续从 RAM 中全速执行。信息存储器与主内存闪存区域均可用于存储数据或代码,或者同时存储这两者。唯一的区别在于:信息内存由 128 字节的较小数据段组成,而主内存则由 512 字节的数据段组成。尽管器件数据表中规定了限制 Vcc 的最小值,但不需要较高的电压来对快闪进行编程。如欲了解有关 MSP430 闪存的更多信息,敬请参阅用户指南中有关快闪的章节、web 上的应用报告以及特定器件的数据表。 19-问:使 MSP430的基本时钟模块中的DCO保持稳定 答: 通过补偿电压、温度方面的变化以及部件之间的差异,可以对 DCO 频率进行校准并将其设定为指定的频率。通常,低速晶振或外部信号可以通过比较一个低速参考频率周期内出现高速 DCO 时钟周期的次数来实现这一点。借助软件,可以调整基本时钟控制寄存器,以便将DCO 的频率设置为较慢的晶振或信号的所需倍数。该器件的数据表详细介绍了 DCO 的工作范围。《MSP430x1xx 用户指南》提供了有关基本时钟的详细信息。 通过 MSP430 网站可以获得证明DCO设置的范例代码及应用报告。 20-问: MSP430:使用 MSP430 串行编程适配器 MSP-PRGS430 时可能遇到的问题   答: 如欲获得解决使用 MSP-PRGS430 时所出现问题的完整列表,请参阅最新版的“MSP430 系列串行编程适配器手册”,TI 资料号 SLAU048。此外还需安装最新版本的 PC 用户界面软件。该软件可以从 MSP430 网站www.ti.com/msp430 中的“工具更新”上下载。该工具经过了所有 MSP430 OTP 与快闪器件的广泛测试。 21-问:使用 MSP430 快闪仿真工具 (FET) 可能出现的问题 答: 如欲了解解决使用 MSP430 FET 所遇到问题的完整解决方案列表,敬请参阅光盘版的《FET 用户指南》。该指南也会随 FET 软件一起安装。请参阅《FET 用户指南》中的附录“常见问题解答”。请确保安装了最新版的 FET 软件。该软件可以从www.ti.com/MSP430上的“设计资源” ->“开发工具”处下载。更新该软件的同时也会更新《FET 用户指南》 22-问: MSP430:所有MSP430 运算代码的列表(记忆方法)   答: 我们不提供所有运算代码的列表,因为其存在许多可用的寻址模式。但是,根据指令与寻址模式,我们为组成各种运算代码的单个位提供了说明。 《MSP430xxxx 系列用户指南》在“RISC 16 位 CPU”一章中提供了适用于指令集的所有信息。“寻址模式”一节对“As”以及“Ad”位进行了解释。 在“指令集”一节中,您可以了解指令如何从位生成 HEX 表达式: 运算代码 S-Reg (0b0000 = R0, 0b0001 = R1 ... 0b1111 = R15) D-Reg (0b0000 = R0, 0b0001 = R1 ... 0b1111 = R15) Ad As B/W “指令集说明”一节包含了核心指令映射。 “指令周期与长度”部分概括了指令所使用的时钟周期数。 23-问: MSP430:哪种晶振可与 MSP430 一起使用?   答: 32.768kHz 晶振与 MSP430 一起使用时需要遵循的重要规格是: 负载电容(请参阅数据表中的具体说明) 注:有效负载电容 晶振制造商通常会在晶振的数据表中定义有效负载电容。从电子学角度来说,电容器以串行方式连接到引脚XIN 与XOUT上,这时有效负载电容为: C(eff) = {C(XIN) ? C(XOUT)}/{C(XIN) + C(XOUT)} 因此,晶振的数据表中规定12pF的有效负载电容要求在每个引脚XIN 与 XOUT上具有22pF(2 * 12pF = 24pF = 22pF + 2pF 寄生电容)。 MSP430x1xx 与 MSP430x3xx 系列为32kHz振荡器提供了约12pF的固定集成负载电容器,并且无需任何其它外部负载电容器即可支持需要6pF有效负载电容的晶振。高频率 XTAL 振荡器无内置负载电容器。 MSP430x4xx 系列为低频率与高频率模式下的LFXT1 振荡器提供了软件可选的集成负载电容器。该器件数据表中提供了可选值。XT2 振荡器没有任何内置负载电容器。 ESR 为了确保振荡器操作稳定,MSP430x1xx 与MSP430x3xx 系列均需要ESR < 50kOhm的32kHz晶振。MSP430x4xx 系列的低功耗振荡器需要 ESR < 100kOhm的 32kHz 晶振。 高频率晶振的建议 ESR 值是 > “第三方”,然后单击“第三方工具” 2-通过引导加载程序:    TI 建议您使用第三方网页上列出的工具, 例如来自Elprotronic的快速BSL编程器、 Gessler Electronic GmbH. 以及来自Softbaugh的MSP430 Flash Bootloader 继续访问 取消访问http://www.MSP430.com/ - 单击“设计资源”>>“第三方”,然后单击“第三方工具”   两种不同编程方法的特性: 1-通过JTAG:   您可以烧断保险丝。   MSP-PRGS430、MSP-GANG430和 第三方群组编程器均支持烧断保险丝的功能。但MSP-FETP430IF不支持!   不可能通过保险丝已烧断的 JTAG 来进行任何 JTAG 访问或对 器件重新编程。 2-通过引导加载程序:   不可能烧断保险丝。   您可以对保险丝已烧断的器件快闪进行读取、擦除及重新编程。 “读取”功能受密码保护。 该密码是中断向量表的目录。 何时使用何种工具: 1-MSP430 快闪仿真工具接口板 MSP-FETP430IF:   适用于程序开发。   可与 IAR 嵌入式工作台开发工具配合使用。   是所有快速入门快闪仿真工具的一部分。   无法烧断保险丝。 2-TI 串行编程适配器 MSP-PRGS430:   适用于生产。   用于MS Windows的编程器类用户界面。   MS-Windows DLL,可轻松实施到其它软件系统中   将文件的内容写入MSP430 快闪中。   读取 MSP430 快闪的内容并将其存储到文件中。   可以烧断保险丝。   无法写入保险丝已烧断器件的快闪中。 3-Gessler 的“MSP430 FLASH 编程套件”、来自 Elprotronic 的快速 BSL 编程器以及来自 Softbaugh 的、支持引导加载程序的“MSP430 闪存引导加载程序”:   用于软件现场升级。   用于 MS Windows 的编程器类用户界面。   MS-Windows DLL,可轻松实施到其它软件系统中   将文件的内容写入 MSP430 闪存中。   读取MSP430快闪的内容并将其存储到文件中。   无法烧断保险丝。   可以写入保险丝已烧断器件的快闪中。 该功能受密码保护。 您所需的密码是中断向量表的目录。 4-群组编程器MSP-GANG430:   适用于生产。   用于MS Windows的编程器类用户界面。   MS-Windows DLL,可轻松实施到其它软件系统中   将文件的内容写入MSP430快闪中。   读取该内容 25-问:处理多个同时发生的外部中断   答: 是的,只要确定了最低要求的中断事件脉宽,MSP430 就永远不会丢失中断。即使已经接受了中断请求并为其提供了服务,也应保留这些多个源中断的标记,因此,每个得到服务的标记都必须在其相应的中断服务例程内重新进行设定。这会导致 CPU 识别出其余的暂挂中断。 26-问: MSP430:电流高于期望值!   答: 导致耗流量高于预期值的一个问题是未使用的输入。为了避免这一问题,所有未使用的 I/O引脚都必须保留打开状态,并切换到端口功能,保持与输出配置相同的方向。器件用户指南的系统复位、中断与操作模式一章的连接未使用引脚一节中列出了所有未使用引脚的正确终止。 提示: 将未使用的 Test/Vpp 引脚连接到 Vss (GND) 是一种很好的设计实践。如果需要将此引脚路由到JTAG 连接器以进行调试,则外部下拉电阻器将提高 EMI/EMC 性能。
    5. 嵌入式软件测试的10大秘诀 2/2151 嵌入式系统 2010-03-19
      6.以退为进    猎人为了不使自己在森林里迷路,他常常会在树木上流下一些标记,以备自己将来有一天迷路时可以根据这些标记找到出路。对过去代码的修改进行跟踪记录对将来出现问题之后的调试很有帮助。假如有一天,你最近一次修改的程序跑了很久之后忽然死掉了,那么你这时的第一反映就是我到底改动了些什么呢,因为上次修改之前是好的。那么如何检测这次相对于上次的修改呢?没错,代码控制系统SCS或称版本控制系统VCS(Concurrent Version Control,CVS是VCS的演化版本)。将上个版本check in下来后和当前测试版本比较。比较的工具可以是SCS/VCS/CVS自带的diff工具或其它功能更强的比较工具,比如BeyondCompare和ExamDiff。通过比较,记录所有改动的代码,分析所有可能导致问题的可疑代码。 7.确定测试的完整性    你怎么知道你的测试有多全面呢?覆盖测试(coverage testing)可以回答这个问题。覆盖测试工具可以告诉你CPU到底执行了那些代码。好的覆盖工具通常可以告诉你大概20%到40%代码没有问题,而其余的可能存在bug。覆盖工具有不同的测试级别,用户可以根据自己的需要选择某个级别。即使你很确信你的单元测试已经很全面并且没有dead code,覆盖工具还是可以为你指出一些潜在的问题,看下面的代码: if (i >= 0 && (almostAlwaysZero == 0 || (last = i))) 如果almostAlwaysZero为非0,那么last=i赋值语句就被跳过,这可能不是你所期望的。这种问题通过覆盖工具的条件测试功能可以轻松的被发现。    总之,覆盖测试对于提高代码质量很有帮助。 8.提高代码质量意味着节省时间    有研究表明软件开发的时间超过80%被用在下面几个方面: .调试自己的代码(单元测试) .调试自己和其他相关的代码(模块间测试) .调试整个系统(系统测试) 更糟糕的是你可能需要花费10-200倍的时间来找一个bug,而这个bug在开始的时候可能很容易就能找到。一个小bug可能让你付出巨大的代价,即使这个bug对整个系统的性能没有太大的影响,但很可能会影响让那些你可以看得到的部分。所以我们必须要养成良好的编码和测试手段以求更高的代码质量,以便缩短调试的代码。 9.发现它,分析它,解决它    这世界没有万能的膏药。profile再强大也有力不从心的时候;内存监视器再好,也有无法发现的时候;覆盖工具再好用,也有不能覆盖的地方。一些隐藏很深的问题即使用尽所有工具也有可能无法查到其根源,这时我们能做的就是通过这些问题所表现出来的外在现象或一些数据输出来发现其中的规律或异常。一旦发现任何异常,一定要深入地理解并回溯其根源,直到解决为止。 10.利用初学者的思维    有人这样说过:“有些事情在初学者的脑子里可能有各种各样的情况,可在专家的头脑里可能就很单一”。有时候,有些简单的问题会被想的很复杂,有些简单的系统别设计的很复杂,就是由于你的“专家思维”。当你被问题难住时,关掉电脑,出去走走,把你的问题和你的朋友甚至你的小狗说说,或许他们可以给你意想不到的启发。            总结:嵌入式调试也是一门艺术。就想其它的艺术一样,如果你想取得成功,你必须具备智慧、经验并懂得使用工具。只要我们能够很好地领悟Oracle这十条秘诀,我相信我们在嵌入式测试方面就能够取得成功。
    6. 4本嵌入式电子书:ARM入门文章集锦等 253/74917 ARM技术 2009-12-16
      好资料,谢谢分享
    7. 免费了,只要回帖就行 185/36638 模拟电子 2009-06-12
      谢谢楼主分享
    8. 华为硬件工程师手册目前最全版本 271/81942 FPGA/CPLD 2009-01-07
      hehe ,看看
    9. 推荐:好教程.ADS1.2步步学.... 110/37383 嵌入式系统 2008-12-17
      不错啊,谢谢分享~~~~~~~~~
    10. 嵌入式 清华大学 Arm 培训教材 651/532708 单片机 2008-12-17
      UP  UP  UP
    11. arm学习报告一二三 非常经典!! 139/49227 单片机 2008-12-17
      好东西哦,谢谢分享
    12. 顶! 谢谢了!
    13. C51源程序集锦 13/7951 51单片机 2008-02-20
      我解压成功了,密码是:www.ec66.com
    14. 5款ALTERA FPGA开发板原理图合集 571/209993 FPGA/CPLD 2008-02-20
      谢谢楼主了
    15. 常用元件选择表 192/52940 PCB设计 2008-02-20
      :) 谢谢楼主了,真的很不错啊 !!

最近访客

< 1/1 >

统计信息

已有117人来访过

  • 芯积分:--
  • 好友:--
  • 主题:24
  • 回复:15

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言