c++程序设计_基于proteus的51单片机开发实例30-模块化程序设计

1. 基于proteus的51单片机开发实例30-模块化程序设计

1.1. 实验目的

9e8d481575e0e08355d4ff91234d6965.png

模块化程序设计

不知不觉我们的51单片机开发实例已经进行到第三十篇了,是时候进行一个总结和反思了,总结什么?反思什么呢?我们先从程序结构开始吧。

总结在前面的29个例子中的程序,我们会发现:所有的程序都在一个main.c文件中,第一个程序只有不到20行,电脑屏幕上直接能够从头看到尾,这个程序看起来非常直观,所有程序语句都是一目了然的。随着学习的深入,我们编写的程序是越来越复杂了,程序的长度是疯狂地增加。到了第29个实例,我们的程序量已经接近500行了,假设我们要找最后一个函数的内容,那就要用鼠标拨拉好一会才能找到这个函数,是不是会有“好长啊”的感慨?

更为致命的是,我们这个程序中既有延时程序、又有液晶显示程序、还有DS18B20的读写程序。所有这个程序都挤在一个main.c文件中,即使我们已经按照延时、显示、读写进行了划分,整体感觉是不是有些乱?

现在我们看看DS18B20学习实验的第三个程序,这个程序里面有很多函数,这些函数的声明和定义在整个程序里面占了很大的比例。我们在编写和使用这些函数的时候,需要不停的翻找相关的程序部分。显得很麻烦。而且整个程序显得有些乱。那么能不能把程序精简一下,能不能把具有相关功能的函数放在一起,能不能向我们使用头文件的时候,直接使用一个包含命令就把一些相关功能包含到程序里,而我们在程序里只要调用我们用到的函数就能够实现我们想要达到的目的呢?

答案是肯定的!

那么该怎么办?今天我们就学习一下模块化程序设计,把程序进行合理的规划!

本实例的目的:了解模块化程序设计的思路和方法。

1.2. 设计思路

本实例的设计思路是:将《基于proteus的51单片机开发实例29-单总线DS18B20的读写》中的程序代码按照延时功能、LCD1602液晶显示功能、DS18B20的读写控制功能这三个部分,使用模块化程序设计的方法,将这三个部分分别封装为三个.c和.h文件,然后在main.c文件中使用宏定义语句调用。从而完成模块化程序设计。

0e50da0463f6d5f3e531b2a6adce9d77.png

模块化程序设计

1.3. 基础知识

现在我们看看《基于proteus的51单片机开发实例29-单总线DS18B20的读写》中的程序代码,这个程序里面有很多函数,这些函数的声明和定义在整个程序里面占了很大的比例。我们在编写和使用这些函数的时候,因为很多函数都不是独立,需要不停的翻找相关的程序部分。显得很麻烦。而且整个程序显得有些乱。

那么能不能把程序精简一下,能不能把具有相关功能的函数放在一起,能不能像我们使用头文件的时候,直接使用一个包含命令就把一些相关功能包含到程序里,而我们在程序里只要调用我们用到的函数就能够实现我们想要达到的目的呢?

答案是肯定的!

解决方法是:化整为零,把负载的程序按照功能分解成不同的小模块,分别实现。

1.3.1. 模块化程序设计简介

模块化程序设计是指将实现同一功能的程序整合起来,封装到一个程序模块中,这样在使用该功能的时候,可以直接调用该模块中的相关函数进行操作。

在进行程序设计时把一个大的程序按照功能划分为若干小的程序,每个小的程序完成一个确定的功能,在这些小的程序之间建立必要的联系,互相协作完成整个程序要完成的功能。通常我们称这些小的程序为程序的模块。

fad210984aaf69ec858d9777cb3b2950.png

模块化程序设计

具体到程序来说,模块通常是指可以用一个名字调用的一个程序段。对于不同的程序设计语言,模块的实现和名称也不相同,在BASIC,FORTRAN语言中的模块称作子程序;C语言中的模块叫函数

1.3.2. 2、模块化程序设计思路

模块化程序设计的思路是这样的:将一个大的程序按功能分割成一些小模块。

