记录电子设计(温度控制器通过蓝牙同手机通信)

记录关于电子设计

选题内容

利用焊接完的电路板完成软件的设计,本次选的题目为温度控制器与蓝牙通信,最终达到手机端能收到温度控制器测得的实时温度,其中温度控制器的核心部件是DS18B20芯片和LCD1602A液晶显示芯片,蓝牙通信的核心部件是HC-08蓝牙串口通信模块,DS18B20芯片用来实现温度测量功能;LCD1602A液晶显示芯片用来实现测量温度显示功能,HC-08蓝牙串口通信模块作为上位安卓机同52单片机通信的桥梁,达到单片机能将所测得温度发送给上位机,上位机能向单片机发送一些指令的效果。

本次所选的题目,温度控制器实现了实时显示当前温度功能,可以设置上限阈值,即温度报警值,当温度达到阈值时蜂鸣器会响起滴答滴答的声音,同时LCD显示屏右上角显示出“W”代表进入报警状态此时的温度控制器仍然正常工作,当温度低于阈值时解除报警状态。除此之外,还设计了一个APP通过蓝牙模块同单片机通信,可以达到通过手机就能查看当前单片机测得的温度,查看阈值,调整阈值的功能。此项目综合实现了多方面的功能,运用了多个芯片和组件,对单片机知识的掌握是很好的一次考察,通过此项目的实现,提高了我对单片机知识的综合掌握程度。

具体实现

温度控制器主要涉及到的硬件资源有STC89C52RC、LCD1602A显示屏芯片、DS18B20芯片、蜂鸣器、HC-08蓝牙模块。此次实验搭建的蓝牙通信APP使用的是基AppInventor2服务器的WXbit图像化编程工具,能够较为轻松的搭建出一个APP。

在这里插入图片描述
在这里插入图片描述

逻辑设计

在这里插入图片描述

按照既定计划,本项目的流程为,先实现读取DS18B20模块数据,送给LCD1602模块显示,再之后就是最困难的通信模块构建,本次是基于蓝牙模块实现单片机同上位机(安卓手机)之间的通信,这就需要考虑到它们之间波特率的问题,由于此次实验通过的单片机晶振是12Mhz,12Mhz晶振通信起来误差是非常大的,这是由于其并计算初值时存在的误差。而市面上的蓝牙模块其默认波特率大都为9600,采用9600波特率,单片机根本无法同蓝牙模块建立稳定的通信,所以就要求使用AT指令调整波特率,调整到4800,并且波特率翻倍的情况下才能实现误差为0.16%的通信,较为可靠。

其中最头疼的就是数据如何存储发送了,因为串口一次只能发送八位数据,而获取的温度值是有小数的,所以我尝试了两种方案,一是将数据分为整数部分和小数部分,分两次发送,二是将数据存为字符数组,直接发送字符数组,实践证明,第二种效果较好。

在这里插入图片描述

蓝牙模块同51系列单片机通信

最重要的方面就是波特率设置啦,这个方面刚开始做的时候说实话踩了不少坑,因为学校电子设计提供的板子上面的晶振是12Mhz,总所周知,12Mhz的晶振通信起来误差是非常大的,这是由于其并计算初值时存在的误差。

最开始,我采用了杨老师提供的蓝牙模块,调试开始!经过一晚上的摸索,始终没能成功通信,这个时候仔细查阅发现,这个蓝牙模块波特率是固定9600的,而12Mhz的晶振产生9600的波特率,误差会达到5%左右,这是无法接受的,所以理所应当的通信不上。然后我在我的另外一个11.0592Mhz的单片机上面尝试成功。真的头很大,搞了一晚上还以为是单片机串口坏了。

之后,我购买了一个波特率可调的蓝牙模块,提供AT指令将蓝牙模块的波特率调为了4800,(经过查阅资料,发现当51单片机波特率调为4800时,波特率翻倍)这个时候误差会来到0.16%,这个误差能勉强接受,经过调试之后,通过手机上的蓝牙调试软件控制单片机P1口灯开关,成功!!!

然后就开始思考如何完成自己想做。

具体代码

//主函数
#include <REGX52.H>
#include "DS18b20.h"
#include "LCD1602.h"
char RECEIVED_CMD;
unsigned char flag = 0 ;      	// 数据接收的标志位
extern unsigned int tvalue;			//温度值
extern unsigned char tflag;			//温度正负标志
unsigned char disdata[7]; 			// 温度数据,使用8字节数组来存储
unsigned char chg[3];                 //存放阈值
unsigned int wrong = 30;

