wasdpkj 发表于 2013-4-7 09:06:09

用了几天写成的码表,决定开个源



用328做mcu,ds1307做时钟功能,44e霍尔元件,5110做显示

目前有速度、单次时间、单次里程、总里程、时间显示

设置我采用红外遥控进行,CH+和CH-可以调车轮半径,按EQ进入时间设置,EQ切换,加、减、快进、快退用来调增减

关于电池:
我直接用手机锂电池供电(3.7v),背光关闭电流32ma,背光开启电流42ma,一个电池用几天不是问题


电路以及用到的库在帖子最后面提供下载,我采用了单层pcb,便于大家自己制作
你需要遵循如下协议:



#include "U8glib.h"
#include <Wire.h>
#include <EEPROM.h>
#include <DS1307.h>
#include <IRremote.h>

#define zdpin 1
#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);}
#define EEPROM_read(address, p){int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp=EEPROM.read(address+i);}

#define jsLCDa 2000                        //设置时显示时间
boolean lcda = false;
long TIMELCDa;

int LCDSW=0;
int R;    //cm
boolean Rsetup,Rsetdown;

long CACHEDELAY;

int Reep;        //xxeep判断数值是否更改,set为设置值
float MILEeep;

struct config_type
{
int EEPROMMILE;
int EEPROMMILEs;
int EEPROMR;
};


/*-------lcd------*/
U8GLIB_PCD8544 u8g(5, 6, 8, 7, 9);                // SPI Com: CLK = 5, DIN = 6, CE = 8, DC = 7, Reset = 9


int num;
float SPEED;
float ALLMILE;
float ONEMILE,ONEMILEcache;

long RPM;
/*------计时-----*/
long timea,timeb;

long time,timecache;
boolean timeSTA;

/*----time----*/
String comdata = "";//串口数据缓存
int numdata = {
0}
, j = 0, mark = 0;
int rtc;
int TIMEshi, TIMEfen, TIMEmiao;        //时钟

#define SHEtimeOUT 6000

int sheshi, shefen;
int shenum;

booleanshesta = false, shesw, sheDOWN = false, sheUP = false;

long SHEtime;

/*----MENU----*/
#define MENUtimeOUT 5000
boolean MENUsta = false, MENUsw = false, MENUup = false, MENUdown = false, MENUup10x = false, MENUdown10x = false;

int MENUswNUM = 0;
long MENUtime;

/*-------ir------*/
int RECV_PIN = A0;                //红外输入

IRrecv irrecv(RECV_PIN);
decode_results results;



void setup ()
{
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;
Reep = config_readback.EEPROMR;

attachInterrupt(zdpin,light,FALLING);                //检测中断

CACHEDELAY=millis();
ONEMILEcache=ALLMILE;

RTC.SetOutput(DS1307_SQW32KHZ);


irrecv.enableIRIn();                                 //开始采集
}

void loop()
{   
Rsetup = false;
Rsetdown = false;

    MENUup = false;
    MENUdown = false;
    MENUup10x = false;
    MENUdown10x = false;
    MENUsw = false;

shesw=false;

RTC.get(rtc, true);
TIMEshi = rtc;
TIMEfen = rtc;
TIMEmiao = rtc;

/*=================红外控制=================*/
if (irrecv.decode(&results))
{
    voir();
}

/*=======码表=======*/
if(num>refresh)
{
    jisuan();
    timea=millis();
    num=1;
}

ONEMILE=ALLMILE-ONEMILEcache;

if(millis()-timeb>timeOUT)
{
    RPM=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)        //判断EEPROM是否有改变
    {
      eeprom_write();
      MILEeep = ALLMILE;
      Reep = R;
    }
    CACHEDELAY=millis();
}

/*==============半径设置=================*/
if(Rsetup==true)
    R++;
if(Rsetdown==true)
    R--;

if(R>60)
    R=10;
