C语言嵌入式开发.ppt

上传人:本田雅阁 文档编号:2142794 上传时间:2019-02-21 格式:PPT 页数:34 大小:147.51KB
返回 下载 相关 举报
C语言嵌入式开发.ppt_第1页
第1页 / 共34页
C语言嵌入式开发.ppt_第2页
第2页 / 共34页
C语言嵌入式开发.ppt_第3页
第3页 / 共34页
亲,该文档总共34页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《C语言嵌入式开发.ppt》由会员分享,可在线阅读,更多相关《C语言嵌入式开发.ppt(34页珍藏版)》请在三一文库上搜索。

1、C语言嵌入式开发,纲要,嵌入式C开发背景介绍 硬件平台和交叉编译环境 软件结构设计 内存操作 屏幕操作 键盘操作 性能优化,背景,不同于一般形式的软件编程,嵌入式系统编程建立在特定的硬件平台上,势必要求其编程语言具备较强的硬件直接操作能力。无疑,汇编语言具备这样的特质。但是,由于汇编语言开发的复杂性,它并不是嵌入式系统开发的一般选择。而与之相比,C语言-一种“高级的低级“语言,则成为嵌入式系统开发的最佳选择。,硬件平台,(1) 以通用处理器为中心的协议处理模块,用于网络控制协议的处理; (2) 以数字信号处理器(DSP)为中心的信号处理模块,用于调制、解调和数/模信号转换,硬件说明,CPU:8

2、0186字长是16位,可以寻址到的内存空间为1MB FLASH和RAM几乎是每个嵌入式系统的必备设备,前者用于存储程序,后者则是程序运行时指令及数据的存放位置。系统所选择的FLASH和RAM的位宽都为16位,与CPU一致 实时钟芯片可以为系统定时,给出当前的年、月、日及具体时间(小时、分、秒及毫秒),主要作用是提供中断裁决 NVRAM(非易失去性RAM)具有掉电不丢失数据的特性,可以用于保存系统的设置信息 UART则完成CPU并行数据传输与RS-232串行数据传输的转换 键盘控制器和显示控制器则完成系统人机界面的控制,交叉编译环境,嵌入式系统需要良好的软件开发环境的支持,由于嵌入式系统的目标机

3、资源受限, 不可能在其上建立庞大、复杂的开发环境,因而其开发环境和目标运行环境相互分离。 嵌入式应用软件的开发方式一般是 在宿主机(Host)上建立开发环境, 进行应用程序编码和交叉编译,然后宿主机同目标机(Target)建立连接, 将应用程序下载到目标机上进行交叉调试,经过调试和优化, 将应用程序固化到目标机中实际运行,软件结构设计,模块划分 多任务还是单任务 单任务程序典型架构 中断服务程序 硬件驱动模块 C的面向对象化,模块划分,硬件驱动模块,一种特定硬件对应一个模块; 软件功能模块,其模块的划分应满足低偶合、高内聚的要求,硬件驱动模块,中断服务程序ISR 硬件初始化 a.修改寄存器,设

4、置硬件参数(如UART应设置其波特率,AD/DA设备应设置其采样速率等); b.将中断服务程序入口地址写入中断向量表: 3.设置CPU针对该硬件的控制线 a.如果控制线可作PIO(可编程I/O)和控制信号用,则设置CPU内部对应寄存器使其作为控制信号; b.设置CPU内部的针对该设备的中断屏蔽位,设置中断方式(电平触发还是边缘触发)。 4.提供一系列针对该设备的操作接口函数。例如,对于LCD,其驱动模块应提供绘制像素、画线、绘制矩阵、显示字符点阵等函数;而对于实时钟,其驱动模块则需提供获取时间、设置时间等函数。,多任务还是单任务,所谓“单任务系统“是指该系统不能支持多任务并发操作,宏观串行地执

5、行一个任务。而多任务系统则可以宏观并行(微观上可能串行)地“同时“执行多个任务 单任务用于简单的低端硬件平台,比如哑终端之类的,使用死循环处理任务流程 多任务用于较高端的平台,如uclinux,Win ce,Vxworks,使用中断调用处理任务流程,单任务程序典型架构,从CPU复位时的指定地址开始执行; 跳转至汇编代码startup处执行; 跳转至用户主程序main执行,在main中完成: a.初试化各硬件设备; b.初始化各软件模块; c.进入死循环(无限循环),调用各模块的处理函数,中断服务程序,中断是嵌入式系统中重要的组成部分,但是在标准C中不包含中断。许多编译开发商在标准C上增加了对中

