STC89C52RC单片机额外篇 06 - 认识高内聚、低耦合的模块化编程_单片机关于模块间解决耦合问题

sbit DS18B20_DATA=P3^7;
sbit BUZZ=P1^0;
//************************常量数组(段码表)声明*********************
uint8 code SegCodeTable[]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//****************************全局变量声明***************************
int Temperature;
//****************************函数原型声明***************************
void DS18B20Init();
void DS18B20BitWrite(bit Bit);
bit DS18B20BitRead();
void DS18B20ByteWrite(uint8 Byte);
uint8 DS18B20ByteRead();
void GetTemperature();
void DispTemperature();
void Delay(uint16 ms);
void AlarmCheck();
//*******************************主函数******************************
void main()
{
while(1)
{
GetTemperature(); //采集当前温度
DispTemperature(); //显示当前温度
AlarmCheck();
}
}
//*************************DS18B20初始化函数*************************
void DS18B20Init()
{
uint16 i;
while(1)
{
DS18B20_DATA=0;
i=640;
while(–i); //延时800us(STC12C5A60S2,11.0592MHz,代码5级优化)
DS18B20_DATA=1;
i=56;
while(–i); //延时70us
if(DS18B20_DATA1) continue; //无响应则重发复位脉冲
i=224;
while(–i); //延时280us
if(DS18B20_DATA
1) break; //复位成功
}
i=160;
while(–i); //延时200us
}
//***********************DS18B20位写操作函数*************************
void DS18B20BitWrite(bit Bit)
{
uint16 i;
DS18B20_DATA=0;
i=4;
while(–i); //延时5us
DS18B20_DATA=Bit; //发送1位数到DS18B20
i=48;
while(–i); //延时60us
DS18B20_DATA=1;
}
//**********************DS18B20位读操作函数**************************
bit DS18B20BitRead()
{
bit temp;
uint16 i;
DS18B20_DATA=0;
i=4;
while(–i); //延时5us
DS18B20_DATA=1;
i=4;
while(–i); //延时5us
temp=DS18B20_DATA; //读来自DS18B20的1位数
i=48;
while(–i); //延时60us
return temp;
}
//**********************DS18B20字节写操作函数************************
void DS18B20ByteWrite(uint8 Byte)
{
uint8 i;
for(i=0;i<8;i++) //一共发送8位
{
if( Byte&0x01==1 ) //先发最低位
DS18B20BitWrite(1); //发送1
else
DS18B20BitWrite(0); //发送0
Byte>>=1;
}
}
//**********************DS18B20字节读操作函数************************
uint8 DS18B20ByteRead()
{
uint8 i,temp=0;
for(i=0;i<8;i++) //一共读8位
{
temp>>=1; //字节变量右移
if(DS18B20BitRead()1) //读取1位数据并存入临时变量temp中
temp|=0x80; //temp最高位置1
}
return temp; //返回读到的8位数
}
//*****************************温度采集函数**************************
void GetTemperature()
{
uint8 Buff[2],i;
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0x44); //启动温度转换
for(i=0;i<250;i++)
DispTemperature(); //等待750ms,期间不断刷新LED显示
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0xbe); //准备读转换结果
Buff[0]=DS18B20ByteRead(); //读温度值低字节
Buff[1]=DS18B20ByteRead(); //读温度值高字节
Temperature=(Buff[1]<<8)+Buff[0]; //拼成16位温度值
}
//******************************温度显示函数*************************
void DispTemperature()
{
uint8 temp;
temp=(Temperature>>4)/10; //显示十位
if(temp
0)
SEG_CODE_PORT=0xFF ; //十位为0则隐去
else
SEG_CODE_PORT=SegCodeTable[temp];
BIT_CODE_PORT=0xF5; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(Temperature>>4)%10]&0x7F; //显示个位(带点)
BIT_CODE_PORT=0xF6; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(Temperature&0x0F)*10/16]; //显示十分位
BIT_CODE_PORT=0xF7; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
}
//********************************超温报警函数***************************//
void AlarmCheck()
{
uint8 i;
if(Temperature > 0x01F8 ) //判断温度是否超过31.5℃
{
for(i=0;i<50;i++)
{
BUZZ=~ BUZZ ;
Delay(1); //控制无源蜂鸣器发声50ms
}
BUZZ=1;
Delay(100);
}
}
//******************************软件延时函数*************************
void Delay(uint16 ms)
{
uint16 i;
do{
i=790;
while(–i); //延时1ms(STC12C5A60S2,11.0592MHz,代码5级优化)
} while(–ms);
}


