> 文档中心 > 单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)


单片机零基础入门(9-1)实战:模块化编程—(以及无法显示头文件(.h)的解决方案)

本文作为单片机零基础入门(8-5)模块化编程的拓展和补充,比前面的单片机零基础入门(8-5)模块化编程更为详细。

一、回顾

上篇文章,单片机零基础入门(8-4)实战:单片机动态数码管消影—附源代码。
解决了问题:如果多个位置显示不同的数字,就会出现字影,而不是清晰的显示对应的数字。

本节内容主要是:C语言预编译、如何创建工程文件、如何添加模块化编程文件、没有显示头文件(.h文件)的解决方案。

文末有两个案例(含源代码和原理图):
案例1:利用模块化利用LED灯写一个流水灯(逐个引脚定义使用版)。
案例2:利用模块化利用LED灯写一个流水灯(使用一个P2搞定所有的引脚)。



二、问题:

每个人的编程习惯不一样,编程风格不一样,所以会导致有时候阅读代码很吃力。在实际工作过程中,代码维护起来也不方便,后期项目升级或者变更,也会造成更多时间的浪费。这时候,就需要一个可以让代码看起来更规范,更整洁的规则,他就是:模块化编程
当我们把代码根据模块来编写后,会大大降低阅读代码的人的困难,提高效率,也便于后期的维护或升级。

本节解决题目:把“Delay.c”文件独立出来写,在主函数里面调用一个“Delay.h”文件,既可实现点亮LED灯。实现模块化编程



二、传统编程和模块化编程:

传统方式编程:所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路。
模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等。



三、模块化编程的框图示例和详解

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

1、模块化编程的操作

模块化编程仅需要在工程中新建一个.c文件,将需要实现某个功能的模块代码(函数的主体)放到.c里面,将函数的声明放到对应的.h里面。最后调用时,仅仅需要调用.h文件声明一下就行了。


2、注意事项:

(1).c文件:函数、变量的定义。
(2).h文件:可被外部调用的函数、变量的声明。

(3)任何自定义的变量、函数在调用前必须有定义或声明(同一个.c)。
(4)使用到的自定义函数的.c文件必须添加到工程参与编译。
(5)使用到的.h文件必须要放在编译器可寻找到的地方(工程文件夹根目录、安装目录、自定义)。


3、C语言预编译

C语言的预编译以#开头,作用是在真正的编译开始之前,对代码做一些处理(预编译)

预编译 意义
#include 把REGX52.H文件的内容搬到此处
#define PI 3.14 定义PI,将PI替换成3.14
#define ABC 定义ABC
ifndef XX_H 如果没有定义_XX_H_
#endif 与#ifndef,#if匹配,组成“括号”

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

此外还有#ifdef,#if,#else,#elif,#undef等
注:

//例子1:#ifdef AAA int a=1#endif//如果定义了AAA,“int a=1”才会参与编译。
//例子2#define AAA  //定义AAA#ifdef AAA   int b=0//int b=0参与编译#endif//#define定义AAA,#ifdef判断(是否)定义了AAA,int b=0参与编译,#endif结束。


四、创建模块化文件步骤:

1、创建main.c文件

步骤1、创建新项目:

打开keil----创建新项目,点击创建新工程。

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤2、选择项目创建的文件夹

在文件名写项目名称(注意,不要填写中文)
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤3、选择单片机的芯片

选择对应单片机的芯片(开发板的芯片,我这里是AT89C51.),点击“OK”

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤4、展开项目

点击“Target 1”展开“Source Group 1”
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤5、新建.C文件

鼠标右击“Source Group 1”,点击“Add New Item toGroup “Source Group 1”…”(可以理解为:在“Source Group 1”的文件夹里面创建新文件)。

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤6、创建主函数

选择“.c”文件,命名为“main”,点击“Add”。
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤7、查看添加成功的主函数

查看main.c文件已经添加成功,在main.c中添加头文件(#include ),然后先把框架搭建好,查看编译是否有问题。
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

2、添加Delay.c和Delay.h文件

步骤同前面“创建main.c”。

2.1、添加Delay.c文件

步骤和创建main.c文件一致,就不一一赘述,详细步骤看截图。

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)


2.2、添加Delay.h文件

步骤也是和前面添加.c文件一样,就不一一赘述,但是,注意,这次创建的.h文件,所以创建时选择“Header File (.h)”文件

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

注意:
1、创建头文件时,需要选择“Header File (.h)”文件。
2、命名时,和对应的.c文件命名一致。


3、问题:无法显示头文件??不存在刚刚添加的.h怎么办?

问题:当完成2.2的步骤时,竟然意外发现Delay.h文件没有展示出来,到底怎么回事呢??如下图:
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

别怕!!!!
解决方案来啦:
点击烟花旁边的小魔方,再点击添加文件,找到此目录下的.h文件,确定既可。如下图:

步骤1、 点击工具栏的小魔方,点击添加文件(Add files)。如下图:

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)
步骤2、 文件类型选择"."也就是所有类型文件,最后选择需要添加的头文件“Delay.h”文件。如下图:

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

步骤3、 最后:查看列表,此时缺少的头文件显示在列表内了。如下图:

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

到此,又完美解决一个问题。



五、模块化编程实例:

1、头文件的编写:

Delay.h文件添加成功后,里面填写什么内容?代码如下:
Delay.h文件里面固定内容如下:

#ifndef _DELAY_H_#define _DELAY_H_// 此处添加对应.c的函数名既可。#endif

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)


2、Delay.c文件

Delay.c文件里面是起延迟作用的代码。如下图:

void Delay500ms()//@12.000MHz{unsigned char i, j, k;i = 4;j = 205;k = 187;do{do{while (--k);} while (--j);} while (--i);}

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)


3、完善Delay.h文件

