基于stc15f204s的水晶倒計時牌
第一次在這發帖,如有不周請指正!
以前在網上發現了一個神操作,就是把搭棚電路封裝在滴膠里,美觀耐用且防止氧化。與其說是電路制作,我覺得是藝術品。寒假正好沒事干,就搞了一個倒計時牌,把之前學的51單片機知識用一用,順便督促一下自己珍惜時間。
剛開始是想用 STC15F104E(因為買多了)【注意,這個單片機內部定時器是T0和T1,跟現在的新產品不一樣】 ,做了幾個功能發現到處出bug,而且下載器里面沒有這個型號,數據手冊里面也只不過提了一兩次。后來一查發現這個型號早已經停產了,而且它的定時器和外部中斷由BUG(怒)。于是換了個stc15w204s。工欲善其事必先利其器,計劃在面包板上先做程序,調試好確定管腳分配后再搭棚。面包板接觸不好(通病),所以做了個單片機轉接座:
1583236459511.jpg (3.58 MB, 下載次數: 78)
下載附件
單片機轉接座
2020-3-3 20:08 上傳
1583236398866.jpg (4.46 MB, 下載次數: 84)
下載附件
實驗用面包板
2020-3-3 20:08 上傳
程序不是很復雜,有的地方有點啰嗦(大神勿噴),這里簡單解釋一下,整體思路是單片機驅動hc595,595驅動三位數碼管的段,單片機用9012擴流驅動數碼管的位,int0借1838b紅外接收,再加上ds1302時鐘芯片和ds18b20溫度芯片,還剩一個管腳接了rgb自閃燈(本來可以接紅外發射實現數據雙向傳輸的,不過我懶得寫程序和功能了)平時單片機就是while(1)等待,刷新、ir接收什么的全靠兩個定時器T0 T1和外部中斷0觸發。紅外接收程序是我自己想的,非常繁瑣(本可以簡單一些,不過我這么寫可以最大程度上減少誤觸發)。
單片機代碼如下:- #include<STC15.h>
- #include<stdio.h>
- #include<INTRINS.H>
- sfr WDT_COUNTER = 0xc1;//【下載的時候請勾選‘上電復位由硬件啟動看門狗’】
- //sbit CLR_WDT = WDT_COUNTER^5; //軟件置1,防止誤殺
- /*
- STC15w204s單片機,。數碼管共陽,0亮1滅。
- 使用兩片74hc595擴充管腳數目,連接ds1302時鐘芯片和1838B紅外接收頭。
- **********IR接收程序(NEC協議)************
- 基于狀態機,拒絕軟件delay函數,只使用一個定
- 時器和一個中斷(必須支持上升/下降沿中斷),
- 有利于系統資源的節約。程序錯誤無累計,利于
- 長期穩定運行。使用定時器作為時間基準,如需
- 要移植程序,只需要按照源程序時間要求重新生
- 成定時器初始化函數。其中所有關鍵組件,均已
- 在其后注明【這是計劃的一部分】。
- *******************************2020年2月20日
- BUG記錄:
- int0輸入信息量過大會造成程序跑飛
- */
- typedef unsigned char u8;//【這是計劃的一部分】
- typedef unsigned int u16;
- //595引腳連接(待定)Q0對應低位,Q7對應高位
- sbit ser=P5^5; //也叫SI
- sbit srclk=P1^5; //刷新輸出,上升沿有效
- sbit rclk=P1^4; //內部移位,上升沿有效
- //1838B
- sbit ir=P3^2;//【這是計劃的一部分】
- //18B20
- sbit DSPORT=P5^4;
- //DS1302
- sbit RST=P1^3; //控制器復位 高電平時才能工作,其實與復位關系不大
- sbit DSIO=P1^2; //數據
- sbit SCLK=P1^1; //時
- //led
- sbit led=P1^0;
- //有關于紅外接收的狀態標志位,定時器用t0,中斷用int0。【這是計劃的一部分】
- bit iract=0; //紅外活動
- u8 irstate=0; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- bit started=0; //已收到報頭,請忽視報尾
- bit t0reset=0; //定時器0溢出就回到等待狀態
- bit int0reset=0; //int0觸發就回到等待狀態
- bit int0negfall=0; //忽視int0的下降沿(只允許上升沿中斷)
- u8 bitamount=0; //收到的總位數(0-32)
- bit irbit=0; //當前ir位數
- u8 ir1=0x00,ir2=0xff,ir3=0x00,ir4=0xff;//ir接受結果
- bit irreceived=0;//如有待處理的紅外信息,此位置1
- u8 irresult=0;//irdecode函數解碼結果
- //system
- u16 data count=1000;
- u8 data stat=1;//0熄屏;1正常帶溫度;2正常無溫度;3設置界面(3set,4h十位,5h個位,6d百位,7d十位,8d個位)
- u8 data days=123; //倒計時應該顯示的天數,同步存放于0000h
- u8 data wk=0x00;//上次查詢到的星期,將與此次查詢到的比較同步存放于0001h
- u8 data keynum=0;//按鍵輸入的數字
- //sbit led=P1^2;
- //顯示相關變量
- u8 code duan[]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0x11,0xc1,0x63,0x85,0x61,0x71,//0-15
- 0x02,0x9e,0x24,0x0c,0x98,0x48,0x40,0x1e,0x00,0x08,0x10,0xc0,0x62,0x84,0x60,0x70,//16-31
- 0xff,0xef,0x91};//數碼管顯示,0-9,A,b,C,d,E,F,不亮,(5)(14),_,H,(13).0-34
- u8 data num2,num1,num0;
- u8 data w=2;//數碼管的位號
- sbit wei0=P3^3;
- sbit wei1=P3^7;
- sbit wei2=P3^6;
- //18b20
- int temp;//溫度*100
- //1302
- //---DS1302時鐘初始化2016年5月7日星期六12點00分00秒。---//
- //---存儲順序是秒,分,時, 日, 月, 星期, 周年,存儲格式是用BCD碼---//
- //u8 TIME[7] = {0, 0, 0x12, 0x07, 0x05, 0x06, 0x16};
- u8 TIME[7]= {0x00, 0x55, 0x23, 0x15, 0x10, 0x02, 0x19}; //星期是time[5],小時是time【2】
- u8 timeset[7]={0x00, 0x02, 0x13, 0x07, 0x12, 0x06, 0x19};
- //---DS1302寫入和讀取時分秒的地址命令---//
- //---秒分時日月周年 最低位讀寫位;-------//
- u8 code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
- u8 code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //兩者的區別只在于末位(發送的時候作為最先發送的)用于決定該命令是讀還是寫
- //基本函數
- void hc595write();
- void intinit();
- void Timer1Init();
- //紅外相關函數
- void irinit();
- void irdecode();
- //溫度相關函數
- void Ds18b20Init();
- void Ds18b20WriteByte(unsigned char dat);
- unsigned char Ds18b20ReadByte();
- int Ds18b20ReadTemp();
- //eeprom相關函數
- void iaperase(unsigned char addrh,unsigned char addrl);
- void iapwrite(unsigned char addrh,unsigned char addrl,unsigned char dat);
- unsigned char iapread(unsigned char addrh,unsigned char addrl);
- void iaprst();
- //ds1302相關函數
- void Ds1302Write(u8 addr, u8 dat);
- u8 Ds1302Read(u8 addr);
- void Ds1302set();
- void Ds1302ReadTime();
- void intinit()
- {
- EA=1;
- ET0=1;
- //ET1=1;
- IE2=0x04; //T2使能,T2的優先級固定為低。IE2不可位尋址,ET2在右數第三位。
- EX0=1; //P3.2中斷使能
- IT0=1; //P3.2僅接受下降沿中斷【這是計劃的一部分】
- PX0=1; //P3.2中斷優先級高,又因為自然優先級的緣故,高于T0。
- PT0=1; //T0優先級高
- //PT1=0; //T1優先級低
- }
- void Timer2Init(void) //5毫秒@11.0592MHz
- {
- AUXR &= 0xFB; //定時器時鐘12T模式
- T2L = 0x00; //設置定時初值
- T2H = 0xEE; //設置定時初值
- AUXR |= 0x10; //定時器2開始計時
- }
- void irdecode()
- {
- switch(ir3)
- {
- case 0x16:
- irresult=0;
- break;
- case 0x0c:
- irresult=1;
- break;
- case 0x18:
- irresult=2;
- break;
- case 0x5e:
- irresult=3;
- break;
- case 0x08:
- irresult=4;
- break;
- case 0x1c:
- irresult=5;
- break;
- case 0x5a:
- irresult=6;
- break;
- case 0x42:
- irresult=7;
- break;
- case 0x52:
- irresult=8;
- break;
- case 0x4a:
- irresult=9;
- break;
- case 0x45:
- irresult=10;//電源鍵
- break;
- case 0x47:
- irresult=11;//菜單鍵
- break;
- case 0x15:
- irresult=12;//播放鍵
- break;
-
- }
- }
- void irinit() //紅外接受狀態0的初始化函數【這是計劃的一部分】,狀態標志初始化,定時器初始化,int0初始化,數據接收配置初始化
- {
- iract=0;
- irstate=0;//紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- started=0;
- t0reset=0;
- int0reset=0;
- int0negfall=0;
- EX0=1; //P3.2中斷使能
- IT0=1; //P3.2僅接受下降沿中斷【這是計劃的一部分】
- PX0=1;
-
- AUXR &= 0x7F; //定時器時鐘12T模式
- TMOD &= 0xF0; //設置定時器模式(先清零)
- TMOD |= 0x01; //設置定時器模式(再寫入)統一規定:T0,16位不自動重裝載,12T。
- TF0 = 0; //清除TF0標志
- TR0 = 0; //定時器0不計時
-
- EX0=1; //P3.2中斷使能
- IT0=1; //P3.2僅接受下降沿中斷
- PX0=1; //P3.2中斷優先級高,又因為自然優先級的緣故,高于T0。
-
- bitamount=0;
-
- }
- void hc595write(void) //給595輸入數據c是數碼管,最后送進去的那一位出現在q0
- {
- u8 t=0,a=0,shu=0x00;//t是循環變量,a是待發送的值,先發送級聯的那片,顯示8段,再發送直連的
- wei2=1;
- wei1=1;
- wei0=1;
- switch(w)
- {
- case 0:
- shu=duan[num0];
- break;
- case 1:
- shu=duan[num1];
- break;
- case 2:
- shu=duan[num2];
- break;
- }
- for(t=0;t<=7;t++)//數字區,8位
- {
- if((shu&0x01)==0)
- ser=0;
- else
- ser=1;
- rclk=1;
- rclk=0;
- shu=shu>>1;
- }
- if(w>=2)//可以控制掃描順序
- w=0;
- else
- w++;
- srclk=1;
- srclk=0;
- switch(w)
- {
- case 0:
- wei0=0;
- break;
- case 1:
- wei1=0;
- break;
- case 2:
- wei2=0;
- break;
- }
- }
- void main() // 我是main函數
- {
- int a=3;
- led=1;
- srclk=0;
- rclk=0;
- ser=0;
- wk=iapread(0x00,0x01);
- days=iapread(0x00,0x00);
- intinit(); //【這是計劃的一部分】
- Timer2Init();
- WDT_COUNTER=0x37;//【這不是計劃的一部分】
- irinit();
- num2=24;
- num1=24;
- num0=24;//試機
- while(1)
- {
- //跑飛的時候while(1)里面的內容仍然正常執行
- }
- }
- void timer2() interrupt 12//正常顯示的掃描刷新步驟
- {
- if(irreceived==1)//有按鍵剛剛按下且未處理
- {
- irdecode();
- switch(irresult)
- {
- case 10://電源鍵
- {
- if(stat==0)
- {
- stat=1;
- num2=days/100;
- num1=(days%100)/10;
- num0=days%10;
- }
- else
- {
- stat=0;
- num2=32;
- num1=32;
- num0=32;
- hc595write();
- }
- break;
- }
- case 11://菜單鍵
- {
- if(stat<=2)
- {
- stat=3;//確認進入設置模式
- num2=34;//H
- num1=33;//_
- num0=34;//H
- }
- else
- {
- stat=1;
- }
- break;
- }
- case 12://播放鍵
- {
- if(stat==1)
- stat=2;
- if(stat==2)
- stat=1;
- break;
- }
- case 0:
- led=~led;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- keynum=irresult;//先記錄下鍵值
- switch (stat)
- {
- case 3:
- timeset[2]=keynum*16;
- num1=keynum;
- num0=33;//_
- stat=4;
- break;
- case 4:
- timeset[2]=timeset[2]+keynum;
- num2=33;//_
- num1=13;//d
- num0=13;//d
- stat=5;
- break;
- case 5:
- days=keynum*100;
- num2=keynum;
- num1=33;//_
- num0=13;//d
- stat=6;
- break;
- case 6:
- days=days+keynum*10;
- num1=keynum;
- num0=33;//_
- stat=7;
- break;
- case 7:
- days=days+keynum;
- Ds1302set();//向ds1302寫入小時
- iaperase(0x00,0x00);
- iapwrite(0x00,0x00,days);
- Ds1302ReadTime();
- wk=TIME[5];
- iapwrite(0x00,0x01,wk);//向eeprom寫入正確的天數和星期
- num2=days/100;
- num1=(days%100)/10;
- num0=days%10;//更新顯示內容
- stat=1;
- break;
- }
- break;
- }
- irreceived=0;
- }
- if(count>0)
- {
- count--;
- if(count==1000)
- WDT_COUNTER=WDT_COUNTER|0x10; //WDT喂狗【這是計劃的一部分】
- }
- else
- {
- count=2000;//count溢出之時,應向時鐘芯片詢問日期,1000->5s
- WDT_COUNTER=WDT_COUNTER|0x10; //WDT喂狗【這是計劃的一部分】
- Ds1302ReadTime();
- if(wk!=TIME[5])//星期數發生變化
- {
- wk=TIME[5];//更新星期
- if(days>0)
- days--;//更新天數
- else
- stat=0;
- iaperase(0x00,0x00);
- iapwrite(0x00,0x00,days);
- iapwrite(0x00,0x01,wk);//向eeprom寫入正確的天數和星期
- }
- }
- if((stat==1)&&(count==1500))//
- {
- temp=Ds18b20ReadTemp();
- num2=temp % 10000 / 1000;
- num1=(temp % 1000 / 100)+16;
- num0=temp % 100 / 10;
- }
- else if((stat==1|stat==2)&&count==1000)
- {
- num2=days/100;
- num1=(days%100)/10;
- num0=days%10;
- //num2=33;
- //num1=TIME[2]/16;
- //num0=TIME[2]%16;
- }
-
- if(stat==0)
- {
-
- }
- else
- {
- hc595write();
- }
- }
- void timer0() interrupt 1
- {
- if(t0reset==0)//定時器0溢出就回到等待狀態標志位
- {
- if(irstate==1)
- {
- irstate=2; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- t0reset=1; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=1; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=0; //P3.2=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式,2ms
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0xCD; //設置定時初值
- TH0 = 0xF8; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- }
- else if(irstate==3)
- {
- irstate=4; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- t0reset=1; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=1; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=0; //=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 2.5ms
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0x00; //設置定時初值
- TH0 = 0xF7; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- }
- else if(irstate==5)//重頭戲:判斷邏輯值【6-long】
- {
- irstate=6; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;
- irbit=1;
- //out=0;
-
- t0reset=0; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=1; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=0; //=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 1200us
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0xAE; //設置定時初值
- TH0 = 0xFB; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- if(bitamount<=7) //【禁忌二重奏之一】
- {
- ir1=ir1>>1;
- ir1=ir1+(irbit*0x80);
- }
- else if(bitamount<=15)
- {
- ir2=ir2>>1;
- ir2=ir2+(irbit*0x80);
-
- }
- else if(bitamount<=23)
- {
- ir3=ir3>>1;
- ir3=ir3+(irbit*0x80);
- }
- else
- {
- ir4=ir4>>1;
- ir4=ir4+(irbit*0x80);
- }
-
- bitamount++;
-
- if(bitamount>=32)
- {
- irreceived=1;
- irinit();
-
- }
- }
- }
- else
- {
-
- irinit();
- }
- }
- void int0() interrupt 0
- {
- _nop_();
- _nop_();
- _nop_();
- if((ir==1)|(int0negfall==0))//如果“忽視下降沿”標志位為1時(&)為下降沿(輸入端=0),就不能執行下面的程序。
- {
- if(int0reset==1)//如果“觸發中斷即復位”標志位為1,就立刻復位。
- {
-
- irinit();
-
- }
- else//好戲開始
- {
- if(irstate==0)//報頭低開始 0未激活;1報頭低;2報頭升;3報頭高;4報頭降;5高電平;6低電平
- {
- iract=1; //紅外活動
- irstate=1; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- t0reset=0; //定時器0溢出就回到等待狀態
- int0reset=1; //int0觸發就回到等待狀態
- int0negfall=0; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=0; //=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //8毫秒@11.0592MHz 定時器時鐘12T模式
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0x33; //設置定時初值
- TH0 = 0xE3; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- }
- else if(irstate==2)//報頭高開始
- {
- irstate=3; //紅外接受狀態0-7{未激活;報頭低;報頭升;報頭高;報頭降;高電平1;高電平2;低電平}
- t0reset=0; //定時器0溢出就回到等待狀態
- int0reset=1; //int0觸發就回到等待狀態
- int0negfall=0; //忽視int0的下降沿(只允許上升沿中斷),下降沿此時不會觸發reset
- IT0=0; //=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 3.5ms
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0x66; //設置定時初值
- TH0 = 0xF3; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- }
- else if(irstate==4)//高電平開始【5-first】
- {
- irstate=5; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- t0reset=0; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=0; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=1; //P3.2=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 840us
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0xFA; //設置定時初值
- TH0 = 0xFC; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- //out=1;
-
- if(started==0)//收到的是報頭
- {
- started=1;
- }
- else//收到的是報尾
- {
- iract=0;
- started=0;
- irinit();
- }
- }
- else if(irstate==5)//低電平開始【6-short】
- {
- irstate=6; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- irbit=0;
- //out=0;
-
- t0reset=1; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=1; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=0; //P3.2=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 840us
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0xFA; //設置定時初值
- TH0 = 0xFC; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- if(bitamount<=7) //【禁忌二重奏之二】
- {
- ir1=ir1>>1;
- ir1=ir1+(irbit*0x80);
- }
- else if(bitamount<=15)
- {
- ir2=ir2>>1;
- ir2=ir2+(irbit*0x80);
-
- }
- else if(bitamount<=23)
- {
- ir3=ir3>>1;
- ir3=ir3+(irbit*0x80);
- }
- else
- {
- ir4=ir4>>1;
- ir4=ir4+(irbit*0x80);
- }
-
- bitamount++;
-
- if(bitamount>=32)
- {
- irreceived=1;
- irinit();
-
- }
- }
- else if(irstate==6)//收到上升沿信號,由低電平轉為高電平狀態【5-repeat】
- {
- irstate=5; //紅外接受狀態0-6{未激活;報頭低;報頭升;報頭高;報頭降;高電平;低電平}
- t0reset=0; //定時器0溢出就回到等待狀態
- int0reset=0; //int0觸發就回到等待狀態
- int0negfall=0; //忽視int0的下降沿(只允許上升沿中斷)
- IT0=1; //P3.2=1僅接收下降沿中斷,=0上下皆可
-
- AUXR &= 0x7F; //定時器時鐘12T模式 840us
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0xFA; //設置定時初值
- TH0 = 0xFC; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
-
- //out=1;
-
- }
-
- }
- }
-
- }
- /*
- 日志:在完成了數碼管顯示和定時
- 器中斷的基礎上,新增了狀態機查
- 詢紅外信號輸入的功能,在15w204
- s上能穩定運行。2020-2-21
- */
- void Ds18b20Init()
- {
- unsigned char i,j;
- DSPORT=1; //將總線拉高4us
- _nop_();
- _nop_();
- i = 8;
- while (--i);
- DSPORT=0; //然后拉低總線480us
- i = 6;
- j = 38;
- do
- {
- while (--j);
- } while (--i);
- DSPORT=1; //然后拉高總線,如果DS18B20做出反應會將在15us~60us后總線拉低
- i = 6;
- j = 38;
- do
- {
- while (--j);
- } while (--i);
- }
- void Ds18b20WriteByte(unsigned char dat)
- {
- unsigned char i,j,e;
- for(e=8;e>0;e--)
- {
- DSPORT=0; //每寫入一位數據之前先把總線拉低1us
- _nop_();
- _nop_();
- _nop_();
- DSPORT=dat&0x01; //然后寫入一個數據,從最低位開始
- i = 1;//延時68us,持續時間最少60us
- j = 184;
- do
- {
- while (--j);
- } while (--i);
- DSPORT=1; //然后釋放總線,至少1us給總線恢復時間才能接著寫入第二個數值
- dat>>=1;
- }
- }
- unsigned char Ds18b20ReadByte()
- {
- unsigned char byte,i,j;
- for(j=8;j>0;j--)
- {
- DSPORT=0;//先將總線拉低1us
- _nop_();
- _nop_();
- _nop_();
- byte>>=1;
- DSPORT=1;//然后釋放總線
- _nop_();//延時15us等待數據穩定[]
- i = 39;
- while (--i);
- if(DSPORT)
- byte|=0x80;
- i = 122;//delay45us
- while (--i);
- }
- return byte;
- }
- int Ds18b20ReadTemp()
- {
- int temp=0;
- int tp;
- u8 i,j;
- unsigned char tmh,tml;
- Ds18b20Init();
- Ds18b20WriteByte(0xcc);
- Ds18b20WriteByte(0x44);
- _nop_();//delay125us
- _nop_();
- i = 2;
- j = 84;
- do
- {
- while (--j);
- } while (--i);
- Ds18b20Init();
- Ds18b20WriteByte(0xcc);
- Ds18b20WriteByte(0xbe);
- tml=Ds18b20ReadByte();
- tmh=Ds18b20ReadByte();
-
- temp=tmh;
- temp<<=8;
- temp|=tml;
- if((temp&0xf800)==0xf800) //*0.0625是把16進制轉化位10進制所需,原始信息里的16代表1攝氏度。
- {
- temp=temp-1;//如果溫度是零下,此處未加入負溫度標志位,所以顯示的還是正的
- temp=~temp;
- tp=temp;
- temp=tp*0.0625*100+0.5;
- }
- else
- {
- tp=temp;//如果溫度是零上
- temp=tp*0.0625*100+0.5;
- }
- return temp;
- }
- /*
- 日志 移植了某大佬的ds18b20程序,
- 并使之能在stc-y5內核單片機上運
- 行。正常情況下輸出的16bit信息可
- 以表示12位精度的溫度,但是stc單
- 片機不支持浮點數運算,所以temp
- 是乘了100的。所有延時函數(微秒
- 級)均已內置,無需調用,也不費
- 什么時間。 2020-2-24
- */
- //eeprom操作--IAP法
- void iaprst() //復位
- {
- IAP_CONTR=0;
- IAP_CMD=0;
- IAP_TRIG=0;
- IAP_ADDRH=0x80;
- }
- unsigned char iapread(unsigned char addrh,unsigned char addrl)
- {
- unsigned char dat;
- IAP_CONTR=0x83; //適用于12mhz以下的頻率
- IAP_CMD=1;
- IAP_ADDRL=addrl;
- IAP_ADDRH=addrh;
- IAP_TRIG=0x5a;
- IAP_TRIG=0xa5;
- _nop_();
- _nop_();
- dat=IAP_DATA;
- iaprst();
- return dat;
- }
- void iapwrite(unsigned char addrh,unsigned char addrl,unsigned char dat)
- {
- IAP_CONTR=0x83;//適用于12mhz以下的頻率
- IAP_CMD=2;
- IAP_ADDRL=addrl;
- IAP_ADDRH=addrh;
- IAP_DATA=dat;
- IAP_TRIG=0x5a;
- IAP_TRIG=0xa5;
- _nop_();
- _nop_();
- iaprst();
- }
- void iaperase(unsigned char addrh,unsigned char addrl)
- {
- IAP_CONTR=0x83;//適用于12mhz以下的頻率
- IAP_CMD=3;
- IAP_ADDRL=addrl;
- IAP_ADDRH=addrh;
- IAP_TRIG=0x5a;
- IAP_TRIG=0xa5;
- _nop_();
- _nop_();
- iaprst();
- }
- /*
- 日志 增加了關于eeprom的操作的函數
- ,現學現賣,一共就三個函數(iapinit
- 不需要管),204s就只有兩個扇區,
- 0000-01ff,0200-03ff,每個地址號
- 都能存儲一個char,一共是1024個。
- 使用方法:(先讀出原有數據,)再
- 擦除扇區(擦除地址是扇區的首地址
- ),然后寫入新值,(最后讀出來)。
- 打算用0000存儲倒計時還剩多少天,
- 0001存儲當前的日期。程序上電先把
- 日期和倒數讀到ram里,每隔幾秒詢
- 問1302,若有不同,則ram日期更新
- ,倒數減一(檢測大于0),重寫
- eeprom。 2020-2-25
- */
- /*******************************************************************************
- * 函 數 名 : Ds1302Write
- * 函數功能 : 向DS1302命令(地址+數據)
- * 輸 入 : addr,dat
- * 輸 出 : 無
- *******************************************************************************/
- void Ds1302Write(u8 addr, u8 dat)
- {
- u8 n;
- RST = 0;
- _nop_();
- SCLK = 0;//先將SCLK置低電平。
- _nop_();
- RST = 1; //然后將RST(CE)置高電平。
- _nop_();
- for (n=0; n<8; n++)//開始傳送八位地址命令
- {
- DSIO = addr & 0x01;//數據從低位開始傳送
- addr >>= 1;
- SCLK = 1;//數據在上升沿時,DS1302讀取數據
- _nop_(); //時鐘高電平時數據需要保持不動
- SCLK = 0;
- _nop_();
- }
- for (n=0; n<8; n++)//寫入8位數據
- {
- DSIO = dat & 0x01;
- dat >>= 1;
- SCLK = 1;//數據在上升沿時,DS1302讀取數據
- _nop_();
- SCLK = 0;
- _nop_();
- }
-
- RST = 0;//傳送數據結束
- _nop_();
- }
- /*******************************************************************************
- * 函 數 名 : Ds1302Read
- * 函數功能 : 讀取一個地址的數據
- * 輸 入 : addr
- * 輸 出 : dat
- *******************************************************************************/
- u8 Ds1302Read(u8 addr)
- {
- u8 n,dat,dat1;
- RST = 0;
- _nop_();
- SCLK = 0;//先將SCLK置低電平。
- _nop_();
- RST = 1;//然后將RST(CE)置高電平。
- _nop_();
- for(n=0; n<8; n++)//開始傳送八位地址命令
- {
- DSIO = addr & 0x01;//數據從低位開始傳送
- addr >>= 1;
- SCLK = 1;//數據在上升沿時,DS1302讀取數據
- _nop_();
- SCLK = 0;//DS1302下降沿時,放置數據
- _nop_();
- }
- _nop_();
- for(n=0; n<8; n++)//讀取8位數據
- {
- dat1 = DSIO;//從最低位開始接收
- dat = (dat>>1) | (dat1<<7);
- SCLK = 1;
- _nop_();
- SCLK = 0;//DS1302下降沿時,放置數據
- _nop_();
- }
- RST = 0;
- _nop_(); //以下為DS1302復位的穩定時間,必須的。
- SCLK = 1;
- _nop_();
- DSIO = 0;
- _nop_();
- DSIO = 1;
- _nop_();
- return dat;
- }
- /*******************************************************************************
- * 函 數 名 : Ds1302Init
- * 函數功能 : 初始化DS1302.
- * 輸 入 : 無
- * 輸 出 : 無
- *******************************************************************************/
- void Ds1302set()
- {
- u8 n;
- Ds1302Write(0x8E,0X00); //關閉寫保護功能
- for (n=0; n<7; n++)//寫入7個字節的時鐘信號:分秒時日月周年 !!!此操作會破壞原有的時間數據!!!
- {
- Ds1302Write(WRITE_RTC_ADDR[n],timeset[n]);
- }
- Ds1302Write(0x8E,0x80); //打開寫保護功能
- }
- /*******************************************************************************
- * 函 數 名 : Ds1302ReadTime
- * 函數功能 : 讀取時鐘信息
- * 輸 入 : 無
- * 輸 出 : 無
- *******************************************************************************/
- void Ds1302ReadTime()
- {
- u8 n;
- for (n=0; n<7; n++)//讀取7個字節的時鐘信號:分秒時日月周年
- {
- TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
- }
-
- }
- /*
- 添加了ds1302函數,通過全局變量傳遞
- 數據。通過每5秒鐘檢測一下星期并與
- ram里面的值比較,若有變化就日期減
- 一,并更新eeprom里面的值。注意ds1302
- 的數據格式,比如’13點’不是0x0c,
- 而是0x13,此之謂8421bcd碼.
- */
復制代碼 stc15.h可以用stc下載工具添加了mcu型號到keil中后再keil的文件夾里面找到,所有的函數都在里面了,(幫助沒黑幣的小白真正實現白嫖),標有這是計劃的一部分的是與ir接收相關的函數(包括看門狗設置)。說實在的,這是我首次給51單片機寫這么長的代碼。里面有的函數是我之前學的時候借鑒壇里大神的,在此表示感謝。

硬件制作
搭棚過程是先從數碼管做起的(隔壁五家的垃圾數碼管雖然便宜,可挑了半天才找到個好的)
搭棚的過程沒怎么拍全,因為當時自己也沒有做下去的信心
|