安卓手机与蓝牙模块联合调试(四)—— 单片机数据上传至蓝牙(STC89C52 + DS18b20)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010898329/article/details/82390167

系列博文:

(1)安卓手机与蓝牙模块联合调试(一)—— 蓝牙模块的串口通讯 

(2)安卓手机与蓝牙模块联合调试(二)—— 单片机蓝牙控制LED灯亮灭(上)

(3)安卓手机与蓝牙模块联合调试(三)—— 单片机蓝牙控制LED灯亮灭(下)

(4)安卓手机与蓝牙模块联合调试(四)—— 单片机数据上传至蓝牙(STC89C52 + DS18b20)

本教程的项目地址:1989Jiangtao/BluetoothSCM: 安卓手机通过蓝牙与单片机通信-发送指令/接收数据​​​​​​​


        前面三篇文章中我们介绍了蓝牙的基本操作指令,以及手机如何通过蓝牙下发指令控制单片机亮灭LED的操作,这一篇我来带大家实现数据从单片机上传到手机。

1.首先看下DS18b20获取到的温度,OLED显示。

看下DS18b20的源码部分,这个模块的代码网上也有很多的参考。

#include "DS18b20.h"

unsigned int tvalue;//温度值
unsigned char tflag;//温度正负标志

void delay(unsigned int i)
{
 while(i--);
}

void Init_DS18B20(void)
{
	unsigned char x=0;
	DQ = 1;    
	delay(8);  
	DQ = 0;    
	delay(80); 
	DQ = 1;    
	delay(14);
	x=DQ;      
	delay(20);
}

unsigned char ReadOneChar(void)
{
	unsigned char i=0;
	unsigned char dat = 0;
	for (i=8;i>0;i--)
	{
		DQ = 0; 
		dat>>=1;
		DQ = 1; 
		if(DQ)
		 dat|=0x80;
		delay(4);
	}
	return(dat);
}

void WriteOneChar(unsigned char dat)
{
 unsigned char i=0;
 for (i=8; i>0; i--)
 {
  DQ = 0;
  DQ = dat&0x01;
  delay(5);
  DQ = 1;
  dat>>=1;
 }
}

int ReadTemperature(void)
{
	unsigned char a=0;
	unsigned char b=0;

	Init_DS18B20();
	WriteOneChar(0xCC); 
	WriteOneChar(0x44); 
	Init_DS18B20();
	WriteOneChar(0xCC);
	WriteOneChar(0xBE);
	a=ReadOneChar();
	b=ReadOneChar();
	tvalue = b;
	tvalue <<= 8;
	tvalue = tvalue|a;
	if(tvalue<0x0fff)
		tflag=0;
	else
  {
		tvalue=~tvalue+1;
		tflag=1;
  }
	tvalue = tvalue*(0.625);//温度值扩大10倍,精确到1位小数
	return(tvalue);
}

顺带放上可能会用到的DS18b20.h头文件。

#ifndef __DS18B20_H_
#define __DS18B20_H_

#include "STC89C5xRC_RDP.h"

sbit DQ = P4^0; // 定义温度接口

void Init_DS18B20(void);  // 初始化
unsigned char ReadOneChar(void);  // 读一位数据
void WriteOneChar(unsigned char dat); // 写一位数据
int ReadTemperature(void); // 读取温度

#endif 

2.温度上传到手机。

先看下演示的效果,随后放上我的main.c,我的电路中Ds18b20接的是P4.0,在上面的头文件中也有定义。

/****************************************
**       蓝牙串口接收数据
** 
**   作者:江涛
**   时间:2018/08/31
**   描述:串口发送数据兼用OLED显示
****************************************/
#include "STC89C5xRC_RDP.h"
#include "string.h"     // 要使用字符串对比函数,需要引入该头文件
#include "OLED.h"       // OLED显示屏头文件
#include "DS18b20.h"

// 定义系统时钟和串口波特率
#define FOSC 11059200L      // 系统时钟
#define BAUD 9600           // 串口波特率

/******变量声明*********/ 
char RECEIVED_CMD[10] ;       // 暂定为10字节的指令
char RECEIVED_INDEX ;         // 数组指示索引,当接收到一个数据之后,索引会跟随增加
unsigned char flag = 0 ;      // 数据接收的标志位

/******命令常量*******/
code const char* LED_ON = "ON\r\n" ;
code const char* LED_OFF = "OFF\r\n" ;

extern unsigned int tvalue;//温度值
extern unsigned char tflag;//温度正负标志
unsigned char disdata[7]; // 温度数据,使用8字节数组来存储

/*******函数声明*********/
void Init_UART(); // 初始化串口
void UART_SendData(char dat); // 串口发送数据
void UART_SendStr(char* str); // 串口发送字符串

void ds1820disp(); // 温度显示


