函数是函数
指针是指针
指针函数是函数
函数指针是指针
函数指针的本质是指针,指针的本质是地址,函数指针指向的对象是某一个函数。
函数指针一般用作函数的参数,函数的参数是函数的四个要素之一,函数包括函数名,函数返回值,函数参数,函数体。假如我们写了一个函数经常被调用,比如再单片机中经常使用的I2C通信中经常使用的I2C起始信号,那我们就可以把我们实现好的起始信号函数的名字作为参数传递给某个函数,这个函数名字就可以赋值给一个函数指针变量。
比如我们声明一个指向整型的指针变量是不是要强调指针的类型是int 用 int *a; 就可以声明一个指针,并且知道声明的是int型的指针。
显然指向函数指针和指向某种数据类型的指针是有区别的,类似的当我们声明一个函数指针的时候需要交代指针指向的函数这个函数的返回值类型是什么样子的,函数的参数列表是什么样的。一句话概括就是不管是声明指针还是声明函数你都要把要声明的东西讲清楚。指针你要告诉我指向谁,是一个整型变量还是一个字符型变量,还是指向的是一个函数,如果指针指向的是函数那就是函数指针,那么再声明的时候你就要讲清楚函数的特征,这里特征就是函数的返回值类型和函数参数列表,当然你是声明函数指针那么指针的名字是必须的。
函数返回值类型 (*指针变量名)([形参列表]);
double (*pf)(int);
这里一定不能把double (pf)(int);中pf上的括号去掉,为什么?因为去掉了就变成另外一种含义
double (*pf)(int) //pf为声明的函数指针,指向一个返回值为double的函数
函数指针是指针 是一个指针变量指向一个函数
double *pf (int) //pf为声明的函数名字,函数的返回值为double型的指针。
指针函数是函数 是一个返回值为指针的函数
这种写法在函数调用的时候就非常方便,只需要把函数名字赋值给一个函数指针变量,然后把这些变量用结构体管理起来,通过结构体传参就可以实批量函数的操作。
typedef struct
{
void (*Init)(void);
void (*Disable)(void);
void (*SDAOutPut)(uint8_t pdata);
void (*SCLOutPut)(uint8_t pdata);
void (*SDAInputConfig)(void);
void (*SCLInputConfig)(void);
void (*SDAOutputConfig)(void);
void (*SCLOutputConfig)(void);
uint8_t(*ReadSDAInput)(void);
uint8_t(*ReadSCLInput)(void);
void (*Delay)(void);
uint8_t error;
}IIC_PIN;
void at24InfoInit(void)
{
AT24.Disable = at24c128_iicDisable;
AT24.Init = at24c128_iicInit;
AT24.SDAOutPut = at24c128_SDAOutPut;
AT24.SCLOutPut = at24c128_SCLOutPut;
AT24.SDAOutputConfig = at24c128_SDAOutputConfig;
AT24.SCLOutputConfig = at24c128_SCLOutputConfig;
AT24.SDAInputConfig = at24c128_SDAInputConfig;
AT24.SCLInputConfig = at24c128_SCLInputConfig;
AT24.ReadSDAInput = at24c128_ReadSDAInput;
AT24.ReadSCLInput = at24c128_ReadSCLInput;
AT24.Delay = at24c128_Delay;
IIC_Init(&AT24);
}
AT24是一个结构体,通过结构体引用可以给结构体成员变量赋值,赋值的函数有独特的功能比如这里它们就是存储器的一些操作函数
static void at24c128_iicInit(void)
{
printf("此函数作用是配置i2c引脚模式\r\n");
}
static void at24c128_iicDisable(void)
{
printf("此函数作用是把i2c关闭\r\n");
}
static void at24c128_SDAOutPut(uint8_t pdata)
{
uint8_t bit;
pdata ? (bit = 1) : (bit = 0);
printf("此函数作用是把i2c的数据线拉高或者拉低这里是%d\r\n",bit);
}
static void at24c128_SCLOutPut(uint8_t pdata) {
uint8_t bit;
pdata ? (bit = 1) : (bit = 0);
printf("此函数作用是把i2c的时钟线拉高或者拉低这里是%d\r\n",bit);
}
static void at24c128_SDAInputConfig(void) {
// gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
printf("此函数作用是把i2c的数据线设置成上拉输入如果已经设置开漏则NOP\r\n");
}
static void at24c128_SCLInputConfig(void) {
//gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
printf("此函数作用是把i2c的时钟线设置成上拉输入如果已经设置开漏则NOP\r\n");
}
static void at24c128_SDAOutputConfig(void) {
//gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
printf("此函数作用是把i2c的数据线设置成推挽输出如果已经设置开漏则NOP\r\n");
}
static void at24c128_SCLOutputConfig(void) {
//gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
printf("此函数作用是把i2c的时钟线设置成推挽输出如果已经设置开漏则NOP\r\n");
}
static uint8_t at24c128_ReadSDAInput(void) {
/*return gpio_input_bit_get(GPIOB, GPIO_PIN_7) ? 1 : 0;*/
printf("此函数作用是把i2c的数据线电平读出来\r\n");
}
static uint8_t at24c128_ReadSCLInput(void) {
/*return gpio_input_bit_get(GPIOB, GPIO_PIN_6) ? 1 : 0;*/
printf("此函数作用是把i2c的时钟线电平读出来\r\n");
}
static void at24c128_Delay(void)
{ // 4.7us
for (uint8_t i = 0; i < 15; i++)
{
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
//__NOP(); __NOP(); __NOP(); __NOP(); __NOP();
}
printf("此函数作用是产生4.7us的延时\r\n");
}