咋一看,感觉这个程序写得挺不错,不过稍微细心斟酌,其实模块化的程度只是一般般,有些函数的内部还是有一定的耦合度!下面对各模块函数进行分析:


### 2 DS18B20驱动函数



//*************************DS18B20初始化函数*************************
void DS18B20Init()
{
uint16 i;
while(1)
{
DS18B20_DATA=0;
i=640;
while(–i); //延时800us(STC12C5A60S2,11.0592MHz,代码5级优化)
DS18B20_DATA=1;
i=56;
while(–i); //延时70us
if(DS18B20_DATA1) continue; //无响应则重发复位脉冲
i=224;
while(–i); //延时280us
if(DS18B20_DATA
1) break; //复位成功
}
i=160;
while(–i); //延时200us
}
//***********************DS18B20位写操作函数*************************
void DS18B20BitWrite(bit Bit)
{
uint16 i;
DS18B20_DATA=0;
i=4;
while(–i); //延时5us
DS18B20_DATA=Bit; //发送1位数到DS18B20
i=48;
while(–i); //延时60us
DS18B20_DATA=1;
}
//**********************DS18B20位读操作函数**************************
bit DS18B20BitRead()
{
bit temp;
uint16 i;
DS18B20_DATA=0;
i=4;
while(–i); //延时5us
DS18B20_DATA=1;
i=4;
while(–i); //延时5us
temp=DS18B20_DATA; //读来自DS18B20的1位数
i=48;
while(–i); //延时60us
return temp;
}
//**********************DS18B20字节写操作函数************************
void DS18B20ByteWrite(uint8 Byte)
{
uint8 i;
for(i=0;i<8;i++) //一共发送8位
{
if( Byte&0x01==1 ) //先发最低位
DS18B20BitWrite(1); //发送1
else
DS18B20BitWrite(0); //发送0
Byte>>=1;
}
}
//**********************DS18B20字节读操作函数************************
uint8 DS18B20ByteRead()
{
uint8 i,temp=0;
for(i=0;i<8;i++) //一共读8位
{
temp>>=1; //字节变量右移
if(DS18B20BitRead()==1) //读取1位数据并存入临时变量temp中
temp|=0x80; //temp最高位置1
}
return temp; //返回读到的8位数
}


这部分函数的实现几乎很接近高内聚的方式了,模块化程度很高!


### 3 温度采集函数



//*****************************温度采集函数**************************
void GetTemperature()
{
uint8 Buff[2],i;
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0x44); //启动温度转换
for(i=0;i<250;i++)
DispTemperature(); //等待750ms,期间不断刷新LED显示
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0xbe); //准备读转换结果
Buff[0]=DS18B20ByteRead(); //读温度值低字节
Buff[1]=DS18B20ByteRead(); //读温度值高字节
Temperature=(Buff[1]<<8)+Buff[0]; //拼成16位温度值
}


温度采集函数,我们可以理解为在驱动层之上的逻辑,换句话说,我们要用DS18B20驱动函数实现温度采集的功能,所以温度采集函数调用DS18B20驱动函数的接口是要足够简单并可读性高。


从温度采集函数的内部实现可以看出(我们先不看`DispTemperature()`函数),启动温度转换与转换读取结果这个步骤其实也可以封装成DS18B20驱动函数的一个接口,对于`buff`与`Temperature`应该是用于接收接口中返回的数据(一般接口就得掩盖其内部的实现细节)。如下所示:



//*************************DS18B20温度转换函数***********************
void DS18B20Conversion()
{
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0x44); //启动温度转换
}

//*************************DS18B20温度读取函数***********************
void DS18B20Read(uint8 buff[])
{
DS18B20Init(); //DS18B20初始化
DS18B20ByteWrite(0xCC); //跳过ROM匹配(因为只有一个DS18B20)
DS18B20ByteWrite(0xbe); //准备读转换结果
buff[0]=DS18B20ByteRead(); //读温度值低字节
buff[1]=DS18B20ByteRead(); //读温度值高字节
}

//*****************************温度采集函数**************************
void GetTemperature(int *temperature)
{
uint8 Buff[2],i;
DS18B20Conversion(); // 启动DS18B20温度转换
for(i=0;i<250;i++)
DispTemperature(); // 等待750ms,期间不断刷新LED显示
DS18B20Read(Buff); // 读取DS18B20温度数据
*temperature=(Buff[1]<<8)+Buff[0]; //拼成16位温度值
}


咦,这里的`temperature`变量为啥是指针类型?不知道大家初次学C语言的时候是否还记得使用普通变量作为形参传入到函数内部却无法修改这个变量的值这个例子。如果实在想不起怎么办?这里博主有篇博文可以帮到大家:《[C语言知识汇总 | 53-C语言指针变量作为函数参数]( )》。


