智能车制作

 找回密码
 注册

扫一扫,访问微社区

12
返回列表 发新帖
楼主: abigale001
打印 上一主题 下一主题

[软件类] 关于在IAR在例程之上添加自己的代码的多文件处理问题

[复制链接]

1

主题

12

帖子

0

精华

注册会员

Rank: 2

积分
129
威望
65
贡献
30
兑换币
40
注册时间
2018-5-11
在线时间
17 小时
11#
 楼主| 发表于 2018-8-4 09:25:36 | 只看该作者
日常上来看一眼大佬有没有解答
回复

使用道具 举报

0

主题

4

帖子

0

精华

注册会员

Rank: 2

积分
32
威望
20
贡献
10
兑换币
11
注册时间
2018-11-15
在线时间
1 小时
12#
发表于 2018-11-16 00:05:11 | 只看该作者
我也才开始做智能车,什么都不懂,前几天把我的菜单函数从主函数的源文件移出去时也遇到了好多问题。最后搞来搞去终于好了。其实你不会可以把.h文件空着,全部写到.c文件里。这样不会出错。
回复

使用道具 举报

0

主题

4

帖子

0

精华

注册会员

Rank: 2

积分
32
威望
20
贡献
10
兑换币
11
注册时间
2018-11-15
在线时间
1 小时
13#
发表于 2018-11-16 00:10:24 | 只看该作者
  1. #ifndef __MENU_H
  2. #define __MENU_H

  3. #include "common.h"
  4. #include "MK60_flash.h"

  5. #define SECTOR_NUM  (FLASH_SECTOR_NUM-1)

  6. extern uint8 func_index;

  7. extern int pid,speed,angle;

  8. //extern void(*current_operation_index)();

  9. extern uint8 mybit(int m);

  10. uint8 mybit(int m);

  11. void fun0();
  12. void fun1();
  13. void fun2();
  14. void fun3();
  15. void fun4();
  16. void fun5();
  17. void fun6();
  18. void fun7();
  19. void fun8();
  20. void fun9();
  21. void fun10();
  22. void fun11();
  23. void fun12();
  24. void menu();

  25. #endif
