锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

嵌入式C知识点总结

时间:2022-09-14 02:30:00 三极管2p4m

在网上看到很多嵌入式C的知识点,总想积累起来。所谓不积小流,不积小步,不至千里。

1、#define SENCONDS_PER_YEAR (60*60*24*365)UL

1)宏定义语法,格式

2)直观地表达这个数字的意义(一年多少秒)

3)这个数字会溢出16位机器,需要长整形手术L,同时是无符号数,所以使用UL

2、#define MIN(A,B) ((A)<=(B)?(A)(B))

1)三重条件操作符会使编译器产生比例if-than-else更优化的代码 注意inline嵌入式代码也可以生成

2)宏中的参数需要使用括号括起来

3)leaset = MIN(*P ,a); 这句话会有什么错误?

操作优先级高于*,所以会先地址 ,然后取值,会得到不确定的结果。

3.预处理器表示 #error目的是什么?

1)应用广泛,在预处理阶段,当处理到这里时,会产生预处理错误,并输出自定义错误。

# error [用户定制的错误信息]

例如,如果检测到编译环境C 提醒用户在C编译环境中运行。

4、死循环(Infinite loops)

自己习惯使用 while(1){},结构一目了然。并且可以定义变量=1.变量名可以写成一定的死循环运行条件,一目了然。

当然,有些人喜欢 for(;){},没有问题。

5、变量定义

a) 一个整型数 (An integer)

b) 指向整形数的指针 (A pointer to an integer)

c) 指向指针的指针,它指向的指针是指向整形数 (A pointer to a pointer to an integer)

d) 一个数组有10个整形数 (An array of 10 integers)

e) 数组有10个指针,该指针指向整形数 (An array of 10 pointers to integers)

f) 一个指向10个整形数组 (A pointer to an array of 10 integers)

g) 指向函数的指针,该函数有一个整形参数,并返回一个整形数 (A pointer to a function that takes an integer as an argument and returns an integer)

h) 一个有10个指针的数组指向一个函数,它有一个整形参数并返回一个整形参数( An array of ten pointers to functions that take an integer argument and return an integer )

答案:

a) int a; // 一个整型数 An integer

b) int *a; // 指向整形数的指针 A pointer to an integer

c) int **a; // 指向指针的指针 A pointer to a pointer to an integer

d) int a[10]; // 一个数组有10个整形数 An array of 10 integers

e) int *a[10]; // 一个有10个指针的数组 An array of 10 pointers to integers

f) int (*a)[10]; // 一个指向10个整形数组 A pointer to an array of 10 integers

g) int (*a)(int); // 指向函数的指针 A pointer to a function a that takes an integer argument and returns an integer

h) int (*a[10])(int); // 一10个指针的数组指向整形函数和整形参数 An array of 10 pointers to functions that take an integer argument and return an integer

6、static 作用

1)static变量和函数存储在静态存储区域,并在程序开始时初始化。唯一的初始化。静态变量值可以改变。地址在开始时初始化。

2)模块中的函数只能调用静态变量和静态函数,模块外的函数不能调用

7、关键字Const含义

1)只读的

2)编译器不会去更改const定义的变量

3)代码更紧凑

扩展:

const int a; 定义一个int类型只读变量a

int const a;同上

const int *a; 定义指向常规整形数的指针(整形数不能改变,指针可以改变)

int* const a; 定义指向整形数的常指针(整形数可以修改,指针不能修改)

int const *a const; 定义指针的定义(整形数和指针不能更改)

Const使用好处:

1)为了告诉用户该参数的应用目的,声明一个参数为常量。

2)使用关键字给优化器一些额外的信息const可能会产生更紧凑的代111码

3)编译器可以自然保护这些变量,提醒用户不要改变,减少bug

8、关键字volatile 举例

1)

#define __O volatile /*!< defines 'write only' permissions */

#define __IO volatile /*!< defines 'read / write' permissions */

#define __I volatile const

__IO uint32_t u32IEN;

__IOuint32_t IEN;

__I  uint32_t  LTRIG_FLAG:1;

状态寄存器

2)中断服务子程序会访问到非自动变量(Non-automatic variables)

3)被多线程访问到的变量

尤其注意后面两条,会产生意想不到的bug

参数可以是const 又可以是 volatile的,比如说1)中的 __I    LTRIG_FLAG。一边被定义为状态标识的都需要是const和voltile的。

int square(volatile int *ptr)

{ reutrn *ptr * *ptr;

}

这段代码,ptr指向地址的值,或许或会变化,所以得到的返回值未必是想要的

应该改成这样

int a = *ptr;

return a*a;

9、位操作

1)设置int 变量 a 的第三位

2)清楚int 变量a的第三位

操作过程中其它位保持不变

