嵌入式C编程要点

模块划分

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

(2) 某模块提供给其它模块调用的外部函数及数据需要在头文件中以extern声明。

(3) 模块内的函数和全局变量需要冠以static关键字声明。

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

(5) 防止重定义,使用“#ifndef - #define - #endif”结构。



单任务程序典型架构

(1) 从CPU复位时的指定地址开始执行。

(2) 跳转至汇编代码的startup处执行。

(3) 跳转至用户主程序main执行并完成:硬件设备和软件模块的初始化,进入无限循环以调用各模块的处理函数。



中断服务程序

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

中断服务程序需要满足如下要求:

(1) 不能返回值

(2) 不能传递参数

(3) ISR应该尽量短小

(4) printf函数会带来重入和性能问题,不能采用



硬件驱动模块

硬件初始化过程:

(1) 修改寄存器,设置硬件参数

(2) 将ISR入口地址写入中断向量表(vector table)

(3) 设置CPU针对该硬件的控制线,如果控制线可用于PIO(可编程I/O)和控制信号用,则设置CPU内部对应寄存器使其作为控制信号;设置CPU内部的针对该设备的中断屏蔽位,设置中断方式(电平触发或边缘触发)

(4) 提供一系列针对该设备的操作接口函数



C的面向对象化

在面向对象语言里,出现了“类”的概念。类是对特定数据的特定操作的集合体。类包含两个范畴:数据和行为。而C语言中的struct仅仅是数据的集合,我们可以利用函数指针将struct模拟为一个包含数据和操作的“类”。

在C语言中,可以模拟出面向对象的三个特性:封装、继承、多态。但更多的时候,我们只是需要将数据和行为封装以解决软件结构混乱的问题。C模拟面向对象的思想不在于模拟行为本身,而在于解决某些情况下使用C语言编程时程序整体框架结构分散、数据和函数脱节的问题。

#ifndef C_Class
#define C_Class struct
#endif
C_Class ClassA
...{
C_Class ClassA *A_this; //this指针
void (*Func)(C_Class ClassA *A_this); //函数指针表示行为
//数据
int a;
int b;
};




数据指针

在使用绝对地址指针时,要注意指针自增自减的结果取决于指针指向的数据类型。p++或++p的结果等同于p = p + sizeof(int)。

int *p = (int *)0x0000FFFF;

CPU以字节为单位编址,而C语言指针以指向的数据类型长度作自增和自减。



函数指针

(1) 调用函数实际上等同于“跳转指令+参数传递处理+回归位置入栈”,本质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的pc寄存器。

(2) 因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以“调用”一个根本不存在的函数实体。

typedef void (*lpFunc)(); //定义一个无参数无返回类型的函数指针类型
lpFunc reset = (lpFunc)0xF000FFF0; //函数指针,指向系统初始化的指令
reset(); //调用函数

(3) 函数无他,唯指令集合耳。



数组和动态申请内存

(1) 尽可能选用数组,因为数组不能越界访问。

(2) 如果使用动态申请内存,则申请后一定要判断是否申请成功,并且malloc与free应成对出现。



关键字const

const int a; //该变量的值不能改变
int const a; //该变量的值不能改变
const int *a; //该指针指向的内存区域的值不能改变
int * const a; //该指针的值不能改变
int const * a const; //该指针的值与指向的内存区域的值都不能改变

(1) 为阅读你的代码的人传达非常有用的信息。

(2) 使编译器很自然地去保护那些不希望被改变的参数,可以减少bug的出现。



关键字volatile

C语言编译器会对用户书写的代码进行优化,比如:

int a, b, c;
a = in(0x100); //读取I/O空间0x100端口的内容
b = a;
a = in(0x100); //再次读入IO空间0x100端口的内容
c = a;

很可能会被编译器优化为:

int a, b, c;
a = in(0x100);
b = a;
c = a;

这样优化的结果很可能导致错误,因为在第一次读取I/O空间0x100端口的值后,很可能被其它程序写入新值,所以第二次读取的值和第一次的值就会不一样。而优化后,两次读取的值就一样了。在变量a定义时加上volatile关键字可以防止编译器的优化。

volatile变量一般使用于如下情况:

(1) 并行设备的硬件寄存器(如:状态寄存器)

(2) 一个中断服务程序中会访问到的非自动变量(也就是全局变量)

