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