C51单片机-示例代码成品(3)——双机通信系统

一、功能介绍

通过机器对话可以实现单片机A从另一个单片机B中获取体温、汇率

二、通信原理流程图

2.1 初始化按键

2.2 功能按键一

2.3 功能按键二与功能按键三

三、矩阵按键模块Key

这里矩阵按键代码只用于单片机A

3.1 Key.c

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
#include <REGX52.H>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
unsigned char KeyScan()
{
unsigned char KeyNumber=0;

P1=0xFF;
P1_3=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}

P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}

P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}

P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}

return KeyNumber;
}

3.2 Key.h

1
2
3
4
5
6
#ifndef __KEY_H__
#define __KEY_H__

unsigned char KeyScan();

#endif

四、延时函数模块Delay

这里延时函数代码只用于单片机B

4.1 Delay.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <REGX52.H>

void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}

4.2 Delay.h

1
2
3
4
5
6
7
#ifndef __DELAY_H__
#define __DELAY_H__

//用户调用函数:
void Delay(unsigned int xms);

#endif

五、DS18B20温度传感器

这里DS18B20代码只用于单片机B

5.1 DS18B20.c

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
#include <REGX52.H>
#include "OneWire.h"

//DS18B20指令
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE

/**
* @brief DS18B20开始温度变换
* @param 无
* @retval 无
*/
void DS18B20_ConvertT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}

/**
* @brief DS18B20读取温度
* @param 无
* @retval 温度数值
*/
float DS18B20_ReadT(void)
{
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=OneWire_ReceiveByte();
TMSB=OneWire_ReceiveByte();
Temp=(TMSB<<8)|TLSB;
T=Temp/16.0;
return T;
}

5.2 DS18B20.h

1
2
3
4
5
6
7
8
#ifndef __DS18B20_H__
#define __DS18B20_H__

void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);

#endif

5.3 OneWire.c

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
#include <REGX52.H>

//引脚定义
sbit OneWire_DQ=P3^7;

/**
* @brief 单总线初始化
* @param 无
* @retval 从机响应位,0为响应,1为未响应
*/
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 247;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay 500us
return AckBit;
}

/**
* @brief 单总线发送一位
* @param Bit 要发送的位
* @retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ=1;
}

/**
* @brief 单总线接收一位
* @param 无
* @retval 读取的位
*/
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}

/**
* @brief 单总线发送一个字节
* @param Byte 要发送的字节
* @retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}

/**
* @brief 单总线接收一个字节
* @param 无
* @retval 接收的一个字节
*/
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}

5.4 OneWire.h

1
2
3
4
5
6
7
8
9
10
11
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__

unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);

#endif

六、字符串处理模块StrFunction

7.1 StrFunction.c

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
#include <REGX52.H>

// 进行字符串的相等判断
unsigned char StrEqual(unsigned char *str, unsigned char *getStr)
{

while(*str!='\0'){
if (*str != *getStr) {
return 0;
}
str++;
getStr++;
}
return 1;
}

void Int2Str(unsigned int num, unsigned char *str)
{
unsigned char nums[5];
unsigned char i = 0,j = 0;
while (num != 0) {
nums[i] = num % 10;
num /= 10;
i++;
}
while (i--) {
*(str + j) = nums[i] + '0';
j++;
}
}


void Float2Str(float value, unsigned char *str)
{
unsigned char IntegerPart;
float DecimalPart;
unsigned char i = 0;
unsigned char j = 0;
char temp;

if (value >= 1)
{
IntegerPart = (unsigned char) value;
DecimalPart = value - IntegerPart;
}
else if (value <= -1)
{
IntegerPart = (unsigned char) (-value);
DecimalPart = -(value + IntegerPart);
}
else
{
IntegerPart = 0;
DecimalPart = value - IntegerPart;
}
// Deal IntegerPart
if (IntegerPart == 0)
{
str[0] = value >= 0 ? '+' : '-';
str[1] = '0';
str[2] = '.';
i = 2;
}
else
{
while(IntegerPart > 0)
{
str[i] = IntegerPart % 10 + '0';
IntegerPart /= 10;
i++;
}
str[i] = value >= 0 ? '+' : '-';
// fix the result
for (j=0;j<i;j++)
{
temp = str[j];
str[j] = str[i - j];
str[i - j] = temp;
}
i++;
str[i] = '.';
}

// convert the Decimalpart
i++;
str[i++] = (unsigned int)(DecimalPart * 10) % 10 + '0';
str[i++] = (unsigned int)(DecimalPart * 100) % 10 + '0';
str[i++] = (unsigned int)(DecimalPart * 1000) % 10 + '0';
str[i++] = (unsigned int)(DecimalPart * 10000) % 10 + '0';
str[i] = '\0';

}

