前段时间接手了一个项目,所以DIY的进程有些停滞。实际编写的程序并没有多长时间,得益于Keil这个强大的IDE。能在第一次做51开发的时候,如此顺利的完成代码。
不多说废话了,说明下代码的具体思路。具体思路根据(六 控制系统原理图)进行拆分。分为温度显示部分、指示灯、温度获取和继电器操控部分。
LEDDisplay.c --- 温度显示模块
PilotLamp.c --- 指示灯控制模块
Temperature.c
12b20Temperature.asm --- 温度读取模块
Relays.c --- 继电器控制部分
系统主要控制的指数
1、读取温度的间隔时间
2、在调整温度的时候显示制冷控制温度时间。
3、当达到制冷温度设定值时,关闭或开启控制器一个缓冲量。防止在阀值的时候出现上下跳变问题。
4、控制调整温度的调节范围和调节量
开发中的主要阻力还是来至于温控IC。18B20的时序操作非常严格。如果要自己写调试太耗时间。因此直接从前辈取材,汇编是控制时序是最精确的,在网上找到的很多代码基本也是以汇编为主。我的代码是从杜洋老师已调整好读写时序的汇编代码改编而来。做了些小改动,把温度的精度提高到0.06°C。
另外一个让人抓狂的问题,没能找到根源解决。汇编和C混合开发中,变量的存储地址出现混乱。主程序部分的变量被汇编中的地址操作覆写,导致变量值被冲掉。不知道动了哪根筋,原来木问题后来才有这个问题。 -_-!!哭啊~~ 只能用一个方式规避这个问题,把被覆写变量的地址改为bdata段地址。修改后暂未发现程序中其他变量被覆写的问题。
主控
PCB设计电路板
调试的效果图
详细的系统小弟就不贴了,可以直接看发在PCB版中的内容。
贴出第一次写51代码^^。小弟有一点开发经验,只是软硬结合的这种模式属于第一个。
--------------------------------
1 #include <STC12C5A60S2.h>
2
3 #include "Pins.h"
4 #include "LEDDisplay.h"
5 #include "Temperature.h"
6 #include "Relays.h"
7 #include "PilotLamp.h"
8
9 #define uchar unsigned char
10 #define uint unsigned int
11
12 // 获取温度的时间间隔
13 #define TEMPGETCOUNT 5000 // 温度读取间隔, 500ms 读一次温度,即1秒读2次温度。
14 #define CHANGINGCOUNT 20000 // 温度调控状态时会显示调控温度值,最长显示时间。
15 #define CRITICALCOUNTDOWN 5 // 温度下临界跳变阀值
16 #define CRITICALCOUNTUP 5 // 温度上临界跳变阀值
17 #define CRITICALCOUNTERR 3 // 温度错误,3次关闭
18 #define DEFAULTCRITICALTEMP 2500 // 默认跳变温度 25°C
19 #define VALIDTEMPERATURE_MAX 3000 // 最大有效温度 30°C
20 #define VALIDTEMPERATURE_MIN 2000 // 最小有效温度 20°C
21 #define TEMPERATURESPET 50 // 0.5 °C 温度调整步长
22
23
24 #define COOL_POWERALL 0xFF // 全力运行
25 #define COOL_MALAISE 0x00 // 萎靡~~~~~ 哇咔咔~~~
26
27 #define KEYPRESS_LONG 200 // 按键长按计数,如一只按住不放
28 #define KEYPRESS_SHORT 15 // 短按计数
29
30
31 #define FOSC 1843200L
32 #define T1MS (65536-FOSC/12/1000) // 计时器工作频率 12T状态
33
34
35 uint CriticalTempVal; // 临界温度,跳变温度
36 uint RealTempVal; // 当前温度,获取一定次数时都
37 uint ChangeCount; // 临界切换计数
38
39 uchar RelayVal; // 继电器状态控制位 从右到左 0x03(0000 0011) 那么第一第二个继电器打开。
40 // 指示灯状态
41 // 第一位 继电器工作状态,灯亮工作状态,灯灭停止制冷
42 // 第二位 是否为自动模式
43 // 第三位 温控器故障
44 // 0000 0111
45 uchar DirectLamp;
46 uchar bdata WorkStatus;
47 sbit InCritical = WorkStatus ^ 0; // 临界状态
48 sbit InWorking = WorkStatus ^ 1; // 工作状态
49 sbit InAuto = WorkStatus ^ 2; // 自动模式
50 sbit InHandOn = WorkStatus ^ 3; // 手动打开状态
51 sbit CanReadTemp = WorkStatus ^ 4; // 是否允许读取温度
52 sbit InInitTemp = WorkStatus ^ 5; // 温度读取是否在初始状态,解决第一次读取出现85°C的问题
53 sbit InChangingTemp = WorkStatus ^ 6; // 在温度调整中
54
55
56 // 温度读取时间间隔,减少18B20的读取次数,
57 // 目的是为数码管能获得比较高的刷新频率,提高显示亮度。
58 // 每次读取会有固定占用时间,能看出每次读取会有变暗的闪烁情况。
59 uint TempTimerSpace;
60
61 uint TempChangingStatusSpace; // 温度调控状态中
62
63 void Init(void);
64 bit CanUpdateTemp(void);
65 void UpdateTemperature(void);
66 void ReadTemperature(void);
67 void UpdateStatus(void);
68 void InitTimer(void);
69 void SearchKeys(void);
70
71 unsigned int GetCriticalTemperature(void);
72 //void SaveCriticalTemperature(unsigned int);
73
74
75 // 按键
76 // 18 K3 17 K4 16 K5
77 sbit Key_Mode = P1 ^ 1;
78 sbit Key_CTDown = P1 ^ 0;
79 sbit Key_CTUp = P0 ^ 0;
80
81 //enum KeyType (TNone=0, KTMode=1, KTCTDown=2, KTCTUp=4);
82
83 uchar KeyCount;
84 uchar KeyTypeVal;
85
86 #define KEYTYPE_NONE 0 // 没有按键使用
87 #define KEYTYPE_MODE 1 // 按下模式切换状态
88 #define KEYTYPE_CTDOWN 2 // 按下温度切换状态
89 #define KEYTYPE_CTUP 4 // 按下温度切换状态
90
91
92 void main()
93 {
94 Init();
95 while(1){
96 if (CanReadTemp)
97 ReadTemperature();
98
99 SearchKeys();
100 UpdateStatus();
101 UpdateRelays(RelayVal);
102
103 if (!InChangingTemp)
104 DisplayTemperature(RealTempVal);
105 else
106 DisplayTemperature(CriticalTempVal);
107
108 DisplayPilotLamp(DirectLamp);
109 }
110 }
111
112 void Init(void){
113 WorkStatus = 0x00;
114 InAuto = 1; // 默认自动模式
115
116 KeyCount = 0;
117 KeyTypeVal = KEYTYPE_NONE;
118 RealTempVal = DEFAULTCRITICALTEMP;
119 CriticalTempVal = GetCriticalTemperature();
120
121 InitTimer();
122 InitPilotLamp();
123 InitView();
124 InitTemperature();
125 InitRealys();
126 }
127
128 void SearchKeys(void){
129 // 模式切换
130 if (Key_Mode == 0){
131 KeyTypeVal = KEYTYPE_MODE;
132 KeyCount++;
133 }
134
135 // 温控温度
136 if (Key_CTDown == 0) {
137 KeyTypeVal = KEYTYPE_CTDOWN;
138 KeyCount ++;
139
140 // 长按状态
141 if (KeyCount > KEYPRESS_LONG) {
142 KeyCount = 0;
143 if (CriticalTempVal > VALIDTEMPERATURE_MIN) {
144 TempChangingStatusSpace = CHANGINGCOUNT;
145 CriticalTempVal -= TEMPERATURESPET;
146 }
147 }
148 }
149
150 // 温控温度
151 if (Key_CTUp == 0) {
152 KeyTypeVal = KEYTYPE_CTUP;
153 KeyCount ++;
154
155 // 长按状态
156 if (KeyCount > KEYPRESS_LONG) {
157 KeyCount = 0;
158 if (CriticalTempVal < VALIDTEMPERATURE_MAX){
159 TempChangingStatusSpace = CHANGINGCOUNT;
160 CriticalTempVal += TEMPERATURESPET;
161 }
162 }
163 }
164
165 if (KeyCount > KEYPRESS_SHORT){
166 if (Key_Mode == 1 && KeyTypeVal == KEYTYPE_MODE){
167 KeyTypeVal = KEYTYPE_NONE;
168 KeyCount = 0;
169 if (InAuto){
170 InAuto = 0;
171 InHandOn = 1;
172 }
173 else {
174 if (InHandOn)
175 InHandOn = 0;
176 else
177 InAuto = 1;
178 }
179 }
180
181 if (Key_CTDown == 1 && KeyTypeVal == KEYTYPE_CTDOWN){
182 KeyTypeVal = KEYTYPE_NONE;
183 KeyCount = 0;
184 if (CriticalTempVal > VALIDTEMPERATURE_MIN) {
185 CriticalTempVal -= TEMPERATURESPET;
186 TempChangingStatusSpace = CHANGINGCOUNT;
187 }
188 }
189
190 if (Key_CTUp == 1 && KeyTypeVal == KEYTYPE_CTUP){
191 KeyTypeVal = KEYTYPE_NONE;
192 KeyCount = 0;
193 if (CriticalTempVal < VALIDTEMPERATURE_MAX) {
194 TempChangingStatusSpace = CHANGINGCOUNT;
195 CriticalTempVal += TEMPERATURESPET;
196 }
197 }
198 }
199 }
200
201
202 void ReadTemperature(void){
203 unsigned int Val;
204
205 Val = GetTemperature();
206
207 // 18B20有个特殊问题,第一次读取会出现 85°C
208 if (InInitTemp && Val == 8500){
209 CanReadTemp = 1;
210 return;
211 }
212
213 RealTempVal = Val;
214 CanReadTemp = 0;
215 InInitTemp = 0;
216 //
217 // 对于临界温度,需要特殊处理。
218 // 防止温控在临界时频繁跳变,当在临界一侧温度超缓冲量时才允许跳转模式。
219 // 当温控探头无效时优先处理
220 //
221 // 如果温控探头被拔出,再次插入的时候会出现 85°C的错误情况
222 // 只要温度读取错误,那么就认为温控探头是被拔出状态。
223 //
224 if (RealTempVal == VAL_ERRTEMPERATURE){
225 InInitTemp = 1;
226 if (InCritical)
227 ChangeCount--;
228 else {
229 InCritical = 1;
230 ChangeCount = CRITICALCOUNTERR;
231 }
232 }
233 else if (InWorking) {
234 if (RealTempVal < CriticalTempVal){
235 if (InCritical)
236 ChangeCount--;
237 else {
238 InCritical = 1;
239 ChangeCount = CRITICALCOUNTDOWN;
240 }
241 }
242 else {
243 InCritical = 0;
244 ChangeCount = 0;
245 }
246 }
247 else {
248 if (RealTempVal > CriticalTempVal){
249 if (InCritical)
250 ChangeCount --;
251 else {
252 InCritical = 1;
253 ChangeCount = CRITICALCOUNTUP;
254 }
255 }
256 else {
257 InCritical = 0;
258 ChangeCount = 0;
259 }
260 }
261
262 }
263
264
265 void InitTimer(void){
266 // 使用定时器1作为时间计数
267 TMOD = 0x01;
268 TL0 = T1MS;
269 TH0 = T1MS >> 8;
270 TR0 = 1;
271 ET0 = 1;
272 EA = 1;
273
274 CanReadTemp = 0;
275 TempTimerSpace = TEMPGETCOUNT; // 第一次温度读取
276 InInitTemp = 1; // 温度处于初始状态,解决85°C问题
277 TempChangingStatusSpace = 0; // 不在调温状态
278 }
279
280
281 void UpdateStatus(void){
282 //
283 // 温控临界跳变, 缓冲计数为零时跳变
284 //
285 //
286 if (InCritical && !ChangeCount){
287 InCritical = 0;
288 if ((RealTempVal != VAL_ERRTEMPERATURE) && (RealTempVal > CriticalTempVal))
289 InWorking = 1;
290 else
291 InWorking = 0;
292 }
293
294 // 是否在调温状态
295 if (TempChangingStatusSpace)
296 InChangingTemp = 1;
297 else
298 InChangingTemp = 0;
299
300 //
301 // 温控状态和手工状态
302 // 温控状态时根据是否工作状态判断,手动模式下通过是否强行开启判断继电器模式
303 //
304 if((InAuto && InWorking) || (!InAuto && InHandOn))
305 RelayVal = COOL_POWERALL;
306 else
307 RelayVal = COOL_MALAISE;
308
309 // 工作状态信息更新
310
311 if (RelayVal > 0)
312 DirectLamp = 1;
313 else
314 DirectLamp = 0;
315
316 if (InAuto)
317 DirectLamp |= 0x02;
318 }
319
320
321 unsigned int GetCriticalTemperature(void){
322 //todo : 这里的值需要从EEPROM中获取
323 return (DEFAULTCRITICALTEMP);
324 }
325 /*
326 void SaveCriticalTemperature(unsigned int Val){
327 //todo : 保存临界温度到EEPROM,防止停电丢失数据
328 }
329 */
330
331 void time0(void) interrupt 1{
332 // 时钟
333 TL0 = T1MS;
334 TH0 = T1MS >> 8;
335 TempTimerSpace--;
336 if (!TempTimerSpace){
337 CanReadTemp = 1;
338 TempTimerSpace = TEMPGETCOUNT;
339 }
340
341 if (TempChangingStatusSpace)
342 TempChangingStatusSpace--;
343 }
|