版权声明:本文为博主原创文章,未经博主允许不得转载。 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”指令的时候,就主动的将温度通过蓝牙上传到手机。