c语言嵌入式编程注意事项.docx
《c语言嵌入式编程注意事项.docx》由会员分享,可在线阅读,更多相关《c语言嵌入式编程注意事项.docx(39页珍藏版)》请在咨信网上搜索。
1、C语言嵌入式系统编程考前须知之背景篇本文的讨论主要围绕以通用处理港为中心的协议处理模块进行,因为它更多地牵 涉到具体的C语言编程技巧不同于一般形式的软件编程,嵌入式系统编程建立在特定的硬件平台上,势 必要求其编程语言具备较强的硬件直接操作能力。无疑,汇编语言具备这样的特 质。但是,归因于汇编语言开发过程的复杂性,它并不是嵌入式系统开发的一般 选择。而与之相比,c语言一一种高级的低级语言,那么成为嵌入式系统开发的 最正确选择。笔者在嵌入式系统工程的开发过程中,一次又一次感受到C语言的精 妙,沉醉于c语言给嵌入式开发带来的便利。图1给出了本文的讨论所基于的硬件平台,实际上,这也是大多数嵌入式系 统
2、的硬件平台。它包括两局部:(1)以通用处理器为中心的协议处理模块,用于网络控制协议的处理;(2)以数字信号处理器(DSP)为中心的信号处理模块,用于调制、解调 和数/模信号转换。本文的讨论主要围绕以通用处理器为中心的协议处理模块进行,因为它更多 地牵涉到具体的C语言编程技巧。而DSP编程那么重点关注具体的数字信号处理算 法,主要涉及通信领域的知识,不是本文的讨论重点。着眼于讨论普遍的嵌入式系统C编程技巧,系统的协议处理模块没有选择特 别的CPU,而是选择了众所周知的CPU芯片一80186,每一位学习过微机原理 的读者都应该对此芯片有一个基本的认识,且对其指令集比拟熟悉。80186的字 长是16
3、位,可以寻址到的内存空间为1MB,只有实地址模式。C语言编译生成的 指针为32位(双字),高16位为段地址,低16位为段内编译,一段最多64KB。协议处理模块中的FLASH和RAM儿乎是每个嵌入式系统的必备设备,前者用 于存储程序,后者那么是程序运行时指令及数据的存放位置。系统所选择的FLASH 和RAM的位宽都为16位,与CPU一致。实时钟芯片可以为系统定时,给出当前的年、月、日及具体时间(小时、分、从宏观上给出了一个嵌入式系统软件所包含的主要元素。请记住:软件结构是软件的灵魂!结构混乱的程序面目可憎,调试、测试、 维护、升级都极度困难。C语言嵌入式系统编程考前须知之内存操作在嵌入式系统的编
4、程中,常常要求在特定的内存单元读写内容,汇编有对应的 MOV指令,而除C/C+以外的其它编程语言基本没有直接访问绝对地址的能力数据指针在嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应 的MOV指令,而除C/C+以外的其它编程语言基本没有直接访问绝对地址的能力。 在嵌入式系统的实际调试中,多借助C语言指针所具有的对绝对地址单元内容的 读写能力。以指针直接操作内存多发生在如下儿种情况:(1)某I/O芯片被定位在CPU的存储空间而非I/O空间,而且寄存器对应于 某特定地址;(2)两个CPU之间以双端口 RAM通信,CPU需要在双端口 RAM的特定单元(称 为mail box)书写内
5、容以在对方CPU产生中断;(3)读取在ROM或FLASH的特定单元所烧录的汉字和英文字模。譬如:unsigned char *p = (unsigned char *)0xF000FF00;*p=ll;以上程序的意义为在绝对地址OxFOOOO+OxFFOO (80186使用16位段地址和 16位偏移地址)写入11。在使用绝对地址指针时,要注意指针自增自减操作的结果取决于指针指向的 数据类别。上例中p+后的结果是p二OxFOOOFFOl,假设p指向int,即:int *p = (int *)OxFOOOFFOO;p+(或+p)的结果等同于:p=p+sizeof(int),而p-(或-p)的结果是
6、p二 p-sizeof(int)。同理,假设执行:long int *p = (long int *)OxFOOOFFOO;那么p+(或+p)的结果等同于:p = p+sizeof (long int),而p-(或-p)的结 果是 p = p-sizeof (long int) o记住:CPU以字节为单位编址,而C语言指针以指向的数据类型长度作自增 和自减。理解这一点对于以指针直接操作内存是相当重要的。函数指针首先要理解以下三个问题:(1) C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因 此函数名可以直接赋给指向函数的指针;(2)调用函数实际上等同于调转指令+参数传递处理+回归位
7、置入栈, 本质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的PC寄存器;(3)因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可 以调用一个根本就不存在的函数实体,晕?请往下看:请拿出你可以获得的任何一本大学微型计算机原理教材,书中讲到,186 CPU启动后跳转至绝对地址OxFFFFO (对应C语言指针是OxFOOOFFFO, Oxl-OOO 为段地址,OxFFFO为段内偏移)执行,请看下面的代码:typedef void (*lp) ( ) ; /*定义一个无参数、无返回类型的*/*函数指针类型*/Ip IpReset = (Ip)OxFOOOFFFO; /* 定义一
8、个函数指针,指向*/* CPU启动后所执行第,条指令的位置*/IpReset (); /* 调用函数 */在以上的程序中,我们根本没有看到任何一个函数实体,但是我们却执行了 这样的函数调用:IpReset (),它实际上起到了软重启的作用,跳转到CPU启 动后第一条要执行的指令的位置。记住:函数无它,唯指令集合耳;你可以调用一个没有函数体的函数,本质 上只是换一个地址开始执行指令!数组vs.动态申请在嵌入式系统中动态内存申请存在比一般系统编程时更严格的要求,这是因 为嵌入式系统的内存空间往往是十分有限的,不经意的内存泄露会很快导致系统 的崩溃。所以一定要保证你的malloc和free成对出现,
9、如果你写出这样的一段程序:char * (void)(char *p;p = (char *)malloc(,);if(p二二NULL) f/* 一系列针对p的操作*/return p;在某处调用0,用完中动态申请的内存后将其free,如下:上述代码明显是不合理的,因为违反了 mail。和free成对出现的原那么,即 谁申请,就由谁释放原那么。不满足这个原那么,会导致代码的耦合度增大,因为用户在调用函数时需要知道其内部细节!正确的做法是在调用处申请内存,并传入函数,如下:char *p=malloc (,); if(p=NULL) (p); free(p);p=NULL;而函数那么接收参数p,
10、如下:void (char *p)(/* 一系列针对p的操作*/基本上,动态申请内存方式可以用较大的数组替换。对于编程新手,笔者推 荐你尽量采用数组!嵌入式系统可以以博大的胸襟接收瑕疵,而无法海纳错误。 毕竟,以最笨的方式苦练神功的郭靖胜过机智聪明却范政治错误走反革命道路的 杨康。给出原那么:(1)尽可能的选用数组,数组不能越界访问(真理越过一步就是谬误,数 组越过界限就光荣地成全了一个混乱的嵌入式系统);(2)如果使用动态申请,那么申请后一定要判断是否申请成功了,并且malloc 和free应成对出现!在嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应的 MOV指令,而除C/
11、C+以外的其它编程语言基本没有直接访问绝对地址的能力关键字constconst意味着只读。区别如下代码的功能非常重要,也是老生长叹,如果 你还不知道它们的区别,而且已经在程序界摸爬滚打多年,那只能说这是一个悲 哀:const int a; int const a; const int *a; int * const a; int const * a const;(1)关键字const的作用是为给读你代码的人传达非常有用的信息。例如, 在函数的形参前添加const关键字意味着这个参数在函数体内不会被修改,属于 输入参数。在有多个形参的时候,函数的调用者可以凭借参数前是否有const 关键字,清晰
12、的区分哪些是输入参数,哪些是可能的输出参数。(2)合理地使用关键字const可以使编译器很自然地保护那些不希望被改 变的参数,防止其被无意的代码修改,这样可以减少bug的出现。const在C+语言中那么包含了更丰富的含义,而在C语言中仅意味着:只能 读的普通变量,可以称其为不能改变的变量(这个说法似乎很拗口,但却最 准确的表达了 C语言中const的本质),在编译阶段需要的常数仍然只能以 define宏定义!故在C语言中如下程序是非法的:const int SIZE = 10;char aSIZE; /*非法:编译阶段不能用到变量*/关键字volatileC语言编译器会对用户书写的代码进行优化
13、,譬如如下代码:int a, b, c;a = inWord (Ox 100) ; /*读取I/O空间0x100端口的内容存入a变量*/ b = a;a = inWord (0x100) ; /*再次读取1/0空间0x100端口的内容存入a变 量*/c = a;很可能被编译器优化为:int a, b, c;a = inWord (Ox 100) ; /*读取I/O空间0x100端口的内容存入a变量*/ b = a;c = a;但是这样的优化结果可能导致错误,如果I/O空间0x100端口的内容在执行 第一次读操作后被其它程序写入新值,那么其实第2次读操作读出的内容与第一次 不同,b和c的值应该不
14、同。在变量a的定义前加上volatile关键字可以防止 编译器的类似优化,正确的做法是:volatile int a;volatile变量可能用于如下几种情况:(1)并行设备的硬件寄存器(如:状态寄存器,例中的代码属于此类);(2) 一个中断服务子程序中会访问到的非自动变量(也就是全局变量);(3)多线程应用中被几个任务共享的变量。CPU字长与存储器位宽不一致处理在背景篇中提到,本文特意选择了一个与CPU字长不一致的存储芯片,就是 为了进行本节的诗论,解决CPU字长与存储器位宽不一致的情况。80186的字长 为16,而NVRAM的位宽为8,在这种情况下,我们需要为NVRAM提供读写字节、 字的
15、接口,如下:typedef unsigned char BYTE;typedef unsigned int WORD;/*函数功能:读NVRAM中字节* 参数:wOffset,读取位置相对NVRAM基地址的偏移* 返回:读取到的字节值* /extern BYTE ReadByteNVRAM(WORD wOffset)(LPBYTE IpAddr = (BYTE*) (NVRAM + wOffset * 2); /* 为什么偏移 要 X2? */return *IpAddr;/*函数功能:读NVRAM中字*参数:wOffset,读取位置相对NVRAM基地址的偏移*返回:读取到的字*/extern
16、 WORD ReadWordNVRAM(WORD wOffset) (WORD wTmp = 0;LPBYTE IpAddr;/*读取高位字节*/IpAddr = (BYTE*) (NVRAM + wOffset * 2); /* 为什么偏移要 X 2? */wTmp += (*lpAddr)*256;/*读取低位字节*/IpAddr = (BYTE*) (NVRAM + (wOffset +1) * 2); /* 为什么偏移要X2? */wTmp += *IpAddr;return wTmp;/*函数功能:向NVRAM中写一个字节*参数:wOffset,写入位置相对NVRAM基地址的偏移*
17、byData,欲写入的字节*/extern void WriteByteNVRAM(WORD wOffset, BYTE byData)/*函数功能:向NVRAM中写一个字*/*参数:wOffset,写入位置相对NVRAM基地址的偏移* wData,欲写入的字*/extern void WriteWordNVRAM(WORD wOffset, WORD wData)子贡问日:Why偏移要乘以2?子日:请看图1, 16位80186与8位NVRAM之间互连只能以地址线Al对其AO, CPU本身的AO与NVRAM不连接。因此,NVRAM的地址只能是偶数地址,故每 次以0x10为单位前进!子贡再问:S
18、o why 80186的地址线A0不与NVRAM的A0连接?子日:请看IT论语之微机原理篇,那里面讲述了关于计算机组成 的圣人之道。总结本篇主要讲述了嵌入式系统C编程中内存操作的相关技巧。掌握并深入理解 关于数据指针、函数指针、动态申请内存、const及volatile关键字等的相关 知识,是一个优秀的C语言程序设计师的基本要求。当我们已经牢固掌握了上述 技巧后,我们就已经学会了 C语言的99%,因为C语言最精华的内涵皆在内存操 作中表达。我们之所以在嵌入式系统中使用C语言进行程序设计,99%是因为其强大的 内存操作能力!如果你爱编程,请你爱C语言;如果你爱C语言,请你爱指针;如果你爱指针,请
19、你爱指针的指针!C语言嵌入式系统编程考前须知之屏幕操作现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库,往往只 是需要提供数量有限的汉字供必要的显示功能汉字处理现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库,往 往只是需要提供数量有限的汉字供必要的显示功能。例如,一个微波炉的LCD 上没有必要提供显示电子邮件的功能;一个提供汉字显示功能的空调的LCD 上不需要显示一条短消息,诸如此类。但是一部手机、小灵通那么通常需要包括较完整的汉字库。如果包括的汉字库较完整,那么,由内码计算出汉字字模在库中的偏移是十 分简单的:汉字库是按照区位的顺序排列的,前一个字节为该汉字的区
20、号,后一 个字节为该字的位号。每一个区记录94个汉字,位号那么为该字在该区中的位置。 因此,汉字在汉字库中的具体位置计算公式为:94*(区号-1)+位号-1。减1是因 为数组是以0为开始而区号位号是以1为开始的。只需乘上一个汉字字模占用的 字节数即可,即:(94*(区号-1)+位号-1)*一个汉字字模占用字节数,以16*16 点阵字库为例,计算公式那么为:(94*(区号-1) +(位号-1)*32。汉字库中从该位 置起的32字节信息记录了该字的字模信息。对于包含较完整汉字库的系统而言,我们可以以上述规那么计算字模的位置。 但是如果仅仅是提供少量汉字呢?譬如几十至儿百个?最好的做法是:定义宏:#
21、 define EX FONT CHAR()# define EX_FONT_UNICODE_VAL () 0,# define EX_FONT_ANSI_VAL()(),定义结构体:typedef struct _widc_unicode_fon116x16(WORD ; /* 内码 */BYTE data 32; /* 字模点阵 */Unicode;define CHINESE_CHAR_NUM /* 汉字数量 */字模的存储用数组:Unicode ChineseCHINESE CHAR NUM二EX_FONT_CHAR (业)EX_FONT_UNICODE_VAL(0x4ela)0x04
22、, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0x44, 0x46, 0x24, 0x4c, 0x24, 0x48, 0x14, 0x50, Oxlc, 0x50, 0x14, 0x60, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, Oxff, Oxfe, 0x00, 0x00, 0x00, 0x00EX FONT_ CHAR (中)EX_FONT_UNICODE_VAL(0x4e2d)0x01, 0x00, 0x01, 0x00, 0x21, 0x08, 0x3f, Oxfc, 0x21, 0x08, 0x21, 0x08
23、, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08,0x3f, 0xf8, 0x21, 0x08, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ( EX_FONT_CHAR (云) EX_FONT_UNICODE_VAL (0x4e91) 0x00, 0x00, 0x00, 0x30, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, Oxff, Oxfe, 0x03, 0x00, 0x07, 0x00,0x06, 0x40, 0x0c, 0x20,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 嵌入式 编程 注意事项
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【二***】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【二***】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。