蓝桥杯-单片机基础9——基于2023年官方onewire通信代码外设讲解(温度传感器DS18B20)

蓝桥杯单片机组备赛指南请查看 :本专栏第1篇文章

本文章针对蓝桥杯-单片机组比赛开发板所写,代码可直接在比赛开发板上使用。

型号:国信天长4T开发板(绿板),芯片:IAP15F2K61S2

(使用国信天长蓝板也可以完美兼容,与绿板几乎无差别)


万幸,蓝桥杯比赛板上使用onewire进行通信的外设只有温度传感器——DS18B20

1. 代码目的

        通过对开发板外设DS18B20的正确设置,获取温度传感器的温度数值,并显示到数码管上。

2. 头文件设置

        对于需要进行通信的外设,官方提供了底层onewire.c文件,我们可以直接采用该文件中已经定义好的函数,来对DS18B20进行正确的通信设置。但是,从16年开始为了增加难度,官方提供的代码会故意出现一些错误与遗漏,我们以2023年官方提供的底层文件为参考

下载链接:链接:https://pan.baidu.com/s/1LfixDiinqsOhYbhrAptbMQ      提取码:1111

        要正确使用官方提供的底层文件onewire.c有两种方式:

方式一:(直接复制)

        将该文档中的代码全部复制粘贴到我们建立的工程文件的C文件中,并直接在我们自己的C文件中进行函数调用。缺点是会造成我们的代码文件破500行,调试起来眼花缭乱;优点是简单粗暴,学习成本不高。

方式二:(自定义头文件,推荐)

        该方法比较推崇,建议学会,小蜜蜂老师有一节课专门讲如何操作,这里只介绍该项目的操作过程。

步骤一:建立新建一个头文件,在项目的source group文件夹中右键选择“add new items”,然后添加一个后缀为.h的文件:

        然后keil5就会打开一个新的文本编辑页面,这个页面就需要写我们对官方提供的onewire.c文件的头文件,在这个文件中输入以下内容:

#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__

void Write_DS18B20(unsigned char dat);	
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);

#endif

        中间三行为需要在主函数文件中调用的函数声明,直接在onewire.c文件中复制过来。其他的部分是头文件固定格式,需要牢记。

步骤二:正确添加底层文件onewire.c

        在项目的source group文件夹中右键选择“add existing items”,然后添加百度网盘下载的onewire.c的文件:

        然后keil5工程栏就出现了一个onewire.c的文件,然后我们需要检查该文件是否缺少了一些东西。

        打开该文件,点击编译,我们来看看有什么反应:

        报错提示文件中的DQ变量不存在,因此我们需要在该文件的最上方对DQ变量进行定义,查看比赛提供的原理图:

        可以发现DQ端口外部连接到了P1^4引脚上,因此我们需要在onewire.c中,将DQ变量看作一个特殊位变量,并对其进行定义,定义好之后再次进行编译查看:

        发现报错反而多了一个P1,而P1在公共二进制文件库中可以由头文件reg52.h引用,因此我们需要在onewire.c定义该头文件:

        此时编译后我们发现,错误全部消失,只有一些提示我们存在未调用程序的警告,无所谓,说明我们的修改成功了。

        到此处,对于官方提供的底层代码文件添加完毕,在比赛中,我们可以采用这种一边编译,一边排错的方式对官方埋得坑进行避雷。

        需要我们额外添加的代码只有两行,全部底层文件onewire.c如下:

