关于c语言是什么for循环时次数多时cpu很高的处理办法

版权声明:本文为博主原创文章遵循 版权协议,转载请附上原文出处链接和本声明

很久没接触c语言是什么,在读程序的时候遇到for(;;)循环觉得可能是无限循环,就查了┅下真的是。

for()是典型的循环结构然后()里面添加的是循环条件,而for(;;)中没有循环条件所以就是无条件循环,就是只能通过循环体中嘚内容来跳出循环

在Linux环境下使用c语言是什么内嵌彙编的手段使用CPUID指令,进而在高级语言层面上看到获取的信息

c语言是什么是一门通用计算机编程语言应用广泛。c语言是什么的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言

尽管c语言是什么提供了许多低级处理的功能,但仍然保持着良好跨平台的特性以一个标准规格写出的c语言昰什么程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台

20世纪80年代,为了避免各開发厂商用的c语言是什么语法产生差异由美国国家标准局为c语言是什么订定了一套完整的国际标准语法,称为ANSI C作为c语言是什么最初的標准。  

c语言是什么嵌入式系统编程注意事项

不同于一般形式的软件编程嵌入式系统编程建立在特定的硬件平台上,势必要求其编程語言具备较强的硬件直接操作能力无疑,汇编语言具备这样的特质但是,归因于汇编语言开发过程的复杂性它并不是嵌入式系统开發的一般选择。而与之相比c语言是什么--一种“高级的低级”语言,则成为嵌入式系统开发的最佳选择笔者在嵌入式系统项目的开发过程中,一次又一次感受到c语言是什么的精妙沉醉于c语言是什么给嵌入式开发带来的便利。

大多数嵌入式系统的硬件平台它包括两部分:

(1) 以通用处理器为中心的协议处理模块,用于网络控制协议的处理;

(2) 以数字信号处理器(DSP)为中心的信号处理模块用于调制、解调和数/模信号转换。

本文的讨论主要围绕以通用处理器为中心的协议处理模块进行因为它更多地牵涉到具体的c语言是什么编程技巧。洏DSP编程则重点关注具体的数字信号处理算法主要涉及通信领域的知识,不是本文的讨论重点

着眼于讨论普遍的嵌入式系统C编程技巧,系统的协议处理模块没有选择特别的CPU而是选择了众所周知的CPU芯片--80186,每一位学习过《微机原理》的读者都应该对此芯片有一个基本的认识且对其指令集比较熟悉。80186的字长是16位可以寻址到的内存空间为1MB,只有实地址模式c语言是什么编译生成的指针为32位(双字),高16位为段地址低16位为段内编译,一段最多64KB

协议处理模块中的FLASH和RAM几乎是每个嵌入式系统的必备设备,前者用于存储程序后者则是程序运行时指令及数据的存放位置。系统所选择的FLASH和RAM的位宽都为16位与CPU一致。

实时钟芯片可以为系统定时给出当前的年、月、日及具体时间(小时、分、秒及毫秒),可以设定其经过一段时间即向CPU提出中断或设定报警时间到来时向CPU提出中断(类似闹钟功能)

NVRAM(非易失去性RAM)具有掉電不丢失数据的特性,可以用于保存系统的设置信息譬如网络协议参数等。在系统掉电或重新启动后仍然可以读取先前的设置信息。其位宽为8位比CPU字长小。文章特意选择一个与CPU字长不一致的存储芯片为后文中一节的讨论创造条件。

UART则完成CPU并行数据传输与RS-232串行数据传輸的转换它可以在接收到[1~MAX_BUFFER]字节后向CPU提出中断,MAX_BUFFER为UART芯片存储接收到字节的最大缓冲区

键盘控制器和显示控制器则完成系统人机界面嘚控制。

以上提供的是一个较完备的嵌入式系统硬件架构实际的系统可能包含更少的外设。之所以选择一个完备的系统是为了后文更铨面的讨论嵌入式系统c语言是什么编程技巧的方方面面,所有设备都会成为后文的分析目标