即:把具有相同功能的函数放在一个文件中,然后在主程序里面用#include指令把这个文件包含到主程序文件中,那么在主程序中就可以直接调用这个文件中定义好的函数来实现特定的功能,而在主程序中不用声明和定义这些函数。这样就使主程序显得更加精炼,可读性也会增强。同时,我们把具有相同功能的函数放在同一个文件中,这样有一个很大的优点是便于移植,可以将这个模块化的函数文件很轻松的移植到别的程序中。

综合上述,模块化程序设计的优点是:

●各模块相对独立,功能单一,结构清晰,接口简单.

●控制了程序设计的复杂性.

●缩短了开发周期.

●避免程序开发的重复劳动.

●易于维护和功能扩充.

2288f07ec2e627ef422981c713a0acbc.png

模块化程序设计

3、模块化程序设计的实现

模块化程序的实现是:

一般的做法是:将不同模块(如LCD1602,DS18B20等)都封装成一个文件,然后在主程序中包含这些文件。

将具有相同功能的函数声明以及该模块涉及的端口定义、初始化设置、宏定义等内容编写成一个xxx.h文件文件,将函数的定义、变量的声明及初始化等内容编写为一个xxx.c文件;注意最好把xxx.c文件和xxx.h文件的名称定义成相同的名称。然后在主程序文件中使用#include预编译命令包含xxx.h文件,这样在主程序中就可以调用这个文件中的函数了,同样的,在其它.c文件中,也可以使用#include预编译命令包含xxx.h文件。(就像我们调用编译器中的各种应用库文件一样,比如在keil c51中要调用I/O定义头文件是我们要使用“#include

这样做的优点是,我们可以直接在“.h”文件中查找到我们需要的函数名称,从而在主程序里面直接调用,而不用去关心“.c”文件中的具体内容。如果我们要将该程序移植到不同型号的单片机上,我们同样只需在“.h”文件中修改相应的端口定义即可。

1.3.3. 不同模块之间的函数调用

一般情况下,程序中定义的函数和变量是有一定的作用域的,也就是说,我们在一个模块中定义的变量和函数,它的作用域只限于本模块文件和调用它的程序文件范围内,而在没有调用它的模块程序里面,如果调用它,编译器是会提示错误的,它的函数是不能被使用的。

在对较为复杂的程序进行模块化设计的时候,经常会遇到这样一种情况:一个函数在不同的模块之间都会用到,举例来说,几乎每一个程序中都会用到延时函数,也就是说一般的程序中都需要调用延时函数。出现这种情况该怎么办?难道需要在每个模块中都定义相同的函数?但是我们都知道,程序中,不同的变量和函数只能使用不同的名称,如果一个程序中有两个名称相同的变量或者函数的话,那程序编译的时候会提示我们有重复定义的函数。难道要在不同的模块中为相同功能的函数(功能相同,函数体的内容也相同)起不同的名字,这样岂不是做了很多重复劳动,这样的重复劳动还会造成程序的可读性变得很差。怎么办?

1a187c5050a1d9dea0fb90ea9336172d.png

模块化程序设计

同样的情况也会出现在不同模块程序之间传递数据变量的时候。

在这样的情况下,一种比较好的解决办法是:使用文件包含命令“#include”将一个模块的文件包含到另一个模块文件中,这种方法在只包含很少的模块文件的时候是很方便的,对于比较大的、很复杂的包含很多模块文件的单片机应用程序中,在每一个模块里面都使用包含命令就很麻烦了,并且很容易出错。

出现这种情况的原因是我们在编写单片机程序的时候,我们所定义的函数和变量都被默认为是局部函数和变量,那么它们的作用范围当然是在调用他们的程序之间了。如果我们将这些函数和变量定义为全局的函数和变量,那么,在整个单片机系统程序中,所有的模块之间都可以使用这些函数和变量。

所以,针对这种情况,最好的解决方法是:将需要在不同模块之间互相调用的文件声明为外部函数、变量(或者全局函数、变量)。

将函数和变量声明为全局函数和变量的方法是:在该函数和变量前面加“extern”修饰符。“extern”的英文意思就是“全局”,这样我们就可以将加了“extern”修饰符的函数和变量声明为全局函数和变量,那么在整个单片机系统程序的任何地方,我们都可以随意调用这些全局函数和变量。

例如:

extern void Usart0_Init(void); //USART寄存器设置

extern void Usart0_PutString(unsigned char *pcString);