6、断的支持,提供新的关键字用于标示中断服务程序(ISR),类似于_interrupt、#program interrupt等。当一个函数被定义为ISR的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码。,中断服务程序需要满足如下要求: (1)不能返回值; (2)不能向ISR传递参数; (3) ISR应该尽可能的短小精悍; (4) printf(char * lpFormatString,)函数会带来重入和性能问题,不能在ISR中采用。,C的面向对象化,#ifndef C_Class #define C_Class struct #endif C_Class A C_Cla

7、ss A *A_this; /* this指针 */ void (*Foo)(C_Class A *A_this); /* 行为:函数指针 */ int a; /* 数据 */ int b; ;,我们可以利用C语言模拟出面向对象的三个特性:封装、继承和多态,但是更多的时候,我们只是需要将数据与行为封装以解决软件结构混乱的问题。C模拟面向对象思想的目的不在于模拟行为本身,而在于解决某些情况下使用C语言编程时程序整体框架结构分散、数据和函数脱节的问题,内存操作篇,数据指针 函数指针 数组vs.动态申请 关键字const 关键字volatile CPU字长与存储器位宽不一致处理,数据指针,嵌入式编程

8、中需要指针直接操作内存 某I/O芯片被定位在CPU的存储空间而非I/O空间,而且寄存器对应于某特定地址; 两个CPU之间以双端口RAM通信,CPU需要在双端口RAM的特定单元(称为mail box)书写内容以在对方CPU产生中断 读取在ROM或FLASH的特定单元所烧录的汉字和英文字模。,unsigned char *p = (unsigned char *)0xF000FF00; *p=11;,函数指针,C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以直接赋给指向函数的指针; 调用函数实际上等同于“调转指令参数传递处理回归位置入栈”,本质上最核心的操作是将函数生成的目

9、标代码的首地址赋给CPU的PC寄存器; 因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以“调用“一个根本就不存在的函数实体,typedef void (*lpFunction) ( ); /* 定义一个无参数、无返回类型的 */ /* 函数指针类型 */ lpFunction lpReset = (lpFunction)0xF000FFF0; /* 定义一个函数指针,指向*/ /* CPU启动后所执行第一条指令的位置 */ lpReset(); /* 调用函数 */,数组vs.动态申请,在嵌入式系统中动态内存申请存在比一般系统编程时更严格的要求,这是因为嵌入式系统的内存空间往

10、往是十分有限的,不经意的内存泄露会很快导致系统的崩溃 所以一定要保证你的malloc和free成对出现,尽可能的选用数组,数组不能越界访问; 如果使用动态申请,则申请后一定要判断是否申请成功了,并且malloc和free应成对出现,关键字const,关键字const的作用是为给读你代码的人传达非常有用的信息。例如,在函数的形参前添加const关键字意味着这个参数在函数体内不会被修改,属于“输入参数”。在有多个形参的时候,函数的调用者可以凭借参数前是否有const关键字,清晰的辨别哪些是输入参数,哪些是可能的输出参数。 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防

11、止其被无意的代码修改,这样可以减少bug的出现。,关键字volatile,volatile变量可能用于如下几种情况 并行设备的硬件寄存器(如:状态寄存器); 一个中断服务子程序中会访问到的非自动变量(也就是全局变量); 多线程应用中被几个任务共享的变量。,int a,b,c; a = inWord(0x100); /*读取I/O空间0x100端口的内容存入a变量*/ b = a; a = inWord (0x100); /*再次读取I/O空间0x100端口的内容存入a变量*/ c = a;,int a,b,c; a = inWord(0x100); /*读取I/O空间0x100端口的内容存入a

12、变量*/ b = a; c = a;,CPU字长与存储器位宽不一致处理,,解决CPU字长与存储器位宽不一致的情况。80186的字长为16,而NVRAM的位宽为8,在这种情况下,我们需要为NVRAM提供读写字节、字的接口,屏幕操作篇,汉字处理 系统时间显示 动画显示 菜单操作,汉字处理,现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库,往往只是需要提供数量有限的汉字供必要的显示功能。 不知道日文是否有此情况 要显示特定汉字的时候,只需要从数组中查找内码与要求汉字内码相同的即可获得字模。如果前面的汉字在数组中以内码大小顺序排列,那么可以以二分查找法更高效的查找到汉字的字模,定义宏:

13、# define EX_FONT_CHAR(value) # define EX_FONT_UNICODE_VAL(value) (value), # define EX_FONT_ANSI_VAL(value) (value), 定义结构体: typedef struct _wide_unicode_font16x16 WORD value; /* 内码 */ BYTE data32; /* 字模点阵 */ Unicode; #define CHINESE_CHAR_NUM /* 汉字数量 */ 字模的存储用数组: Unicode chineseCHINESE_CHAR_NUM = EX_F