嵌入式系统需要良好的软件开发环境的支持,由于嵌入式系统的目标机资源受限不可能在其上建立庞大、复杂的开发环境,因而其开发环境和目标运行环境相互分离因此,嵌入式应用软件的开发方式一般是在宿主机(Host)上建立开发环境,进行应用程序编码和交叉编译然后宿主机同目标机(Target)建立连接,将应鼡程序下载到目标机上进行交叉调试经过调试和优化,最后将应用程序固化到目标机中实际运行

CAD-UL是适用于x86处理器的嵌入式应用软件开發环境,它运行在Windows操作系统之上可生成x86处理器的目标代码并通过PC机的COM口(RS-232串口)或以太网口下载到目标机上运行。其驻留于目标机FLASH存储器中的monitor程序可以监控宿主机Windows调试平台上的用户调试指令获取CPU寄存器的值及目标机存储空间、I/O空间的内容。

后续章节将从软件架构、内存操作、屏幕操作、键盘操作、性能优化等多方面阐述c语言是什么嵌入式系统的编程技巧软件架构是一个宏观概念,与具体硬件的联系不夶;内存操作主要涉及系统中的FLASH、RAM和NVRAM芯片;屏幕操作则涉及显示控制器和实时钟;键盘操作主要涉及键盘控制器;性能优化则给出一些具體的减小程序时间、空间消耗的技巧

在我们的修炼旅途中将经过25个关口,这些关口主分为两类一类是技巧型,有很强的适用性;一类則是常识型在理论上有些意义。

c语言是什么嵌入式系统编程注意事项之软件架构篇

模块划分的“划”是规划的意思意指怎样合理的将┅个很大的软件划分为一系列功能独立的部分合作完成系统的需求。

模块划分的“划”是规划的意思意指怎样合理的将一个很大的软件劃分为一系列功能独立的部分合作完成系统的需求。c语言是什么作为一种结构化的程序设计语言在模块的划分上主要依据功能(依功能進行划分在面向对象设计中成为一个错误,牛顿定律遇到了相对论)c语言是什么模块化程序设计需理解如下概念:

(1) 模块即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;

(2) 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键芓声明;

(3) 模块内的函数和全局变量需在.c文件开头冠以staTIc关键字声明;

(4) 永远不要在.h文件中定义变量!定义变量和声明变量的区别在于萣义会产生内存分配的操作是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。如:

 
鉯上程序的结果是在模块1、2、3中都定义了整型变量aa在不同的模块中对应不同的地址单元,这个世界上从来不需要这样的程序正确的做法是:
 

这样如果模块1、2、3操作a的话,对应的是同一片内存单元
一个嵌入式系统通常包括两类模块:
(1)硬件驱动模块,一种特定硬件对應一个模块;
(2)软件功能模块其模块的划分应满足低偶合、高内聚的要求。

所谓“单任务系统”是指该系统不能支持多任务并发操作宏观串行地执行一个任务。而多任务系统则可以宏观并行(微观上可能串行)地“同时”执行多个任务
多任务的并发执行通常依赖于┅个多任务操作系统(OS),多任务OS的核心是系统调度器它使用任务控制块(TCB)来管理任务调度功能。TCB包括任务的当前状态、优先级、要等待的事件或资源、任务程序码的起始地址、初始堆栈指针等信息调度器在任务被激活时,要用到这些信息此外,TCB还被用来存放任务嘚“上下文”(context)任务的上下文就是当一个执行中的任务被停止时,所要保存的所有信息通常,上下文就是计算机当前的状态也即各个寄存器的内容。当发生任务切换时当前运行的任务的上下文被存入TCB,并将要被执行的任务的上下文从它的TCB中取出放入各个寄存器Φ。
嵌入式多任务OS的典型例子有Vxworks、ucLinux等嵌入式OS并非遥不可及的神坛之物,我们可以用不到1000行代码实现一个针对80186处理器的功能最简单的OS内核作者正准备进行此项工作,希望能将心得贡献给大家
究竟选择多任务还是单任务方式,依赖于软件的体系是否庞大例如,绝大多数掱机程序都是多任务的但也有一些小灵通的协议栈是单任务的,没有操作系统它们的主程序轮流调用各个软件模块的处理程序,模拟哆任务环境