在Delay.h文件里面添加对应.c文件的函数名既可。

#ifndef _DELAY_H_#define _DELAY_H_      // 此处添加对应的.c函数名既可void Delay500ms();  //.c里面的函数名#endif

4、在主函数中运用Delay.c的内容

4.1、Delay.h文件内容:

#ifndef __DELAY_H__#define __DELAY_H__      // 此处添加对应的.c函数名既可void Delay200us(unsigned int xms);#endif

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

4.2、Delay.c内容:

void Delay200us(unsigned int xms)//@12.000MHz{unsigned char i, j;while(xms--){i = 3;j = 82;do{while (--j);} while (--i);}}

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

4.3、main.c内容:
单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)



六、代码案例(2个):

前面的文章有详细写到如何看LED和数码管的引脚以及如何定义。忘记了可以跳转到“单片机零基础入门(8-2)实战:在数码管中实现显示一个数字–数码管知识的应用”和“单片机零基础入门(4):实现人生中的第一个流水灯(跑马灯)”文章中再巩固一下。

1、单片机原理图

1.1、原理图总览

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

1.2、原理图LED模块

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

1.3、原理图MCU部分

单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案)

2、使用模块化写一个流水灯。(源码)

2.1、第一种:单个独立LED引脚控制:

代码如下:

//案例1:模块化写一个流水灯(第一种:单个独立LED引脚控制://使用P2_0、P2_1、P2_2....P2_7控制逐个LED亮灭的过程。//led.c#include #include "Delay.h"#include "led.h"void led(){P2_0=0;Delay(500);P2_0=1;Delay(500);P2_1=0;Delay(500);P2_1=1;Delay(500);P2_2=0;Delay(500);P2_2=1;Delay(500);P2_3=0;Delay(500);P2_3=1;Delay(500);P2_4=0;Delay(500);P2_4=1;Delay(500);P2_5=0;Delay(500);P2_5=1;Delay(500);P2_6=0;Delay(500);P2_6=1;Delay(500);P2_7=0;Delay(500);P2_7=1;Delay(500);}/*-------------分隔符----------------------*///led.h#ifndef __LED_H__#define __LED_H__void led();#endif/*-------------分隔符----------------------*///Delay.c/*此处为延时函数用于单片机的延时操作。*/void Delay(unsigned int xms)//@12.000MHz{unsigned char i, j;while(xms--){i = 3;j = 82;do{while (--j);} while (--i);}}/*-------------分隔符----------------------*///Delay.h#ifndef __DELAY_H__#define __DELAY_H__      // 此处添加对应的.c函数名既可void Delay(unsigned int xms);#endif/*-------------分隔符----------------------*///main.c#include #include "Delay.h"#include "led.h"void main(){led();//调用LED控制函数}

2.2、第二种:八位1体LED引脚控制:

第二种为:单片机零基础入门(4):实现人生中的第一个流水灯(跑马灯)的知识。
八位一体,其实就是led.c文件中的定义方式和前面的引脚逐一定义的不同,其他代码都一样。

代码如下:

/*-------------分隔符----------------------*///案例1:模块化写一个流水灯(第二种:八位1体LED引脚控制:)//使用P2控制逐个LED亮灭的过程,无需详细到单个引脚。//led.c#include #include "Delay.h"#include "led.h"/*此处是单片机控制led灯的亮灭--流水灯操作*/void led(){  //1111 1110P2 = 0XFE;//亮第1个灯Delay(500);P2 = 0XFF;//1111 1101P2 = 0XFD;//亮第2个灯Delay(500);P2 = 0XFF;//1111 1011P2 = 0XFB;//亮第3个灯Delay(500);P2 = 0XFF;//1111 0111P2 = 0XF7;//亮第4个灯Delay(500);P2 = 0XFF;//1110 1111P2 = 0XEF;//亮第5个灯Delay(500);P2 = 0XFF;//1101 1111P2 = 0XDF;//亮第6个灯Delay(500);P2 = 0XFF;//1011 1111P2 = 0XBF;//亮第7个灯Delay(500);P2 = 0XFF;//0111 1111P2 = 0X7F;//亮第8个灯Delay(500);P2 = 0XFF;}/*-------------分隔符----------------------*///led.h#ifndef __LED_H__#define __LED_H__void led();#endif/*-------------分隔符----------------------*///Delay.c/*此处为延时函数用于单片机的延时操作。*/void Delay(unsigned int xms)//@12.000MHz{unsigned char i, j;while(xms--){i = 3;j = 82;do{while (--j);} while (--i);}}/*-------------分隔符----------------------*///Delay.h#ifndef __DELAY_H__#define __DELAY_H__      // 此处添加对应的.c函数名既可void Delay(unsigned int xms);#endif/*-------------分隔符----------------------*///main.c#include #include "Delay.h"#include "led.h"void main(){led();//调用LED控制函数}

特别注意:
问题:
有朋友问我, 这个P2的定义怎么来的?
例如:P2 = 0XFF为什么是灭;;P2=0X7F为什么是点亮第8个灯?

答:0XFF是十六进制,单片机的LED点亮方式为二进制,所以,0XFF转化为二进制为:1111 1111;以此计算:0X7F转换为二进制为0111 1111,所以得到第8个灯点亮。



本章节作为单片机零基础入门(8-5)模块化编程的拓展和补充,比前面的[单片机零基础入门(8-5)模块化编程]更为详细,且有实例,但是我在不同时间不同阶段写的文章。

下一篇:不定时更新,具体时间待定。



------人生在勤,不索何获!------



单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案) 创作打卡挑战赛 单片机零基础入门(9-1)实战:模块化编程(模块化两个案例含源码--以及无法显示头文件(.h)的解决方案) 赢取流量/现金/CSDN周边激励大奖