最好的方法

#define BIT3 (0x1 << 3)

static int a;

void set_bit3(void){ a|=BIT3;}

void set_bit3(void){a&=~BIT3;}

要点是 说明常数、|=和&=~操作。

10、访问内存固定位置

int *ptr;

ptr = (int *) 0x67a9;

*ptr = 0xaa55;

将内存地址 0x67a9的值设置为 0xaa55

简写的方式为 *(int * const)(0x67a9) = 0xaa55;

11、中断(Interrupts)

__interrupt double compute_area(double radius)

{ double area = PI * radius * radius;

printf("/nArea = %f", area);

return area;

}

错误有哪些

1)中断函数没有返回值,中断函数没有参数

2)一般的处理器\编译器不允许在中断中进行浮点数运算。中断函数应该是尽可能快速而且有效的。

3)printf函数同第二点的原因。

12、读代码(Code examples)

void foo(void)

{ unsigned int a = 6;

int b = –20;

(a+b >6)?puts(“>6”)puts(“<=6”);

}

符号转换问题,当表达式中存在有符号数和无符号数时所有的操作数都自动转换成无符号类型。

13、评价代码

unsigned int zero = 0;

unsigned int compzero = 0xFFFF;

对于int类型不是16位的处理器来说,上面的代码是不正确的,正确的写法应该是

unsigned int compzero = ~0x0;

14、typedef 类型定义,声明一个已经存在的数据类型的同义字

#define dps struct s*

typedef struct s * tps;

想定义dps和tps是指向结构体 s的指针

tps 会好一些,更加接近类型的含义

比如说

dps p1,p2;   =  struct s* p1,p2; 只是将p1定义为指向结构体的指针,p2是实际的结构体

tps p3,p4;    =  定义两个结构体

15、单片机IO口的驱动能力

M0单片机的IO口可以配置为四种模式 1) input only with high impendence  2)push-pull 3)open-drain 4)Qausi bi-direction(准双端)

M0的IO口可以通过程序配置成高或者是低,电流很大程度上取决于引脚上的外接器件。

当管脚设置为低的时候,允许外不电路想引脚灌入电流,成为“灌电流”。当管脚设置为高的时候从单片机的引脚向外部输出电流,成为“ 拉电流”

可以通过查技术参考手册,找到最大灌电流,和最大拉电流。

如 Nuvoton NUC140最大灌电流和最大拉电流都是35mA(单一引脚)

当想驱动一个发光二极管的时候,可以使用拉电流方式也可以使用灌电流方式。都可以,但是需要注意的是,单片机的拉电流方式的驱动能力都是比较弱的,同时还要考虑到,单片机总的灌电流,拉电流最大值不能超过一定值,不然会对单片机的性能产生负影响。

如果外围设备比较多的话,可以使用管脚控制三极管开关,来对外围电路控制。

在准双向和推挽模式下,具有较好的灌电流能力

拉电流能力,所有的模式都比较弱。如果在开漏模式下,需要外接上拉电阻才具有驱动能力。(比如说I2C引脚需要加上拉)

16、系统时钟配置

这个其实没什么好说的,之前不理解,觉得还很麻烦,理解了觉得很简单。

需要系统时钟的有 系统总线 AHB systemtick 一般的外设

而系统时钟控制器的时钟信号来源为 外部晶振,内部振荡器

PLLFOUT是有外部4~24M或者内部22.1184M(M0)提供,如果设置了PLLFOUT,那么PLLFOUT可以为一些外设提供时钟,同时系统AHB时钟时钟,也可以提供给外设使用 名字叫HCLK

17、C语言字符串

定义一个字符串  char * s = “Hello World”;  自动加 ‘\0’

此时定义的是一个字符指针,指向的是一片连续的地址。如果在程序中有另外一个 字符指针 S2 指向的内容相同的字面量“Hello World”那么S和 S2指向的是同一个地址。

C语言中 字符串不需要用+号连接,这点同高级语言不同。

上面的S地址位于程序代码段,是只读的。C语言默认的是Const 类型。如果试图去操作  S[0] = ‘b';可以编译通过,但是无法执行。

如果想去改变这个字符串需要定义成 字符数组 char s[] = “hello world”;

这是的S是存放在程序指向的ram区,是可以更改的。内存空间会被自动回收。

数组: 这个字符串在这里 作为本地变量空间会被回收

指针:这个字符串不知道在哪里(程序代码区) 处理参数(我需要这样一个字符串作为参数,并且不会更改)

动态分配的空间 malloc函数分配的空间

char buffer[100] = “”; buffer 是一个字符串,并且 buffer[0] = ‘\0’

char buffer[] = “”; buffer长度为1

char **a;

定义一个指针,指向一个字符串的指针

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章