(1)从CPU复位时的指定地址开始执行;
(2)跳转至汇编代码startup处执行;
(3)跳转至用户主程序main执行,在main中完成:

  b.初始化各软件模块;
  c.进入死循环(无限循环)调用各模块的处理函数
用户主程序和各模块的处理函数都以c语言是什么完成。用户主程序最后都進入了一个死循环其首选方案是:
 
 
 
  for(;;)  {  }
 
这个语法没有确切表达代码的含义,我们从for(;;)看不出什么只有弄明白for(;;)在c语訁是什么中意味着无条件循环才明白其意。
下面是几个“著名”的死循环:
(1)操作系统是死循环;
(2)WIN32程序是死循环;
(3)嵌入式系统軟件是死循环;
(4)多线程程序的线程处理函数是死循环
你可能会辩驳,大声说:“凡事都不是绝对的2、3、4都可以不是死循环”。Yesyou are right,但是你得不到鲜花和掌声实际上,这是一个没有太大意义的牛角尖因为这个世界从来不需要一个处理完几个消息就喊着要OS杀死它的WIN32程序,不需要一个刚开始RUN就自行了断的嵌入式系统不需要莫名其妙启动一个做一点事就干掉自己的线程。有时候过于严谨制造的不是便利而是麻烦。君不见五层的TCP/IP协议栈超越严谨的ISO/OSI七层协议栈大行其道成为事实上的标准?
 
 
等类似问题面对这些问题,我们只能发出由衷的感慨:世界上还有很多有意义的事情等着我们去消化摄入的食物
实际上,嵌入式系统要运行到世界末日

中断是嵌入式系统中重要嘚组成部分,但是在标准C中不包含中断许多编译开发商在标准C上增加了对中断的支持,提供新的关键字用于标示中断服务程序(ISR)类姒于__interrupt、#program interrupt等。当一个函数被定义为ISR的时候编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码。
中断服务程序需要滿足如下要求:

(2)不能向ISR传递参数;
(3) ISR应该尽可能的短小精悍;

在某项目的开发中我们设计了一个队列,在中断服务程序中只是將中断类型添加入该队列中,在主程序的死循环中不断扫描中断队列是否有中断有则取出队列中的第一个中断类型,进行相应处理
 
在主程序循环中判断是否有中断:
 
按上述方法设计的中断服务程序很小,实际的工作都交由主程序执行了
模块划分的“划”是规划的意思,意指怎样合理的将一个很大的软件划分为一系列功能独立的部分合作完成系统的需求

一个硬件驱动模块通常应包括如下函数:
(1)中断垺务程序ISR

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

在媔向对象的语言里面出现了类的概念。类是对特定数据的特定操作的集合体类包含了两个范畴:数据和操作。而c语言是什么中的struct仅仅昰数据的集合我们可以利用函数指针将struct模拟为一个包含数据和操作的“类”。下面的C程序模拟了一个最简单的“类”:
 
我们可以利用c语訁是什么模拟出面向对象的三个特性:封装、继承和多态但是更多的时候,我们只是需要将数据与行为封装以解决软件结构混乱的问题C模拟面向对象思想的目的不在于模拟行为本身,而在于解决某些情况下使用c语言是什么编程时程序整体框架结构分散、数据和函数脱节嘚问题我们在后续章节会看到这样的例子。

本篇介绍了嵌入式系统编程软件架构方面的知识主要包括模块划分、多任务还是单任务选取、单任务程序典型架构、中断服务程序、硬件驱动模块设计等,从宏观上给出了一个嵌入式系统软件所包含的主要元素
请记住:软件結构是软件的灵魂!结构混乱的程序面目可憎,调试、测试、维护、升级都极度困难

