|
樓主最近做到一個作業(yè),要求用51單片機(jī)做一個風(fēng)扇溫控檢測系統(tǒng),其功能大概就是:當(dāng)溫度達(dá)到設(shè)定值時候,風(fēng)扇電機(jī)開始轉(zhuǎn)動,以達(dá)到散熱的目的,題目本身沒有什么意思,有意思的是想要用盡可能少的元器件來完成這項(xiàng)工作,要求使用兩個數(shù)碼管,其他沒說,所以我就加了3個按鍵,大體思路是這樣的,開機(jī)以后,正常顯示溫度,按下SET鍵位時候,進(jìn)溫度設(shè)置,兩個按鍵+和-設(shè)置數(shù)值。再按一次SET保存并退出。
最有意思的在于用了兩個標(biāo)志位,這兩個標(biāo)志位簡直沒把我繞暈。現(xiàn)在完成了,發(fā)出來大家一起看看,不在于代碼多好,在于一種解決問題的方法。我把文件發(fā)上來了,大家一起學(xué)習(xí)交流。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
TIM截圖20181216211410.jpg (267.63 KB, 下載次數(shù): 39)
下載附件
2018-12-16 21:13 上傳
TIM截圖20181216211656.jpg (272.1 KB, 下載次數(shù): 42)
下載附件
2018-12-16 21:16 上傳
TIM截圖20181216211828.jpg (241.1 KB, 下載次數(shù): 29)
下載附件
2018-12-16 21:19 上傳
單片機(jī)源程序如下:
- #include "reg52.h"
- #include <intrins.h>
- #define _Nop() _nop_() //定義空指令
- /*-----------------------------------------------
- IO口定義
- -----------------------------------------------*/
- sbit LED_R = P1^6; //紅燈
- sbit BEEP = P2^1; //蜂鳴器
- sbit MOTOR = P2^2; //電機(jī)
- sbit KEY_ADD = P2^5; //加
- sbit KEY_DEC = P2^4; //減
- sbit KEY_SET = P2^3; //確認(rèn)
- sbit ONE = P2^6; //個位位選
- sbit TEN = P2^7; //十位位選
- sbit DQ=P1^7; //DS18B20數(shù)據(jù)
- sbit SDA=P1^1; //模擬I2C數(shù)據(jù)傳送位
- sbit SCL=P1^0; //模擬I2C時鐘控制位
-
-
- /*-----------------------------------------------
- 定義變量
- -----------------------------------------------*/
- unsigned char Set_Flag=0; //
- unsigned char Set_Value=40; //設(shè)定值
- unsigned char Tempature = 0; //溫度
- unsigned char num=40; //數(shù)字
- unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //數(shù)碼管段選
- unsigned char Data=0;
- char Temp[12];
- bit ack; //應(yīng)答標(biāo)志位
- /*-----------------------------------------------
- 延時函數(shù)
- -----------------------------------------------*/
- void Delay_us(unsigned char t)
- {
- while(t--);
- }
- void Delay_ms(unsigned char t)
- {
- int i,j;
- for(i=t;i>0;i--)
- for(j=125;j>0;j--);
- }
- void delay_18B20(unsigned int i)//微秒級延時
- {
- while(i--);
- }
- /*-----------------------------------------------
- DS18B20初始化
- -----------------------------------------------*/
- void ds1820rst(void) /*ds1820復(fù)位*/
- {
- unsigned char x=0;
- DQ = 1; //DQ復(fù)位
- delay_18B20(5); //延時
- DQ = 0; //DQ拉低
- delay_18B20(100); //精確延時大于480us
- DQ = 1; //拉高
- delay_18B20(40);
- }
- unsigned char ds1820rd(void)//從18b20讀取數(shù)據(jù)
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0; //給脈沖信號
- dat>>=1;
- DQ = 1; //給脈沖信號
- if(DQ) dat|=0x80;
- delay_18B20(10);
- }
- return(dat);
- }
- void ds1820wr(unsigned char wdata)/*寫數(shù)據(jù)*/
- {
- unsigned char i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(25);
- DQ = 1;
- wdata>>=1;
- }
- }
- //讀取DS18B20溫度值
- //入口參數(shù):無
- //返回值:溫度值
- unsigned int read_18b20(void)/*讀取溫度值并轉(zhuǎn)換*/
- {
- unsigned char a,b;
- unsigned char tem;
- ds1820rst();
- ds1820wr(0xcc);//*跳過讀序列號*/
- ds1820wr(0x44);//*啟動溫度轉(zhuǎn)換*/
- ds1820rst();
- ds1820wr(0xcc);//*跳過讀序列號*/
- ds1820wr(0xbe);//*讀取溫度*/
- a=ds1820rd();
- b=ds1820rd();
- tem=((b<<4)|(a>>4)); //將高低字節(jié)組合成字
- //Delay_ms(50);
- return tem; //完成溫度轉(zhuǎn)換
- }
- /*-----------------------------------------------
- 數(shù)碼管
- -----------------------------------------------*/
- //共陰數(shù)碼管
- //動態(tài)掃描
- void display(unsigned char Data)
- {
- //P3 = 0;
- ONE = 1; //打開個位位選
- TEN = 0;
- P3 = table[Data/10];//送個位
- Delay_ms(5);//延時
- P3 = 0; //防止重影
- //Delay_us(5);
-
- TEN = 1;
- ONE = 0;
- P3 = table[Data%10];
- Delay_ms(5);
- P3 = 0;
- //Delay_us(5);
- }
- /*-----------------------------------------------
- 按鍵處理函數(shù)
- -----------------------------------------------*/
- char S_F=0;
- unsigned char Key_Value(void)
- {
- if(!KEY_ADD || !KEY_DEC||!KEY_SET) // 檢測是否有任意按鍵按下
- {
- Delay_ms(20);
- Set_Flag = 1; //切換到顯示設(shè)置值
- if(!KEY_ADD) //如果檢測到低電平,說明按鍵按下
- {
- Delay_ms(10); //延時去抖,一般10-20ms
- if(!KEY_ADD) //再次確認(rèn)按鍵是否按下,沒有按下則退出
- {
- while(!KEY_ADD);//如果確認(rèn)按下按鍵等待按鍵釋放,沒有釋放則一直等待
- {
- if(num<99) //加操作
- num++;
- }
- }
- }
- if(!KEY_DEC) //如果檢測到低電平,說明按鍵按下
- {
- Delay_ms(10); //延時去抖,一般10-20ms
- if(!KEY_DEC) //再次確認(rèn)按鍵是否按下,沒有按下則退出
- {
- while(!KEY_DEC);//如果確認(rèn)按下按鍵等待按鍵釋放,沒有釋放則一直等待
- {
- if(num>0) //減操作
- num--;
- }
- }
- }
- if(!KEY_SET) //如果檢測到低電平,說明按鍵按下
- {
- Delay_ms(10); //延時去抖,一般10-20ms
- if(!KEY_SET) //再次確認(rèn)按鍵是否按下,沒有按下則退出
- {
- //Set_Flag = 0;
- while(!KEY_SET);//如果確認(rèn)按下按鍵等待按鍵釋放,沒有釋放則一直等待
- {
- //將當(dāng)前值作為設(shè)定值
-
- //Set_Flag = 0; //切換到顯示溫度值
- }
- if(S_F)
- Set_Flag=0;
- }
- }
- }
-
- Set_Value = num;
- return (num);
- }
- /*-----------------------------------------------
- 24C02初始化
- -----------------------------------------------*/
- /*------------------------------------------------
- 啟動總線
- ------------------------------------------------*/
- void Start_I2c()
- {
- SDA=1; //發(fā)送起始條件的數(shù)據(jù)信號
- _Nop();
- SCL=1;
- _Nop(); //起始條件建立時間大于4.7us,延時
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=0; //發(fā)送起始信號
- _Nop(); //起始條件鎖定時間大于4μ
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù)
- _Nop();
- _Nop();
- }
- /*------------------------------------------------
- 結(jié)束總線
- ------------------------------------------------*/
- void Stop_I2c()
- {
- SDA=0; //發(fā)送結(jié)束條件的數(shù)據(jù)信號
- _Nop(); //發(fā)送結(jié)束條件的時鐘信號
- SCL=1; //結(jié)束條件建立時間大于4μ
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=1; //發(fā)送I2C總線結(jié)束信號
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 字節(jié)數(shù)據(jù)傳送函數(shù)
- 函數(shù)原型: void SendByte(unsigned char c);
- 功能: 將數(shù)據(jù)c發(fā)送出去,可以是地址,也可以是數(shù)據(jù),發(fā)完后等待應(yīng)答,并對
- 此狀態(tài)位進(jìn)行操作.(不應(yīng)答或非應(yīng)答都使ack=0 假)
- 發(fā)送數(shù)據(jù)正常,ack=1; ack=0表示被控器無應(yīng)答或損壞。
- ------------------------------------------------------------------*/
- void SendByte(unsigned char c)
- {
- unsigned char BitCnt;
-
- for(BitCnt=0;BitCnt<8;BitCnt++) //要傳送的數(shù)據(jù)長度為8位
- {
- if((c<<BitCnt)&0x80)SDA=1; //判斷發(fā)送位
- else SDA=0;
- _Nop();
- SCL=1; //置時鐘線為高,通知被控器開始接收數(shù)據(jù)位
- _Nop();
- _Nop(); //保證時鐘高電平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0;
- }
-
- _Nop();
- _Nop();
- SDA=1; //8位發(fā)送完后釋放數(shù)據(jù)線,準(zhǔn)備接收應(yīng)答位
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop();
- _Nop();
- if(SDA==1)ack=0;
- else ack=1; //判斷是否接收到應(yīng)答信號
- SCL=0;
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 字節(jié)數(shù)據(jù)傳送函數(shù)
- 函數(shù)原型: unsigned char RcvByte();
- 功能: 用來接收從器件傳來的數(shù)據(jù),并判斷總線錯誤(不發(fā)應(yīng)答信號),
- 發(fā)完后請用應(yīng)答函數(shù)。
- ------------------------------------------------------------------*/
- unsigned char RcvByte()
- {
- unsigned char retc;
- unsigned char BitCnt;
-
- retc=0;
- SDA=1; //置數(shù)據(jù)線為輸入方式
- for(BitCnt=0;BitCnt<8;BitCnt++)
- {
- _Nop();
- SCL=0; //置時鐘線為低,準(zhǔn)備接收數(shù)據(jù)位
- _Nop();
- _Nop(); //時鐘低電平周期大于4.7us
- _Nop();
- _Nop();
- _Nop();
- SCL=1; //置時鐘線為高使數(shù)據(jù)線上數(shù)據(jù)有效
- _Nop();
- _Nop();
- retc=retc<<1;
- if(SDA==1)retc=retc+1; //讀數(shù)據(jù)位,接收的數(shù)據(jù)位放入retc中
- _Nop();
- _Nop();
- }
- SCL=0;
- _Nop();
- _Nop();
- return(retc);
- }
- /*----------------------------------------------------------------
- 應(yīng)答子函數(shù)
- 原型: void Ack_I2c(void);
-
- ----------------------------------------------------------------*/
- void Ack_I2c(void)
- {
-
- SDA=0;
- _Nop();
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop(); //時鐘低電平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //清時鐘線,鉗住I2C總線以便繼續(xù)接收
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 非應(yīng)答子函數(shù)
- 原型: void NoAck_I2c(void);
-
- ----------------------------------------------------------------*/
- void NoAck_I2c(void)
- {
-
- SDA=1;
- _Nop();
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop(); //時鐘低電平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //清時鐘線,鉗住I2C總線以便繼續(xù)接收
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 向有子地址器件發(fā)送多字節(jié)數(shù)據(jù)函數(shù)
- 函數(shù)原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
- 功能: 從啟動總線到發(fā)送地址,子地址,數(shù)據(jù),結(jié)束總線的全過程,從器件
- 地址sla,子地址suba,發(fā)送內(nèi)容是s指向的內(nèi)容,發(fā)送no個字節(jié)。
- 如果返回1表示操作成功,否則操作有誤。
- 注意: 使用前必須已結(jié)束總線。
- ----------------------------------------------------------------*/
- bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
- {
- unsigned char i;
- Start_I2c(); //啟動總線
- SendByte(sla); //發(fā)送器件地址
- if(ack==0)return(0);
- SendByte(suba); //發(fā)送器件子地址
- if(ack==0)return(0);
- for(i=0;i<no;i++)
- {
- SendByte(*s); //發(fā)送數(shù)據(jù)
- Delay_ms(1);
- if(ack==0)return(0);
- s++;
- }
- Stop_I2c(); //結(jié)束總線
- return(1);
- }
- /*----------------------------------------------------------------
- 向有子地址器件讀取多字節(jié)數(shù)據(jù)函數(shù)
- 函數(shù)原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
- 功能: 從啟動總線到發(fā)送地址,子地址,讀數(shù)據(jù),結(jié)束總線的全過程,從器件
- 地址sla,子地址suba,讀出的內(nèi)容放入s指向的存儲區(qū),讀no個字節(jié)。
- 如果返回1表示操作成功,否則操作有誤。
- 注意: 使用前必須已結(jié)束總線。
- ----------------------------------------------------------------*/
- bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
- {
- unsigned char i;
- Start_I2c(); //啟動總線
- SendByte(sla); //發(fā)送器件地址
- if(ack==0)return(0);
- SendByte(suba); //發(fā)送器件子地址
- if(ack==0)return(0);
- Start_I2c();
- SendByte(sla+1);
- if(ack==0)return(0);
- for(i=0;i<no-1;i++)
- {
- *s=RcvByte(); //發(fā)送數(shù)據(jù)
- Ack_I2c(); //發(fā)送就答位
- s++;
- }
- *s=RcvByte();
- NoAck_I2c(); //發(fā)送非應(yīng)位
- Stop_I2c(); //結(jié)束總線
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼
0.png (52.1 KB, 下載次數(shù): 34)
下載附件
2018-12-16 21:38 上傳
所有資料51hei提供下載:
tempature.zip
(98.2 KB, 下載次數(shù): 62)
2018-12-16 21:15 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
評分
-
查看全部評分
|