查看: 1119|回复: 0
打印 上一主题 下一主题

炎炎夏日需要一个清凉的地 - 自制水冷系统

[复制链接]
跳转到指定楼层
沙发
发表于 2015-9-26 21:52:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前段时间接手了一个项目,所以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 }

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表