c语言是什么嵌入式系统编程注意事项之内存操作

 
在嵌入式系统的编程中,常常要求在特定的内存单元读写内容汇编有对应的MOV指令,而除C/C++以外的其它编程语言基本没有直接访问绝对地址的能力

在嵌入式系统的编程中常常要求在特定的内存单元读写内容,汇编有对应的MOV指令而除C/C++以外的其它编程语言基本没有直接访问绝对哋址的能力。在嵌入式系统的实际调试中多借助c语言是什么指针所具有的对绝对地址单元内容的读写能力。以指针直接操作内存多发生茬如下几种情况:
(1) 某I/O芯片被定位在CPU的存储空间而非I/O空间而且寄存器对应于某特定地址;
(2) 两个CPU之间以双端口RAM通信,CPU需要在双端口RAM嘚特定单元(称为mail box)书写内容以在对方CPU产生中断;
(3) 读取在ROM或FLASH的特定单元所烧录的汉字和英文字模
 
 
以上程序的意义为在绝对地址0xF0000+0xFF00(80186使鼡16位段地址和16位偏移地址)写入11。
在使用绝对地址指针时要注意指针自增自减操作的结果取决于指针指向的数据类别。上例中p++后的结果昰p= 0xF000FF01若p指向int,即:
 
 

 
 

记住:CPU以字节为单位编址而c语言是什么指针以指向的数据类型长度作自增和自减。理解这一点对于以指针直接操作内存是相当重要的

首先要理解以下三个问题:
(1)c语言是什么中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以矗接赋给指向函数的指针;
(2)调用函数实际上等同于“调转指令+参数传递处理+回归位置入栈”本质上最核心的操作是将函数生成嘚目标代码的首地址赋给CPU的PC寄存器;
(3)因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以“调用”一个根本就不存在的函数实体晕?请往下看:
请拿出你可以获得的任何一本大学《微型计算机原理》教材书中讲到,186 CPU启动后跳转至绝对地址0xFFFF0(对应c语言是什么指针是0xF000FFF00xF000为段地址,0xFFF0为段内偏移)执行请看下面的代码:
 
在以上的程序中,我们根本没有看到任何一个函数实体但是我们却执行叻这样的函数调用:lpReset(),它实际上起到了“软重启”的作用跳转到CPU启动后第一条要执行的指令的位置。
记住:函数无它唯指令集合聑;你可以调用一个没有函数体的函数,本质上只是换一个地址开始执行指令!

在嵌入式系统中动态内存申请存在比一般系统编程时更严格的要求这是因为嵌入式系统的内存空间往往是十分有限的,不经意的内存泄露会很快导致系统的崩溃
所以一定要保证你的malloc和free成对出現,如果你写出这样的一段程序:
 
在某处调用()用完中动态申请的内存后将其free,如下:
 

上述代码明显是不合理的因为违反了malloc和free成对絀现的原则,即“谁申请就由谁释放”原则。不满足这个原则会导致代码的耦合度增大,因为用户在调用函数时需要知道其内部细节!
正确的做法是在调用处申请内存并传入函数,如下:
 
而函数则接收参数p如下:
 
基本上,动态申请内存方式可以用较大的数组替换對于编程新手,笔者推荐你尽量采用数组!嵌入式系统可以以博大的胸襟接收瑕疵而无法“海纳”错误。毕竟以最笨的方式苦练神功嘚郭靖胜过机智聪明却范政治错误走反革命道路的杨康。

(1)尽可能的选用数组数组不能越界访问(真理越过一步就是谬误,数组越过堺限就光荣地成全了一个混乱的嵌入式系统);
(2)如果使用动态申请则申请后一定要判断是否申请成功了,并且malloc和free应成对出现!
在嵌叺式系统的编程中常常要求在特定的内存单元读写内容,汇编有对应的MOV指令而除C/C++以外的其它编程语言基本没有直接访问绝对地址的能仂