6.2 StrFunction.h

1
2
3
4
5
6
7
8
9
#ifndef __STRFUNCTION_H__
#define __STRFUNCTION_H__

//用户调用函数:
unsigned char StrEqual(unsigned char *str);
unsigned char Int2Str(unsigned int num, unsigned char *str);
void Float2Str(float value, unsigned char *str);
#endif

七、串口模块UART

7.1 UART.c

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
#include <REGX52.H>


// 串口初始化
void UART_Init(void) //4800bps@11.0592MHz
{
PCON |= 0x80; //
SCON = 0x50; //
TMOD &= 0x0F; //
TMOD |= 0x20; //
TL1 = 0xF4; //
TH1 = 0xF4; //
ET1 = 0; //
TR1 = 1; //
EA = 1;
ES = 1;
}

// 发送一位字符
void UART_SendByte(unsigned char byte) {
SBUF = byte;
while(TI == 0);
TI = 0;
}

// 发送一个数字
void UART_SendNum(unsigned int num) {
unsigned char nums[5];
unsigned char i = 0;
while (num != 0) {
nums[i] = num % 10;
num /= 10;
i++;
}
while (i--) {
UART_SendByte(nums[i] + '0');
}
}

// 发送一行字符串
void UART_SendString(unsigned char *str) {
while(*str!='\0'){
SBUF = *str;
while(TI == 0);
TI = 0;
str++;
}
}

7.2 UART.h

1
2
3
4
5
6
7
8
9
10
11
#ifndef __UART_H__
#define __UART_H__

//用户调用函数:
void UART_Init(void);
void UART_SendByte(unsigned char byte);
void UART_SendNum(unsigned int num);
void UART_SendString(unsigned char *str);

#endif

八、显示屏幕LCD1602模块

8.1 LCD1602.c

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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;

i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}

/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}

/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}

/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}

/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}

/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}

/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}

/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}

/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}

8.2 LCD1602.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

九、main模块

9.1 单片机A的main.c

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
#include <REGX52.H>
#include "StrFunction.h"
#include "UART.h"
#include "LCD1602.h"
#include "Key.h"
#define MaxStrLen 20
#define MaxExRate 5
unsigned char getStr[MaxStrLen];
unsigned char strIndex = 0;