在这里,我们将这4个函数都定义成为全局函数,那么,在一个单片机系统中,在整个程序的任何地方,我们都可以直接调用这些函数。

注意:在调用的时候直接使用函数名称即可,“extern”这个修饰符不必再调用的时候写上。

同样的,对于变量的定义我们可以使用同样的方法:

extern int second;

在这里,我们定义了一个全局的整形变量second;

1.4. 电路设计

本实例沿用实例29的电路。

1.5. 程序设计

本实例中,我们分别按照功能划分,将程序中的延时程序中的函数声明封装在Delay.h文件中,变量声明和函数定义封装在Delay.c文件中;

液晶显示程序中的端口定义、函数声明封装在LCD1602.h文件中,变量声明和函数定义封装在LCD1602.c文件中,DS18B20读写程序中的端口定义、函数声明封装在DS18B20.h文件中,变量声明和函数定义封装在DS18B20.c文件中。

按照我们说的步骤建好上面程序文件后,按照下图进行操作。

28ba692e8053c4416fea519a762e2e3f.png

添加.c文件的方法

在主程序以及各个.c文件中,使用下面的预编译命令将不同程序模块中的函数“包含”进来。

#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  // 

也许有细心的朋友会发现,不同的#include与编译指令还有细微的差别,例如,调用51单片机头文件和C语言库函数使用的是下面的语句

#include    //包含单片机寄存器的头文件#include  //包含_nop_()函数定义的头文件

而针对我们自己编写的.h文件,使用的是下面的语句

#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  //

看出来了吧?调用keil里面自带的头文件时,文件名是用尖括号<>括起来的,而调用我们自己编写的头文件时,文件名是用""括起来的。这是为什么呢?简单说,使用尖括号<>括起来的头文件,编译器在编译时,先从编译器安装的目录下开始搜索这个文件,而用""括起来的头文件,编译的时候,先从我们建立的单片机项目文件中搜索该文件。

下面是Delay.h文件的代码。

 //Delay.h/*****************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/void delay1ms();/*****************************************************函数功能:延时若干毫秒入口参数:n***************************************************/ void delaynms(unsigned int n);

下面是Delay.c文件的代码。

//Delay.c#include    //包含单片机寄存器的头文件#include  //包含_nop_()函数定义的头文件#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  ///*****************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/void delay1ms(){   unsigned char i,j; for(i=0;i<10;i++)  for(j=0;j<33;j++)   ;  }/*****************************************************函数功能:延时若干毫秒入口参数:n***************************************************/ void delaynms(unsigned int n) {   unsigned int i;for(i=0;i

下面是LCD1602.h文件的代码。

 /*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。result=1,忙碌;result=0,不忙***************************************************/bit BusyTest(void);/*****************************************************函数功能:将模式设置指令或显示地址写入液晶模块入口参数:dictate***************************************************/void WriteInstruction (unsigned char dictate);/*****************************************************函数功能:指定字符显示的实际地址入口参数:x***************************************************/ void WriteAddress(unsigned char x); /*****************************************************函数功能:将数据(字符的标准ASCII码)写入液晶模块入口参数:y(为字符常量)***************************************************/ void WriteData(unsigned char y); /*****************************************************函数功能:对LCD的显示模式进行初始化设置***************************************************/void LcdInitiate(void);/******************************************************************************以下是与温度有关的显示设置 ******************************************************************************/ /*****************************************************函数功能:显示没有检测到DS18B20***************************************************/   void display_error(void);/*****************************************************函数功能:显示说明信息***************************************************/   void display_explain(void);/*****************************************************函数功能:显示温度符号***************************************************/   void display_symbol(void);/*****************************************************函数功能:显示温度的小数点***************************************************/   void display_dot(void);/*****************************************************函数功能:显示温度的单位(Cent)***************************************************/   void display_cent(void);/*****************************************************函数功能:显示温度的整数部分入口参数:x***************************************************/ void display_temp1(unsigned char x); /*****************************************************函数功能:显示温度的小数数部分入口参数:x***************************************************/  void display_temp2(unsigned char x);

下面是LCD1602.c文件的代码。

