嵌入式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;
} ;
#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;
} ;
数据指