if(R<10)
    R=60;

    /*==================Time======================*/
    if(shesta == true)        //进入设置状态
    {
      voshe();
    }
    if(shesw == true)                //切换
      shenum++;
    if(shenum > 2)                //范围
      shenum = 1;

    RTC.get(rtc, true);
    TIMEshi = rtc;
    TIMEfen = rtc;
    TIMEmiao = rtc;

    if (sheshi > 23)
    {
      sheshi = 1;
    }
    if (sheshi < 0)
    {
      sheshi = 23;
    }

    if (shefen > 59)
    {
      shefen = 0;
    }
    if (shefen < 0)
    {
      shefen = 59;
    }

/*===========LCD===========*/
if(Rsetup == true || Rsetdown == true)                        //触发
{
    TIMELCDa = millis();
    lcda = true;
}
if(lcda == true)
{
    voLCDdelay();
}

u8g.firstPage();
do {
    draw();
}
while( u8g.nextPage() );

}

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;

EEPROM_write(0, config);         // 变量config存储到EEPROM,地址0写入
}

void voadd(int add)
{
if (add < 10)
    u8g.print("0");
}


void voLCDdelay()                        //显示超时
{
if (millis() - TIMELCDa > jsLCDa && lcda == true)                                //设置刷新频率
{
    lcda = false;
}
}


void voir()
{
unsigned long remote = results.value;                //设红外信号为remote

    if(remote == (-1))                //溢出时
{
    Serial.print(results.value, HEX);   //输出红外线解码结果(十六进制)
}
switch (remote)
{
case 0xFFE21D:                        //CH+
    Rsetup = true;
    LCDSW=1;
    break;

case 0xFFA25D:                        //CH-
    Rsetdown = true;
    LCDSW=1;
    break;

    case 0xFF906F:                        //EQ
      shesw = true;
      voshe();
      voshesta();
      break;

    case 0xFFE01F:                        //-
      MENUdown = true;
      break;

    case 0xFFA857:                        //+
      MENUup = true;
      break;

    case 0xFF22DD:                        //PREV
      MENUdown10x = true;
      break;

    case 0xFF02FD:                        //NEXT
      MENUup10x = true;
      break;
}

irrecv.resume();                 // 返回值

}

void draw() {

u8g.drawLine(51, 0,   51, 10);
u8g.drawLine(0, 11,   83, 11);

u8g.drawLine(0, 29,   83, 29);
u8g.drawLine(0, 39,   83, 39);

u8g.setFont(u8g_font_6x13Br);
u8g.setPrintPos(0, 9);

voadd(int(SPEED*10)/10);
u8g.print(int(SPEED*10)/10);      //SPEED
u8g.print(".");
u8g.print(int(SPEED*10)%10);
u8g.print(" KPH");

u8g.setPrintPos(54, 8);
    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(0, 26);
u8g.setFont(u8g_font_6x13);
u8g.print("ONCE");
u8g.setFont(u8g_font_chikitar);
u8g.print(": ");
u8g.setPrintPos(28, 20);
{
    u8g.setFont(u8g_font_fixed_v0r);
    voadd(ONEMILE);
    u8g.print((int)ONEMILE);        //单次里程
    u8g.print(".");
    u8g.print(int(ONEMILE*10)%10);
    u8g.print(int(ONEMILE*100)%10);       
    u8g.print("km");
}

u8g.setPrintPos(28, 28);
{
    u8g.setFont(u8g_font_fixed_v0r);
    voadd(time/1000/60/60);
    u8g.print(time/1000/60/60);        //单次时间
    u8g.setFont(u8g_font_chikitar);
    u8g.print("hr");
    u8g.setFont(u8g_font_fixed_v0r);
    voadd(time/1000/60%60);
    u8g.print(time/1000/60%60);       
    u8g.setFont(u8g_font_chikitar);
    u8g.print("min");
}


{
    u8g.setFont(u8g_font_chikitar);
    u8g.setPrintPos(0, 37);
    u8g.print("MILE: ");        //总里程

    u8g.setPrintPos(26, 38);
    u8g.setFont(u8g_font_fixed_v0r);
    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.setFont(u8g_font_fixed_v0r);
    u8g.print(int(ALLMILE*10)%10);
    u8g.setFont(u8g_font_chikitar);
    u8g.print("km");
}


u8g.setFont(u8g_font_chikitar);

u8g.setPrintPos(1, 46);

if (lcda == true)    //半径设置
{
    if(LCDSW==1)
    {
      u8g.print("Wheel radius: ");
      voadd(R);
      u8g.print(R);
      u8g.print("cm");
    }
}
else
{
    u8g.print("--Design By PKJ--");
}

}


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;
}