//LCD1602.c#include    //包含单片机寄存器的头文件#include  //包含_nop_()函数定义的头文件#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  //unsigned char code digit[10]={"0123456789"};     //定义字符数组显示数字unsigned char code Str[]={"laomashitu MCU"};    //说明显示的是温度unsigned char code Error[]={"Check Error!"};     //说明没有检测到DS18B20unsigned char code Temp[]={"wendu:"};             //说明显示的是温度unsigned char code Cent[]={"du"};              //温度单位/*******************************************************************************以下是对液晶模块的操作程序*******************************************************************************/sbit RS=P2^4;           //寄存器选择位,将RS位定义为P2.0引脚sbit RW=P2^5;           //读写选择位,将RW位定义为P2.1引脚sbit E=P2^6;            //使能信号位,将E位定义为P2.2引脚sbit BF=P0^7;           //忙碌标志位,,将BF位定义为P0.7引脚/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。result=1,忙碌;result=0,不忙***************************************************/bit BusyTest(void)  {    bit result;RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态    RW=1;    E=1;        //E=1,才允许读写    _nop_();   //空操作    _nop_();    _nop_();     _nop_();   //空操作四个机器周期,给硬件反应时间    result=BF;  //将忙碌标志电平赋给result   E=0;         //将E恢复低电平   return result;  }/*****************************************************函数功能:将模式设置指令或显示地址写入液晶模块入口参数:dictate***************************************************/void WriteInstruction (unsigned char dictate){       while(BusyTest()==1);   //如果忙就等待 RS=0;                  //根据规定,RS和R/W同时为低电平时,可以写入指令 RW=0;    E=0;                   //E置低电平(根据表8-6,写指令时,E为高脉冲,                           // 就是让E从0到1发生正跳变,所以应先置"0" _nop_(); _nop_();               //空操作两个机器周期,给硬件反应时间 P0=dictate;            //将数据送入P0口,即写入指令或地址 _nop_(); _nop_(); _nop_(); _nop_();               //空操作四个机器周期,给硬件反应时间 E=1;                   //E置高电平 _nop_(); _nop_(); _nop_(); _nop_();               //空操作四个机器周期,给硬件反应时间  E=0;                  //当E由高电平跳变成低电平时,液晶模块开始执行命令 }/*****************************************************函数功能:指定字符显示的实际地址入口参数:x***************************************************/ void WriteAddress(unsigned char x) {     WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x" }/*****************************************************函数功能:将数据(字符的标准ASCII码)写入液晶模块入口参数:y(为字符常量)***************************************************/ void WriteData(unsigned char y) {    while(BusyTest()==1);    RS=1;           //RS为高电平,RW为低电平时,可以写入数据  RW=0;  E=0;            //E置低电平(根据表8-6,写指令时,E为高脉冲,                     // 就是让E从0到1发生正跳变,所以应先置"0"  P0=y;           //将数据送入P0口,即将数据写入液晶模块  _nop_();  _nop_();   _nop_();     _nop_();       //空操作四个机器周期,给硬件反应时间  E=1;           //E置高电平  _nop_();  _nop_();  _nop_(); _nop_();        //空操作四个机器周期,给硬件反应时间 E=0;            //当E由高电平跳变成低电平时,液晶模块开始执行命令 }/*****************************************************函数功能:对LCD的显示模式进行初始化设置***************************************************/void LcdInitiate(void){    delaynms(15);               //延时15ms,首次写指令时应给LCD一段较长的反应时间    WriteInstruction(0x38);     //显示模式设置:16×2显示,5×7点阵,8位数据接口delaynms(5);                //延时5ms ,给硬件一点反应时间    WriteInstruction(0x38);delaynms(5);               //延时5ms ,给硬件一点反应时间WriteInstruction(0x38);     //连续三次,确保初始化成功delaynms(5);               //延时5ms ,给硬件一点反应时间WriteInstruction(0x0c);     //显示模式设置:显示开,无光标,光标不闪烁delaynms(5);               //延时5ms ,给硬件一点反应时间WriteInstruction(0x06);     //显示模式设置:光标右移,字符不移delaynms(5);                //延时5ms ,给硬件一点反应时间WriteInstruction(0x01);     //清屏幕指令,将以前的显示内容清除delaynms(5);             //延时5ms ,给硬件一点反应时间 } /******************************************************************************以下是与温度有关的显示设置 ******************************************************************************/ /*****************************************************函数功能:显示没有检测到DS18B20***************************************************/   void display_error(void) {       unsigned char i;      WriteAddress(0x00);    //写显示地址,将在第1行第1列开始显示   i = 0;                //从第一个字符开始显示while(Error[i] != '0')  //只要没有写到结束标志,就继续写{WriteData(Error[i]);   //将字符常量写入LCDi++;                 //指向下一个字符delaynms(100);        //延时100ms较长时间,以看清关于显示的说明}while(1)              //进入死循环,等待查明原因  ;}/*****************************************************函数功能:显示说明信息***************************************************/   void display_explain(void) {       unsigned char i;      WriteAddress(0x00);    //写显示地址,将在第1行第1列开始显示   i = 0;                //从第一个字符开始显示while(Str[i] != '0')  //只要没有写到结束标志,就继续写{WriteData(Str[i]);   //将字符常量写入LCDi++;                 //指向下一个字符delaynms(100);        //延时100ms较长时间,以看清关于显示的说明}}/*****************************************************函数功能:显示温度符号***************************************************/   void display_symbol(void) {       unsigned char i;      WriteAddress(0x40);    //写显示地址,将在第2行第1列开始显示   i = 0;                //从第一个字符开始显示while(Temp[i] != '0')  //只要没有写到结束标志,就继续写{WriteData(Temp[i]);   //将字符常量写入LCDi++;                 //指向下一个字符delaynms(50);        //延时1ms给硬件一点反应时间}}/*****************************************************函数功能:显示温度的小数点***************************************************/   void display_dot(void){          WriteAddress(0x49);  //写显示地址,将在第2行第10列开始显示    WriteData('.');      //将小数点的字符常量写入LCD delaynms(50);         //延时1ms给硬件一点反应时间}/*****************************************************函数功能:显示温度的单位(Cent)***************************************************/   void display_cent(void){           unsigned char i;          WriteAddress(0x4c);        //写显示地址,将在第2行第13列开始显示   i = 0;                    //从第一个字符开始显示 while(Cent[i] != '0')     //只要没有写到结束标志,就继续写{WriteData(Cent[i]);     //将字符常量写入LCDi++;                 //指向下一个字符delaynms(50);        //延时1ms给硬件一点反应时间}}/*****************************************************函数功能:显示温度的整数部分入口参数:x***************************************************/ void display_temp1(unsigned char x){ unsigned char j,k,l;     //j,k,l分别储存温度的百位、十位和个位j=x/100;              //取百位k=(x%100)/10;    //取十位l=x%10;             //取个位  WriteAddress(0x46);    //写显示地址,将在第2行第7列开始显示WriteData(digit[j]);    //将百位数字的字符常量写入LCDWriteData(digit[k]);    //将十位数字的字符常量写入LCDWriteData(digit[l]);    //将个位数字的字符常量写入LCDdelaynms(50);         //延时1ms给硬件一点反应时间      } /*****************************************************函数功能:显示温度的小数数部分入口参数:x***************************************************/  void display_temp2(unsigned char x){ WriteAddress(0x4a);      //写显示地址,将在第2行第11列开始显示WriteData(digit[x]);     //将小数部分的第一位数字字符常量写入LCDdelaynms(50);          //延时1ms给硬件一点反应时间} 

