【STM32】基础知识 第五课 C 语言基础知识

【STM32】基础知识 第五课 C 语言基础知识

  • stdint.h 简介
  • 位操作
    • 寄存器位赋值
  • 宏定义
    • 带参数的宏定义
    • 条件编译
    • 头文件编译
    • 代码条件编译
    • extern 声明
  • 类别名 (typedef)
    • 结构体
  • 指针
    • 指针使用的常见问题
    • 代码规范

stdint.h 简介

stdint.h 是从 C99 中引进的一个标准 C 库的文件. 路径: “D:\MDK5.34\ARM\ARMCC\include”

【STM32】基础知识 第五课 C 语言基础知识_第1张图片

位操作

运算符 含义 运算符 含义
& 按位与 ~ 按位取反
| 按位或 << 左移
^ 按位异或 >> 右移

按位与:

num1 运算符 num2 结果
0 & 0 0
1 & 0 0
0 & 1 0
1 & 1 1

按位或:

num1 运算符 num2 结果
0 | 0 0
1 | 0 1
0 | 1 1
1 | 1 1

按位异或:

num1 运算符 num2 结果
0 ^ 0 0
1 ^ 0 1
0 ^ 1 1
1 ^ 1 0

按位取反:

num 运算符 结果
1001 ~ 0110
1100 ~ 0011
1010 ~ 0101
1111 ~ 0000

左移:

num 运算符 结果
10110011 <<2 11001100
11010010 <<3 10010000
10001010 <<4 10100000

右移:

num 运算符 结果
10110011 >>2 00101100
11010010 >>3 00011010
10001010 >>4 00001000

寄存器位赋值

uint32_t temp = 0;

给位 6 赋值为 0:

  1. temp &= 0xFFFFFFBF;
  2. temp &= ~(1<<6);

给位 6 赋值位 0:

  1. temp |= 0x00000010;
  2. temp |= 1>>6;

按位异或翻转位 6:

  1. temp ^= 0x00000010;
  2. temp ^=1<<6;

宏定义

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

格式:

#define 标识符 字符串
  • 标识符: 宏定义的名字
  • 字符串: 常数, 表达式, 格式串等

例子:

#define PI 3.1415926
#define HSE_VALUE 8000000U

带参数的宏定义

#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) 来构造宏定义, 这样不会受到大括号, 分号, 运算符优先级等的影响, 总是会按照你期望的方式调用运行.

例子:

// 定义
#define foo(x) bar(x); baz(x)

// 调用
foo(wolf);

// 宏扩展为
bar(wolf); baz(wolf); 

条件编译

让编译器只对满足条件的代码进行编译, 不满足条件的不参与编译!

指令 作用
#if 编译预处理条件指令, 类似 if
#ifdef 判断某个宏是否已被定义
#ifndef 判断某个宏是否未被定义
#elif 若前面的条件不满足, 则判定新的条件, 类似 else if
#else 若前面的件不满足, 则执行后面的语句, 类似 else
#endif #if, #ifdef, #ifndef的结束标志

头文件编译

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

代码条件编译

#if SYS_SUPPORT_OS
	code
#endif

extern 声明

放在函数 / 变量前, 表示此函数 / 变量在其他文件定义, 以便文件引用.

extern unit16_tg_usart_rx_sta;
extern void delay_us(unit32_t nus);

类别名 (typedef)

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

格式:

typedef 现有类型 新名字

例子:

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

类型别名应用:

Struct GPIO_TypeDef
{
	_IO uint32_t CRL;
	_IO uint32_t CRH;
	...
};
Struct GPIO_TypeDef gpiox
typedef struct
{
	__IO uint32_t CRL;
	__IO uint32_t CRH;
	...
}GPIO_TypeDef;
GPIO_TypeDef gpiox

结构体

由若干基本数据类型集合组成的一种自定义数据类型, 也叫聚合类型.

格式:

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

例子:

struct student
{
	char *name;  // 姓名
	int num;  // 学号
	int age;  // 年龄
	char group;  // 所在学习小组
	float score;  // 成绩
};

创建学生变量:

struct student student;
student.name = "我是小白呀";
student.num = 1;
student.age = 18;
student.group = "A";
student.score  = 99;

应用举例 (ST 源码, 使用类型别名)

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

指针

指针就是内存的地址, 指针变量是保存了指针的变量.

格式:

类型名 *指针变量名

例子:

char *p_str = "This is a test";
  • *p_str: 取 p_str 变量的值
  • &p_str: 取 p_str 变量的地址

【STM32】基础知识 第五课 C 语言基础知识_第2张图片

指针使用的常见问题

  1. 未分配内存就使用 (野指针)
  2. 越界使用

错误用法1 (未分配内存):

char *p_buf;
p_buf[0] = 100;
p_buf[1] = 200;
p_buf[2] = 300;

错误用法2 (越界使用):

uint9_t buf[5] = {1, 2, 3, 4, 5};
uint8_t *p_buf = buf;
p_buf[5] = 200;
p_buf[6] = 250;

代码规范

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

出处: 笔记摘自正点原子

你可能感兴趣的:(stm32,单片机,嵌入式硬件)