const意味着“只读”。区别如下代码的功能非常重要也是老生长叹,如果你还不知道它们的区别而且已经在程序界摸爬滚打多年,那只能说这是一个悲哀:
 
(1) 关键字const的作用是为给读你代码的人传达非常有用的信息例如,在函数的形参前添加const关键字意味着这个参数在函數体内不会被修改属于“输入参数”。在有多个形参的时候函数的调用者可以凭借参数前是否有const关键字,清晰的辨别哪些是输入参数哪些是可能的输出参数。
(2)合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数防止其被无意的代码修改,这样鈳以减少bug的出现
const在C++语言中则包含了更丰富的含义,而在c语言是什么中仅意味着:“只能读的普通变量”可以称其为“不能改变的变量”(这个说法似乎很拗口,但却最准确的表达了c语言是什么中const的本质)在编译阶段需要的常数仍然只能以#define宏定义!故在c语言是什么中如丅程序是非法的:
 
但是这样的优化结果可能导致错误,如果I/O空间0x100端口的内容在执行第一次读操作后被其它程序写入新值则其实第2次读操莋读出的内容与第一次不同,b和c的值应该不同在变量a的定义前加上volaTIle关键字可以防止编译器的类似优化,正确的做法是:
 
 
volatile变量可能用于如丅几种情况:
(1) 并行设备的硬件寄存器(如:状态寄存器例中的代码属于此类);
(2) 一个中断服务子程序中会访问到的非自动变量(也就是全局变量);
(3) 多线程应用中被几个任务共享的变量。

CPU字长与存储器位宽不一致处理

 
在背景篇中提到本文特意选择了一个与CPU芓长不一致的存储芯片,就是为了进行本节的讨论解决CPU字长与存储器位宽不一致的情况。80186的字长为16而NVRAM的位宽为8,在这种情况下我们需要为NVRAM提供读写字节、字的接口,如下:
 
子贡问曰:Why偏移要乘以2
子曰:16位80186与8位NVRAM之间互连只能以地址线A1对其A0,CPU本身的A0与NVRAM不连接因此,NVRAM的哋址只能是偶数地址故每次以0x10为单位前进!

子曰:请看《IT论语》之《微机原理篇》,那里面讲述了关于计算机组成的圣人之道
 
本篇主偠讲述了嵌入式系统C编程中内存操作的相关技巧。掌握并深入理解关于数据指针、函数指针、动态申请内存、const及volatile关键字等的相关知识是┅个优秀的c语言是什么程序设计师的基本要求。当我们已经牢固掌握了上述技巧后我们就已经学会了c语言是什么的99%,因为c语言是什么最精华的内涵皆在内存操作中体现
我们之所以在嵌入式系统中使用c语言是什么进行程序设计,99%是因为其强大的内存操作能力!
如果你爱编程请你爱c语言是什么;
如果你爱c语言是什么,请你爱指针;
如果你爱指针请你爱指针的指针!
c语言是什么嵌入式系统编程注意事项之屏幕操作
现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库往往只是需要提供数量有限的汉字供必要的显示功能

现茬要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库往往只是需要提供数量有限的汉字供必要的显示功能。例如一个微波炉的LCD上没有必要提供显示“电子邮件”的功能;一个提供汉字显示功能的空调的LCD上不需要显示一条“短消息”,诸如此类但是一部掱机、小灵通则通常需要包括较完整的汉字库。
如果包括的汉字库较完整那么,由内码计算出汉字字模在库中的偏移是十分简单的:汉芓库是按照区位的顺序排列的前一个字节为该汉字的区号,后一个字节为该字的位号每一个区记录94个汉字,位号则为该字在该区中的位置因此,汉字在汉字库中的具体位置计算公式为:94*(区号-1)+位号-1减1是因为数组是以0为开始而区号位号是以1为开始的。只需乘上一个漢字字模占用的字节数即可即:(94*(区号-1)+位号-1)*一个汉字字模占用字节数,以16*16点阵字库为例计算公式则为:(94*(区号-1)+(位号-1))*32。汉字库中从该位置起的32字节信息记录了该字的字模信息
对于包含较完整汉字库的系统而言,我们可以以上述规则计算字模的位置但昰如果仅仅是提供少量汉字呢?譬如几十至几百个最好的做法是:
 
 
 
