基于蓝牙的无线数据采集系统

项目四:基于蓝牙的无线数据采集系统

关于串口通讯的文章:https://blog.csdn.net/jx_lihuifu/article/details/80308364
关于蓝牙模块设置的文章:https://blog.csdn.net/qimi923511491/article/details/82928743

总简介

本系统本两个部分,一个部分是采集端,一个是接收端。采集端由温度传感器DS18B20、主蓝牙ATK-HC05(蓝牙2.0)、光敏电阻及一个51单片机小系统组成。接收端由一个从蓝牙模块、报警模块、温度设定与显示模块组成。

系统工作原理

单片机串口通讯的工作原理及蓝牙通讯协议。
单片机串口通信原理
DS18B20单总线协议
典型的单总线命令序列如下 :
第一步:初始化
第二步:ROM命令(跟随需要交换的数据 )

基于蓝牙的无线数据采集系统_第1张图片
第三步:功能命令(跟随需要交换的数据)**
读或者写命令
DS18B20温度传感器只有三个引脚,只需要分别接电源、地及中间的引脚接到单片机的普通I/O口既可以与单片机进行通信。DS18B20是单总线通信方式,只需要一条总线就可以与单片机实现双向通信,可读可写,而且支持多点组网方式,可以实现多点测温,接线简单,使用方便。DS18B20引脚图如下图3-5所示。
基于蓝牙的无线数据采集系统_第2张图片
DS18B20单总线协议虽然接线简单,但是对于程序部分的时隙要求非常高,DS18B20有严格的时序通讯协议,下图3-6是DS18B20的初始化时序图。
基于蓝牙的无线数据采集系统_第3张图片
在主机初始化过程,主机(即通过单片机操作)拉低单总线至少 480us, 以产生(Tx) 复位脉冲。接着,主机释放总线,并进入接收模式(Rx)。 当总线被释放后,5k上拉电阻将单总线拉高。在单总线器件检测到上升沿后,延时 15-60us,接着从机(也就是传感器自己)通过拉低总线 60-240 us, 以产生应答脉冲 ,所以在初始化过程中我们需要做的就是拉低总线480us以上。

*******************************************************************************
* 函数名      : Ds18b20Init
* 函数功能		   : 初始化
* 输入           :* 输出         	 :初始化成功返回1,不成返回0
*******************************************************************************/