### 4 温度显示函数



//******************************温度显示函数*************************
void DispTemperature()
{
uint8 temp;
temp=(Temperature>>4)/10; //显示十位
if(temp==0)
SEG_CODE_PORT=0xFF ; //十位为0则隐去
else
SEG_CODE_PORT=SegCodeTable[temp];
BIT_CODE_PORT=0xF5; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(Temperature>>4)%10]&0x7F; //显示个位(带点)
BIT_CODE_PORT=0xF6; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(Temperature&0x0F)*10/16]; //显示十分位
BIT_CODE_PORT=0xF7; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
}


继续沿用前面的思维,从温度显示函数的内部实现来看,函数的执行是包括对`Temperature`变量的某些位进行取出、然后对数码管各个位进行显示,其实我们也可实现单独对数码管的显示函数,但是这个可能意义不是太大,为什么呢?因为数码管的电子线路连接有几种方式,且也有共阴与共阳之分,另外数码管的位选数量也可能不一样,要达到“统一”是没这么简单的!所以这里只是单独把`Temperature`变量抽取出来变成函数的实参变量即可:



//******************************温度显示函数*************************
void DispTemperature(int temperature)
{
uint8 temp;
temp=(temperature>>4)/10; //显示十位
if(temp==0)
SEG_CODE_PORT=0xFF ; //十位为0则隐去
else
SEG_CODE_PORT=SegCodeTable[temp];
BIT_CODE_PORT=0xF5; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(temperature>>4)%10]&0x7F; //显示个位(带点)
BIT_CODE_PORT=0xF6; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
SEG_CODE_PORT=SegCodeTable[(temperature&0x0F)*10/16]; //显示十分位
BIT_CODE_PORT=0xF7; //选择显示位置
Delay(1);
BIT_CODE_PORT=0xFF;
}


### 5 超温报警函数



//********************************超温报警函数***************************//
void AlarmCheck()
{
uint8 i;
if(Temperature > 0x01F8 ) //判断温度是否超过31.5℃
{
for(i=0;i<50;i++)
{
BUZZ=~ BUZZ ;
Delay(1); //控制无源蜂鸣器发声50ms
}
BUZZ=1;
Delay(100);
}
}


来,我们继续!超温报警函数也是我们需求想要的功能,这里可以提取出蜂鸣器发声函数,温度变量也进一步提取,当然还可选择传入一个超温报警值作为变量,传入的超温值可以使用宏定义来表示,方便修改:



//***************************温度报警值定义**************************
#define MAX_TEMP 0x01F8 // 31.5℃

//******************************蜂鸣器发声函数***************************//
void BuzzerSounds()
{
uint8 i;
for(i=0;i<50;i++)
{
BUZZ=~ BUZZ ;
Delay(1); //控制无源蜂鸣器发声50ms
}
BUZZ=1;
Delay(100);
}

//********************************超温报警函数***************************//
void AlarmCheck(int temperature, int max_temperature)
{
if(temperature > max_temperature)
{
BuzzerSounds(); // 蜂鸣器发声
}
}


### 6 main函数


前面把`temperature`变量通过函数传值的方式来获取温度值与显示温度值,那么对于全局变量中`Temperature`就可以去掉了,最终`main`函数是这样子的:



//*******************************主函数******************************
void main()
{
int temperature = 0;
while(1)
{
GetTemperature(&temperature); //采集当前温度
DispTemperature(temperature); //显示当前温度
AlarmCheck(temperature, MAX_TEMP); //判断温度是否超过31.5℃
}
}


### 7 最终文件
## 最后

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/890f6b17ef98558582cf442b889303fa.png)

![img](https://img-blog.csdnimg.cn/img_convert/677df75b04edba6d3ad853ec856a7684.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/dbcc33d2a809ab99a95de8f82a687788.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/e8d09c1b6125ddd360fdcb64a4e1d0b8.png)

![img](https://img-blog.csdnimg.cn/img_convert/bbedf145951d89a045274741a335f4a7.png)

![img](https://img-blog.csdnimg.cn/img_convert/c2b467f0b0536aebc8531bd7cb1ae0a9.png)

![](https://img-blog.csdnimg.cn/img_convert/761aa86db82691a5d459c38a43e1945d.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


15598638154)]

[外链图片转存中...(img-WVXJtP9J-1715598638155)]

 [外链图片转存中...(img-Nye3WzB6-1715598638155)]

[外链图片转存中...(img-oJhK3Fbq-1715598638156)]

[外链图片转存中...(img-zEik8eRM-1715598638157)]

[外链图片转存中...(img-jxdiiydR-1715598638157)]

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值