下面是DS18B20.h文件的代码。

//DS18B20.hsbit DQ=P3^3;/*****************************************************函数功能:将DS18B20传感器初始化,读取应答信号出口参数:flag ***************************************************/bit Init_DS18B20(void);/*****************************************************函数功能:从DS18B20读取一个字节数据出口参数:dat***************************************************/ unsigned char ReadOneChar(void);/*****************************************************函数功能:向DS18B20写入一个字节数据入口参数:dat***************************************************/  WriteOneChar(unsigned char dat);/*****************************************************函数功能:做好读温度的准备***************************************************/ void ReadyReadTemp(void); 

下面是DS18B20.c文件的代码。

//DS18B20.c#include    //包含单片机寄存器的头文件#include  //包含_nop_()函数定义的头文件#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  //extern unsigned char time;   //设置全局变量,专门用于严格延时/*****************************************************函数功能:将DS18B20传感器初始化,读取应答信号出口参数:flag ***************************************************/bit Init_DS18B20(void){ bit flag;         //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在 DQ = 1;           //先将数据线拉高 for(time=0;time<2;time++) //略微延时约6微秒     ; DQ = 0;           //再将数据线从高拉低,要求保持480~960us for(time=0;time<200;time++)  //略微延时约600微秒     ;         //以向DS18B20发出一持续480~960us的低电平复位脉冲  DQ = 1;           //释放数据线(将数据线拉高)   for(time=0;time<10;time++)     ;  //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲) flag=DQ;          //让单片机检测是否输出了存在脉冲(DQ=0表示存在)       for(time=0;time<200;time++)  //延时足够长时间,等待存在脉冲输出完毕      ; return (flag);    //返回检测成功标志}/*****************************************************函数功能:从DS18B20读取一个字节数据出口参数:dat***************************************************/ unsigned char ReadOneChar(void) {unsigned char i=0;unsigned char dat;  //储存读出的一个字节数据for (i=0;i<8;i++) {      DQ =1;       // 先将数据线拉高   _nop_();    //等待一个机器周期    DQ = 0;      //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序dat>>=1;   _nop_();     //等待一个机器周期      DQ = 1;     //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备   for(time=0;time<2;time++)             ;      //延时约6us,使主机在15us内采样   if(DQ==1)      dat|=0x80;  //如果读到的数据是1,则将1存入datelsedat|=0x00;//如果读到的数据是0,则将0存入dat     //将单片机检测到的电平信号DQ存入r[i]   for(time=0;time<8;time++)      ;              //延时3us,两个读时序之间必须有大于1us的恢复期    }                     return(dat);    //返回读出的十进制数据}/*****************************************************函数功能:向DS18B20写入一个字节数据入口参数:dat***************************************************/  WriteOneChar(unsigned char dat){unsigned char i=0;for (i=0; i<8; i++) {  DQ =1;         // 先将数据线拉高  _nop_();     //等待一个机器周期   DQ=0;          //将数据线从高拉低时即启动写时序         DQ=dat&0x01;   //利用与运算取出要写的某位二进制数据,                       //并将其送到数据线上等待DS18B20采样 for(time=0;time<10;time++)     ;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样  DQ=1;          //释放数据线      for(time=0;time<1;time++)  ;//延时3us,两个写时序间至少需要1us的恢复期  dat>>=1;       //将dat中的各二进制位数据右移1位 }  for(time=0;time<4;time++)              ; //稍作延时,给硬件一点反应时间}/************************************************函数功能:做好读温度的准备***************************************************/ void ReadyReadTemp(void){      Init_DS18B20();     //将DS18B20初始化WriteOneChar(0xCC); // 跳过读序号列号的操作WriteOneChar(0x44); // 启动温度转换     for(time=0;time<100;time++)            ; //温度转换需要一点时间Init_DS18B20();     //将DS18B20初始化WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位}