复制代码

  1. #include "menu.h"
  2. #include "include.h"

  3. int pid,speed,angle;
  4. uint8 func_index=0;
  5. void (*current_operation_index)();
  6. void (*current_operation)();
  7. typedef struct
  8. {
  9.         uint8_t current;
  10.         uint8_t up;
  11.         uint8_t down;
  12.         uint8_t enter;
  13.         void (*current_operation)();
  14. }key_table;

  15. key_table table[]=
  16. {
  17.         {0,1,1,1,(*fun0)},

  18.         {1,0,2,4,(*fun1)},
  19.         {2,1,3,5,(*fun2)},
  20.         {3,2,1,6,(*fun3)},

  21.         {4,7,8,1,(*fun4)},
  22.         {5,9,10,2,(*fun5)},
  23.         {6,11,12,3,(*fun6)},

  24.         {7,7,8,1,(*fun7)},
  25.         {8,7,8,1,(*fun8)},
  26.         {9,9,10,2,(*fun9)},
  27.         {10,9,10,2,(*fun10)},
  28.         {11,11,12,3,(*fun11)},
  29.         {12,11,12,3,(*fun12)},

  30. };
  31. ......
  32. void fun12()
  33. {
  34.         angle-=1;
  35.         OLED_ShowString(80,0," pid",12);
  36.         OLED_ShowString(80,12," speed",12);
  37.         OLED_ShowString(80,24,"*angle",12);
  38.         OLED_Showint(110,0,pid,mybit(pid),12);
  39.         OLED_Showint(110,12,speed,mybit(speed),12);
  40.         OLED_Showint(110,24,angle,mybit(angle),12);
  41.         OLED_Refresh_Gram();
  42. }

  43. void menu()
  44. {
  45.         if(key_check(KEY_2)==KEY_DOWN)
  46.         {
  47.                 func_index=table[func_index].up;
  48.                 OLED_Clear();
  49.                 current_operation_index=table[func_index].current_operation;
  50.                 (*current_operation_index)();
  51.                
  52.                 while(key_check(KEY_2)==KEY_DOWN)
  53.                 {
  54.                         DELAY_MS(20);
  55.                 }
  56.         }

  57.         if(key_check(KEY_8)==KEY_DOWN)
  58.         {
  59.                 func_index=table[func_index].down;
  60.                 OLED_Clear();
  61.                 current_operation_index=table[func_index].current_operation;
  62.                 (*current_operation_index)();
  63.                
  64.                 while(key_check(KEY_8)==KEY_DOWN)
  65.                 {
  66.                         DELAY_MS(20);
  67.                 }
  68.         }

  69.         if(key_check(KEY_4)==KEY_DOWN)
  70.         {
  71.                 func_index=table[func_index].enter;
  72.                 OLED_Clear();
  73.                 current_operation_index=table[func_index].current_operation;
  74.                 (*current_operation_index)();
  75.                
  76.                 while(key_check(KEY_4)==KEY_DOWN)
  77.                 {
  78.                         DELAY_MS(20);
  79.                 }
  80.         }

  81.         if(key_check(KEY_0)==KEY_DOWN)
  82.         {
  83.                 flash_erase_sector(SECTOR_NUM);                               
  84.                   if( 1 == flash_write(SECTOR_NUM, 0, pid) )
  85.                 {
  86.                         pid = flash_read(SECTOR_NUM,0,int);
  87.                 };
  88.                 if( 1 == flash_write(SECTOR_NUM, 8, speed) )
  89.                 {
  90.                         speed = flash_read(SECTOR_NUM,8,int);
  91.                 };
  92.                 if( 1 == flash_write(SECTOR_NUM, 16, angle) )
  93.                 {
  94.                         angle = flash_read(SECTOR_NUM,16,int);
  95.                 };

  96.                 OLED_ShowString(80,52,"saved",12);
  97.                 OLED_Refresh_Gram();
  98.                 while(key_check(KEY_0)==KEY_DOWN)
  99.                 {
  100.                         DELAY_MS(20);
  101.                 }
  102.        
  103.         }

  104.        
  105. }
复制代码

这是我从主函数源文件里出来写的menu.h和menu.c文件,当时什么都不懂,全局变量报错,反正各种报错......至少现在不报错了。。
回复

使用道具 举报

1

主题

12

帖子

0

精华

注册会员

Rank: 2

积分
129
威望
65
贡献
30
兑换币
40
注册时间
2018-5-11
在线时间
17 小时
14#
 楼主| 发表于 2018-11-25 16:40:55 | 只看该作者
浮白揽月 发表于 2018-11-16 00:05
我也才开始做智能车,什么都不懂,前几天把我的菜单函数从主函数的源文件移出去时也遇到了好多问题。最后搞 ...

好主意,下次试试
回复

使用道具 举报

0

主题

4

帖子

0

精华

注册会员

Rank: 2

积分
32
威望
20
贡献
10
兑换币
11
注册时间
2018-11-15
在线时间
1 小时
15#
发表于 2018-11-30 14:59:59 | 只看该作者
[转载]预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。
在C 语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。

  预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:

        指令              用途
         #                  空指令,无任何效果
         #include      包含一个源代码文件
         #define        定义宏
         #undef         取消已定义的宏
         #if               如果给定条件为真,则编译下面代码
         #ifdef          如果宏已经定义,则编译下面代码
         #ifndef        如果宏没有定义,则编译下面代码
         #elif            如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
         #endif         结束一个#if……#else条件编译块
         #error        停止编译并显示错误信息

  一、文件包含
        #include预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。标准C编译器至少支持八重嵌套包含。
        预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。这样就可以在多次包含同一个头文件时,通过给定编译时的条件来达到不同的效果。例如:

#define AAA
        #i nclude "t.c"
        #undef AAA
        #i nclude "t.c"

        为了避免那些只能包含一次的头文件被多次包含,可以在头文件中用编译时条件来进行控制。例如:
        /*my.h*/
        #ifndef MY_H
        #define MY_H
          ……
        #endif

        在程序中包含头文件有两种格式:
        #i nclude <my.h>
        #i nclude "my.h"
         第一种方法是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种方法是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。

