keil多文件组织方法
方法一
首先新建一个main.c的文件,加入到项目中,该文件中主要写main函数,然后,新建文件,如delay.c,编写内容之后,不要加入到项目,而是在main.c文件的开始写上#include“delay.c”,编译,你会发现delay.c已经在你main.c下面出现了,其他的函数同样的道理。下面是main.c文件
#include <reg52.h> //编译系统先编译该文件 #include"delay.c" //接着编译该文件 #include"display.c" //然后编译该文件 #include"timet0.c" //再编译该文件 main() { TMOD=0x01; EA=; ET0=; TR0=; TH0=(-)/; TL0=(-)%; ) { display1(); delay(); display2(); delay(); } LED1=; }
执行编译后,你发现所有的.c文件全部在main.c的子目录下,编译系统编译时候,按照给定的顺序进行编译,含有全局变量的文件要放到最前面,否则编译时候会出现没有定义变量的错误,如在display.c文件
unsigned char flag; //全局变量,其他函数中用 sbit LED1=P1^; //全局变量,其他函数中用 sbit LED2=P2^; //全局变量,其他函数中用 display1() { if(flag) LED1=~LED1; } display2() { delay1m(); LED2=; delay(); LED2=; delay(); }
定义的全局变量,会被各个文件用到。
其实这种算不上是多文件形式,而是单一文件的不同组织形式,但是却清晰了,便于阅读。这种组织也不必要要写头文件等。
方法二
首先新建一个 main.c 的文件,加入到项目中,该文件中主要写 main 函数,然后,新建文件,如 delay.c,编写内容之后,加入到项目,但是在 main.c 文件的开始不要写上#include“delay.c”, 其他的函数同样的处理。
要调用全局变量的方法:新建头文件,如:file.h,在头文件 file.h 中用写入:
#ifndef __file_H__ /*防止 graphics.h 被重复引用*/ #define __file_H__ extern void function(); //声明全局函数 #endif
再不管三七二十一,把函数体放在任何一个你写有#include“file.h”的 XX.C 文件中就可以了
方法三
通常一个C51程序工程按功能可以分成多个模块(文件), 一个模块通常由两个文档组成,一个头文件 *.h, 对模块中的数据结构和函数原型进行描述;另一个为C文件*.C , 对数据实例或对象进行定义,以及函数算法的具体实现,如I2C.C, ADC.C, DAC.C, LED.C 等,为了文件的调用,我们要为每个模块定义一个头文件,以I2C.C 来说,定义I2C.H。
#ifndef GRAPHICS_H /*防止graphics.h被重复引用*/ #define GRAPHICS_H #include <math.h> /*引用标准库的头文件*/ … #include “myheader.h” /*引用非标准库的头文件*/ … void Function1(…); /*全局函数声明*/ … class Box /*类结构声明*/ { … }; #endif
模块化的程序是黑盒,只向外提供接口(全局变量、外部函数),而不需要让调用者了解其中过程。尽可能地少定义接口,有利于保持模块的独立性(不需要让使用者知道的内部函数与静态全局变量,不需要在H文件中给出,以避免使用者疑惑)在需要调用此模块的文件中写入include语句。一个好的工程,H文件的组织是很清晰的,只看H文件就能够写主程序调用相应的C模块。
头文件的格式如下(I2C.H为例):
/********************************************************************/ #ifndef I2C_H /*是否没有定义过 "I2C_H”, 防止重定义*/ #define I2C_H /*定义"I2C_H" */ .......... bit SetSDA ( bit Up_Down ); bit SetSCL ( bit Up_Down ); #endif /********************************************************************/
I2C.C格式如下:
/**********************************************************************/ #include < stdio.h > #include "I2C.h" void SendByte ( uchar c ); /*内部函数在.H 头文件中不描述*/ bit SetSDA ( bit Up_Down) { .......... }; bit SetSCL ( bit Up_Down) { .......... }; /**********************************************************************/
另外一种写法:
/*=================================================*/ #ifndef I2C_H #define I2C_H .......... exten bit SetSDA ( bit Up_Down ); exten bit SetSCL ( bit Up_Down); #endif /*=================================================*/
I2C.C格式如下:
/*========================================================*/ #include<stdio.h> void SendByte(uchar c); /*内部函数在.H 头文件中不声明*/ bit SetSDA (bit Up_Down) { .......... }; bit SetSCL (bit Up_Down) { .......... }; /*========================================================*/
方法四
首先,我们需要一个新文档,这个文档的建立有两种方法(以 delay1s 函数为例)。第一种,在工程目录下建立一个 delay1s.txt 然后将其改名为 delay1s.h。因为都是同编码的所以不会出现乱码,然后在工程中将其打开。第二种方法是直接在工程中新建一个文档,然后保存的时候将名字保存为 delay1s.h 即可。如果是需要添加很多文件的话建议使用第一种方法,这是个人建议。其次,我们需要编写 delay1s.h 这个文件的内容,其内容如下:
#ifndef _DELAY1S_H_ #define _DELAY1S_H_ void delay1s(); //延时函数 #endif
这个是头文件的定义,作用是声明了 delay1s()函数,因为如果在别的函数中,我们需要用到 delay1s()函数的话,若不事先声明则在编译的时候会出错。对于#ifndef……#define……#endif;这个结构大概的意思就是说如果没有定义(宏定义)一个字符串,那么我们就定义它,然后执行后面的语句,如果定义过了那么就跳过不执行任何语句。
关于为什么要使用这么一个定义方法,比如在 led_on()函数中我们调用了 delay1s()函数,然后在 main()函数中我们也调用了 delay()函数,那么,在 led_on()函数中我就就要包含头文件 delay1s.h,然后在 main()函数中也要包含 delay1s.h,若主函数中我们调用过 led_on(),那么在编译的时候,遇到 delay1s()和 led_on()的时候就会对 delay1s.h 进行两次解释,那么就会出现错误。若有以上预处理命令的话,那么在第二次的时候这个_DELAY1S_H_已经被定义过了,那么就不会出现重复定义的问题。这就是它的作用。但是注意,在编译器进行编译的时候头文件不参与编译。
再次,我们建立一个 led_on.h,起代码内容如下:
#ifndef _LED_ON_H_ #define _LED_ON_H_ void led_on(); //灯闪烁 #endif
作用同 delay1s.h,不理解的话可以再看一下上面的解释。
最后,将我们上次说的三个函数补充完整。
在 led_on()函数中,我们用到了 51 单片机的一些寄存器的定义,所以我们要包含 reg52.h,而且我们用到了delay1s()函数,所以我们要包含 delay1s.h,故 led_on()函数的代码如下:
#include <reg52.h> #include “delay1s.h” //注意这里没有分号 void led_on() { P0=0x00; delay1s(); P0=0xff; delay1s(); }
Main 函数的代码如下:
#include <reg52.h> #include “delay1s.h” void main() { led_on(); delay1s(); //在这里其实只有第一句就可以了,这句是不必要的 led_on(); //这也是不必要的 }
在这个函数中,为了再次说明一下#ifndef……#define……#endif 这个结构的定义,大家可以把所有的.h 文件中的这个结构去掉,然后编译一下看一下效果。
到这里相信大家对于这种模块化的写法就有大概的了解了,如果我们想添加新功能的时候,比如我们要添加一个流水灯的功能,那么,我们只需要增加一个 led_circle.c 和 led_circle.h,然后按照上述步骤添加进工程即可,程序的其他部分不需要任何改动。显然这是很方便的。其实函数的声明可以使用 extern 关键字,C 语言中默认都是这个类型的,所以可以不用写。
keil多文件组织方法的更多相关文章
- Keil的使用方法 - 常用功能(一)
Ⅰ.概述 学习一门软件的开发,开发工具的掌握可以说尤为重要.由于Keil集成开发工具支持多种MCU平台的开发,是市面上比较常见的,也是功能比较强大一款IDE.所以,对于大多数人说,选择Keil几乎是单 ...
- Keil的使用方法(汇总)
推荐 分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来! http://www.captainbed.net/strongerhuang 软件的开发 ...
- Keil的使用方法 - 常用功能(二)
Ⅰ.概述 上一篇文章是总结关于Keil使用方法-常用功能(一),关于(文件和编译)工具栏每一个按钮的功能描述和快捷键的使用. 我将每一篇Keil使用方法的文章都汇总在一起,回顾前面的总结请点击下面的链 ...
- 在实际项目开发中keil的调试方法
转载2015-06-14 20:23:04 一.在keilc的调试状态下,如何观察各个片内外设的运行状态?如何修改它们的设置? 在调试状态下,点击Peripherals菜单下的不同外设选项命令,就会 ...
- Keil出错解决方法
1.安装KEIL5后创建工程后出现这个报错 解决方法:打开下图目录的文件. Keil.STM32F1xx_DFP.pdsc文件是只读文件,必须将只读属性取消. 如下图所示,注释掉红色圆圈的哪一行,保存 ...
- Keil共存的方法 - Keil MDK兼容Keil C51,实操可行
记录一下成功使Keil MDK和Keil C51共存的过程! 之前一直用Keil C51开发,最近需要用到ARM9内核的IC,就需要Keil C51和Keil MDK共存.看了一下网上几个教程,方法大 ...
- Keil(MDK-ARM)使用教程(一)_界面+菜单
Ⅰ.概述 今天总结Keil(MDK-ARM)界面和菜单相关的内容,详情请往下看. 关于Keil的下载.安装和新建工程我已将在前面做了详细的总结,不懂的可以参考我博客里面相关的文章.该文章是在新建好工程 ...
- stm32新建工程详细步骤
记得好早以前为了建一个keil的工程折腾了好久,在这里写写基本的Keil工程创建方法,以防自己以后再忘记: 新建工程 保存工程 选择器件 在这边新建文件夹,然后就是添加程序代码到里面去了.其中一些文件 ...
- 下位机多个".c, .h"文件的相互包含及排版
一.背景: 自从接触单片机编程以来,由于工作上的需要,不可避免的时常会接手别人的代码,但常常由于上一位同事的编码随意性有点大,导致可读性非常的差,有时候不得不完全舍弃原有代码,推倒重来,无形中增加了工 ...
随机推荐
- Linux学习笔记总结--memcached配置
Memcached是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等.简单的说就是将数据调用到 ...
- Hibernate 配置派生属性
在持久化类中,有些属性在表中没有对应的字段,可以在映射文件中设置派生属性. 比如在一个订单中有多个商品的价格,但没有计算总的价格,可以在持久化类中增添一个统计总价格的属性,在映射文件中配置一些信息. ...
- [学习笔记]设计模式之Adapter
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 Adapter(适配器)模式主要解决接口不匹配的问题.为此,让我们要回到最初Builder模式创建平行世界时,白雪公主和小霍比特人的谜 ...
- CocoaPods 原理分享及遇到的问题改进
cocoapods 原理分享及问题阐述 cocoapods 管理私有工程,需要两个git 仓库, repo 仓库,保存podspec 文件,告诉我们项目从哪来, 项目 仓库,保存工程文件,告诉我们引用 ...
- spring+hibernate+jpa+Druid的配置文件,spring整合Druid
spring+hibernate+jpa+Druid的配置文件 spring+hibernate+jpa+Druid的完整配置 spring+hibernate+jpa+Druid的数据源配置 spr ...
- springMvc解决json中文乱码
springMvc解决json中文乱码 springMvc解决json中文乱码,springMvc中文乱码,spring中文乱码 >>>>>>>>> ...
- 雷鸟(Thunderbird)收取Gmail出错,收到警告邮件
如题,每次打开thunderbird都会收到以下提醒邮件,后来发现,只要将thunderbird中和google服务有关的插件卸载掉就可以了 We prevented the sign-in atte ...
- 浅谈C#关于AOP编程的学习总结
难得在这样一个节日里给写出一篇博客,却没有佳人相约,没办法,这就是一个程(dan)序(shen)猿(gou)的真实生活情景,每天除了coding还是coding.唉..污染各位看官的眼了.好吧,进入正 ...
- Fragment的生命周期和Activity之间的通信以及使用
Fragment通俗来讲就是碎片,不能单独存在,意思就是说必须依附于Activity,一般来说有两种方式把Fragment加到Activity,分为静态,动态. 静态即为右键单击,建立一个Fragme ...
- SQL使用存儲過程訪問不同服務器
用openrowset连接远程SQL或插入数据 --如果只是临时访问,可以直接用openrowset --查询示例 select * from openrowset('SQLOLEDB', 'sql服 ...