• 嵌入式C知识点总结


    在网上看到很多嵌入式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;
        __IO uint32_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”;  自动加 ‘’

    此时定义的是一个字符指针,指向的是一片连续的地址。如果在程序中有另外一个 字符指针 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] = ‘’ 

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

    char **a;

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

  • 相关阅读:
    Sitecore 9 为什么数据驱动的组织选择它
    Sitecore 个性化
    Sitecore 9 您应该了解的所有新功能和变化
    Sitecore客户体验成熟度模型之旅
    Sitecore 8.2 工作流程
    sitecore-多变量测试与A / B测试概念论述
    sitecore
    cesium1.65api版本贴地贴模型标绘工具效果(附源码下载)
    leaflet结合geoserver利用WFS服务实现图层新增功能(附源码下载)
    openlayers6实现webgl点图层渲染效果(附源码下载)
  • 原文地址:https://www.cnblogs.com/-liszt/p/3887285.html
Copyright © 2020-2023  润新知