好東東啊,樓主的諾基亞5110屏碼表源程序如下:
- /*=========自行車碼表=========*/
- #include "Arduino.h"
- #include "U8glib.h"
- #include <Wire.h>
- #include <EEPROM.h>
- #include <DS1307.h>
- //#include <IRremote.h>
- //#define LCD_CMD 0
- #define zdpin 1 //中斷源可選值為0或1,分別對應2號和3號引腳
- #define timeOUT 3000 //檢測速度超時
- #define EEPDELAY 5000 //EEPROM更新檢測
- #define refresh 5 //刷新圈數
- #define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
- #define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}
- int adc_key_val[5] ={50, 200, 400, 600, 800 };
- int NUM_KEYS = 5;
- int adc_key_in;
- int key = -1;
- int oldkey = -1;
- #define jsLCD 6000 //設置時顯示時間
- boolean lcda = false; //boolean 數據類型 boolean 變量存儲為 8 位(1 個字節)的數值形式,但只能是 True 或是 False
- boolean lcdb = false;
- long TIMELCDa; //長整數型變量 可以存儲32位(4字節)
- long TIMELCDb;
- int LCDSW=0;//整數數據類型占用2字節,范圍-32768到32767
- int lcdSW=0;
- int R; //cm
- int V; //km/h
- boolean Rsetup,Vsetup; //半徑數值
- long CACHEDELAY;
- int Reep; //xxeep判斷數值是否更改,set為設置值
- int Veep;
- float MILEeep; //浮點型數據,就是有小數點的數字,經常被用來模擬連續值
- struct config_type
- {
- int EEPROMMILE;
- int EEPROMMILEs;
- int EEPROMR;
- int EEPROMV;
- };
- /*-------lcd------*/
- U8GLIB_PCD8544 u8g(5, 6, 8, 7, 9); // SPI Com: CLK = 5, DIN = 6, CE = 8, DC = 7, Reset = 9
- int BGKEY = 10;//背光燈按鍵引腳
- int SUM = 0; //背光燈亮度值
- int Flag_up = 1; //按鍵掃描
- int beeppin = 12; //蜂鳴器引腳定義
- int num;
- float SPEED;
- float MSPEED; //平均速度
- float ALLMILE; //所有的里程
- float ONEMILE,ONEMILEcache;
- long RPM; //每分鐘的旋轉次數
- /*------計時-----*/
- long timea,timeb;
- long time,timecache;
- boolean timeSTA;
- //*----time----*/
- String comdata = ""; //串口數據緩存
- int numdata[7] = {0}, j = 0, mark = 0;
- int rtc[7];
- int TIMEshi, TIMEfen, TIMEmiao; //時鐘
- #define SHEtimeOUT 6000
- int sheshi, shefen;
- int shenum;
- boolean shesta = false, shesw, sheDOWN = false, sheUP = false;
- long SHEtime;
- /*----MENU----*/
- //#define MENUtimeOUT 5000
- boolean MENUup = false, MENUdown = false;//MENUsta = false, MENUsw = false, MENUup10x = false, MENUdown10x = false;
- //int MENUswNUM = 0;
- //long MENUtime;
- /*-------ir------*/
- //int RECV_PIN = A0; //紅外輸入
- //IRrecv irrecv(RECV_PIN);//定義IRrecv對象來接收紅外線信號
- //decode_results results;//解碼結果放在decode_results構造的對象results里
- /*-----------------按鍵設置-----------------*/
- //將adc(模數轉換器)值轉換為鍵號
- int get_key(unsigned int input)
- {
- int k;
- for (k = 0; k < NUM_KEYS; k++)
- {
- if (input < adc_key_val[k])
- return k;
- }
- if (k >= NUM_KEYS)k = -1; // 未按有效鍵
- return k;
- }
- /*利用芯片內部1.1v基準電壓反算出電源電壓(模擬輸入端口A7)*/
- unsigned int ADCValue;
- double Voltage;
- double Vcc;
- //讀取vcc電壓
- long readVcc() {
- long result;
- // Read 1.1V reference against AVcc 讀取1.1V AVcc
- ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
- delay(2); // Wait for Vref to settle 等待Vref解決
- ADCSRA |= _BV(ADSC); // Convert 轉換
- while (bit_is_set(ADCSRA,ADSC));
- result = ADCL;
- result |= ADCH<<8;
- result = 1125300L / result; // Back-calculate AVcc in mV 反算出AVcc 為mv
- return result;
- }
- void setup ()
- {
- u8g.setContrast(140);//設置對比度0-255
- pinMode(BGKEY, INPUT_PULLUP); //按鍵IO設定為帶上拉輸入
- pinMode(11,OUTPUT); //該端口需要選擇有~號標識的數字口(有~號表示是支持PWM的引腳)*/
- pinMode(beeppin, OUTPUT);//蜂鳴器輸出
-
- /*按著背光燈按鍵同時上電,開機后數據清零*/
- if(digitalRead(BGKEY) == LOW)
- {
- for (int i = 0 ; i < EEPROM.length() ; i++) {
- EEPROM.write(i, 0);
- }
- }
- Serial.begin(9600);
- /*EEPROM讀取賦值*/
- config_type config_readback;
- EEPROM_read(0, config_readback);
- ALLMILE = float(config_readback.EEPROMMILE+(config_readback.EEPROMMILEs/10.0));
- MILEeep = config_readback.EEPROMMILE;
- R = config_readback.EEPROMR;
- V = config_readback.EEPROMV;
- Reep = config_readback.EEPROMR;
- Veep = config_readback.EEPROMV;
- attachInterrupt(zdpin,light,FALLING); //檢測中斷
- /*中斷函數(attachInterrupt):attachInterrupt(interrupt,function,mode)
- interrupt:中斷源(在Arduino中,中斷源可選值為0或1,一般分別對應2號和3號引腳)
- function:需要中斷的函數名
- mode:LOW(低電平觸發)、CHANGE(變化時觸發)、
- RISING(低電平變為高電平觸發)、FALLING(高電平變為低電平觸發)
- 注意:在寫代碼時,interrupt處要寫成0或1,不能寫成2或3*/
- CACHEDELAY=millis();
- ONEMILEcache=ALLMILE;
-
- RTC.SetOutput(DS1307_SQW32KHZ);
- // irrecv.enableIRIn(); //啟動紅外解碼 開始采集
-
- adc_key_in = analogRead(0); //從傳感器讀取值
- key = get_key(adc_key_in); //轉換成按鍵
- }
-
- void loop()
- {
- Rsetup = false;
- Vsetup = false;
- MENUup = false;
- MENUdown = false;
- // MENUup10x = false;
- //MENUdown10x = false;
- //MENUsw = false;
- shesw = false;
- RTC.get(rtc, true);
- TIMEshi = rtc[2];
- TIMEfen = rtc[1];
- TIMEmiao = rtc[0];
- /*----------背光燈亮度調整----------*/
- if ( ScanKey() == 1) //當有按鍵按下時
- {
- SUM+=63; //SUM加一
- tone(beeppin,4000);
- delay(30);
- noTone(beeppin);
- }
- if (SUM >252)
- {
- SUM = 0;
- }
- /*=================紅外控制=================*/
- //if (irrecv.decode(&results))
- // {
- // voir();
- //}
- /*=================按鍵控制=================*/
- adc_key_in = analogRead(0); //從傳感器讀取值
- key = get_key(adc_key_in);
- if (key != oldkey) //如果檢測到按鍵
- {
- delay(50); //去抖動時間
- tone(beeppin,4000);
- delay(30);
- noTone(beeppin);
- voir();
- }
-
- /*=======碼表=======*/
- if(num>refresh)
- {
- jisuan();
- timea=millis();
- num=1;
- }
- ONEMILE=ALLMILE-ONEMILEcache;
- if(millis()-timeb>timeOUT)
- {
- RPM=0; //每分鐘圈數=0
- SPEED=0;
- timeSTA=false;
- timecache=millis()-time;
- }
- else
- {
- timeSTA=true;
- time=millis()-timecache;
- }
- if(ALLMILE>9999)
- {
- ALLMILE=0;
- }
- /*==========EEPROM==========*/
- if (millis() - CACHEDELAY > EEPDELAY)
- {
- if(MILEeep != ALLMILE||Reep!=R||Veep!=V) //判斷EEPROM是否有改變
- {
- eeprom_write();
- MILEeep = ALLMILE;
- Reep = R;
- Veep =V;
- }
- CACHEDELAY=millis();
- }
- /*==============半徑設置=================*/
- if(Rsetup==true)
- R++;
- if(R>50)
- R=1;
- // if(R<10)
- // R=60;
- /* ==============限速警報設置================= */
- if(Vsetup==true)
- V += 5; //每按一次加 5 km/h
-
- if(V>120) //大于120 km/h 返回 5km/h
- V=5;
- /*==================Time======================*/
- if(shesta == true) //進入設置狀態
- {
- voshe();
- }
- if(shesw == true) //切換
- shenum++;
- if(shenum > 2) //范圍
- shenum = 1;
- /* RTC.get(rtc, true);
- TIMEshi = rtc[2];
- TIMEfen = rtc[1];
- TIMEmiao = rtc[0];*/
- if (sheshi > 23)
- {
- sheshi = 1;
- }
- if (sheshi < 0)
- {
- sheshi = 23;
- }
- if (shefen > 59)
- {
- shefen = 0;
- }
- if (shefen < 0)
- {
- shefen = 59;
- }
- /*===========LCD===========*/
- if(Rsetup == true ) //半徑設置觸發
- {
- TIMELCDa = millis();
- lcda = true;
-
- }
- if(lcda == true)
- {
- voLCDadelay();
- }
-
- if( Vsetup == true) //限速報警設置觸發
- {
- TIMELCDb = millis();
- lcdb = true;
-
- }
- if(lcdb == true)
- {
- voLCDbdelay();
- }
-
- u8g.firstPage();
- do {
- draw();
- }
- while( u8g.nextPage() );
-
- if(SPEED > V) //
- {
- baojing();
- }
- else
- {
- digitalWrite(beeppin, LOW);
- }
- }
- void jisuan()
- {
- ALLMILE+=((float(refresh)*(2.0*3.1416*(R/100.0))))/1000.0; //總里程累加
- RPM=60000/((millis()-timea)/refresh); //轉速
- SPEED=((RPM*(2.0*3.14159*(R/100.0)))*60.0)/1000.0; //速度
- }
- void light() //計數
- {
- num++;
- timeb=millis();
- }
- void eeprom_write()
- {
- config_type config; // 定義結構變量config,并定義config的內容
- config.EEPROMMILE = int(ALLMILE);
- config.EEPROMMILEs = int(ALLMILE*10)%10;
- config.EEPROMR = R;
- config.EEPROMV = V;
- EEPROM_write(0, config); // 變量config存儲到EEPROM,地址0寫入
- }
-
- void voadd(int add)
- {
- if (add < 10)
- u8g.print("0");
- }
- void voLCDadelay() //顯示超時
- {
- if (millis() - TIMELCDa > jsLCD && lcda == true) //設置刷新頻率
- {
- lcda = false;
- }
- }
- void voLCDbdelay()
- {
- if (millis() - TIMELCDb > jsLCD && lcdb == true) //設置刷新頻率
- {
- lcdb = false;
- }
- }
- void voir()
- {
- switch(key)
- {
- case 0:
- Rsetup = true;
- LCDSW=1;
- break;
- case 1:
- Vsetup = true;
- lcdSW=1;
- break;
- case 2:
- shesw = true;
- voshe();
- voshesta();
- break;
- case 3:
- MENUdown = true;
- break;
- case 4:
- MENUup = true;
- break;
- }
-
- delay(100);
- }
- //將ADC值轉換為鍵號
- /*
- unsigned long remote = results.value; //設紅外信號為remote
- if(remote == (-1)) //溢出時
- {
- Serial.print(results.value, HEX); //輸出紅外線解碼結果(十六進制)
- }
- switch (remote)
- {
- case 0xFD6897: //CH+
- Rsetup = true;
- LCDSW=1;
- break;
- case 0xFDE817: //CH-
- Rsetdown = true;
- LCDSW=1;
- break;
- case 0xFDA857: //EQ
- shesw = true;
- voshe();
- voshesta();
- break;
- case 0xFD9867: //-
- MENUdown = true;
- break;
- case 0xFD18E7: //+
- MENUup = true;
- break;
- case 0xFD12ED: //PREV
- MENUdown10x = true;
- break;
- case 0xFD48B7: //NEXT
- MENUup10x = true;
- break;
- }
- irrecv.resume(); // 返回值
- }
- */
- void draw() {
- Vcc = readVcc()/1000.0;//將讀取的vcc電壓mv轉換為v
- ADCValue = analogRead(7);
- Voltage = (ADCValue / 1023.0) * Vcc;
- MSPEED=(ONEMILE/time)*1000*60*60;
- u8g.setDefaultForegroundColor();
- u8g.drawLine(0, 19, 83, 19);
- u8g.drawLine(0, 27, 83, 27);
- u8g.drawLine(27, 28, 27, 40);
- u8g.drawLine(0, 41, 84, 41);
-
- u8g.setFont(u8g_font_ncenB08r);
- u8g.setPrintPos(45, 18);
- u8g.print("Km/h");
- /*--------電量顯示--------*/
- if (Voltage >=3.9){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- u8g.drawBox(80,5,2,2);//電池電量段
- u8g.drawBox(80,8,2,2);
- u8g.drawBox(80,11,2,2);
- u8g.drawBox(80,14,2,2);
- }
- if (Voltage <3.9 && Voltage >=3.7 ){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- u8g.drawBox(80,8,2,2);//電池電量段
- u8g.drawBox(80,11,2,2);
- u8g.drawBox(80,14,2,2);
- }
- if (Voltage <3.7 && Voltage>=3.5 ){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- u8g.drawBox(80,11,2,2);//電池電量段
- u8g.drawBox(80,14,2,2);
- }
- if (Voltage <3.5 && Voltage >=3.2){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- u8g.drawBox(80,14,2,2);//電池電量段
- }
- if (Voltage <3.2 && Voltage >=3.0 ){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- }
- if (Voltage < 3.0 ) { //當VCC電壓小于3v時圖標閃爍,電池電量不足警告
- if(millis()/1000%2!=0){
- u8g.drawLine(80, 2, 81, 2);
- u8g.drawFrame(78,3,6,15);//電池外形
- u8g.drawLine(79, 4, 82, 17);
- }
- else{
- u8g.setPrintPos(80, 2); //只要是不影響其他顯示此位置可任選
- u8g.print("");
- }
- }
- /*背光燈4檔可調,當電池電壓低于3.2v時背光燈熄滅,節約電能*/
- if(Voltage >=3.2){
- analogWrite(11,SUM);//使用PWM控制11號口輸出,變量n的取值范圍是0-255
- }
- else{
- digitalWrite(11, LOW);
- }
-
- u8g.setPrintPos(47, 7);
- if(shesta == true) //進入設置狀態
- {
- u8g.setFont(u8g_font_6x12);
- switch(shenum)
- {
- case 1:
- {
- if((millis() / 1000) % 2 != 0)
- {
- voadd(sheshi);
- u8g.print(sheshi);
- }
- else
- u8g.print(" ");
- u8g.print(":");
- voadd(shefen);
- u8g.print(shefen);
- }
- ;
- break;
- case 2:
- {
- voadd(sheshi);
- u8g.print(sheshi);
- u8g.print(":");
- if((millis() / 1000) % 2 != 0)
- {
- voadd(shefen);
- u8g.print(shefen);
- }
- else
- {
- u8g.print(" ");
- }
- }
- ;
- break;
- }
- }
- else //正常顯示時間
- {
- u8g.setFont(u8g_font_6x12);
- voadd(TIMEshi);
- u8g.print(TIMEshi); //hou
- if(millis()/1000%2!=0)
- u8g.print(":");
- else
- u8g.print(" ");
- voadd(TIMEfen);
- u8g.print(TIMEfen); //min
- }
- u8g.setPrintPos(1, 26);
- {
- u8g.setDefaultForegroundColor();
- u8g.drawBox(0, 20, 84, 8);
- u8g.setDefaultBackgroundColor();
- u8g.setFont(u8g_font_chikitar);
- u8g.print("MSPEED:");//平均時速
- u8g.setPrintPos(40, 26);
- voadd(MSPEED);
- u8g.print(int (MSPEED*10)/10);
- u8g.print(".");
- u8g.print(int (MSPEED*10)%10);
- }
- u8g.setFont(u8g_font_04b_03b);
- u8g.setPrintPos(62, 26);
- u8g.print("km/h");
- u8g.setDefaultForegroundColor();
- u8g.setPrintPos(0, 39); //單次里程
- u8g.setFont(u8g_font_6x13);
- u8g.print("ONCE");
- u8g.setPrintPos(32, 34);
- {
- u8g.setFont(u8g_font_chikitar);
- voadd(ONEMILE);
- u8g.print((int)ONEMILE);
- u8g.print(".");
- u8g.print(int(ONEMILE*10)%10);
- u8g.print(int(ONEMILE*100)%10);
- }
- u8g.setPrintPos(32, 40); //單次時間
- {
- u8g.setFont(u8g_font_chikitar);
- voadd(time/1000/60/60);
- u8g.print(time/1000/60/60);
- u8g.print(" hr ");
-
- voadd(time/1000/60%60);
- u8g.print(time/1000/60%60);
- }
- u8g.setFont(u8g_font_chikitar);
- u8g.setPrintPos(70, 34);
- u8g.print("km");
- u8g.setPrintPos(70, 40);
- u8g.print("min");
-
- if (lcda == true) //半徑設置
- {
-
- if(LCDSW==1)
- {
- u8g.setDefaultForegroundColor();
- u8g.drawBox(0, 42, 84, 6);
- u8g.setDefaultBackgroundColor();
- u8g.setFont(u8g_font_chikitar);
- u8g.setPrintPos(1, 47);
- u8g.print("Wheel radius: ");
- voadd(R);
- u8g.print(R);
- u8g.setPrintPos(72, 47);
- u8g.print("cm");
- }
- }
- else
- {
- u8g.setDefaultForegroundColor();
- u8g.setFont(u8g_font_chikitar);
- u8g.setPrintPos(0, 48);
- u8g.print("MILE: "); //總里程
- u8g.setPrintPos(32, 48);
- if(int(ALLMILE*10)/10<10)
- {
- u8g.print("000");
- }
- if(int(ALLMILE*10)/10>10 && int(ALLMILE*10)/10<100)
- {
- u8g.print("00");
- }
- if(int(ALLMILE*10)/10>100 && int(ALLMILE*10)/10<1000)
- {
- u8g.print("0");
- }
- u8g.print(int(ALLMILE));
- u8g.print(".");
- u8g.print(int(ALLMILE*10)%10);
- u8g.setPrintPos(70, 48);
- u8g.print("km");
- }
- if (lcdb == true) //報警設置
- {
- if(lcdSW==1)
- {
- u8g.setDefaultForegroundColor();
- u8g.drawBox(0, 0, 44, 19);
- u8g.setDefaultBackgroundColor();
- u8g.setFont(u8g_font_5x8);
- u8g.setPrintPos(5, 8);
- u8g.print("SPEED/L");
- u8g.setPrintPos(4, 18);
- voadd(V);
- u8g.print(V);
- u8g.setPrintPos(21, 18);
- u8g.print("km/h");
- }
- }
- else
- {
- u8g.setDefaultForegroundColor();
- u8g.setFont(u8g_font_timB18r);
- u8g.setPrintPos(0, 18);
- voadd(int(SPEED*10)/10);
- if(SPEED >=100){
- u8g.print(int(SPEED*10)/10); //SPEED
- }
- else{
- u8g.print(int(SPEED*10)/10); //SPEED
- u8g.print(".");
- u8g.print(int(SPEED*10)%10);
- }
- }
- }
- void voshe()
- {
- if(shenum == 0) //初始賦值
- {
- sheshi = TIMEshi;
- shefen = TIMEfen;
- }
- RTC.stop(); //準備寫入時間
- if(millis() - SHEtime > SHEtimeOUT) //超時
- {
- shesta = false; //退出設置
- shenum = 0; //初始
- RTC.set(DS1307_HR, sheshi);
- RTC.set(DS1307_MIN, shefen);
- RTC.set(DS1307_SEC, 0);
- RTC.start();
- }
- if(MENUup == true || MENUdown == true )//|| MENUup10x == true || MENUdown10x == true //觸發時
- {
- voshesta();
- }
- switch(shenum) //按鍵作用
- {
- case 1:
- {
- if(MENUup == true)
- {
- sheshi++;
- }
- if(MENUdown == true)
- {
- sheshi--;
- }
- /* if(MENUup10x == true)
- {
- sheshi += 10;
- }
- if(MENUdown10x == true)
- {
- sheshi -= 10;
- }*/
- };
- break;
- case 2:
- {
- if(MENUup == true)
- {
- shefen++;
- }
- if(MENUdown == true)
- {
- shefen--;
- }
- /* if(MENUup10x == true)
- {
- shefen += 10;
- }
- if(MENUdown10x == true)
- {
- shefen -= 10;
- }*/
- };
- break;
- }
- }
- void voshesta() //觸發時間設置狀態
- {
- SHEtime = millis();
- shesta = true;
- }
- int ScanKey() //按鍵掃描程序,返回鍵值
- {
- if (Flag_up && digitalRead(BGKEY) == LOW) //當Flag_up = 1并且按鍵按下時
- {
- Flag_up = 0; //清空Flag_up
- delay(20); //延時去抖動
- if (digitalRead(BGKEY) == LOW) //按鍵按下
- {
- return 1; //返回鍵值1
- }
- }
- if (digitalRead(BGKEY) == HIGH) //按鍵松開時候
- {
- Flag_up = 1; //置位Flag_up
- }
- return 0; //返回鍵值0
- }
- void baojing()
- {
- tone(beeppin,4500);
- delay(50);
- noTone(beeppin);
- tone(beeppin,4500);
- delay(50);
- noTone(beeppin);
- }
復制代碼 |