(3) 多线程应用中被几个任务共享的变量



CPU字长于存储器位宽

某CPU字长为16位,NVRAM的位宽为8位,在这种情况下,我们需要为NVRAM提供读写字节、字的操作,如下:

typedef unsigned char BYTE;
typedef unsigned int WORD;
BYTE readByte_NVRAM(WORD offset)
...{
LPBYTE lpAddr = (BYTE *)(NVRAM + offset*2);
return *lpAddr;
}
WORD readWord_NVRAM(WORD offset)
...{
WORD wTmp = 0;
LPBYTE lpAddr;
lpAddr = (BYTE *)(NVRAM + offset*2);
wTmp += (*lpAddr) << 8;
lpAddr = (BYTE *)(NVRAM + (offset+1)*2);
wTmp += *lpAddr;
return wTmp;
}


为什么在上例中偏移要乘以2?

因为16位的CPU与8位的NVRAM之间互联只能以地址线A1对其A0,CPU本身的A0与NVRAM不连接,因此NVRAM的地址只能是偶数地址,故每次以0x10为单位。



寄存器变量

当对一个变量频繁读写时,需要反复访问内存,从而花费大量存取时间。为此,C语言提供了一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用 时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符为register,循环计数是应用寄存器变量的最好候选者。

只有局部自动变量和形参才能定义成寄存器变量。因为寄存器变量属于动态储存方式,凡采用静态存储方式的变量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部static变量。

register是一个“建议型”关键字,表示程序建议该变量放于寄存器中,但最终该变量可能因为条件不满足而未能成为寄存器变量,被放置于存储器中,这个情况下,编译器并不会报错(在C++语言中,还有一“建议型”关键字,inline)。



内嵌汇编

程序中对时间要求苛刻的部分可以用内嵌汇编来重写,以带来速度上的显著提高。但是,开发和测试汇编代码是一件艰苦的工作,它将花费更长的时间,因而要慎重选择汇编的部分。

在程序中,存在一个80-20原则,即20%的程序消耗了80%的时间,因而我们要改进效率,最主要是考虑改进那20%的部分。

在C程序中,可以直接插入__asm{}内嵌汇编语句:

/**//* 把两个参数值相加,放入另一全局变量中 */
int result;
void add(long a, long *b)
...{
__asm
...{
MOV AX, a
MOV BX, b
ADD AX, [BX]
MOV result, AX
}
}

利用硬件特性

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

CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM

对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从中读取代码执行,但通常不是一个好方法,我们最好在系统启动时将FLASH或ROM中的目标代码复制到RAM中再执行以提高取指令的速度。

对于UART等设备,其内部有一定容量的接受BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断。

对某设备能采取DMA方式,就应该采用DMA方式。DMA方式在读取目标中包含的存储信息较大时效率较高,其数据传输基本单位是块,而所传输的数据是从设备直接送入内存。DMA方式比起中断驱动方式,减少了CPU对外设的干预,进一步提高了CPU与外设间的并行处理。

位操作

在C语言中的位操作可以减少除法和模运算。在计算机程序中数据的位是可以操作的最小单位,理论上可以用“位操作”来完成所有的运算和操作,因而,灵活的位操作可以有效提高程序运行的效率。

/**//* 效率较低的操作 */
int i,= 1024 / 16;
int j = 986 % 32;

/**//* 效率较高的操作 */
int i = 1024 >> 4;
int j = 986 – (986 >> 5 << 5);

对于以2的指数次方为“*”、“/”或“%”因子的数学运算,转化为移位运算通常可以提高算法的效率,因为乘除运算指令周期通常比移位运算要大。

C语言位操作除了可以提高运算效率外,在嵌入式系统编程中,最典型的应用是位间的与(&)、或(|)、非(~)操作,这个嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行置位。

/**//* 将某CPU中断屏蔽控制寄存器的第6位设置为0(开中断2) */
#define INT_I2_MASK 0x0040
wTmp = in(INT_MASK);
out(INT_MASK, wTmp &~INT_I2_MASK);

