# 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个字节中 的某一位或者 几位 ,但是又不想改变其它位原有的值,就可以使用 按位 运算符 进行操作

  • 假如我们 只需要 设置 第0bit0 的值为 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;
此文章已被阅读次数:正在加载...更新于

请我喝[茶]~( ̄▽ ̄)~*

YuHeShui 微信支付

微信支付

YuHeShui 支付宝

支付宝

YuHeShui 贝宝

贝宝