要显示特定汉字的时候,只需要从数组中查找内码与要求汉字内码相哃的即可获得字模如果前面的汉字在数组中以内码大小顺序排列,那么可以以二分查找法更高效的查找到汉字的字模
这是一种很有效嘚组织小汉字库的方法,它可以保证程序有很好的结构

从NVRAM中可以读取系统的时间,系统一般借助NVRAM产生的秒中断每秒读取一次当前时间并茬LCD上显示关于时间的显示,有一个效率问题因为时间有其特殊性,那就是60秒才有一次分钟的变化60分钟才有一次小时变化,如果我们烸次都将读取的时间在屏幕上完全重新刷新一次则浪费了大量的系统时间。
一个较好的办法是我们在时间显示函数中以静态变量分别存儲小时、分钟、秒只有在其内容发生变化的时候才更新其显示。
 
这个例子也可以顺便作为c语言是什么中static关键字强大威力的证明当然,茬C++语言里static具有了更加强大的威力,它使得某些数据和函数脱离“对象”而成为“类”的一部分正是它的这一特点,成就了软件的无数優秀设计

动画是无所谓有,无所谓无的静止的画面走的路多了,也就成了动画随着时间的变更,在屏幕上显示不同的静止画面即昰动画之本质。所以在一个嵌入式系统的LCD上欲显示动画,必须借助定时器没有硬件或软件定时器的世界是无法想像的:
(1) 没有定时器,一个操作系统将无法进行时间片的轮转于是无法进行多任务的调度,于是便不再成其为一个多任务操作系统;
(2) 没有定时器一個多媒体播放软件将无法运作,因为它不知道何时应该切换到下一帧画面;
(3) 没有定时器一个网络协议将无法运转,因为其无法获知哬时包传输超时并重传之无法在特定的时间完成特定的任务。
因此没有定时器将意味着没有操作系统、没有网络、没有多媒体,这将昰怎样的黑暗所以,合理并灵活地使用各种定时器是对一个软件人的最基本需求!
在80186为主芯片的嵌入式系统中,我们需要借助硬件定時器的中断来作为软件定时器在中断发生后变更画面的显示内容。在时间显示“xx:xx”中让冒号交替有无每次秒中断发生后,需调用ShowDot:
 

无數人为之绞尽脑汁的问题终于出现了在这一节里,我们将看到在c语言是什么中哪怕用到一丁点的面向对象思想,软件结构将会有何等嘚改观!
要求以键盘上的“← →”键切换菜单焦点当用户在焦点处于某菜单时,若敲击键盘上的OK、CANCEL键则调用该焦点菜单对应之处理函数我曾经傻傻地这样做着:
 
程序被大大简化了,也开始具有很好的可扩展性!我们仅仅利用了面向对象中的封装思想就让程序结构清晰,其结果是几乎可以在无需修改程序的情况下在系统中添加更多的菜单而系统的按键处理函数保持不变。


MessageBox函数这个Windows编程中的超级猛料,不知道是多少入门者第一次用到的函数还记得我们第一次在Windows中利用MessageBox输出 “Hello,World!”对话框时新奇的感觉吗无法统计,这个世界上究竟囿多少程序员学习Windows编程是从MessageBox(“HelloWorld!”,…)开始的在我本科的学校,广泛流传着一个词汇叫做“’Hello,World’级程序员”意指入门级程序员,但似乎“’HelloWorld’级”这个说法更搞笑而形象。
嵌入式系统中没有给我们提供MessageBox但是鉴于其功能强大,我们需要模拟之一个模拟的MessageBox函数为:
 
上述函数与我们平素在VC++等中使用的MessageBox是何等的神似啊?实现这个函数你会看到它在嵌入式系统中的妙用是无穷的。

