C语言操作寄存器和函数指针
创始人
2025-07-01 14:20:37
0

typedef函数指针类型

#include 
//函数指针类型别名
/*
	* 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)); //输出信息科技
	return0;
}

寄存器

有限存贮容量的高速存贮部件 。寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储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
{
    unsignedchar x : 3; //冒号后面的证书指定了该位段所占用的位的数目。
    unsignedchar y : 2;
    unsignedchar z : 1;
}ex0_t;
// 共同体位域
union example1
{
    unsignedchar x : 3;
    unsignedchar y : 2;
    unsignedchar z : 1;
}ex1_u;

位域大小原则 :整个结构体位域的总大小为最宽基本类型成员大小的整数倍。

位域基本都使用无符号类型。

位域注意

  • 结构体位域成员不能使用取址操作
  • 结构体成员不能够使用static修饰
  • 结构体位域成员不能使用数组。

不同的处理器,不同的编译器对位域的影响,位域虽然能够以位的形式操作数据,但是也被人们告知要慎重使用,原因在于不同的处理器结构,不同的编译器对于位域的一些特征会产生不同的结果。

处理器大端模式,小端模式的处理器也会对下面的结构体位域产生不一样的存储方式。

不同的编译器,结构体位域成员不同类型,不同的编译器对于位域会有不同的结果

当成员大小之和超过一个基本存储空间时,不同的编译器也会有不同的处理方式。

typedefunion
{
    unsignedchar Byte;
    struct
    {
        unsignedchar bit012 : 3;
        unsignedchar bit34  : 2;
        unsignedchar bit5   : 1;
        unsignedchar bit6   : 1;
        unsignedchar bit7   : 1;
    }bits;
}registerType;

存储0x0000 8000定义一个指针指向地址:

registerType *pReg = (register*)0x00008000;
// 使用位域寄存器进行赋值
pReg->bits.bit5 = 1;
pReg->bits.bit012 = 7;

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...