轉載請注明:@小五義 http://www.cnblogs.com/xiaowuyi
歡迎加入討論群 64770604
常常聽到老媽在做飯時說“開鍋15分鍾后叫我一下”,為何不做個定時器,來提醒老媽呢?結合前面學習的知識,再加上1302時間模塊,我決定自己做一個。
一、本次實驗所需器材
1、Arduino UNO板 https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-15820725129.16.AtgoEm&id=545093340395
2、1602液晶板:http://www.cnblogs.com/xiaowuyi/p/3390024.html(或者http://wikicode.net/?p=232)已經介紹過。
3、DS1302實時時鍾模塊:DALLAS 公司推出的涓流充電時鍾芯片,內含有一個實時時鍾/日歷和31 字節靜態RAM ,通過簡單的串行接口與單片機進行通信。實時時鍾/日歷電路提供秒、分、時、日、周、月、年的信息,每月的天數和閏年的天數可自動調整。時鍾操作可通過 AM/PM 指示決定采用24 或12 小時格式。DS1302 與單片機之間能簡單地采用同步串行的方式進行通信,僅需用到三個口線:(1)RST 復位(2)I/O 數據線(3)SCLK串行時鍾。
(1)DS1302主要性能指標
★ 實時時鍾具有能計算2100 年之前的秒、分、時、日、星期、月、年的能力,還有閏年調整的能力
★ 31 8 位暫存數據存儲RAM
★ 串行 I/O 口方式使得管腳數量最少
★ 寬范圍工作電壓2.0 5.5V
★ 工作電流 2.0V 時,小於300nA
★ 讀/寫時鍾或RAM 數據時有兩種傳送方式單字節傳送和多字節傳送字符組方式
★ 8 腳DIP 封裝或可選的8 腳SOIC 封裝根據表面裝配
★ 簡單 3 線接口
★ 與 TTL 兼容Vcc=5V
★ 可選工業級溫度范圍-40 +85
★ 雙電源管用於主電源和備份電源供應
(2)接線方法(以本實驗程序為例)
VCC→+5V/3.3V
GND→GND
CLK→5
DAT→3
RST→2
4、按鈕開關一個:按鈕開關在連接時,需要接一個1KΩ電阻做為下拉電阻。具體關於按鈕的使用可參考(http://www.geek-workshop.com/forum.php?mod=viewthread&tid=74)
5、蜂鳴器一個
6、電阻:1KΩ電阻、10KΩ電阻
二、硬件連接方法
DS1602的連接主要采用四位連接法(http://www.cnblogs.com/xiaowuyi/p/3390024.html),端口為12,11,9,8,7,6。DS1302的連接方法上面已給出,另外按鈕開關、蜂鳴器等的連接具體見下圖。
三、程序代碼
具體代碼如下:
// DS1302: RST pin -> Arduino Digital 2 // DAT pin -> Arduino Digital 3 // CLK pin -> Arduino Digital 5 #include <LiquidCrystal.h> #include <DS1302.h> LiquidCrystal lcd(12, 11, 9, 8, 7, 6); DS1302 rtc(2, 3, 5); int j=0;//記錄定時設定分鍾數 int time=0;//remine the last time int button=13;//13口控制按鈕 boolean onoff= LOW; //記錄按鈕狀態 boolean timefix=LOW;//記時器開關,LOW表示未定時,HIGH表示定時 unsigned long buttonHoldTime = 0;//按鈕按下持續時間 int buttonStateOld;//按鈕上一時刻狀態 int buttonState;//按鈕本時刻狀態 void ting()//控制蜂鳴器發聲 { int checkstate = digitalRead(button); for(int i=0;i<80;i++)//輸出一個頻率的聲音 { digitalWrite(10,HIGH);//發聲音 delay(1);//延時1ms digitalWrite(10,LOW);//不發聲音 delay(1);//延時ms } for(int i=0;i<100;i++)//輸出另一個頻率的聲音,這里的100與前面的80一樣,用來控制頻率,可以自己調節 { digitalWrite(10,HIGH); delay(2); digitalWrite(10,LOW); delay(2); } } void clockdate()//1602顯示時間 { lcd.clear(); //清屏 lcd.setCursor(0,0); lcd.print(rtc.getDateStr(FORMAT_LONG,FORMAT_BIGENDIAN, '-'));//從1302的庫文件可以看出,這里有下面幾種格式FORMAT_BIGENDIAN:2010-01-01;FORMAT_LITTLEENDIAN:01-01-2010 lcd.setCursor(11,0); lcd.print(rtc.getDOWStr()); lcd.setCursor(14,0); lcd.print(" "); lcd.setCursor(0, 1) ; lcd.print(rtc.getTimeStr()); } void setup() { lcd.begin(16, 2); //初始化LCD pinMode(10,OUTPUT);//設置數字IO腳模式,OUTPUT為輸出 pinMode(button,INPUT);//設置引腳為輸入模式 // 設置時鍾初始值 rtc.halt(false); rtc.writeProtect(false); rtc.setDOW(SATURDAY); // 設置星期 rtc.setTime(22, 56,00); //設置時間 rtc.setDate(9, 11, 2013); // 設置日期2013年11月9日 rtc.writeProtect(true); } void loop() { buttonState = digitalRead(button); delay(20); if (buttonState==HIGH && buttonStateOld==LOW)//按鈕狀態發生變化 { buttonHoldTime = millis();//用millis()時間函數來記時,該函數最長記錄時間為9小時22分,由於本程序最多記錄60分鍾,所以可以使用 buttonStateOld =buttonState; if (onoff==HIGH)//當進入定時設置狀態時 { if (j>59) { j=0; timefix=LOW; } else { j=j+1; timefix=HIGH; } lcd.setCursor(11,0); lcd.print(j); } } else if (buttonState ==HIGH && buttonStateOld==HIGH)//判斷按鈕是否持續按下 { if (millis()-buttonHoldTime>3000)//當按鈕持續按下3秒種進入定時狀態 { buttonStateOld=LOW; if (onoff==LOW)//進入 { j=0; timefix=LOW; lcd.clear(); //清屏 lcd.setCursor(0,0); lcd.print("Fixed Time:"); lcd.setCursor(11,0); lcd.print(j); lcd.setCursor(13,0); lcd.print("min"); onoff=HIGH; } else//退出 { clockdate(); // Serial.println(rtc.getTimeStr()); buttonHoldTime = millis(); onoff= LOW; } } else { buttonStateOld =buttonState; } } else { buttonStateOld =buttonState; } if (onoff==LOW) { clockdate(); } if (timefix==HIGH && j>0 && onoff==LOW) { unsigned long delaytime=j*60000;//把分鍾計算成秒 if ((millis()-buttonHoldTime)>=delaytime ) { do { buttonState = digitalRead(button); ting(); }while (buttonState==LOW);//當按下按鈕后,停止蜂鳴 j=0; } else { clockdate(); } } delay(1000); }
這個代碼中,初始時間是設定好的,即2013年11月9日22點56分,因此本程序沒有加入時鍾時間設定功能,也可以再加上幾個按鈕,加上時間調節功能。另外在判斷按鈕按下時間這里,本程序的方法自我感覺有時笨,但也沒想出更好的方法,哪位有更好的方法,請給指導一下,謝謝。
四、實現效果
實現過程中,發現存在兩個問題,一個是按鈕不是很靈敏,另一個是最后再退出調時狀態時,長按3秒,時間會增加1分鍾。如原本設定12分鍾,退出時長按3秒會依然會變成13分鍾。