嵌入式学习(二) 嵌入式系统C 语言

单任务程序典型架构

(1)从 CPU 复位时的指定地址开始执行
(2)跳转至汇编代码 startup 处执行;
(3)跳转至用户主程序 main 执行,在 main 中完成:
a.初试化各硬件设备;
b.初始化各软件模块;
c.进入死循环(无限循环)
d调用各模块的处理函数

下面是几个"著名"的死循环:
(1)操作系统是死循环;
(2)WIN32 程序是死循环;
(3)嵌入式系统软件是死循环;
(4)多线程程序的线程处理函数是死循环

中断服务程序

中断是嵌入式系统中重要的组成部分,但是在标准 C 中不包含中断。许多编译开发商在标准 C 上增加了对中断的支持,提供新的关键字用于标示中断服务程序 (ISR),类似于__interrupt、#program interrupt 等。当一个函数被定义为 ISR 的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码。中断服务程序需要满足如下要求:
(1)不能返回值;
(2)不能向 ISR 传递参数;
(3) ISR 应该尽可能的短小精悍;
(4) printf(char * lpFormatString,…)函数会带来重入和性能问题,不能在 ISR 中采
用。

硬件驱动模块通常应包括如下函数:
  • (1)中断服务程序 ISR
  • (2)硬件初始化
    • a.修改寄存器,设置硬件参数
    • b.将中断服务程序入口地址写入中断向量表:
  • (3)设置 CPU 针对该硬件的控制线
    • a.如果控制线可作 PIO(可编程 I/O)和控制信号用,则设置 CPU 内部对应寄存器使其作为控制信号;
    • b.设置 CPU 内部的针对该设备的中断屏蔽位,设置中断方式(电平触发还是边缘触发)
  • (4)提供一系列针对该设备的操作接口函数。

C 的面向对象化

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

内存操作

数据指针

在嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应的 MOV指令,而除 C/C++以外的其它编程语言基本没有直接访问绝对地址的能力。在嵌入式系统的实际调试中,多借助 C 语言指针所具有的对绝对地址单元内容的读写能力。以指针直接操作内存多发生在如下几种情况:

  • 某 I/O 芯片被定位在 CPU 的存储空间而非 I/O 空间,而且寄存器对应于某特定地址;
  • 两个 CPU 之间以双端口 RAM 通信, CPU 需要在双端口 RAM 的特定单元(称为mail box)书写内容以在对方 CPU 产生中断;
  • 读取在 ROM 或 FLASH 的特定单元所烧录的汉字和英文字模。
函数指针

首先要理解以下三个问题:
(1)C 语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以直接赋给指向函数的指针;
(2)调用函数实际上等同于"调转指令+参数传递处理+回归位置入栈",本质上最核心的操作是将函数生成的目标代码的首地址赋给 CPU 的 PC 寄存器;
(3)因为函数调用的本质是跳转到某一个地址单元的 code 去执行,所以可以"调用"一个根本就不存在的函数实体

数组

嵌入式系统中动态内存申请存在比一般系统编程时更严格的要求,这是因为嵌入式系统的内存空间往往是十分有限的,不经意的内存泄露会很快导致系统的崩溃。给出原则:

  • (1)尽可能的选用数组,数组不能越界访问(真理越过一步就是谬误,数组越过界限就光荣地成全了一个混乱的嵌入式系统)

  • (2)如果使用动态申请,则申请后一定要判断是否申请成功了,并且 malloc 和 free应成对出现!

关键字 const

(1)关键字 const 的作用是为给读你代码的人传达非常有用的信息。例如,在函数的形参前添加 const 关键字意味着这个参数在函数体内不会被修改,属于"输入参数"。在有多个形参的时候,函数的调用者可以凭借参数前是否有 const 关键字,清晰的辨别哪些是输入参数,哪些是可能的输出参数。
(2)合理地使用关键字 const 可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改,这样可以减少 bug 的出现

关键字 volatile

volatile是一个类型修饰符(type specifier).volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

  • (1) 并行设备的硬件寄存器(如:状态寄存器,例中的代码属于此类);
  • (2) 一个中断服务子程序中会访问到的非自动变量(也就是全局变量);
  • (3) 多线程应用中被几个任务共享的变量。
使用寄存器变量

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

  • (1) 只有局部自动变量和形参才可以定义为寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部 static 变量;
  • (2) register 是一个"建议"型关键字,意指程序建议该变量放在寄存器中,但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中,但编译器中并不报错(在 C++语言中有另一个"建议"型关键字:inline)
硬件特性

首先要明白 CPU 对各种存储器的访问速度,基本上是:
CPU 内部 RAM >外部同步 RAM> 外部异步 RAM >FLASH/ROM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值