/*******************************************************************************
* 函 数 名 : UART_Get
* 函数功能 : 处理UART传来的整组数据的函数,
主要功能:处理UART传来的数据
如果接收到温度信息,则会在LCD1602显示温度内容;
如果接收到汇率信息,则会在LCD1602显示汇率内容

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void UART_Get()
{
unsigned char rateShowLine; // 汇率显示的行数
// 进行温度请求后将得到的温度信息进行温度的显示
if (getStr[0] == '+' || getStr[0] == '-') {
// 这两句是为了清楚LCD1602,避免出现显示错误
LCD_ShowString(1,1," ");
LCD_ShowString(2,1," ");
// 温度显示
LCD_ShowString(1,1,"Now Temperature ");
LCD_ShowString(2,5, "0000");
LCD_ShowString(2,1,getStr);
}
// 除了温度请求外,得到自然就是汇率信息了
else {
// 获取汇率信息第8位数据的信息,从而进行显示
rateShowLine = getStr[7] - '0';
getStr[7] = ' ';

LCD_ShowString(rateShowLine,1,getStr);
// if (getStr[7] == '1') {
// getStr[7] = ' ';
// LCD_ShowString(1,1,getStr);
// }
// else if (getStr[7] == '2') {
// getStr[7] = ' ';
// LCD_ShowString(2,1,getStr);
// }
}
}

/*******************************************************************************
* 函 数 名 : UART_Routine
* 函数功能 : UART中断函数,
主要功能:UART接收到数据后发生中断进行处理
如果接收到';',说明收到的一组数据结束,
需要对这组数据进行处理并且清除接收数据的容器;
如果接收数据满,则会直接清除接收数据的容器,不作回应。

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void UART_Routine() interrupt 4
{
if (RI == 1) {
// 如果收到';'说明到达一组数据的尽头,所以需要进行判断和清除
if (SBUF == ';') {
RI = 0;
UART_Get();
strIndex = 0;
return;
}
getStr[strIndex] = SBUF;
RI = 0; //
strIndex++;
// 如果一次性收到的数据过多,也会清除数据
if (strIndex == MaxStrLen) {
// UART_SendString("INPUT TO MANY!");
strIndex = 0;
}
}
}

/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
主要功能:初始化一些硬件,并且不断扫描按键,实现询问的功能。
如果接收到';',说明收到的一组数据结束,
需要对这组数据进行处理并且清除接收数据的容器;
如果接收数据满,则会直接清除接收数据的容器,不作回应。

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main(void)
{
unsigned char exrate = 0;
LCD_Init();
UART_Init();
while(1) {
// 扫描矩阵键盘按键
unsigned char key_push = KeyScan();
if (key_push == 1) { // 初始化按键,请求连接,如果不请求连接的话后续按键将无法得到回应
UART_SendString("Ask to connect;");
}
else if (key_push == 2) { // 功能按键一,请求温度信息
UART_SendString("Temper;");
}
else if (key_push == 3) { // 功能按键二:请求汇率
UART_SendString("Exchange rate ");
// 逐位发送,主要是为了让exrate变得可以调整,方便进行功能拓展
UART_SendByte(exrate + '0');
UART_SendByte(';');
exrate++;
if (exrate == MaxExRate) exrate = 0;
}
else if (key_push == 4) { // 功能按键三:汇率逆序
UART_SendString("Exchange rate inver;");
}
}
}


9.2 单片机B的main.c

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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <REGX52.H>
#include "StrFunction.h"
#include "UART.h"
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#define MaxStrLen 20
#define MaxExRate 5
#define RateStrLen 6
#define CNY "CNY "
#define ConsNum "1.0000 "
unsigned char getStr[MaxStrLen];
unsigned char strIndex = 0;
unsigned char isRateInver = 0;
float temperature;
unsigned char whatRate;
unsigned char isConnected;
unsigned char code *rate[3][5] = {{"1.0866 ", "0.1394 ", "0.1276 ", "4.40 ", "20.7104"},
{"0.9202 ", "7.1728 ", "7.8370 ", "0.22727", "0.04829"},
{"HKD ", "USD ", "EUR ", "TWD ", "JPY "}};


/*******************************************************************************
* 函 数 名 : sendLine
* 函数功能 : 发送行数据,用于汇率查询的功能


* 输 入 : line = 1,通过UART发送的数据为请求数据的单片机需要显示的第一行数据;
* line = 2,通过UART发送的数据为请求数据的单片机需要显示的第二行数据;
* str1:需要发送的一组数据中前面的部分;str2:需要发送的一组数据中后面的部分。
* 输 出 : 无
*******************************************************************************/
void sendLine(unsigned char line, unsigned char *str1, unsigned char *str2)
{
unsigned char *tmp;
// 如果是汇率逆序的状态,所要显示的str就要进行交换
if (isRateInver == 1) {
tmp = str1;
str1 = str2;
str2 = tmp;
}
UART_SendString(str1);
// 这里的line处于整个16位数据的第8位,这样传输到另外一个单片机就便于其将信息显示到LCD1602对应的列上
// 本质上将line信号也一同传输过去,并且不会干扰传输过去的有效信息
UART_SendByte(line + '0');
UART_SendString(str2);
UART_SendByte(';');
}