/*	# 	单总线代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/

#include <reg52.h>  //引入头文件,排除P1不存在错误


sbit DQ = P1^4;  //根据原理图定义特殊位变量DQ


//
void Delay_OneWire(unsigned int t)  
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

步骤三:在主函数文件中,添加头文件:

3. 原理图介绍

        该外设已经有了固定的硬件连接,因此我们只需要关注其DQ位与单片机的P14引脚连接到了一起。

对DS18B20外设的额外介绍:

        DQ全称为数字信号输入输出端,该传感器的最低温度精度为0.0625℃,并将读取到的温度保存到MSB、LSB两个8位寄存器当中。寄存器各位如下:

MSBSSSSS2^62^52^4
LSB2^32^22^12^02^{-1}2^{-2}2^{-3}2^{-4}

从表格中进行观察我们可以发现,

        高位的MSB寄存器的前5位用于表示温度是否为整数,当全为0时极为整数,编程时不需要在意。最后3位与LSB的高4位共同构成温度的整数部分值

        LSB的低4位构成了温度的小数部分。

        温度具体数值转换方式与二进制转十进制相同,编程时,只需要将MSB和LSB中的有效数值位读取出来,合并成一个11位的2进制数,并乘以精度0.0625即可得到当前的准确温度值。

        但是温度是存在小数的,因此我们常常将温度值乘以10,构成一个无小数的整数,从而便于在数码管中进行显示。

4. DS18B20操作流程

4.1 时序操作流程

1DS18B20初始化复位
2写入0xCC,跳过ROM寻址指令
3写入0x44,开始温度转换
4延时700~900ms
5DS18B20初始化复位
6写入0xCC,跳过ROM寻址指令
7写入0xBE,读取高速暂存器
8读取温度数值存入LSB
9读取温度数值存入MSB

        以上所有的操作,除了第4步延时以外,其余函数都在官方提供的底层代码中直接调用。为了方便使用,我们常常自己写延时函数,并且在延时函数中放入我们的数码管刷新函数,避免在这段延时期间,数码管产生明显的闪烁。

4.2 程序操作流程

        一般我们不可能遇到温度为零下的可能,因此我直接去掉了判断温度是否大于零的部分。

        最后三行为数值提取的思路,不要死记,建议理解,注意对temperature的左移和右移会引起其值的大小变化:右移4位相当于除以16,或者乘以0.0256

5. 代码参考

#include <reg52.h>
#include <intrins.h>
#include "onewire.h"

void SMGrunning ();

unsigned char code duanma[10] = { 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 };
unsigned char code duanma_dot[10] = { 0x40 , 0x79 , 0x24 , 0x30 , 0x10 , 0x12 , 0x02 , 0x78 , 0x00 , 0x10 };


void Delay2ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 20;
	j = 50;
	do
	{
		while (--j);
	} while (--i);
}

void Delay800ms()		//@12.000MHz
{
	unsigned char j;

	_nop_();
	_nop_();
	j = 20;
	do
	{
		SMGrunning ();
	} while (--j);
	
}


void select_HC573 ( unsigned char channal )
{
	switch ( channal )
	{
		case 4:
			P2 = ( P2 & 0x1f ) | 0x80;
		break;
		case 5:
			P2 = ( P2 & 0x1f ) | 0xa0;
		break;
		case 6:
			P2 = ( P2 & 0x1f ) | 0xc0;
		break;
		case 7:
			P2 = ( P2 & 0x1f ) | 0xe0;
		break;

			
	}
}

void SMG_state ( unsigned char pos_SMG , unsigned char value_SMG )
{
	select_HC573 ( 6 );
	P0 = 0x01 << pos_SMG;
	select_HC573 ( 7 );
	P0 = value_SMG;
}

void SMG_all_down ()
{
	select_HC573 ( 6 );
	P0 = 0xff;
	select_HC573 ( 7 );
	P0 = 0xff;
}

unsigned int temperature = 0;
void ds18b20_temperature ()
{
	unsigned char LSB,MSB;
	init_ds18b20();
	Write_DS18B20(0xcc);	
	Write_DS18B20(0x44);
	Delay800ms();
	init_ds18b20();
	Write_DS18B20(0xcc);	
	Write_DS18B20(0xbe);
	
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	

	temperature = MSB;
	temperature = ( temperature << 8 ) | LSB;
	temperature = (temperature >> 4)*10 + (LSB & 0x0f)*0.625;

}


void SMGrunning ()
{

	
	SMG_state( 0 , 0xff );
	Delay2ms();
	SMG_state( 1 , 0xff );
	Delay2ms();
	SMG_state( 2 , 0xff );
	Delay2ms();
	SMG_state( 3 , 0xff );
	Delay2ms();
	SMG_state( 4 , 0xff );
	Delay2ms();
	SMG_state( 5 , duanma[temperature/100] );
	Delay2ms();
	SMG_state( 6 , duanma_dot[temperature/10%10] );
	Delay2ms();
	SMG_state( 7 , duanma[temperature%10] );
	Delay2ms();
	
	SMG_all_down ();
	
}

int main ()
{
	while ( 1 )
	{
		ds18b20_temperature ();
		SMGrunning ();
	}
}

6. 编程思路重述

定义一个全局变量temperature,用于使用官方提供的函数进行DS18B20温度获取

时序步骤:

        初始化、写入0xCC、写入0X44

        初始化、写入0XCC、写入0XBE

        读取温度到LSB、读取温度到MSB

        整合MSB和LSB获得最终数据

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值