基于stm32嵌入式基础——指针(嵌入式中常用指针原理)
目录
一、引言
本文的内容的唯一目的:让小白尽快上手,初高中解题的关键就是“题型”,现在我将平时可能遇到的“题型”分享给大家。本文所写的函数,是以模块化形式,需要用户自己写main函数调用。
二、指针基础
1、同级赋值

可以理解为使用&升级指针,使用*降级指针。
/*跨级赋值*/
void lsy_point_test3 (void)
{
int *p;
int a;
/*跨级赋值的情况:p是指针而a是变量值*/
//p=a;
/*a升级成为地址(一级指针)*/
p=&a;
/*p降级成为0级指针*/
a=*p;
}
2、相关内存
/*指针实现操控地址后的变量达到间接访问,指针存放数据单元首地址占x位(64位电脑就是占64字节)*/
void lsy_point_test1 (void)
{
static int a;
static char b=0x10;
static char *p1;
static int *p2;
p1=&b;
p2=&a;
printf("%d\n",sizeof(a) );//4
printf("%d\n",sizeof(b) );//1
printf("%d\n",sizeof(p1) );//8
printf("%x\n",b);//打印变量b 66
printf("%x\n",p1);//打印指针变量p1,其实就是b的首地址 61fe0b
printf("%x\n",p2);//打印指针变量p2,其实就是a的首地址 61fe0c
printf("%x\n",*p1);//取出p指针指向的数据内容,间接访问 66
/*指针其实只需要知道首地址,以及数据单元大小就可以往下找*/
/*指针移动的数据宽度与其本身定义的数据类型有关,定义的是char一个一个(字节)向下移,定义的是int就是四个四个(字节)往下移*/
//p1++;
/*p++的情况*/
//printf("%x\n",p1);//61fe0f=61fe0b
//printf("%x\n",p2);//61fe10=61fe0c+4
/*让p1和p2指向同一个首地址*/
p1=p1+5;
p2++;
/*同时获得地址的数据*/
printf("%x\n",*p1);//这个为10,与其指向的数据类型(char)有关,显示一个字节
printf("%x\n",*p2);//这个为61fe10,与其指向的数据类型(int)有关,显示四个字节
}
搞清楚以下问题:
1、p++是如何移动的,和哪个数据类型有关,是和指向的变量的数据类型有关还是和创建的指针数据类型有关。
2、假如是int型那么一共有四个字节,假如只用到一个字节,那么可以自己试试打印出其他字节里存放的内容。(下文中直接访问物理地址中有提及)
三、嵌入式常见指针方案
1、使用指针传递参数
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
使用结构体指针作为参数,从而可以传递多个参数,而我们只需要提供一个首地址。
/*通过传入结构体首地址完成对以下参数的传输*/
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
GPIOC_BASE是一个16进制数需要强制转换成地址,这也是指针的一大功能——物理地址的访问,下面提供一个例子来加深理解。
/*********物理地址访问*********/
void test6(void)
{
int *a;
int b=0x35;
a=&b;
printf("第一次:%x\n",a);
a++;
printf("第二次:%x\n",a);
printf("61fde4:%x\n",*((int *)(0x61fde4)));
printf("61fde5:%x\n",*((int *)(0x61fde5)));
}
这里先打印出指针获得地址,再对地址强制转换然后取值得到具体地址里的值。
2、使用指针获得多个参数
在实际应用中,我们会通过串口通信联系多个设备,通过创建缓存区去获得多个数据。
void Send(const uint8_t *data,uint8_t length)
{
uint8_t i;
for (i = 0; i < length; i++)
{
SendByte(data[i]);//发送一个字节
}
}
这里先发送一个字节,将你想发送的数据一个字节一个字节的发送。
void recievedata(unsigned char *data,int count)
{
unsigned char i;
for (i = 0; i < count; i++)
{
/* code */
data[i]=airdata[i];
}
}
利用接收缓存区获取多个数据。
3、函数句柄
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
defaultTaskHandle是这个任务的句柄,其实就是指针函数的引用。接下来我们看看defaultTaskHandle是如何被创建的。
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
可以看到这个osThreadNew返回值是一个任务句柄,我们可以看看这个任务句柄的数据类型。
typedef void *osThreadId_t;
通过这条可以看到这个类型是void *。
osThreadId_t defaultTaskHandle;
因此defaultTaskHandle是一个void*类型。之后可以通过对返回的任务句柄来控制这个任务。

osThreadNew的定义里我们可以看到返回值包含了这个任务的许多信息,包括这个任务的name、id等等,因此这里的任务句柄就像是这个任务的身份证。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)