【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。

这里写目录标题

  • 1.stdint.h简介(了解)
  • 2.位操作(掌握)
    • 2.1给寄存器某个位赋值
  • 3.宏定义(掌握)
    • 3.1带参数的宏定义
  • 4.条件编译(掌握)
  • 5.extern声明 (掌握)
  • 6.类型别名(typedef)(掌握)
  • 7.结构体(掌握)
  • 8.指针(掌握)
  • 9.代码规范(熟悉)
  • 10.总结(了解)

1.stdint.h简介(了解)

  stdint.h 是从 C99 中引进的一个标准 C 库的文件,可以在MDK5的安装路径:D:\MDK5.34\ARM\ARMCC\include中找到。
  stdint.h 定义了很多类型别名,将有符号的char类型定义别名为int8_t等,使用此套别名有易于移植。
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第1张图片
  在MDK中需要配置才能支持使用S99标准,默认是勾选的
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第2张图片

2.位操作(掌握)

【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第3张图片
  只要相与的两位,有一位是0结果则是0;只要相或的两位,有一位是1结果则是1;只要相异或的两位不同,一位是0一位是1结果则为1;按位取反,0变成1,1变成0;如果左移,右边补0;如果右移,需要分有无符号位,无符号左边直接补0,有符号的话最左边的是符号位,0为正数,1为负数,正数左侧空出的补0,负数左侧空出的补1。
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第4张图片

2.1给寄存器某个位赋值

举个例子:uint32_t temp = 0;
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第5张图片
  如果将位6赋值1,一种方法就是,先将位6与0相与(&)清0,其余位为1,再用或的方式,将位6置一;方法2是将位6与1左移6位取反的值相与进行清0,然后再与1左移六位进行或运算。按位异或可用于某个位的翻转,将位6与1异或,位6本身为1将变成0,本身为0则变成1。
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第6张图片

3.宏定义(掌握)

  宏定义可以:提高效率、可读性、易改性,核心是替换

#define   标识符   字符串

标识符:宏定义的名字,变量一般为小写,为了区分宏定义和变量,标识符中的英文字母建议大写,标识符是一个临时的符号,不占用内存,宏定义属于在预处理过程中需要处理的代码,。
字符串:常数、表达式、格式串等

举例】:

#define     PI           3.14159
#define     HSE_VALUE    8000000U 

3.1带参数的宏定义

  下面的do-while语句中用了一个三目运算符,x?A:B,如果x成立,即非0,则返回A,否则返回B。

#define LED1(x)   do{  x ? \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)

  建议大家使用 do{ … }while(0) 来 构造宏定义,这样不会受到大括号、分号、运算符优先级等的影响,总是会按你期望的方式调用运行!

4.条件编译(掌握)

  条件编译也属于程序预处理阶段处理的代码,让编译器只对满足条件的代码进行编译,不满足条件的不参与编译!

【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第7张图片
举例1】:头文件编译,可以避免头文件被重复引用。

#ifndef 	_LED_H
#define 	_LED_H
#include "./SYSTEM/sys/sys.h"
code
#endif

举例2】:代码条件编译

#if   SYS_SUPPORT_OS
       code
#endif

5.extern声明 (掌握)

  放在函数/变量前,表示此函数/变量在其他文件定义,以便本文件引用。
用法举例

extern uint16_t g_usart_rx_sta;
extern void delay_us(uint32_t nus); 

6.类型别名(typedef)(掌握)

  为现有数据类型创建一个新的名字,或称为类型别名,用来简化变量的定义。
格式】:

typedef   现有类型   新名字

举例】:

typedef   unsigned  char 			uint8_t;
typedef   unsigned  short  int 		uint16_t;
typedef   unsigned  int 			uint32_t;

  以后定义unsigned char数据类型,就可直接用uint8_t来定义数据类型。
类型别名应用】:

Struct GPIO_TypeDef
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;};//定义结构体类型
Struct    GPIO_TypeDef    gpiox//定义结构体变量

  没有使用typedef定义结构体变量的格式:Struct+结构体名+变量名。使用typedef struct定义结构体类型,定义结构体变量时不用再写struct。

typedef struct
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;} GPIO_TypeDef;
GPIO_TypeDef    gpiox

7.结构体(掌握)

  由若干基本数据类型集合组成的一种自定义数据类型,也叫聚合类型。
【格式】:

struct   结构体名
{
          成员列表;
} 变量名列表(可选)

应用举例1】:

struct student
{
    char  	*name;		/* 姓名 */
    int     num;  		/* 学号 */
    int     age; 		/* 年龄 */
    char	group;  	/* 所在学习小组 */
    float  	score;  	/* 成绩 */
}stu1, stu2;
void main()
{
struct student stu3,stu4;
stu3.name = "张三";
stu3.num = 1; 
stu3.age = 18; 
stu3.group = 'A';
stu3.score = 80.9;
}

应用举例2】:ST源码,使用类型别名(摘自:stm32f1xx_hal_gpio.h

typedef struct
{
  uint32_t 	Pin ;		/* 引脚号 */
  uint32_t 	Mode ;		/* 工作模式 */
  uint32_t 	Pull ;      /* 上下拉 */
  uint32_t 	Speed ;		/* IO速度 */
} GPIO_InitTypeDef;

8.指针(掌握)

  指针就是内存的地址,指针变量是保存了指针的变量。
格式】:

类型名  * 指针变量名

应用举例】:

char * p_str = “This is a test!; 
*p_str:取p_str 变量的值,也就是‘T’
&p_str:取p_str变量本身的地址,而不是‘T’的地址,指针变量的地址是处理器最大位数,比如说32位,和数据类型无关。

应用举例】:
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第8张图片

uint8_t  buf[5] = {1, 3, 5, 7, 9}; 
uint8_t  * p_buf = buf;//取数组名首地址0x0002
*p_buf取指针变量地址上的值,也就是1
p_buf[0]将指针变量当数组用下标是0值为1
p_buf[1]值为3
p_buf++;指向的地址0x0002地址加1,变成0x0003,不能buf[++]
*p_buf取指针变量地址上的值,也就是3
p_buf[0]值为3,指针指向的地址第一个元素

  指针使用的2大最常见问题:1,未分配(申请)内存就用;2,越界使用。下面的左图定义指针变量并没有赋初始值,初始值为随机数,指向了一个随机的地址,可能指向一个真实的内存,也可能指向一个不真实存在的内存,指向真实地址可能编译过程中不会报错,运行也不会有问题,也可能指向关键参数地址,重新赋值操作会造成程序运行结果不正常,指向不真实的地址,会报内存错误。右图为越界使用,越界也可能不会报错,可能导致内存冲突。
【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第9张图片

9.代码规范(熟悉)

  正点原子做了代码规范,可以在路径:A盘 ->1,入门资料 -> 《嵌入式单片机 C代码规范与风格.pdf》找到。
规范的关键点

  1. 所有函数/变量名字非特殊情况,一般使用小写字母;
  2. 注释风格使用 doxgen 风格,除屏蔽外,一律使用 /* */ 方式进行注释;
  3. TAB 键统一使用 4 个空格对齐,不使用默认的方式进行对齐;
  4. 每两个函数之间,一般有且只有一个空行;
  5. 相对独立的程序块之间,使用一个空行隔开;
  6. 全局变量命名一般用 g_开头,全局指针命名一般用 p_开头;
  7. if、 for、 while、 do、 case、 switch、 default 等语句单独占一行,一般无论有多少行执行语句,都要用加括号: {}。

10.总结(了解)

【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。_第10张图片

你可能感兴趣的:(#,STM32-HAL库,stm32,c语言,代码规范,单片机,嵌入式)