void UART_Init(); // 初始化串口
void UART_SendData(char dat); // 串口发送数据
void UART_SendStr(char* str); // 串口发送字符串
void ds1820disp(); 	// 温度显示
void change();			//转化阈值为字符数组
void main() 
{
	unsigned int temperature , old ; // 保存温度数值
	int A=5000;
	UART_Init();  // 串口初始化
	LCD_Init();  // 显示屏 初始化
	LCD_ShowString(1,1,"Temperature");
	P1_4 = 0;
	temperature = ReadTemperature(); 
	old = temperature ; 
	ds1820disp(); // 转换温度
	LCD_ShowString(2,1,disdata);
	LCD_ShowNum(2,13,wrong,2);
	while(1){
		temperature=ReadTemperature();  // 读取一次新的温度
		LCD_ShowNum(2,13,wrong,2); //2行13列显示wrong值
		LCD_ShowChar(2,16,'C');
if (temperature != old )	   
{	 
			old = temperature;
			ds1820disp(); // 转化温度
			LCD_ShowString(2,1,disdata); // 显示温度
	  }
		if(temperature > wrong * 10)
{
				P1_4 = !P1_4; //发出报警声
				while(A--);
				A=5000;
				LCD_ShowChar(1,16,'W');
		}
		else
{
			LCD_ShowChar(1,16,'N');
			P1_4 = 0;
		}
		if(flag) // 接收数据完毕一次,就会进入中断一次{
			flag = 0 ; // 将标志位还原,使得串口又可以重新接收数据			
			if(RECEIVED_CMD == '0')
{
				UART_SendStr(disdata);//向串口发送数据,发送的是当前温度
			}
			else if(RECEIVED_CMD == '3')
{
				change();
				UART_SendStr(chg);		//发送阈值
			}
			else if(RECEIVED_CMD == '1')
{
				wrong ++ ;//阈值加
			}
			else if(RECEIVED_CMD  == '2'){
				wrong -- ;//阈值减
			}			
			RECEIVED_CMD =' ';
		}
	}
}
//串口初始化
void UART_Init()
{
	SCON=0x50;
	PCON |= 0x80;
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF3;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	EA=1;
	ES=1;
	//打开两个外部中断
	IT0 = 1;
	IT1 = 1;
	EX0 = 1;
	EX1 = 1;
}
void UART_Isr() interrupt 4 using 1
{
	// 串口接收中断处理
	if(RI) {
		RI = 0 ;                              // 清除中断标志位
		RECEIVED_CMD = SBUF ; // 保存串口接收的数据
		flag = 1 ;           // 接收结束,到循环中处理接收的数据
		}
	// 串口发送中断处理
	if(TI)
{
		TI = 0 ;  // 清发送中断标志位
	}	
}
//开关K1
void int0() interrupt 0
{
	wrong ++;
}
//开关K2
void int1() interrupt 2
{
	wrong --;
}
//通过串口发送一位数据
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=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位显示符号
			}
		}
}
//转换阈值
void change(){
	chg[0] = wrong / 10 + 0x30;
	chg[1] = wrong % 10 + 0x30;
}

//温度测量模块
#include "DS18b20.h"
unsigned int tvalue;//温度值
unsigned char tflag;//温度正负标志
//延时函数
void delay(unsigned int i){
 while(i--);
}
//初始化DS18B20
void Init_DS18B20(void){
	unsigned char x=0;
	DQ = 1;    //让DQ置1
	delay(8);  
	DQ = 0;    //DQ拉低
	delay(80); //延时480-960us
	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;	//若是dat最高位置1,不是则置0
		delay(4);
	}
	return(dat);}
void WriteOneChar(unsigned char dat){
 unsigned char i=0;
 for (i=8; i>0; i--)	//循环八次得出数据{
  DQ = 0;		 //DQ先置低电平
  DQ = dat&0x01;  //取最低位
  delay(5);
  DQ = 1;	
  dat>>=1;		//由低位向高位发送数据
 }
}
int ReadTemperature(void)
{
	unsigned char a=0;
	unsigned char b=0;
	Init_DS18B20();		//启动DS18B20
	WriteOneChar(0xCC); 	//跳过读序列号的操作
	WriteOneChar(0x44); 	//启动温度转化
	Init_DS18B20();				//启动DS18B20
	WriteOneChar(0xCC);		//跳过读序列号的操作
	WriteOneChar(0xBE);		//读取温度寄存器等(共可读9个寄存器)前两个是温度
	a=ReadOneChar();			//读取温度低位
	b=ReadOneChar();			//读取温度高位
	tvalue = b;					//处理数据
	tvalue <<= 8;				//高位左移八位
	tvalue = tvalue|a;
	if(tvalue<0x0fff)		//小于0x0fff为正数
		tflag=0;
	else{
		tvalue=~tvalue+1;		//取反加一
		tflag=1;						//负数
  }
	tvalue = tvalue*(0.625);//温度值扩大10倍,精确到1位小数
	return(tvalue);
}

具体项目:https://github.com/KrealHtz/Studywork

版权声明:本文为CSDN博主「KrealHtz0.0」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_46637857/article/details/121679977

生成海报
点赞 0

KrealHtz0.0

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

3D电路——搭棚数码管时钟

title: 3D电路——搭棚数码管时钟 date: 2021-12-13 15:24:15 tags: 电子设计 前言 ​ 电子时钟是一种采用数字电路实现显示时、分、秒数字的计时装置,是人们日常生活中不可缺少的物品&#xff

【浅谈HC05 蓝牙模块与与蓝牙模块连接】

两个蓝牙模块配对通信 在通常的电子设计中,一般采用蓝牙模块与上位机(手机)连接来与电子设备通信,实现对电子设备的控制。当然也可以通过WiFi模块等其他通信模块进行通信。这里就介绍一下蓝牙

RT-Thread Studio移植LAN8720A驱动

RTT网络协议栈驱动移植(霸天虎) 1、新建工程 ​ 工程路径不含中文路径名,工程名用纯英文不含任何符号。 2、用CubeMx配置板子外设 2.1、配置时钟 ​ 按照自己板子配置相应时钟。

ESP8266 无限重启踩坑

最近做了一个电子墨水屏万年历,在移植屏幕代码时遇到了esp8266无限软复位的问题,如果你的串口打印是以下图片所示,那么恭喜你问题解决了。 造成软复位的原因是因为,程序里有死循环&#xf