[开发工具] 使用STM32CubeIDE踩的小坑——在别的文件定义的函数无法在main.c里正常调用

[复制链接]
665|1
 楼主| xiaoqizi 发表于 2025-6-13 21:47 | 显示全部楼层 |阅读模式
事情原委
在Key.c和Key.h文件里,我参照了原子哥的按键扫描函数,有如下的程序片段:

key.h代码片段:
#ifndef HEY_H
#define KEY_H

#include "main.h"

//下面的方式是通过直接操作HAL库函数方式读取IO
#define KEY0        HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)  //KEY0按键PE4
#define KEY1        HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)  //KEY1按键PE3
#define KEY2        HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)         //KEY2按键PE2
#define WK_UP       HAL_GPIO_ReadPin(LEY_UP_GPIO_Port,LEY_UP_Pin)  //WKUP按键PA0

#define KEY0_PRES         1
#define KEY1_PRES        2
#define KEY2_PRES        3
#define WKUP_PRES   4

#define CONTINUE_PRESS     (uint8_t)1
#define NOT_CONTINUE_PRESS (uint8_t)0

uint8_t KEY_Scan(uint8_t mode);

#endif/*KEY_H*/



key.c代码片段:
#include "Key.h"

/****************************************************
* Function: Scan Keys handle function
* Usage:call it in while(1)
* Parameter:
*     mode = 1: support continuous press
*     mode = 0: Do not support continuous press
* Return Value: Key code(such as: KEY0_PRES)
* Notice: Handle priority: KEY0>KEY1>KEY2>WK_UP!
* *************************************************/
uint8_t KEY_Scan(uint8_t mode)
{
        //assert

    static uint8_t key_up = 1;     //按键松开标志
    if(mode == 1)
    {
            key_up = 1;    //支持连按
    }
    if(key_up && (KEY0 == 0 || KEY1 ==  0 || KEY2 == 0 || WK_UP == 1))
    {
            HAL_Delay(10000);

        key_up = 0;

        if(0 == KEY0)
                return KEY0_PRES;
        else if(KEY1==0)
                return KEY1_PRES;
        else if(KEY2==0)
                return KEY2_PRES;
        else if(WK_UP==1)
                return WKUP_PRES;
    }
    else if(KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && WK_UP == 0)
    {
            key_up = 1;
    }
    else
    {
            /*do nothing*/
    }
    return 0;   //无按键按下
}



main.c文件中的调用
/* USER CODE BEGIN Includes */
#include "Key.h"
/* USER CODE END Includes */


  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
          keyCode = KEY_Scan(NOT_CONTINUE_PRESS);
          ... ...
  }


编译报错现象

图片中可以看到编译器报错:没有定义这个函数!!!

67117684b70af99a7d.png

问题排查
头文件路径包含了吗?
从报错上看,没有说找不到头文件的问题。而我也确实包含了,下图:

88321684b70a915f2a.png

我的Key.c和Key.h在自己新建的文件夹下,上面可以看到已经包含了头文件路径。

我的函数定义、声明、调用完全一样吗?
如果我的函数定义和声明有一点点的不同,也会出问题。
不论是函数名还是参数,或者是返回值类型。
经过对比,完全一致!

再加个extern 函数声明试试?
在main.c加入:

/* USER CODE BEGIN 0 */
extern uint8_t KEY_Scan(uint8_t mode);
/* USER CODE END 0 */


再次编译仍旧报错!

还真是不如Keil好用……
代码没有问题,头文件路径也包含了,就是搞错说我的函数没有定义。

问题解决
在一筹莫展的时候,我想到一个问题:

我的Key.c有被编译吗?
在keil中不涉及这个问题,只要你写了一个.c函数,在工程目录下就会被编译。但在STM32CubeIDE里面也是这样的吗?
于是有如下设置:

64395684b709bf3608.png

之后编译就正常通过了。

问题延申——keil就不用管这个问题吗?
为了防止疑惑的朋友发问,我这里特意现场测试一下:

54711684b7092c3f74.png

新建test.h
#ifndef TEST_H
#define TEST_H
char test(void);
#endif


新建test.c
#include "test.h"

char test(void)
{
        char ii = 5;
        return ii;
}


在 main.c 测试一下
#include "test.h"
int main(void)
{
        char i = test();
        ... ...
}


编译成功

88771684b708987898.png

这里没有特意新建文件夹,再添加到工程中,增加头文件路径,只为证明Keil里不需要对.c文件设置编译。

代码补充的细节内容
为了让代码更加健壮,

打开宏定义USE_FULL_ASSERT
方法如下:

24782684b7082a2a0e.png

打开之后,有什么好处?

69922684b707d0d958.png

具体体现到函数入参上就是对参数进行一下判断,比如:

81290684b7078495f7.png

KEY_Scan函数入参增加断言

13791684b707368f8e.png

增加定义:

#define CONTINUE_PRESS     (uint8_t)1
#define NOT_CONTINUE_PRESS (uint8_t)0

#define IS_KEY_CONTINUOUS_MODE(MODE) (((MODE) == CONTINUE_PRESS) || ((MODE) == NOT_CONTINUE_PRESS))



如此就保证了,入参只有以上两种之一才会正确。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/smart_boy__/article/details/148239502

jf101 发表于 2025-7-7 22:32 | 显示全部楼层
其实一般就是头文件的引用很关键
您需要登录后才可以回帖 登录 | 注册

本版积分规则

130

主题

4344

帖子

3

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