[应用方案] 函数指针的用法

[复制链接]
 楼主| heisexingqisi 发表于 2025-2-27 11:57 | 显示全部楼层 |阅读模式
实现思路
定义灯效函数:
每个灯效(如正向流水、反向流水、闪烁等)实现为一个独立的函数。

定义函数指针类型:
使用 typedef 定义一个函数指针类型,方便调用。

主循环调用函数指针:
在主循环中通过函数指针依次调用不同的灯效函数。

  1. #include "hc32f10x.h"

  2. // 定义函数指针类型
  3. typedef void (*LightEffectFunc)(void);

  4. // 延时函数
  5. void delay(u16 n)
  6. {
  7.     u16 i, j;
  8.     for (i = 0; i < n; i++)
  9.         for (j = 0; j < n; j++);
  10. }

  11. // 配置系统时钟
  12. void RCC_Configuration(void)
  13. {
  14.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  15. }

  16. // 配置 GPIO
  17. void GPIO_Configuration(void)
  18. {
  19.     GPIO_InitTypeDef GPIO_InitStructure;

  20.     // 配置 GPIOB 的 Pin_0 到 Pin_7 为推挽输出
  21.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
  22.                                   GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  23.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  // 推挽输出模式
  24.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度 50MHz
  25.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  26.     // 初始化时将所有 LED 熄灭
  27.     GPIO_Write(GPIOB, 0xFF); // 0xFF 表示所有引脚输出高电平(熄灭)
  28. }

  29. // 灯效 1:正向流水灯
  30. void LightEffect_Forward(void)
  31. {
  32.     for (int i = 0; i < 8; i++)
  33.     {
  34.         GPIO_WriteBit(GPIOB, GPIO_Pin_0 << i, Bit_RESET); // 点亮 LED
  35.         delay(500); // 延时
  36.         GPIO_WriteBit(GPIOB, GPIO_Pin_0 << i, Bit_SET);   // 熄灭 LED
  37.     }
  38. }

  39. // 灯效 2:反向流水灯
  40. void LightEffect_Backward(void)
  41. {
  42.     for (int i = 7; i >= 0; i--)
  43.     {
  44.         GPIO_WriteBit(GPIOB, GPIO_Pin_0 << i, Bit_RESET); // 点亮 LED
  45.         delay(500); // 延时
  46.         GPIO_WriteBit(GPIOB, GPIO_Pin_0 << i, Bit_SET);   // 熄灭 LED
  47.     }
  48. }

  49. // 灯效 3:闪烁灯
  50. void LightEffect_Blink(void)
  51. {
  52.     for (int i = 0; i < 3; i++) // 闪烁 3 次
  53.     {
  54.         GPIO_Write(GPIOB, 0x00); // 点亮所有 LED
  55.         delay(500);
  56.         GPIO_Write(GPIOB, 0xFF); // 熄灭所有 LED
  57.         delay(500);
  58.     }
  59. }

  60. // 灯效 4:交替闪烁
  61. void LightEffect_Alternate(void)
  62. {
  63.     for (int i = 0; i < 3; i++) // 交替闪烁 3 次
  64.     {
  65.         GPIO_Write(GPIOB, 0xAA); // 点亮奇数位 LED (0xAA = 10101010)
  66.         delay(500);
  67.         GPIO_Write(GPIOB, 0x55); // 点亮偶数位 LED (0x55 = 01010101)
  68.         delay(500);
  69.     }
  70. }

  71. int main()
  72. {
  73.     RCC_Configuration();    // 配置系统时钟
  74.     GPIO_Configuration();   // 配置 GPIO

  75.     // 定义函数指针数组
  76.     LightEffectFunc lightEffects[] = {
  77.         LightEffect_Forward,  // 正向流水灯
  78.         LightEffect_Backward, // 反向流水灯
  79.         LightEffect_Blink,    // 闪烁灯
  80.         LightEffect_Alternate // 交替闪烁
  81.     };

  82.     int effectCount = sizeof(lightEffects) / sizeof(lightEffects[0]); // 灯效数量

  83.     while (1)
  84.     {
  85.         // 依次调用不同的灯效函数
  86.         for (int i = 0; i < effectCount; i++)
  87.         {
  88.             lightEffects[i](); // 通过函数指针调用灯效函数
  89.             delay(1000);      // 灯效之间的延时
  90.         }
  91.     }
  92. }
