单片机学习中的模块化编程,例程:51单片机驱动LCD1602,开发软件:keil 您所在的位置:网站首页 51单片机中文编程 单片机学习中的模块化编程,例程:51单片机驱动LCD1602,开发软件:keil

单片机学习中的模块化编程,例程:51单片机驱动LCD1602,开发软件:keil

2024-03-21 06:41| 来源: 网络整理| 查看: 265

    在刚接触到单片机时,代码较短,单片机功能的实现函数都写在main.c一个文件。随着学习的深入,多模块的使用和代码量的增加使得单用一个.c文件显得程序很混乱。模块化编程的使用可增强代码的可读性,可移植性。这里以51单片机驱动LCD1602的为例讲解。

 一、知识储备---#ifndef

作用:防止头文件的重复包含和编译

定义

  #ifndef x

  #define x

  ...

  #endif

  这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种----条件编译。 C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。

  #ifndef x

  //先测试x是否被宏定义过

  #define x

  //如果没有宏定义下面就宏定义x并编译下面的语句

  ...

  #endif

  //如果已经定义了则编译#endif后面的语句

  条件指示符#ifndef检查预编译常量在前面是否已经被宏定义。如果在前面没有被宏定义,则条件指示符的值为真,于是从#ifndef到#endif之间的所有语句都被包含进来进行编译处理。相反,如果#ifndef指示符的值为假,则它与#endif指示符之间的行将被忽略。条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。

补充一些内容

  千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。

  还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:

  #ifndef

  #define

  ......

  #endif

  在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:LCD1602.h

  #ifndef __LCD1602_H_

  #define __LCD1602_H_

  ......

#endif

#ifndef xxx//如果没有定义xxx #define xxx//定义xxx #endif //结束如果 这个用法主要是在头文件中,主要是为了防止类重复的include,所以在类的头文件之前加上前面两个,用类名替代xxx,在最后加上最后一句。

 

了解更多:https://blog.csdn.net/qq_33658067/article/details/79443014

 

二、keil上的实现

1、创建工程,这里不做过多叙述。

2、工程分组,c文件的添加,按图示步骤进行。

3.头文件的编写及路径添加,LCD1602.h

#ifndef __LCD1602_H_ //检测是否被定义 #define __LCD1602_H_ //未定义则为初次调用该头文件,则定义该宏 #include "reg51.h" //51单片机特殊功能寄存器声明文件 #define LCD1602_DATAPINS P0 //管脚定义 sbit LCD1602_RS=P2^6; //管脚定义 sbit LCD1602_RW=P2^5; sbit LCD1602_E=P2^7; void LcdInit(void); //.c文件中的函数声明 void LCD_CLR(void); void LcdWriteCom(unsigned char com); void LcdWriteData(unsigned char dat); void LCD1602_SYB(unsigned char x,unsigned char y,unsigned char *str); void LCD1602_NUM(unsigned char x,unsigned char y,int a); void LCD1602_FLOAT(unsigned char x,unsigned char y,double dat); #endif //结束如果  

如对应c文件有全局变量且要在其它地方使用,可在#define 后声明该变量, 如 extern int val。

如在一些情况下管脚不对应,只需更改宏定义的管脚,很方便移植性强。

按以下步骤添加头文件路径。

4、C文件的编写,LCD1602.c

#include "reg51.h" //51单片机特殊功能寄存器声明文件 #include "LCD1602.h" //对应的头文件 #include "delay.h" //需用到延时函数 #include "stdio.h" //--------写命令 void LcdWriteCom(unsigned char com) { LCD1602_E = 0; LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_DATAPINS = com; LCD1602_E = 1; delay_12us(1); LCD1602_E = 0; delay_12us(1); } //--------写数据 void LcdWriteData(unsigned char dat) { LCD1602_E = 0; LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_DATAPINS = dat; LCD1602_E = 1; delay_12us(1); LCD1602_E = 0; delay_12us(1); } //--------清屏 void LCD_CLR(void) { LcdWriteCom(0x01);//清屏 delay_ms(5); } //--------初始化 void LcdInit(void) { LcdWriteCom(0x38);//设置为8总线,双行显示,5*10点阵字符 LcdWriteCom(0x0c);//开启显示,不显示光标 LcdWriteCom(0x06);//自左向右显示,显示内容不移动 LCD_CLR(); } //--------从x行y列坐标处开始显示字符串 void LCD1602_SYB(unsigned char x,unsigned char y,unsigned char *str) { unsigned char addr,i; if(x==1) addr = 0x00+y-1; else addr = 0x40+y-1; LcdWriteCom(addr+0x80);//设置显示地址 while(*str!='\0') { i++; LcdWriteData(*str++); } // while(i0;c--) for(b=142;b>0;b--) for(a=2;a>0;a--); } void delay_12us(unsigned char c) { unsigned char a; for(c;c>0;c--) for(a=4;a>0;a--); }

 

 

--By Young

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有