下面是主程序文件的代码。

   //实例72:DS18B20温度检测及其液晶显示#include    //包含单片机寄存器的头文件#include  //包含_nop_()函数定义的头文件#include"LCD1602.h"  //#include"DS18B20.h"  //#include"Delay.h"  //unsigned char time;   //设置全局变量,专门用于严格延时/*****************************************************函数功能:主函数***************************************************/  void main(void) {    unsigned char TL;     //储存暂存器的温度低位     unsigned char TH;    //储存暂存器的温度高位     unsigned char TN;      //储存温度的整数部分  unsigned int TD;       //储存温度的小数部分   LcdInitiate();         //将液晶初始化   delaynms(5);        //延时5ms给硬件一点反应时间if(Init_DS18B20()==1)    display_error();display_explain();   display_symbol();    //显示温度说明      display_dot();       //显示温度的小数点      display_cent();      //显示温度的单位   while(1)                //不断检测并显示温度 {ReadyReadTemp();     //读温度准备   TL=ReadOneChar();    //先读的是温度值低位TH=ReadOneChar();    //接着读的是温度值高位TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16                  //这样得出的是温度的整数部分,小数部分被丢弃了   TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,                  //这样得到的是温度小数部分的第一位数字(保留1位小数) display_temp1(TN);    //显示温度的整数部分   display_temp2(TD);    //显示温度的小数部分        delaynms(10);                   }  }

1.6. 实例仿真

根据前面的说明,按照步骤建立起模块化程序结构。编译后,按照上一实例的方法进行仿真,观察非模块化方法编写的程序,以及用模块化方法编写的程序在运行结果上是完全一样的。