/*******程序入口*********/
void main() 
{

	unsigned int temperature , old ; // 保存温度数值
	
	Init_UART();  // 串口初始化
	
	LCD_Init();  // OLED 初始化
	LCD_CLS();   // 清屏
	
	LCD_P8x16Str(0 , 0 , "TEMP:");  // 温度开始位置
	
	temperature = ReadTemperature(); 
	old = temperature ; 
	ds1820disp(); // 显示温度
	UART_SendStr(disdata); // 向串口发送数据
	LCD_P8x16Str(5*8 , 0 , disdata); // 显示温度
	
	while(1)
	{
		
		temperature=ReadTemperature();  // 读取一次新的温度
    if (temperature != old )	  
	  {	 
			old = temperature;
			ds1820disp(); // 显示温度
			UART_SendStr(disdata); // 向串口发送数据
			LCD_P8x16Str(5*8 , 0 , disdata); // 显示温度

	  }
		
		if(flag) // 接收数据完毕一次,就会进入中断一次
		{
			flag = 0 ; // 将标志位还原,使得串口又可以重新接收数据
					
			if(strcmp(RECEIVED_CMD , LED_ON) == 0)
			{
				P2 = 0xFF ; // P2口全亮
			}
			else if(strcmp(RECEIVED_CMD , LED_OFF) == 0)
			{
				P2 = 0x00 ; // P2口全灭
			}
			
			// 用完之后要记得数组清零处理
      RECEIVED_INDEX = 0 ;        // 数组指引复位
      memset(RECEIVED_CMD,0,10);  // 清0数组
		}
	}
}

/******************
** 初始化串口
*******************/
void Init_UART()
{
		SCON = 0x50;                     //设置8位数据位
		TMOD = 0x20;                     //8位自动重载
		TH1 = TL1 = -(FOSC/12/32/BAUD);  //设置重载值
		TR1 = 1;                         //使能时钟
		ES = 1;                          //使能串口中断
		EA = 1;                          //开中断开关
}

/********************
** 串口中断处理
*********************/
void UART_Isr() interrupt 4 using 1
{
	// 串口接收中断处理
	if(RI) 
	{
		RI = 0 ;                              // 清除中断标志位
		RECEIVED_CMD[RECEIVED_INDEX] = SBUF ; // 保存串口接收的数据
		if(RECEIVED_CMD[RECEIVED_INDEX] == 0x0A ){ // 遇到了结束符号
			 flag = 1 ;           // 接收结束,到循环中处理接收的数据
		}else {
			 RECEIVED_INDEX ++ ;   // 继续接收数据
		}
	}

	// 串口发送中断处理
	if(TI)
	{
		TI = 0 ;  // 清发送中断标志位
	}
		
}

/**************************
** 通过串口发送一位数据
***************************/
void UART_SendData(char dat)
{
	ES = 0 ;      // 串口工作的时候禁止中断
	SBUF = dat ;  // 待发送的数据放到SBUF中
	while(!TI) ;  // 等待发送完毕
	TI = 0 ;      // 清TI中断
	ES = 1 ;      // 打开中断
}

/*****************************
**  通过串口发送字符串
******************************/
void UART_SendStr(char *str)
{
		do
		{
			UART_SendData(*str);
		}while(*str ++  != '\0' ); // 一直到字符串结束
}


/***************************
** 温度值显示
***************************/
void ds1820disp()
{ 	
	unsigned char flagdat;
	
    if(tflag==0)
//		flagdat=0x20;//正温度不显示符号
	    flagdat=0x2b;//正温度显示符号
	else
		flagdat=0x2d;//负温度显示负号:-
	
	disdata[1]=tvalue/1000+0x30;//百位数
	disdata[2]=tvalue%1000/100+0x30;//十位数
	disdata[3]=tvalue%100/10+0x30;//个位数
	disdata[4]= 0x2E ;//小数点
	disdata[5]=tvalue%10/1+0x30;//小数位

	if(disdata[1]==0x30) // 如果百位为0
	{
		disdata[0]= 0x20; // 第一位不显示
		disdata[1]= flagdat; // 百位显示符号
		if(disdata[2]==0x30) //如果百位为0,十位为0
		{
			disdata[1]=0x20; // 百位不显示符号
			disdata[2]=flagdat; // 10位显示符号
		}
	}
}

注释中已经写得很清楚了,温度值显示的函数中要注意ASCII码的对应关系就行,0x20是空,0x30是“0”,0x2E是小数点“.”。

3.小结。

       主函数中设定的规则是当前的温度不等于上一次记录的温度,就会刷新OLED显示,同时将新的温度数据通过蓝牙串口发送到手机,实现读取温度的功能,也可以写到命令中,当获取到注入“TEMP”指令的时候,就主动的将温度通过蓝牙上传到手机。

猜你喜欢

转载自blog.csdn.net/u010898329/article/details/82390167