二、宏
        宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换成宏定义时的值。宏最常见的用法是定义代表某个值的全局符号。宏的第二种用法是定义带参数的宏,这样的宏可以象函数一样被调用,但它是在调用语句处展开宏,并用调用时的实际参数来代替定义中的形式参数。
    1.#define指令
        #define预处理指令是用来定义宏的。该指令最简单的格式是:首先神明一个标识符,然后给出这个标识符代表的代码。在后面的源代码中,就用这些代码来替代该标识符。
宏表示的值可以是一个常量表达式,其中允许包括前面已经定义的宏标识符。例如:
            #define ONE 1
            #define TWO 2
            #define THREE (ONE+TWO)
        注意上面的宏定义使用了括号。尽管它们并不是必须的。但出于谨慎考虑,还是应该加上括号的。



3.#运算符
        出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。有时把这种用法的#称为字符串化运算符。例如:

            #define PASTE(n) "adhfkj"#n

            main()
            {
               printf("%s\n",PASTE(15));
            }
        宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。所以输出应该是adhfkj15。


    4.##运算符
        ##运算符用于把参数连接到一起。预处理程序把出现在##两侧的参数合并成一个符号。看下面的例子:

            #define NUM(a,b,c) a##b##c
            #define STR(a,b,c) a##b##c

            main()
            {
                printf("%d\n",NUM(1,2,3));
                printf("%s\n",STR("aa","bb","cc"));
            }

        最后程序的输出为:
                 123
                 aabbcc


三、条件编译指令
    条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。
    1.#if指令
        #if指令检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else、#elif或#endif为止;否则就不编译。

    2.#endif指令
        #endif用于终止#if预处理指令。

            #define DEBUG 0
            main()
            {
                #if DEBUG
                    printf("Debugging\n");
                #endif
                    printf("Running\n");
            }

        由于程序定义DEBUG宏代表0,所以#if条件为假,不编译后面的代码直到#endif,所以程序直接输出Running。
        如果去掉#define语句,效果是一样的。


    3.#ifdef和#ifndef
        #define DEBUG

         main()
        {
            #ifdef DEBUG
                printf("yes\n");
            #endif
            #ifndef DEBUG
                printf("no\n");
            #endif
        }
        #if defined等价于#ifdef; #if !defined等价于#ifndef


    4.#else指令
        #else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。#endif指令将中指上面的条件块。

        #define DEBUG

        main()
        {
            #ifdef DEBUG
                printf("Debugging\n");
            #else
                printf("Not debugging\n");
            #endif
                printf("Running\n");
       }



    5.#elif指令
        #elif预处理指令综合了#else和#if指令的作用。

        #define TWO

        main()
        {
            #ifdef ONE
                printf("1\n");
            #elif defined TWO
                printf("2\n");
            #else
                printf("3\n");
            #endif
        }
        程序很好理解,最后输出结果是2。

     6.其他一些标准指令
        #error指令将使编译器显示一条错误信息,然后停止编译。
        #line指令可以改变编译器用来指出警告和错误信息的文件号和行号。
        #pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。
回复

使用道具 举报

0

主题

4

帖子

0

精华

注册会员

Rank: 2

积分
32
威望
20
贡献
10
兑换币
11
注册时间
2018-11-15
在线时间
1 小时
16#
发表于 2018-11-30 15:00:53 | 只看该作者
【转载】如果说难题最难的部分是基本概念,可能很多人都会持反对意见,但实际上也确实如此。我高中的时候学物理,老师抓 的重点就是概念——概念一定要搞清,于是难题也成了容易题。如果你能分析清楚一道物理难题存在着几个物理过程,每一个过程都遵守那一条物理定律(比如动量 守恒、牛II定律、能量守恒),那么就很轻松的根据定律列出这个过程的方程,N个过程必定是N个N元方程,难题也就迎刃而解。即便是高中的物理竞赛难题, 最难之处也不过在于:
(1)、混淆你的概念,让你无法分析出几个物理过程,或某个物理过程遵循的那条物理定律;
(2)、存在高次方程,列出方程也解不出。而后者已经是数学的范畴了,所以说,最难之处还在于掌握清晰的概念;
  程序设计也是如此,如果概念很清晰,那基本上没什么难题(会难在数学上,比如算法的选择、时间空间与效率的取舍、稳定与资源的平衡上)。但是,要掌握清晰的概念也没那么容易。比如下面这个例子,看看你有没有很清晰透彻的认识。