/**//* 将该位设置为1 */
wTmp = in(INT_MASK);
out(INT_MASK, wTmp | INT_I2_MASK);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 嵌入Linux C语言应用程序设计是指在嵌入设备上使用C语言编写应用程序,以实现特定功能的过程。华清远见培训PDF是一种培训资料,用于指导学习如何进行嵌入Linux C语言应用程序设计的相关技术。 在嵌入Linux C语言应用程序设计中,我们需要了解Linux操作系统的基本概念和原理,以及嵌入系统的特点和应用场景。同时,我们也需要掌握C语言的基本语法和常用的编程技巧。 这门培训课程的目标是教授学员如何使用C语言开发嵌入应用程序,并深入理解Linux系统的底层原理。培训材料以PDF形提供,方便学员在自己的电脑上随时学习和参考。 在课程中,我们将学习如何利用Linux的系统调用和API来开发应用程序,如文件操作、进程管理、网络通信等。同时,我们也将学习如何进行硬件编程,与设备进行交互,如GPIO控制、串口通信等。 除了理论学习,这门培训将通过一些实践项目,帮助学员更好地掌握所学知识。学院将提供实验环境和开发板,供学员进行实践操作。通过这些实践项目,学员可以加深对嵌入Linux C语言应用程序设计的理解,并提高自己的编程能力。 总而言之,嵌入Linux C语言应用程序设计华清远见培训PDF为学员提供了学习嵌入开发的理论知识和实践项目,帮助学员掌握如何用C语言编写嵌入应用程序,并更好地理解Linux系统的工作原理和特点。这对于从事嵌入开发的人员来说,是一门非常有价值的课程。 ### 回答2: 华清远见培训提供了一门关于嵌入Linux C语言应用程序设计的PDF教程。这门教程专注于嵌入Linux系统的C语言编程,旨在帮助学员掌握在嵌入设备上开发应用程序的技能。 教程内容主要包括以下几个方面: 1. 嵌入系统概述:介绍了嵌入系统的基本概念和特点,以及嵌入Linux系统的结构和运行环境。 2. Linux内核编程:讲解了如何进行Linux内核的配置和编译,以及如何开发内核模块和驱动程序。 3. 嵌入应用程序开发:涵盖了Linux下的C语言开发工具链的使用,包括编译、调试和测试等方面的内容。同时,还介绍了常用的嵌入开发库和函数,以及如何进行文件系统的管理和操作。 4. 嵌入设备的外设驱动开发:详细讲解了如何开发各种外设的驱动程序,包括串口、SPI、I2C等接口的使用和操作。 5. 实际项目案例:通过一些实际的嵌入项目案例,帮助学员将所学知识运用到实际的应用中。 这门教程适合已经具备一定编程基础的学员,尤其是对嵌入系统和Linux有一定了解的人群。通过学习这门课程,学员将能够掌握嵌入Linux系统的应用程序设计和开发技巧,提高自己在嵌入领域的竞争力。 ### 回答3: 《嵌入Linux C语言应用程序设计》是华清远见培训机构提供的一门培训课程,主要面向对嵌入Linux系统开发有兴趣的学习者。 嵌入Linux是一种嵌入操作系统,它是将Linux操作系统适配到嵌入设备中的一种实现方嵌入系统是一种专门为具体应用设计的计算机系统,通常它具有小型化、低功耗、实时性要求等特点。而嵌入Linux作为一种开源操作系统,具有稳定性强、适应性广等优点,因此在嵌入设备的开发中得到了广泛应用。 C语言作为一种常用的编程语言,在嵌入系统开发中也是广泛使用的工具。学习《嵌入Linux C语言应用程序设计》课程可以帮助学习者掌握在嵌入Linux环境下进行C语言程序设计的技能。课程内容包括嵌入Linux系统的搭建与配置、嵌入设备的驱动程序编写、应用程序的开发等方面的知识。 在课程中,学习者将通过理论学习和实践操作相结合的方,了解嵌入Linux系统的基本原理和运行机制,并学习如何使用C语言进行嵌入系统的开发。学习者将掌握Linux系统的搭建与配置方法,了解嵌入设备的驱动程序开发流程,并学会使用C语言进行应用程序的编写。通过实际操作,学习者能够熟悉开发工具的使用,掌握调试技巧,提高代码质量和效率。 通过学习《嵌入Linux C语言应用程序设计》课程,学习者能够全面了解嵌入Linux系统的开发流程和技术要点,掌握驱动程序开发和应用程序编写的基本技能,为以后从事嵌入Linux系统开发工作打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值