1.7. 总结

通过本实例,我们学习了如何将功能众多,程序量大的单片机程序分成不同的模块,从而使单片机程序看起来结构清晰,可读性强,可移植性强。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/552140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

反序列化的时候出现eof exception_FastJson序列化时候出现了$ref?还不赶紧学习下...

最近在使用fastjson时候遇到一个问题&#xff0c;后台的数据转化为json字符串后发送到前端时候出现了$ref字样的东西&#xff0c;后来明白了这是引用&#xff0c;下面详细介绍下。一、一个简单的例子先来上一段代码&#xff0c;运行后打印的结果可能出乎意料&#xff0c;代码如…

阿里云 linux mysql数据库_Linux Mysql数据库安全配置

Linux Mysql数据库安全配置目录&#xff1a;1.修改mysql管理员账号root的密码(2种方法)2.修改mysql管理员账号root3.mysql管理员root账号密码遗忘解决办法(2种方法)4.创建数据库用户(3种方法)5.mysql数据库权限管理本地权限网络权限撤销权限删除用户一、修改mysql管理员账号roo…

快速锁屏电脑快捷键_一学就会的8个电脑快捷键一定要掌握!堪称“高效”神器...

日常工作中&#xff0c;电脑是我们常用的设备&#xff0c;为了提高工作效率常常需要牢记一些电脑快捷键&#xff0c;那么有哪些电脑快捷键值得我们牢记呢&#xff1f;下面分享8个实用的电脑快捷键&#xff0c;关键时刻省时又省力哟&#xff01;#1 WindowsL 快速锁屏一般用在暂时…

left join 重复数据_Python数据分析整理小节

