电子设计总结

记录关于电子设计

选题内容

利用焊接完的电路板完成软件的设计,本次选的题目为温度控制器与蓝牙通信,最终达到手机端能收到温度控制器测得的实时温度,其中温度控制器的核心部件是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口灯开关,成功!!!

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

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//主函数
#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;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//温度测量模块
#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


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!