/*******************************************************************************
* 函 数 名 : UART_Get
* 函数功能 : 处理UART传来的整组数据的函数,
主要功能:处理UART传来的数据
如果处于初始状态或者拒绝连接状态,接收到请求连接信息,则会在LCD1602显示连接成功,并且进入连接状态,允许进行数据访问;
如果处于连接状态,接收到请求连接信息,将会在LCD1602显示拒绝连接,进入不连接状态,不允许进行数据访问。
如果处于连接状态,接收到温度请求信息,将会调用自身的DS18B20获取浮点数的温度结果,然后逐个拆解DS18B20来将结果通过UART输出;
如果处于连接状态,接收到汇率逆序输出请求,将会使得自身的汇率输出状态取反,并且将上一次要求输出的的汇率信息逆序分为两组输出;
如果处于连接状态,接收到汇率输出请求,将会根据接收的内容里面的汇率表的索引来将本机表里面对应汇率信息分两组输出。

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void UART_Get()
{
// 初始化的处理,通过该按键可以控制是否连接本单片机
if (StrEqual("Ask to connect", getStr)) {
isConnected = isConnected == 0 ? 1 : 0;
if (isConnected == 1){
LCD_ShowString(1,1,"Connecting ");
LCD_ShowString(2,1,"Successfully!!! ");
}
else{
LCD_ShowString(1,1,"No Connecting ");
LCD_ShowString(2,1," ");
}
}
// 如果连接成功,将会运行使用下面功能
if (isConnected == 1){
// 温度询问信息的回复
if (StrEqual("Temper", getStr)) {
// 调用DS18B20得到float数据
DS18B20_ConvertT();
temperature = DS18B20_ReadT();
// 判断是否为整数从而发送'-' or '+'
if (temperature <0) {
UART_SendByte('-');
temperature = -temperature;
}
else
{
UART_SendByte('+');
}
// 首先发送整数部分
UART_SendNum(temperature);
// 再发送小数点
UART_SendByte('.');
// 再发送小数点后四位
UART_SendNum((unsigned long)(temperature*10000)%10000);
// 补充足够的空格,可以让接收温度信息的单片机进行数据显示的时候可以显示正确,不会被前面的信息影响
UART_SendString(" ");
UART_SendByte(';');
}
// 如果需要进行汇率逆转
else if(StrEqual("Exchange rate inver", getStr)) {
// 先反转后显示
isRateInver = isRateInver == 0 ? 1 : 0;
// sendRate();
sendLine(1, CNY, rate[2][whatRate]);
Delay(300);
sendLine(2, ConsNum, rate[isRateInver][whatRate]);
}
// 这里就是进行汇率读取
else
{
// 得到第15位的数据,从而输出对应序号与人民币之间的汇率
whatRate = getStr[14] - '0';
if (whatRate < 5) {
sendLine(1, CNY, rate[2][whatRate]);
Delay(300);
sendLine(2, ConsNum, rate[isRateInver][whatRate]);
}
}

}
}

/*******************************************************************************
* 函 数 名 : UART_Routine
* 函数功能 : UART中断函数,
主要功能:UART接收到数据后发生中断进行处理
如果接收到';',说明收到的一组数据结束,
需要对这组数据进行处理并且清除接收数据的容器;
如果接收数据满,则会直接清除接收数据的容器,不作回应。

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void UART_Routine() interrupt 4
{
if (RI == 1) { //
if (SBUF == ';') {
RI = 0;
UART_Get();
strIndex = 0;
return;
}
getStr[strIndex] = SBUF;
RI = 0; //
strIndex++;
if (strIndex == MaxStrLen) {
// UART_SendString("INPUT TO MANY!");
strIndex = 0;
}
}
}

/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
主要功能:初始化硬件部分的内容,并进入死循环,整体程序依靠中断运行

* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main(void) {
UART_Init();
DS18B20_ConvertT();
LCD_Init();
Delay(1000);
while(1) {

}

}