一、数据读取1、读写数据库数据读取函数:pandas.read_sql_table(table_name, con, schemaNone, index_colNone, coerce_floatTrue, columnsNone)pandas.read_sql_query(sql, con, index_colNone, coerce_floatTrue)pandas.read_sql(sql, con, index_colNone, coerce_floatTrue,…

win10文件显示后缀名_Win10一开机,内存占用竟高达60%?你可以尝试这样做

说到win10一开机&#xff0c;内存占用竟高达60%&#xff0c;你是怎么处理的呢&#xff1f;深受其害的朋友就此大展身手了&#xff0c;瞅瞅&#xff01;A&#xff1a;我16G内存&#xff0c;也是开机占用了70%多。百度找了很多方法都是不相关的答案&#xff0c;后来发现了关闭快速…

LSTM(长短期记忆网络)的设计灵感和数学表达式

1、设计灵感 LSTM&#xff08;长短期记忆网络&#xff09;的设计灵感来源于传统的人工神经网络在处理序列数据时存在的问题&#xff0c;特别是梯度消失和梯度爆炸的问题。 在传统的RNN&#xff08;循环神经网络&#xff09;中&#xff0c;信息在网络中的传递是通过隐状态向量进…

个人博客代码_Jekyll + Github Pages 搭建个人免费博客

今天亲手通过 Jekyll 搭建了一套免费博客&#xff0c;搭建步骤其实超级简单。你不需要购买域名&#xff0c;也不需要购买服务器&#xff0c;就可以轻松拥有你自己的博客。Jekyll 的核心是一个文本转换引擎。它的方便之处在于支持多种文本标记语言&#xff1a;Markdown&#xff…

js计算排名_今天,我们讲一下,快速排名与黑帽SEO

做个有心人(第7篇)在Web3.0时代&#xff0c;想要获得流量&#xff0c;就必须使用广告手段&#xff0c;用什么广告手段&#xff0c;需要切合自身情况来做&#xff0c;比如说&#xff1a;SEO是免费的&#xff0c;而SEM就是付费的。而SEO快速排名是什么鬼?真的快吗?快速排名究竟…

黑马h5学习代码_如何零基础制作酷炫实用的H5页面

H5页面已经成为了当下移动端主要的宣传方式,一个好的H5页面有极高的营销价值,无论是企业还是个人都非常需要。制作一个炫酷的H5页面一定要会写代码吗,下面千锋网络营销小编就给大家分享如何零基础制作炫酷实用的H5页面。支持H5的Web APP迅猛发展很重要的一点就是APP中的内容产生…

bin文件如何编辑_如何为高通固件创建rawprogram0和patch0文件

这是一个分步教程&#xff0c;显示如何为Qualcomm固件创建rawprogram0.xml和patch0.xml文件。要求下载并安装Python https://www.python.org/downloads/release/python-2710/下载高通GPTtool [ 登录/注册免费下载]下载Notepad https://notepad-plus-plus.org/downloads/来自…

iframe 页面富文本框数据怎么保存_文字太多PPT怎么做都丑?估计是没注意这些细节!...

秋叶 PPT 双 11 大促返场最后 1 天全场精品课享年度超值价千万别错过啦&#xff01;作者&#xff1a;洁洁编辑&#xff1a;躺糖大家好&#xff0c;我是洁洁&#xff01;作为每天倾听你们的困惑的小编之一&#xff0c;我 get 到了一个你们平常做 PPT 会碰到的最头疼的问题&#…

835 由于安全层无法对远程计算机进行身份验证_vscode 插件Remote-ssh远程wsl调试python

解决远程ssh端口非22的问题&#xff0c;见文末参考文献&#xff1a;Developing on Remote Machines using SSH and Visual Studio Code​code.visualstudio.com使用SSH进行远程开发Developing on Remote Machines using SSH and Visual Studio Code使用SSH进行远程开发在Visual…

vue实现查询多条记录_vue.js 实现天气查询

效果预览&#xff1a;http://songothao.gitee.io/weather_query_based_on_vuejs/ 项目已上传码云&#xff1a;叁贰壹/vuejs实现天气查询知乎视频​www.zhihu.com一、使用 axios vue.js:axios-get请求&#xff1a;axios.get(地址?keyvalue&key2value2).then(function(resp…

idea序列化自动生成_serialVersionUID在数据序列化中重要性

作用用于判断序列化文件是否已经失效(过期)。序列化的时候会把这个ID写到文件里。读的时候会把这个ID和代码里的ID比较&#xff0c;如果不一致&#xff0c;表示文件里的已经失效。(will result in an InvalidClassException.)值写为多少你可以写为1L&#xff0c;也可以让IDEA帮…

python找与7相关的数_用python统计并输出1000以内所有能同时被3和7整除的数的个数?...

展开全部 len([i for i in range(1,1001) if i%3i%70]) #!/usr/bin/python3 for i in range(1, 100): if i % 3 0 and i % 7 0: print(i) 100以内能同时被21133&#xff0c;5&#xff0c;7整除的数&#xff0c;除非是52610。 #include int main() {int i,n0; for(i0;i<100…

贝塞尔曲线 java_贝塞尔曲线理论及实现——Java篇

贝塞尔曲线贝塞尔曲线(The Bzier Curves)&#xff0c;是一种在计算机图形学中相当重要的参数曲线(2D&#xff0c;3D的称为曲面)。贝塞尔曲线于1962年&#xff0c;由法国工程师皮埃尔贝塞尔(Pierre Bzier)所发表&#xff0c;他运用贝塞尔曲线来为汽车的主体进行设计。线性曲线给…

java连接access_关于k8s下使用Ingress保持长连接的异常情况排查

写在前面的话应某位友人需求&#xff0c;帮整理下工作中的发生的一些值得记录的文章。于是在友人描述后&#xff0c;为其整理为了文章&#xff0c;供大家一起参考探讨。问题描述在我们中应用有一个使用到Http Long Poll的场景&#xff0c;它需要一个http请求保持最长30秒&#…

罗斯蒙特电磁流量计8723说明书_罗斯蒙特8732E电磁流量计对环境和温度的限制

今天我们来说说美国罗斯蒙特8732E电磁流量计对环境和温度的限制&#xff01;工作温度-40 到 60C(-40 到 140F)&#xff0c;无本地操作界面-20 到 60C(-4 到 140F)&#xff0c;有本地操作界面当温度低于 -20C 时&#xff0c;本地操作界面 (LOI) 将无显示储存-40 到 85C(-40 到 1…

python字符串定义符_python入门——定义字符串

坚持每天更新&#xff0c;帮助入门python。kali linux 小伙伴们&#xff0c;大家好&#xff0c;今下午我们一起学习在python中定义字符串。 那么什么是字符串呢&#xff1f;字符串或串(String)是由数字、字母、下划线组成的一串字符。说白了&#xff0c;就是一堆字符。 在pytho…