代码说明
函数指针类型定义:

typedef void (*LightEffectFunc)(void); 定义了一个函数指针类型 LightEffectFunc,指向无参数、无返回值的函数。

灯效函数:

实现了 4 种灯效:

LightEffect_Forward:正向流水灯。

LightEffect_Backward:反向流水灯。

LightEffect_Blink:所有 LED 同时闪烁。

LightEffect_Alternate:奇数位和偶数位 LED 交替闪烁。

函数指针数组:

将灯效函数的地址存储在数组 lightEffects 中,方便依次调用。

主循环:

通过 for 循环依次调用函数指针数组中的灯效函数,实现花样流水灯效果。

运行效果
上电后,LED 会依次执行以下灯效:

正向流水灯。

反向流水灯。

所有 LED 闪烁。

奇数位和偶数位 LED 交替闪烁。

每种灯效执行完毕后,会延时 1 秒,然后切换到下一种灯效。

 楼主| heisexingqisi 发表于 2025-2-27 11:57 | 显示全部楼层
扩展功能
增加更多灯效:

可以继续添加新的灯效函数,并将其地址加入 lightEffects 数组。

随机灯效:

使用随机数生成器选择灯效函数,实现随机切换效果。

按键控制:

通过按键切换灯效,增加交互性。
yangjiaxu 发表于 2025-2-27 13:12 | 显示全部楼层
点灯其实要是玩的好,效果也是不错的,而且点灯确实锻炼逻辑思路
zerorobert 发表于 2025-4-5 21:01 | 显示全部楼层
函数指针是存储函数地址的变量,通过指针间接调用函数。
chenjun89 发表于 2025-4-5 21:32 来自手机 | 显示全部楼层
函数指针和指针函数要分清楚,函数指针是指函数的入口地址,指针函数是指函数返回的变量位指针。
jkl21 发表于 2025-4-8 09:38 | 显示全部楼层
函数指针数组可以存储多个函数的地址,常用于实现类似“跳转表”的功能。
robertesth 发表于 2025-4-8 11:09 | 显示全部楼层
在使用函数指针之前,总是检查它是否为NULL,以避免调用空指针。
Wxy8030 发表于 2025-4-8 12:01 来自手机 | 显示全部楼层
这个要顶一下
Wxy8030 发表于 2025-4-8 12:01 来自手机 | 显示全部楼层
这个要顶一下
cemaj 发表于 2025-4-8 14:10 | 显示全部楼层
可以将指向无参数函数的指针转换为指向有参数函数的指针,但反过来则不行。
hilahope 发表于 2025-4-8 17:13 | 显示全部楼层
函数指针的声明需要指定函数的返回类型和参数列表。
chenci2013 发表于 2025-4-9 19:55 | 显示全部楼层
回调函数是一种通过函数指针调用的函数。它允许在运行时动态地决定要执行的函数,常用于事件处理、库函数中等。
weifeng90 发表于 2025-4-9 22:13 来自手机 | 显示全部楼层
函数指针就是flash中函数代码的入口地址
1988020566 发表于 2025-4-9 23:06 | 显示全部楼层
可以创建一个函数指针数组,用于存储多个函数的地址
beacherblack 发表于 2025-4-10 02:06 | 显示全部楼层
通过合理使用函数指针,可以实现回调函数、多态行为、动态函数调用等功能。
wangdezhi 发表于 2025-4-10 14:17 | 显示全部楼层
函数指针可以作为参数传递给其他函数,实现回调函数的功能。
10299823 发表于 2025-4-10 15:59 | 显示全部楼层
函数指针的参数类型和返回类型必须与它所指向的函数完全匹配,否则会导致编译错误或未定义行为。
phoenixwhite 发表于 2025-4-10 17:59 | 显示全部楼层
能否将函数指针存储在结构体中?​
jkl21 发表于 2025-4-10 19:40 | 显示全部楼层
通过函数指针数组实现状态机的状态切换。
maudlu 发表于 2025-4-10 21:31 | 显示全部楼层
函数指针是C/C++中非常强大的特性,能够显著提高代码的灵活性和可扩展性。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

157

主题

2770

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部