unsigned char Ds18b20Init()
{
	unsigned int i;
	DSPORT=0;			 //将总线拉低480-960us
	i=70;	
	while(i--);//延时±642us
	DSPORT=1;			//然后拉高总线·如果DS18B20做出反应会在15US-60Us后将总线拉低。
	i=0;
	while(DSPORT)	//等待拉低总线,总线拉低了这个条件就不符合即跳出了
	{
		i++;
		if(i>5000)//等待>5MS
			return 0;//初始化失败
	return 1;//初始化成功

转换命令

*******************************************************************************
* 函数名        : Ds18b20ChangTemp
* 功能		   : 开始转换温度
* 输入          : com
* 输出        	 :*******************************************************************************/

void  Ds18b20ChangTemp()
{
	Ds18b20Init();
	Delay1ms(1);
	Ds18b20WriteByte(0xcc);		//跳过ROM命令		//只有一个期间在线上的时候才能用,不然出错乱
	Ds18b20WriteByte(0x44);	    //温度转换命令 
}

/*******************************************************************************
* 函数名       : Ds18b20WriteByte
* 功能		   : 写入一个字节
* 输入          : dat:一些命令入0xcc跳过ROM命令,0x44温度转换命令,0Xbe发送读取温度命令
* 输出        	 :无
*******************************************************************************/

void Ds18b20WriteByte(unsigned char dat)
{
	unsigned int i,j;
	for(j=0;j<8;j++)
	{
		DSPORT=0;			//每写入一位数据之前都要把总线拉低1us
		i++;
		DSPORT=dat&0x01; //从最低位开始一为一位写入数据
		i=6;
		while(i--); //延迟至少60us
		DSPORT=1;	//释放总线接着写入第二位数
		dat>>=1;
	}
}

读取温度

/*******************************************************************************
* 函数名        : Ds18b20ReadTemp
* 功能		   : 读取温度
* 输入          :无
* 输出        	 :返回16位的温度值
*******************************************************************************/

int Ds18b20ReadTemp()
{
	int temp=0;
	unsigned char tmh,tml;
	Ds18b20ChangTemp();			 	//温度转换命令
	Ds18b20ReadTempCom();			//温度读取命令
	tml=Ds18b20ReadByte();		//开始读,一共16位,先读低字节。
	tmh=Ds18b20ReadByte();		//再读高字节
	temp=tmh;
	temp<<=8;
	temp|=tml;//把两个字节连接起来,一共16位
	return temp;//返回这16位的温度数值
}

至于为什么是16位呢?前5位是符号位,后11位才是数值,其中前7位是整数位,后4位是小数位。
基于蓝牙的无线数据采集系统_第4张图片
**所以DS18B20的温度读取到此结束:总结如下,初始化–ROM命令–功能命令。
因为是单总线通信所以时序很重要,首先是要初始化,拉低总线DSPORT=0 480us以上,再释放15us左右DS18B20做出反应自动拉低总线60-240us这时候就判断是不是变低了即可,变低即成功初始化。然后ROM命令单点总线选跳过的命令,下达温度转换命令,然后就开始读温度的命令,先读低字节再读高字节,总共两个字节16位。**这16位是二进制温度数,需要编程10进制的实际温度值乘以0.0625即可变成实际温度值+0.5四舍五入。这样子再显示出来就可以了。

串口通信方式

1.波特率
每秒传送多少个二进制位数,1波特=1bit/1s (bps)
首先了解串口通信先要熟悉SCON,PCON,TMOD三个寄存器

串口工作方式寄存器SCON,在这里插入图片描述

RI:接收中断标志位,数据接收结束时,标志位会自动置1,需要通过程序将其置0,0

TI:发送中断标志位,数据发送结束时,标志位会自动置1,需要通过程序将其置0,0

RB8:存放发送数据的第9位,0

TB8:存放接收数据的第9位,0

REN:串行接收允许位,1允许串行接收,0禁止串行接收,1

SM2:多机控制位,0

SM1,SM0:串行工作方式

基于蓝牙的无线数据采集系统_第5张图片
基于蓝牙的无线数据采集系统_第6张图片
在这里插入图片描述
基于蓝牙的无线数据采集系统_第7张图片
基于蓝牙的无线数据采集系统_第8张图片
基于蓝牙的无线数据采集系统_第9张图片

PCON寄存器

在这里插入图片描述
SOMD:波特率是否加倍选择位,0波特率不加倍,1波特率加倍

定时计数器寄存器TMOD

在这里插入图片描述
前四位为T1,后四位为T0,串口通信中用T1。
基于蓝牙的无线数据采集系统_第10张图片
串口通信中用工作方式二减少误差。因为可以自动重装。

定时计数器控制寄存器TCON基于蓝牙的无线数据采集系统_第11张图片

基于蓝牙的无线数据采集系统_第12张图片
只需要控制TR1就可以了。为1就启动定时器1.

//串口接收端程序
#include
#include"lcd.h"
sbit LED = P1^0;
sbit buzz = P0^4;
//int a[10];
LED_Buffer[10];
void LcdDisplay(int);
void UsartConfiguration();
void delay_ms(uint x)
{
	uint i,j;
	for(i=x;i>0;i--)
		for(j=148;j>0;j--);
}
/*******************************************************************************
* 函数名        : main

*******************************************************************************/

void main()
{
	UsartConfiguration();
	LcdInit();	
    buzz=1;	
	LcdWriteCom(0x83);	//дµØÖ· 80±íʾ³õʼµØÖ·
	LcdWriteData('C');
	LcdWriteCom(0x80);
	LcdWriteData('+');
	LcdWriteCom(0xC0);
	LcdWriteData('x');
	LcdWriteData('i');
	LcdWriteData('a');
	LcdWriteData('n');
	LcdWriteData('z');
	LcdWriteData('h');
	LcdWriteData('i');
	LcdWriteData(':');
	LcdWriteData('4');
	LcdWriteData('0');
	LcdWriteData('C');
	while(1)
	{
		LcdWriteCom(0x81);
		LcdWriteData(LED_Buffer[0]);//高位
		LcdWriteCom(0x82);
		LcdWriteData(LED_Buffer[1]);//低位
		if(LED_Buffer[0]>='4')
		  buzz=0;
		if(LED_Buffer[0]<='3')
	    buzz=1;
	}
}

/*******************************************************************************
* 函数名        :UsartConfiguration()
* 函数功能		   :串口设置
* 输入         : 无
* 输出        : 无
*******************************************************************************/

void UsartConfiguration()
{
	SCON=0X50;			//串口工作方式1,波特率可变
	TMOD=0X20;			//计数器工作方式2
	PCON=0X80;			//波特率加倍
	TH1=0XF3;				//波特率是4800,根据计算得到定时器初值
	TL1=0XF3;          //TH1和TL1一样当串口工作在方式1时,
	//波特率=(2^SMOD/32)*(单片机时钟频率/((256-X)*12)),X是初值,初值就是0xF3.先知道波特率再算初值。
	ES=1;						//打开接收中断
	EA=1;						//开总中断
	TR1=1;					//开启定时器
}

/*******************************************************************************
* 函数名        :Com_Int()
* 函数功能		   :设置中断服务程序
* 输入         : 无
* 输出        : 无
*******************************************************************************/
void Com_Int(void) interrupt 4//有Interrupt说明是中断服务程序
{
//中断服务程序里面写的是进入中断后干的事情
//中断函数不需要声明
	static uchar i = 2;    //静态变量
	//EA = 0;//关闭总中断其实没有必要关这个
	if(RI == 1)   // RI:接收中断标志位,数据接收结束时,标志位会自动置1,需要通过程序将其置0
	{//中断一次只接受一位数字
		LED_Buffer[i] = SBUF; 
		RI = 0;  
		if(i==0) i = 2;  
		i--;		
	}
	//EA = 1;//打开总中断
	LED = ~LED;//指示灯闪
}

串口发送程序

在这里插入代码片

你可能感兴趣的:(项目)