14、ONT_CHAR(“业“) EX_FONT_UNICODE_VAL(0x4e1a) 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0x44, 0x46, 0x24, 0x4c, 0x24, 0x48, 0x14, 0x50, 0x1c, 0x50, 0x14, 0x60, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 , EX_FONT_CHAR(“中“) EX_FONT_UNICODE_VAL(0x4e2d) 0x01, 0x00, 0x01, 0

15、x00, 0x21, 0x08, 0x3f, 0xfc, 0x21, 0x08, 0x21, 0x08, 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, 0xff, 0x

16、fe, 0x03, 0x00, 0x07, 0x00, 0x06, 0x40, 0x0c, 0x20, 0x18, 0x10, 0x31, 0xf8, 0x7f, 0x0c, 0x20, 0x08, 0x00, 0x00 , EX_FONT_CHAR(“件“) EX_FONT_UNICODE_VAL(0x4ef6) 0x10, 0x40, 0x1a, 0x40, 0x13, 0x40, 0x32, 0x40, 0x23, 0xfc, 0x64, 0x40, 0xa4, 0x40, 0x28, 0x40, 0x2f, 0xfe, 0x20, 0x40, 0x20, 0x40, 0x20, 0x4

17、0, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40 ,系统时间显示,注意刷新问题,没有必要每秒刷新一次分钟和小时的显示,动画显示,充分利用定时器 注意刷新问题,菜单操作,* 将菜单的属性和操作“封装“在一起 */ typedef struct tagSysMenu char *text; /* 菜单的文本 */ BYTE xPos; /* 菜单在LCD上的x坐标 */ BYTE yPos; /* 菜单在LCD上的y坐标 */ void (*onOkFun)(); /* 在该菜单上按下ok键的处理函数指针 */ void (*onCancelFun

18、)(); /* 在该菜单上按下cancel键的处理函数指针 */ SysMenu, *LPSysMenu;,利用了面向对象中的封装思想,就让程序结构清晰,其结果是几乎可以在无需修改程序的情况下在系统中添加更多的菜单,而系统的按键处理函数保持不变。,键盘操作篇,处理功能键 处理数字键 处理用户输入 处理触摸屏,性能优化篇,使用宏定义 使用寄存器变量 内嵌汇编 利用硬件特性 活用位操作,使用宏定义,在C语言中,宏是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。 宏定义“像”函数; 宏定义不是函数,因而需要括上所有“参数”; 宏定义可能产生副作用。因而

19、不要给宏定义传入有副作用的“参数“。,使用寄存器变量,当对一个变量频繁被读写时,需要反复访问内存,从而花费大量的存取时间。为此,C语言提供了一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量,而循环计数是应用寄存器变量的最好候选者。 (1) 只有局部自动变量和形参才可以定义为寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部stati

20、c变量; (2) register是一个“建议“型关键字,意指程序建议该变量放在寄存器中,但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中,但编译器中并不报错(在C+语言中有另一个“建议“型关键字:inline)。,内嵌汇编,程序中对时间要求苛刻的部分可以用内嵌汇编来重写,以带来速度上的显著提高。但是,开发和测试汇编代码是一件辛苦的工作,它将花费更长的时间,因而要慎重选择要用汇编的部分。 在程序中,存在一个80-20原则,即20%的程序消耗了80%的运行时间,因而我们要改进效率,最主要是考虑改进那20%的代码。,利用硬件特性,CPU对各种存储器的访问速度,基本上是: CP

21、U内部RAM 外部同步RAM 外部异步RAM FLASH/ROM 对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度; 对于UART等设备,其内部有一定容量的接收BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断。例如计算机终端在向目标机通过RS-232传递数据时,不宜设置UART只接收到一个BYTE就向CPU提中断,从而无谓浪费中断处理时间; 如果对某设备能采取DMA方式读取,就采用DMA读取,DMA读取方式在读取目标中包含的存

22、储信息较大时效率较高,其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式,减少了CPU 对外设的干预,进一步提高了CPU与外设的并行操作程度。,活用位操作,使用C语言的位操作可以减少除法和取模的运算。在计算机程序中数据的位是可以操作的最小数据单位,理论上可以用“位运算”来完成所有的运算和操作,因而,灵活的位操作可以有效地提高程序运行的效率。举例如下 * 方法1 */ int i,j; i = 879 / 16; j = 562 % 32; /* 方法2 */ int i,j; i = 879 4; j = 562 - (562 5 5);,嵌入式开发的核心就是利用最少的资源最高效地实现所需功能,谢谢大家!,

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

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1