# typedef 函数指针类型
#include <stdio.h> | |
// 函数指针类型别名 | |
/* | |
* int 函数返回值 | |
* (int,int)函数参数,两个参数 int,int | |
* *PTP_TO_FUNC 函数指针,指向函数的指针 | |
*/ | |
typedef int (*PTR_TO_FUNC)(int, int); | |
/* | |
为数组定义别名与函数指针类型别名类似 | |
[4] 数组各属 | |
PTR_TO_ARR 指向数组的名,其数组个数与参数个数相同 | |
在使用是当成一种类型,在为其赋值时需要重新为其添加值 | |
*/ | |
typedef char(*PTR_TO_ARR)[10]; | |
// 实现函数体 | |
int max(int x, int y) | |
{ | |
return x > y ? x : y; | |
} | |
int main(void) | |
{ | |
// 定义数组,等待指向 | |
char str[3][10] = { | |
"嘿嘿", | |
"信息科技", | |
"有限公司" | |
}; | |
// PTR_TO_ARR 结构体指针,仍需要定义别名 | |
PTR_TO_ARR arr = str[1]; | |
// 指向函数 | |
PTR_TO_FUNC func = max; | |
printf("max(6,3): %d\n", (*func)(6, 3)); | |
printf("str[1]: %s\n", (*arr)); // 输出信息科技 | |
return 0; | |
} |
# 寄存器
有限存贮
容量的高速存贮
部件 。 寄存器的功能时存储二进制代码
,它是由具有存储功能
的触发器
组合起来构成的。一个触发器可以存储1位
二进制代码,故存放n位
二进制代码的寄存器
,需要n个触发器
来构成。
# 寄存器分类
基本
寄存器 : 只能并行
送入数据,也只能并行
输出。移位寄存器
中的数据可以在移位脉冲作用下
依次逐位右移
或左移
,数据既可以并行输入
,并行输出
,也可以串行输入
,串行输出
,还可以并行输入
,串行输出或串行输入,并行输出,灵活
,用途广泛
。
# 使用
在
嵌入式
编程中,常常需要对一些寄存器
进行配置
,有的情况下需要改变一1个字节中
的某一位或者几位
,但是又不想改变其它位原有的值,就可以使用按位
运算符进行操作
- 假如我们
只需要
设置第0
位bit0
的值为1时
, 要保持其它位
不发生
变化。
TEST = 0x01 |
此方式如果
高7位没有
使用,就不会有
影响,但是如果高7位
正在被使用
,那么就会发生错误
。
与运算
: 对于二进制位
操作,不管原值是0还是1
,它跟0
进行&与
运算,得到的结果都是0
,而和1
进行&运算
,将保持原来的值不变
或运算
: 不管该位原来的值是0
还是1
,它跟1
进行|
运算,得到的结果都是1
,而跟0
运算,将保持原来的值不变
。`
- 可以使用
或运算
TEST = TEST | 0x01; | |
// 在实际中常用 | |
TEST |= 0x01; |
- 给
Test
的低4位
清0
,高四位
保持不变
TEST &= 0xF0; // 使用十六进制 |
此方法
在单片机中
经常使用,
- 先对需要设置的位用
&
操作符进行清零
操作- 然后用
|
操作符设置值,
- 改变
GPIOA
的状态,先对寄存器
的值进行清零操作,然后根据需要设置的值进行|
或运算
GPIOA->CRL &= 0XFFFFFF0F; // 将第 4~7 位清零 | |
GPIOA->CRL &= 0X00000040; // 设置相应的值,不改变其他位的值 |
# 移位提高可读性
GPIOx->BSRR = (((uint32_t)0x01) << pinpox); // 将 0x01 左移 pinpox 位, |
通过
左移
而不是直接设置一个固定的值
: 为了提高代码
的可读
性,直接就知道修改了第几位
GPIOA->ODR |= 1<<5; //PA.5 输出高,其它位不变 |
# 设置某位为 0
# 简单操作
TIMx->SR = 0xFFF7; // 此方法仍然影响可读性, |
# 库函数
TIMx -> SR = (uint16_t)~TIM_FLAG; |
# TIM_FLAG
定义
设置
SR
的第三位为 0
时即可设置为
TIMx->SR = (uint16_t)~TIM_FLAG_CC3;
#define TIM_FLAG_Update ((uint16_t)0x0001) | |
#define TIM_FLAG_CC1 ((uint16_t)0x0002) | |
#define TIM_FLAG_CC2 ((uint16_t)0x0004) | |
#define TIM_FLAG_CC3 ((uint16_t)0x0008) | |
#define TIM_FLAG_CC4 ((int16_t)0x0010) | |
#define TIM_FLAG_COM ((uint16_t)0x0020) | |
#define TIM_FLAG_Trigger ((uint16_t)0x0040) | |
#define TIM_FLAG_Break ((uint16_t)0x0080) | |
#define TIM_FLAG_CC1OF ((uint16_t)0x0200) | |
#define TIM_FLAG_CC2OF ((uint16_t)0x0400) | |
#define TIM_FLAG_CC3OF ((uint16_t)0x0800) | |
#define TIM_FLAG_CC4OF ((uint16_t)0x1000) |
# 位域
位域:或称之为
位段
,英文表达式Bit field
是一种数据结构,可以把数据以位元的形式紧凑
的存储,并允许程序员对此结构进行位元
进行操作。优势:
- 可以使数据单元
节省存储空间
- 位段可以很方便地访问一个整数值的部分内容从而
简化程序源代码
。位域可以分为
两大类
,一个是结构体位域
,一个是共同体位域
,由于共同体和结构体两者在定义上的形式都是相同的,从位域的定义形式上看,两者也基本都是相同的。
struct 位域结构体 | |
{ | |
类型说明符 位域名 : 长度; | |
}结构体变量名; | |
// 结构体位域 | |
struct example0 | |
{ | |
unsigned char x : 3; // 冒号后面的证书指定了该位段所占用的位的数目。 | |
unsigned char y : 2; | |
unsigned char z : 1; | |
}ex0_t; | |
// 共同体位域 | |
union example1 | |
{ | |
unsigned char x : 3; | |
unsigned char y : 2; | |
unsigned char z : 1; | |
}ex1_u; |
位域大小
原则 : 整个结构体位域的总大小
为最宽
基本类型成员大小
的整数倍
。
位域
基本都使用无符号类型
。
# 位域注意
- 结构体位域成员
不能
使用取址操作
- 结构体成员
不能
够使用static修饰
- 结构体
位域
成员不能使用数组
。
不同的处理器
,不同的编译器
对位域的影响,位域
虽然能够以位
的形式操作数据,但是也被人们告知要慎重
使用,原因在于不同的处理器
结构,不同的编译器对于位域的一些特征会产生不同的结果。处理器
大端模式
,小端模式
的处理器也会对下面的结构体位域
产生不一样
的存储方式。
不同的编译器
,结构体位域
成员不同类型
,不同的编译器对于位域会有不同的结果当
成员大小之和超
过一个基本存储空间
时,不同的编译器也会有不同的处理方式
。
typedef union | |
{ | |
unsigned char Byte; | |
struct | |
{ | |
unsigned char bit012 : 3; | |
unsigned char bit34 : 2; | |
unsigned char bit5 : 1; | |
unsigned char bit6 : 1; | |
unsigned char bit7 : 1; | |
}bits; | |
}registerType; |
存储
0x0000 8000
定义一个指针指向地址
registerType *pReg = (register*)0x0000 8000; | |
// 使用位域寄存器进行赋值 | |
pReg->bits.bit5 = 1; | |
pReg->bits.bit012 = 7; |