经过几天的奋斗(并不) 总算写完了!
俗话说: 电路简单 程序就麻烦 我算是体会到了 555
以后再也不图省事了 软件可比硬件让人头大多啦!
这个温度计所有的显示部分都是一个IO来控制 用的型号是STC15W104 扩展用的2片 74HC595
当时看中它的程序空间大 结果其实也没那么大,嘎嘎 结果EEPROM只有1K了
好了 进入正题 我先自吹自擂一下 (啊?! 谁扔的臭鸡蛋!)
从左到右 三个按钮 1 2 3
按钮1:短按 查看最大最小温湿度 每按一次切换显示1个 这些数据全部存储在内部的FlashRom中 会自动更新
长按 清除内部FlashRom存储的数据 并用当前的测量值全部填充
按钮2:显示模式轮换,三个模式:温湿度自动轮换 仅温度 仅湿度
其中温湿度自动轮换时间可调 显示的数值是每次切换温湿度的时候测量的
仅温度 仅湿度 这两个的数据是 每半秒更新一次(不可调 但是可以在编译前调好,我设置的是半秒)
这2个模式貌似每次更新的时候 LED会闪一下 没办法 设计缺陷555 谁叫他1个IO干完全部的显示呢?
按钮3:切换自动轮换的时间 ,我设置了3个挡位 2.5s 5s 10s ,同时这个还会自动存储在FlashROM里,只需要设定时间一次~~
P.S 最后加点感想: 这次又学到了很多东西,还专门写了2个C文件模块,模块化编程好啊~ 赞美C语言!
昨天晚上写这个程序,写的头很大,来来回回删了又写写了又删 ,起码删了300行,可谓是绞尽脑汁,我那10毫升的大脑都要变成浆糊啦!
今晚折腾出来了 我甚开心,赶紧拍下照片发帖留念了,MCU的世界真是美妙....我永远喜欢单片机!
单片机源程序如下:
#include "stc15f2k60s2.h"#include "dht11.h" #include "iaprom.h" #define u8 unsigned char #define u16 unsigned int u8 code SMGtable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//最后这个是负号 void IOinit(); void LEDsDisplay(u8 Number,u8 position); void Timer0Init(); void hc595activate(); void hc595send (u8 sbyte); void Delay10ms(); void AllDisplay(u8 Integer,u8 Decimal); void keyscan(); void CheckMaxMin(); void NormalMode(); void TemponlyMode(); void HumionlyMode(); void ModeInit(); void ModeSelect(); //选择3种模式 void ViewMaxMin(); //查看最大最小温湿度 sbit LCHCK=P3^2; //595的时钟 sbit SFTCK=P3^3; sbit sb1=P3^4; //MaxMin按钮1 检查max min,4 组数据切换,长按清空flash存储区 sbit sb2=P3^5; //mode按钮sb2 切换模式 湿度温度自动切换 长温度 长湿度 sbit sb3=P3^0; //切换时间sb3 自动切换时间调整 2.5S 5S 10S 三档 50 100 200 extern bit TempPoOrNe; //温度正负位 bit TempHumiSelect=1; //1=Temp 0=Humi int Temp,Humi; u8 Time50ms=0; //50ms标志位 u8 SetTimes=50; //设定的时间 分别是 50(默认) 100 200 u8 SetMode=0x00; //模式标志位 分别为 0x00 0x11 0x22 自动切换 长温度 长湿度 u8 ConditionLeds=0x0f; //后4位控制4个LED灯泡的亮灭 0x01 MAX ,0x02 Min ,0x04 Temp ,0x08 Humi void main() { IOinit(); Delay1000ms();//延时1s 等待传感器就位 Timer0Init(); //定时器0初始化 EA=1;ET0=1; //开中断,开定时器0中断 GetTempAndHumi(); // 先读取一次温湿度 ModeInit(); //从ROM中读取mode 进行初始化 while(1) { ModeSelect(); //选择模式 每个模式也负责读取温度 CheckMaxMin(); keyscan(); } } void keyscan() { if(sb1==0||sb2==0||sb3==0) { Delay10ms(); if(sb1==0) { Timer0Init(); Time50ms=0; while(!sb1); Delay10ms(); if(Time50ms>20) //>1000ms { IapEraseSector(0x0000); IapProgramWord(0x0000,Temp); IapProgramWord(0x0002,Humi); IapProgramWord(0x0004,Temp); IapProgramWord(0x0006,Humi); } else { ViewMaxMin(); //短按操作 } Timer0Init(); //复位中断 Time50ms=0; } if(sb2==0) //切换模式 { if(SetMode==0x00) SetMode=0x11; else if(SetMode==0x11) SetMode=0x22; else if(SetMode==0x22) SetMode=0x00; else SetMode=0x00; while(!sb2); Delay10ms(); IapEraseSector(0x0200); //擦除扇区 IapProgramByte(0x0200,SetMode); //写入更改后的模式 Time50ms=0; } if(sb3==0&&SetMode==0x00) //调整自动切换时间 2.5s 5s 10s { while(!sb3); Delay10ms(); if(SetTimes==50) SetTimes=100; else if(SetTimes==100) SetTimes=200; else if(SetTimes==200) SetTimes=50; else SetTimes=50; } } } void CheckMaxMin() //将读取到的温度湿度和存储的最大最小值对比,如果有更大/更小的,就写入 { int MaxTemp,MaxHumi,MinTemp,MinHumi; Temp=TempInteger*10+TempDecimal; //把温度转化带正负的Int 如24.4 -> 244 if(TempPoOrNe!=1) Temp=Temp*-1; //判断温度正负 Humi=HumiInteger*10+HumiDecimal; //湿度转化 ,其实可以用无符号 因为湿度是不可能是负数.但是我偷懒了 MaxTemp=IapReadWord(0x0000); //从Rom中读取一些参数 做个留存保护 MaxHumi=IapReadWord(0x0002); MinTemp=IapReadWord(0x0004); MinHumi=IapReadWord(0x0006); if(Temp>MaxTemp||Temp<MinTemp||Humi>MaxHumi||Humi<MinHumi) //如果需要更新 { IapEraseSector(0x0000); if(Temp>MaxTemp) IapProgramWord(0x0000,Temp); else IapProgramWord(0x0000,MaxTemp); if(Temp<MinTemp) IapProgramWord(0x0004,Temp); else IapProgramWord(0x0004,MinTemp); if(Humi>MaxHumi) IapProgramWord(0x0002,Humi); else IapProgramWord(0x0002,MaxHumi); if(Humi<MinHumi) IapProgramWord(0x0006,Humi); else IapProgramWord(0x0006,MinHumi); } } void ModeInit() { SetMode=IapReadByte(0x0200); } void ViewMaxMin() //查看最大最小 { int cache; u8 cache1,cache2; Time50ms=0; while(sb1) //有按下就会继续往下执行 否则return { ConditionLeds=0x05; //最大温度灯亮 cache=IapReadWord(0x0000); if(cache<0) { TempPoOrNe=0; cache=cache*-1; } else TempPoOrNe=1; cache1=cache/10;cache2=cache%10; AllDisplay(cache1,cache2);//这是最大温度 if(Time50ms>100) { Time50ms=0; GetTempAndHumi(); TempHumiSelect=1; return; //五秒不再按按钮就会自动退出 } } Delay10ms(); //按键消抖 while(!sb1); //等你松手 Delay10ms(); //按键消抖 Time50ms=0; while(sb1) //等你继续按下 { ConditionLeds=0x09; //最大湿度灯亮 cache=IapReadWord(0x0002); cache1=cache/10;cache2=cache%10; AllDisplay(cache1,cache2);//这是最大温度 if(Time50ms>100) { Time50ms=0; GetTempAndHumi(); TempHumiSelect=1; return; //五秒不再按按钮就会自动退出 } } Delay10ms(); //按键消抖 while(!sb1); //等你松手 Delay10ms(); //按键消抖 Time50ms=0; while(sb1) //等你继续按下 { ConditionLeds=0x06; //最小温度 cache=IapReadWord(0x0004); if(cache<0) { TempPoOrNe=0; cache=cache*-1; } else TempPoOrNe=1; cache1=cache/10;cache2=cache%10; AllDisplay(cache1,cache2);//这是最小温度 if(Time50ms>100) { Time50ms=0; GetTempAndHumi(); TempHumiSelect=1; return; //五秒不再按按钮就会自动退出 } } Delay10ms(); //按键消抖 while(!sb1); //等你松手 Delay10ms(); //按键消抖 Time50ms=0; while(sb1) //等你继续按下 { ConditionLeds=0x0a; cache=IapReadWord(0x0006); cache1=cache/10;cache2=cache%10; AllDisplay(cache1,cache2);//这是最小湿度 if(Time50ms>100) { Time50ms=0; GetTempAndHumi(); TempHumiSelect=1; return; //五秒不再按按钮就会自动退出 } } Delay10ms(); //按键消抖 while(!sb1); //等你松手 GetTempAndHumi(); Delay10ms(); //按键消抖 TempHumiSelect=1; Time50ms=0; } void NormalMode() //常规模式 { if(TempHumiSelect) { ConditionLeds=0x04; //亮温度灯 AllDisplay(TempInteger,TempDecimal); } else { ConditionLeds=0x08; //亮湿度灯 AllDisplay(HumiInteger,HumiDecimal); } if(Time50ms>SetTimes) { Time50ms=0; TempHumiSelect=~TempHumiSelect; GetTempAndHumi();//每次切换时读取一次温湿度 } } void TemponlyMode() //仅温度 { ConditionLeds=0x04; //亮温度灯 AllDisplay(TempInteger,TempDecimal); if(Time50ms>10) //500ms { Time50ms=0; GetTempAndHumi();//每次切换时读取一次温湿度 } } void HumionlyMode() //仅湿度 { ConditionLeds=0x08; //亮湿度灯 AllDisplay(HumiInteger,HumiDecimal); if(Time50ms>10) //500ms { Time50ms=0; GetTempAndHumi();//每次切换时读取一次温湿度 } } void ModeSelect() { if(SetMode==0x00) NormalMode(); else if(SetMode==0x11) TemponlyMode(); else if(SetMode==0x22) HumionlyMode(); else NormalMode(); } void IOinit(void) { //P3 0 1 2 3 4 5 x x // 阻 默 默 默 阻 阻 x x //M1 1 0 0 0 1 1 x x //M0 0 0 0 0 0 0 x x P3M1=0x31; P3M0=0x00; } void LEDsDisplay(u8 Number,u8 position) //在单个数码管和所有led灯珠显示内容 ,会自动在第三位上加上小数点 { u8 i=0,j=0xf0; i=(clrbit(j,position+3))+ConditionLeds; // 计算需要输出的位选+led指示灯亮灭情况 hc595send(i); //发送位选和状态显示灯状态位 if(position==3) hc595send(SMGtable[Number]|0x80); //第三位加个小数点 else hc595send(SMGtable[Number]); hc595activate(); } void AllDisplay(u8 Integer,u8 Decimal) //扫描显示所有4个数码管和led灯珠 //也进行显示正负 { if(TempPoOrNe!=1) { LEDsDisplay(10,1); //显示负号位 ,否则不显示 } if(Integer/10%10!=0) //判断十位是否需要消隐 { LEDsDisplay(Integer/10%10,2); //十位 } LEDsDisplay(Integer/1%10,3); //个位 LEDsDisplay(Decimal/1%10,4); //小数点后1位 } void Timer0Init() // 50ms @12Mhz 计时器0初始化 { AUXR &= 0x7F; //12T TMOD &= 0xF0; TL0 = 0xB0; TH0 = 0x3C; TF0 = 0; TR0 = 1; } void Timer0 () interrupt 1 //计时器0中断 { Time50ms++; } void hc595send (u8 sbyte) //移位输出8位数据至移位寄存器中 高位先进入移位寄存器 { u8 i=0; for(i=0;i<8;i++) { SFTCK=0; dat11=getbit(sbyte,7-i); SFTCK=1; } } void hc595activate() //让595输出寄存器输出移位寄存器保存的结果 { LCHCK=0; LCHCK=1; LCHCK=0; } void Delay10ms() //@12.000MHz 软延时10ms { unsigned char i, j; i = 117; j = 184; do { while (--j); } while (--i); }
复制代码