普通浏览复制代码
//a.h
void foo();
//a.c
#include "a.h"  //我的问题出来了:这句话是要,还是不要?
void foo()
{
    return;
}
//main.c
#include "a.h"
int main(int argc, char *argv[])
{
   foo();
 return 0;
}
  
针对上面的代码,请回答三个问题:

a.c 中的 #include "a.h" 这句话是不是多余的?
为什么经常见 xx.c 里面 include 对应的 xx.h?
如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起?
(请针对上面3道题仔细考虑10分钟,莫要着急看下面的解释。 考虑的越多,下面理解的就越深。)

  好了,时间到!请忘掉上面的3道题,以及对这三道题引发出的你的想法,然后再听我慢慢道来。正确的概念是:从C编译器角度看,.h和.c皆是浮云,就是改名为.txt、.doc也没有大的分别。换句话说,就是.h和.c没啥必然联系。.h中一般放的是同名.c文件中定义的变量、数组、函数的 声明,需要让.c外部使用的声明。这个声明有啥用?只是让需要用这些声明的地方方便引用。因为 #i nclude "xx.h" 这个宏其实际意思就是把当前这一行删掉,把 xx.h 中的内容原封不动的插入在当前行的位置。由于想写这些函数声明的地方非常多(每一个调用 xx.c 中函数的地方,都要在使用前声明一下子),所以用 #i nclude "xx.h" 这个宏就简化了许多行代码——让预处理器自己替换好了。也就是说,xx.h 其实只是让需要写 xx.c 中函数声明的地方调用(可以少写几行字),至于 include 这个 .h 文件是谁,是 .h 还是 .c,还是与这个 .h 同名的 .c,都没有任何必然关系。

  这样你可能会说:啊?那我平时只想调用 xx.c 中的某个函数,却 include了 xx.h 文件,岂不是宏替换后出现了很多无用的声明?没错,确实引入了很多垃圾 ,但是它却省了你不少笔墨,并且整个版面也看起来清爽的多。鱼与熊掌不可得兼,就是这个道理。反正多些声明(.h一般只用来放声明,而放不定义,参见拙著 “过马路,左右看”)也无害处,又不会影响编译,何乐而不为呢?

翻回头再看上面的3个问题,很好解答了吧?

答:不一定。这个例子中显然是多余的。但是如果.c中的函数也需要调用同个.c中的其它函数,那么这个.c往往会include同名的.h,这样就不需要为声明和调用顺序而发愁了(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头)。有很多工程甚至把这种写法约定为代码规范,以规范出清晰的代码来。

答:1中已经回答过了。

答:不会。问这个问题的人绝对是概念不清,要不就是想混水摸鱼。非常讨厌的是中国的很多考试出的都是这种烂题,生怕别人有个清楚的概念了,绝对要把考生搞晕。


搞清楚语法和概念说易也易,说难也难。窍门有三点:
不要晕着头工作,要抽空多思考思考,多看看书;
看书要看好书,问人要问强人。烂书和烂人都会给你一个错误的概念,误导你;
勤能补拙是良训,一分辛苦一分才;
回复

使用道具 举报

1

主题

12

帖子

0

精华

注册会员

Rank: 2

积分
129
威望
65
贡献
30
兑换币
40
注册时间
2018-5-11
在线时间
17 小时
17#
 楼主| 发表于 2019-5-28 17:46:52 | 只看该作者
浮白揽月 发表于 2018-11-30 15:00
【转载】如果说难题最难的部分是基本概念,可能很多人都会持反对意见,但实际上也确实如此。我高中的时候学 ...

学到了!耶!谢谢你
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关于我们|联系我们|小黑屋|亿加合和智能车制作 ( 黑ICP备2022002344号

GMT+8, 2024-5-7 04:03 , Processed in 0.069465 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表