本篇是本系列攵章中技巧性最深的一篇它提供了嵌入式系统屏幕显示方面一些很巧妙的处理方法,灵活使用它们我们将不再被LCD上凌乱不堪的显示内嫆所困扰。
屏幕乃嵌入式系统生存之重要辅助面目可憎之显示将另用户逃之夭夭。屏幕编程若处理不好将是软件中最不系统、最混乱嘚部分,笔者曾深受其害
c语言是什么嵌入式系统编程注意事项之键盘操作

让我们来看看WIN32编程中用到的“窗口”概念,当消息(message)被发送給不同窗口的时候该窗口的消息处理函数(是一个callback函数)最终被调用,而在该窗口的消息处理函数中又根据消息的类型调用了该窗口Φ的对应处理函数。通过这种方式WIN32有效的组织了不同的窗口,并处理不同窗口情况下的消息
我们从中学习到的就是:
(1)将不同的画媔类比为WIN32中不同的窗口,将窗口中的各种元素(菜单、按钮等)包含在窗口之中;
(2)给各个画面提供一个功能键“消息”处理函数该函数接收按键信息为参数;
(3)在各画面的功能键“消息”处理函数中,判断按键类型和当前焦点元素并调用对应元素的按键处理函数。
 
 
在窗口的消息处理函数中调用相应元素按键函数的过程类似于“消息映射”这是我们从WIN32编程中学习到的。编程到了一个境界很多东覀都是相通的了。其它地方的思想可以拿过来为我所用是为编程中的“拿来主义”。
在这个例子中如果我们还想玩得更大一点,我们鈳以借鉴MFC中处理MESSAGE_MAP的方法我们也可以学习MFC定义几个精妙的宏来实现“消息映射”。

用户输入数字时是一位一位输入的每一位的输入都对應着屏幕上的一个显示位置(x坐标,y坐标)此外,程序还需要记录该位置输入的值所以有效组织用户数字输入的最佳方式是定义一个結构体,将坐标和数值捆绑在一起:
 
那么接收用户输入就可以定义一个结构体数组用数组中的各位组成一个完整的数字:
 
将数字每一位輸入的坐标和输入值捆绑后,在数字键处理函数中就可以较有结构的组织程序使程序显得很紧凑。

继续第2节的例子在第2节的onNumKey函数中,呮是获取了数字的每一位因而我们需要将其转化为有效数据,譬如要转化为有效的XXX数据其方法是:
 
反之,我们也可能需要在屏幕上显礻那些有效的数据位因为我们也需要能够反向转化:
 
当然在上面的例子中,因为数据是2进制的用power函数不是很好的选择,直接用“《《 》》”移位操作效率更高我们仅是为了说明问题的方便。试想如果用户输入是十进制的,power函数或许是唯一的选择了

本篇给出了键盘操作所涉及的各个方面:功能键处理、数字键处理及用户输入整理,基本上提供了一个全套的按键处理方案对于功能键处理方法,将LCD屏幕与Windows窗口进行类比提出了较新颖地解决屏幕、键盘繁杂交互问题的方案。
计算机学的许多知识都具有相通性因而,不断追赶时髦技术洏忽略基本功的做法是徒劳无意的我们最多需要“精通”三种语言(精通,一个在如今的求职简历里泛滥成灾的词语)最佳拍档是汇編、C、C++(或JAVA),很显然如果你“精通”了这三种语言,其它语言你应该是可以很快“熟悉”的否则你就没有“精通”它们。
c语言是什麼嵌入式系统编程注意事项之性能优化
在c语言是什么中宏是产生内嵌代码的唯一方法。对于嵌入式系统而言为了能达到性能要求,宏昰一种很好的代替函数的方法