Randy 发表于 2013-4-7 09:20:35

好东西,顶一个!

fangtaonj 发表于 2013-4-7 11:14:18

好东西!谢谢楼主!
另外请问楼主速度传感器用的什么?总共就是一个霍尔原件吗?

wasdpkj 发表于 2013-4-7 12:09:53

fangtaonj 发表于 2013-4-7 11:14 static/image/common/back.gif
好东西!谢谢楼主!
另外请问楼主速度传感器用的什么?总共就是一个霍尔原件吗?

一个霍尔,一个磁钢

Athlon 发表于 2013-4-7 13:59:21

LZ我也想做一个 本人刚刚接触代码 看着晕 可以简化一下不要时间和红外吗,直接显示速度 踏频 里程 平均速度就可以了 ,轮子周长设置可以直接放在代码里

duocool 发表于 2013-4-7 15:56:40

楼主是整合成了一个pcb板子么,是参考那个arduino的线路呢

小叉 发表于 2013-4-7 23:05:24

哇,不错哦!!!

wasdpkj 发表于 2013-4-7 23:36:21

duocool 发表于 2013-4-7 15:56 static/image/common/back.gif
楼主是整合成了一个pcb板子么,是参考那个arduino的线路呢

这个你可以参考一下官网的promini,除去下载部分,就可以算最小系统了,我另外加了asp刷机插座:http://arduino.cc/en/Main/ArduinoBoardProMini

wasdpkj 发表于 2013-4-7 23:53:47

本帖最后由 wasdpkj 于 2013-4-7 23:56 编辑

Athlon 发表于 2013-4-7 13:59 static/image/common/back.gif
LZ我也想做一个 本人刚刚接触代码 看着晕 可以简化一下不要时间和红外吗,直接显示速度 踏频 里程 平均速度 ...

那我给你一个基础代码,1602做显示,最基本的功能:
#include <LiquidCrystal.h>
#include <EEPROM.h>

#define zdpin 0
#define timeOUT 3000   //超时
#define R 300    //轮子半径
#define DEFY 1    //安装几个霍尔
#define EEPDELAY 5000

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp);}
#define EEPROM_read(address, p){int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp=EEPROM.read(address+i);}

long CACHEDELAY;

int MILEeep;        //xxeep判断数值是否更改,set为设置值
struct config_type
{
    float EEPROMMILE;
};


/*-------lcd------*/
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);//设置接口

int num;
float SPEED;
float ALLMILE;
long RPM;

long timea,timeb;

long time,timecache;
boolean timeSTA;

void setup ()
{
Serial.begin(9600);
    /*EEPROM读取赋值*/
    config_type config_readback;
    EEPROM_read(0, config_readback);

    MILEeep = config_readback.EEPROMMILE;
    ALLMILE = config_readback.EEPROMMILE;

attachInterrupt(zdpin,light,FALLING);                //?ж?
    lcd.begin(16, 2);                                 //初始化LCD
    lcd.print(" ===Via--PKJ=== ");       //显示文字
    delay(600);                                                 //延时
    lcd.clear();
    CACHEDELAY=millis();
}