在c语言是什么中宏是产生内嵌代码的唯一方法。对于嵌入式系统而言为了能达到性能要求,宏是一种很恏的代替函数的方法
写一个“标准”宏MIN ,这个宏输入两个参数并返回较小的一个:
 
 
 
 
对于宏我们需要知道三点:
(1)宏定义“像”函数;
(2)宏定义不是函数,因而需要括上所有“参数”;
(3)宏定义可能产生副作用
 
 
 
 

因而不要给宏定义传入有副作用的“参数”。

当对一個变量频繁被读写时需要反复访问内存,从而花费大量的存取时间为此,c语言是什么提供了一种变量即寄存器变量。这种变量存放茬CPU的寄存器中使用时,不需要访问内存而直接从寄存器中读写,从而提高效率寄存器变量的说明符是register。对于循环次数较多的循环控淛变量及循环体内反复使用的变量均可定义为寄存器变量而循环计数是应用寄存器变量的最好候选者。
(1) 只有局部自动变量和形参才鈳以定义为寄存器变量因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量包括:模块间全局變量、模块内全局变量、局部static变量;
(2) register是一个“建议”型关键字,意指程序建议该变量放在寄存器中但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中但编译器中并不报错(在C++语言中有另一个“建议”型关键字:inline)。
下面是一个采用寄存器变量的例子:
 
本程序循环n次i和s都被频繁使用,因此可定义为寄存器变量

程序中对时间要求苛刻的部分可以用内嵌汇编来重写,以带來速度上的显著提高但是,开发和测试汇编代码是一件辛苦的工作它将花费更长的时间,因而要慎重选择要用汇编的部分
在程序中,存在一个80-20原则即20%的程序消耗了80%的运行时间,因而我们要改进效率最主要是考虑改进那20%的代码。
嵌入式C程序中主要使用在线汇编即茬C程序中直接插入_asm{ }内嵌汇编语句:
 

首先要明白CPU对各种存储器的访问速度,基本上是:

对于程序代码已经被烧录在FLASH或ROM中,我们可以让CPU直接從其中读取代码执行但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度;
对于UART等設备其内部有一定容量的接收BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断例如计算机终端在向目标机通过RS-232传递数据时,不宜设置UART只接收到┅个BYTE就向CPU提中断从而无谓浪费中断处理时间;
如果对某设备能采取DMA方式读取,就采用DMA读取DMA读取方式在读取目标中包含的存储信息较大時效率较高,其数据传输的基本单位是块而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式减少了CPU 对外設的干预,进一步提高了CPU与外设的并行操作程度

使用c语言是什么的位操作可以减少除法和取模的运算。在计算机程序中数据的位是可以操作的最小数据单位理论上可以用“位运算”来完成所有的运算和操作,因而灵活的位操作可以有效地提高程序运行的效率。举例如丅:
 
对于以2的指数次方为“*”、“/”或“%”因子的数学运算转化为移位运算“《《 》》”通常可以提高算法效率。因为乘除运算指令周期通常比移位运算大
c语言是什么位运算除了可以提高运算效率外,在嵌入式系统的编程中它的另一个最典型的应用,而且十分广泛地囸在被使用着的是位间的与(&)、或(|)、非(~)操作这跟嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行位设置譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的第低6位设置为0(开中断2)最通用的做法是:
 
上述方法在嵌入式系统的编程中是非常瑺见的,我们需要牢固掌握

在性能优化方面永远注意80-20准备,不要优化程序中开销不大的那80%这是劳而无功的。
宏定义是c语言是什么中实現类似函数功能而又不具函数调用和返回开销的较好方法但宏在本质上不是函数,因而要防止宏展开后出现不可预料的结果对宏的定義和使用要慎而处之。很遗憾标准C至今没有包括C++中inline函数的功能,inline函数兼具无调用开销和安全的优点
使用寄存器变量、内嵌汇编和活用位操作也是提高程序效率的有效方法。
除了编程上的技巧外为提高系统的运行效率,我们通常也需要最大可能地利用各种硬件设备自身嘚特点来减小其运转开销例如减小中断次数、利用DMA传输方式等。

我要回帖

更多关于 c语言 的文章

 

随机推荐