void loop()
{   
if(num>9)
{
jisuan();
timea=millis();
num=0;
}

   if(millis()-timeb>timeOUT)
{
RPM=0;
SPEED=0;
timeSTA=false;
timecache=millis()-time;
}
else
{
timeSTA=true;
time=millis()-timecache;
}

      if (millis() - CACHEDELAY > EEPDELAY)
    {
      if(MILEeep != ALLMILE)        //判断EEPROM是否有改变
    {
      eeprom_write();
      MILEeep = ALLMILE;
    }
    CACHEDELAY=millis();
    }

    lcd.setCursor(0, 0) ;                                        //设置光标位置
    lcd.print("RPM:");       
    lcd.print(RPM);       
    lcd.print("   ");       
    lcd.setCursor(8, 0) ;
    lcd.print("SPE:");                       
    if(int(SPEED*10)/10<10)
    {
    lcd.print("0");
    }
    lcd.print(int(SPEED*10)/10);
    lcd.print(".");                              
    lcd.print(int(SPEED*10)%10);                        
    lcd.print("");               

    lcd.setCursor(0, 1) ;
    if(int(ALLMILE*10)/10<10)
   {
       lcd.print("00");
   }
    if(int(ALLMILE*10)/10>10 && int(ALLMILE*10)/10<100)
   {
       lcd.print("0");
   }
    lcd.print(int(ALLMILE*10)/10);                     
    lcd.print(".");                  
    lcd.print(int(ALLMILE*10)%10);               
    lcd.print("KM");                               

    lcd.setCursor(8, 1);
    lcdout(time/1000/60/60);                                        //使屏幕显示文字
    lcd.print(time/1000/60/60);                                        //使屏幕显示文字
    lcd.setCursor(10, 1);
    lcd.print(":");                                        //使屏幕显示文字
    lcdout(time/1000/60%60);                                        //使屏幕显示文字
    lcd.print(time/1000/60%60);                                        //使屏幕显示文字
    lcd.setCursor(13, 1);
    lcd.print(":");                                        //使屏幕显示文字
    lcdout(time/1000%60);                                        //使屏幕显示文字
    lcd.print(time/1000%60);                                        //使屏幕显示文字
               
Serial.println(RPM);
Serial.println("");   
}

void jisuan()
{
ALLMILE=((((10.0*(2.0*3.14159*(R/1000.0))))/1000.0)/DEFY)+ALLMILE;
RPM=(600000/((millis()-timea)))/DEFY;
SPEED=((RPM*(2.0*3.14159*(R/1000.0)))*60.0)/1000.0;
}

void light()
{
num++;
timeb=millis();
}

void lcdout(int lcdOUT)
{
if(lcdOUT<10)
{
lcd.print("0");
}
}


void eeprom_write()
{
    config_type config;                // 定义结构变量config,并定义config的内容
    config.EEPROMMILE = ALLMILE;

    EEPROM_write(0, config);         // 变量config存储到EEPROM,地址0写入
}

duocool 发表于 2013-4-8 09:48:39

请问楼主用的哪款软件设计的板子呢,只能弄弄洞洞板,希望有天也能做个整合的板子

wasdpkj 发表于 2013-4-8 16:12:58

duocool 发表于 2013-4-8 09:48 static/image/common/back.gif
请问楼主用的哪款软件设计的板子呢,只能弄弄洞洞板,希望有天也能做个整合的板子

eagle...........

zfm0610363 发表于 2013-4-8 20:01:09

楼主你好,PCB是一张空白啊,什么都没有,你用什么画的?

zfm0610363 发表于 2013-4-8 20:04:54

楼主你好,PCB是一张空白啊,什么都没有,你用什么画的?

wasdpkj 发表于 2013-4-8 20:04:54

zfm0610363 发表于 2013-4-8 20:01 static/image/common/back.gif
楼主你好,PCB是一张空白啊,什么都没有,你用什么画的?

eagle,挺好用的

zfm0610363 发表于 2013-4-8 20:07:25

楼主你好,PCB是一张空白啊,什么都没有,你用什么画的?
页: [1] 2
查看完整版本: 用了几天写成的码表,决定开个源