手电大家谈-手电筒爱好者之家

 找回密码
 注册成为会员,享受更多功能。

QQ登录

只需一步,快速开始

只需一步,快速开始

搜索
楼主: daniel_wang

[白炽灯] 镁光D型手电驱动板PCB打样收到货了107楼小白鼠报告

[复制链接]

该用户从未签到

 楼主| 发表于 2012-10-10 15:42 | 显示全部楼层
温度测试用的是华强北的金属反光碗+玻璃, 调整到聚光位置, 此时灯泡下部伸出反光碗很多, 大量的光未能通过反光碗反射出去而是留在了手电内部. 使得手电头部很热.
如果有设计合理的反光碗的话估计温度还会再低些.
30W的5761我没测试.. 手里就一只灯泡 还被我弄坏了.
回复

使用道具 举报

  • TA的每日心情
    开心
    2015-2-12 11:02
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2012-10-10 16:00 | 显示全部楼层
    镁光的壳子不错   楼主的面包板很高级的样子
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-10 23:27 | 显示全部楼层
    楼主辛苦,要是能从新设计个定制灯杯就好了!

    {:4_330:}
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-11 09:45 | 显示全部楼层
    daniel_wang 发表于 2012-10-10 15:42
    温度测试用的是华强北的金属反光碗+玻璃, 调整到聚光位置, 此时灯泡下部伸出反光碗很多, 大量的光未能通过 ...

    把G4座的安装铜柱截短一点就能使灯泡下降到原装灯泡所在的位置了。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2022-11-3 09:26
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2012-10-11 10:02 | 显示全部楼层
    潜质贴,精华吧~~
    回复

    使用道具 举报

  • TA的每日心情

    2015-2-28 11:15
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2012-10-11 17:25 | 显示全部楼层
    Blackbird 发表于 2012-10-11 09:45
    把G4座的安装铜柱截短一点就能使灯泡下降到原装灯泡所在的位置了。

    调整到聚光位置
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-14 12:49 来自手机 | 显示全部楼层
    大力支持啊
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-14 12:53 来自手机 | 显示全部楼层
    发现lz用的是松下摔不坏笔记本啊。。。好东西

    期待完工上市
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-6-14 13:55
  • 签到天数: 456 天

    [LV.9]以坛为家II

    发表于 2012-10-14 14:37 | 显示全部楼层
    {:3_122:}期待啊
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-15 08:39 | 显示全部楼层
    minority 发表于 2012-10-14 12:53
    发现lz用的是松下摔不坏笔记本啊。。。好东西

    期待完工上市

    ^_^
    MKII的, 配置很垃圾. 720p及以上无法播放.. 各种卡....
    所以只能用来写一写小程序啥的.
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-15 09:50 | 显示全部楼层
    daniel_wang 发表于 2012-10-15 08:39
    ^_^
    MKII的, 配置很垃圾. 720p及以上无法播放.. 各种卡....
    所以只能用来写一写小程序啥的.

    Panasonic Toughbook的最坚固系列向来都是性能低下的,哈哈,电筒里面的SF,重稳定、恶劣环境!
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-16 09:56 | 显示全部楼层
    硬件的测试和调整已经进行的差不多了, 抽空写点儿软件方面的.
    想自己调整功能修改参数的请继续往下看, 不深奥, 电路电子单片机方面我也是小白(本人经济学出身), 保证白话叙述, 都看得懂.

    关于单片机
      这个驱动板的主控芯片采用的是Atmel公司生产的ATTiny85单片机, 对这个驱动板来说呢, 单片机起到的作用有
    1, 生成PWM波形驱动MOSFet点亮灯泡.
    2, 检测电池电压, 实施电池保护.
    3, 检测并执行相应的按钮动作.
    得益于电子技术的日新月异, 这枚单片机仅需要很少的外围电路就能完成这些功能.

    开发环境简介
    因为我是电子小白, 原厂的开发环境实在用不了, 因为有过多的与单片机寄存器相关的代码需要编写. 所以我选用了目前比较流行的Arduino. 见 http://arduino.cc/
    简单说来, Arduino是一个以Atmel单片机为核心的, 包含硬件和软件两部分的, 集成并封装了Atmel单片机底层代码的, 使得使用者可以在无需学习过多单片机知识的前提下快速简单构建单片机项目的解决方案.
    原装的Arduino软件环境是不支持ATTiny系列单片机的, 很幸运, 有一些外国的大神在Arduino的基础上进行了ATTiny系列单片机的扩展, 使得使用Arduino软件环境开发ATTiny系列单片机程序成为可能.

    开发环境的搭建
    首先去http://arduino.cc/下载开发工具 http://arduino.googlecode.com/files/arduino-1.0.1-windows.zip
    这个是windows版的, 还有Mac, Linux等版本的.
    下载之后安装

    然后下载ATTiny支持, http://code.google.com/p/arduino-tiny/ 这个是Arduino-tiny项目的主页, 点这个链接直接下载ZIP包
    下载之后解压, 按照里面的readme.txt进行安装
    至此. 开发工具就安装好了.

    编程器
    编程器是将自行写的程序写入单片机必备的设备, 受Arduino支持的编程器有很多, 包括但不限于:
    1, Atmel原厂/副厂的AVRISP, AVRISP MKII
    2, 开源的USBTinyISP
    TB上搜吧, 很多.
    买回来之后要装驱动, 需要注意的是如果购买的是Atmel原厂/副厂的AVRISP, AVRISP MKII驱动需要安装Arduino自带的, 否则编程器不会被Arduino开发环境正确识别. windows提示安装驱动的时候将驱动地址指向Arduino安装路径让windows自行寻找即可.注意选中搜索子文件夹.

    程序调试
    如果想自己改动程序的功能实现, 必不可少的就是程序调试了, 调试就需要监视代码的输出. 而单片机并没有显示屏, 我们人类如何获得代码输出呢? 还好, Arduino的底层框架已经为我们解决了这个问题, 那就是串口通讯.
    串口,Serial Port是计算机上常见的接口, 在古代是计算机的标配, 现代因为USB的大量应用已经基本上从笔记本领域消失了, 但台式机基本都有. 要让单片机与计算机的串口进行通信还需要一个TTL转换板, 为什么呢? 简单说来, 串口通讯的标注有很多, RS-232, TTL, RS-485. 搞出这么多个标准是为了适用于不同的环境, 比如单片机多采用TTL, 电脑多采用RS-232. 这些个标准之间无法直接通讯, 必须要经过电平转换. TB搜 RS232转TTL即可.
    木有串口怎么办? 没关系, USB也可以, TB上有很多USB转TTL的板卡可以直接拿来跟单片机连接, 搜索 USB转TTL.

    串口是两线通讯, 相互通讯的两个设备通过两根数据线互传信息, 这两根数据线我们叫它RX,TX. 对某一具体设备来说RX表示数据接收, TX表示数据发送. 如果设备1想与设备2通讯, 则设备1的RX接设备2的TX, 设备1的TX接设备2的RX.
    除此之外相互通讯的设备还需要知道通讯的速率, 单位是bps(bit per second). 即每秒传送的比特数, 测试采用的速率是9600bps, 即每秒钟传输9600个bit, 按一个字节8bit计算就是每秒钟1200byte, 一个byte可以用来储存一个ASCII字符, 所以每秒钟可以传输1200个ASCII字符. 做好这些工作之后, 单片机就可以把检测到的电池电压, 当前的PWM占空比, 按钮按压的状态, 开机时间等信息传给电脑. 在电脑端我们再利用诸如windows 自带的超级终端, 或者串口调试助手等软件就可以直观的看到单片机传回的这些信息了.

    基本的情况先介绍到这里, 图文攻略随后.


    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-16 10:00 | 显示全部楼层
    源代码:

    /*
    *-------------------------------------------------------------------------*
    *                                                                         *
    *  This program is free software: you can redistribute it and/or modify   *
    *  it under the terms of the GNU General Public License as published by   *
    *  the Free Software Foundation, either version 3 of the License, or      *
    *  (at your option) any later version.                                    *
    *                                                                         *
    *  This program is distributed in the hope that it will be useful,        *
    *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
    *  GNU General Public License for more details.                           *
    *                                                                         *
    *  You should have received a copy of the GNU General Public License      *
    *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
    *                                                                         *
    *-------------------------------------------------------------------------*
    */
    /*
    Author:ShaunWang
    QQ:24391917
    http://www.shoudian.org/thread-288761-1-1.html
    Arduino ATTiny 85 Maglite flashlight driver
    Main functionality
    1, Softstart.
    2, Mid power output.
    3, Battery protection, low voltage shutdown.
    4, PWM drive, constant bulb voltage.
    */
    #include <avr/sleep.h>
    #include <PinChangeInterrupt.h>
    #include <SoftwareSerial.h>
    // uncomment to enable serial debug
    //#define DEBUG

    //-------------BEGAIN OF USER EDITABLE PARAMETER SECTION---------------
    //ADJUST THESE PARAMETER VALUE WITH EXTREME CAUTION
    //WRONG VALUE SET MAY CAUSE DAMAGE TO BULB AND BATTERY,
    //MAY ALSO LEAD TO FIRE OR EXPLODE AND TO PERSONAL INJURY
    #define SOFT_START_DURATION 2500 // in ms
    #define DESIGN_BULB_VOLTAGE 6000 // in mV
    /*
    1-LiIon, LiPo discharge to 3000mV
    2-LiFe discharge to 2750mV
    */
    #define BATTERY_TYPE 1
    /*
    set this parameter to non-zero value will disable
    number of battery in series autodetection.
    */
    int SHUTDOWN_VOLTAGE = 0;
    #define BOOST_VOLTAGE 7000 // in mV
    #define NO_ACTIVITY_SLEEP 3000 // in ms
    int PWM_MUL[] = {
      0, // CAUTION:DO NOT MODIFY THIS VALUE
      50, // LOW
      80, // MID
      100,// HIGH
      100 // CAUTION:DO NOT MODIFY THIS VALUE
    };
    int LIION_BATTERY_SERIES_VOLTAGE[] = {
      8400,12600,16800,21000,25200};
    #define LI_ION_DISCHARGE_VOLTAGE 2500
    int LIION_BATTERY_SERIES_SHUTDOWN_VOLTAGE[] = {
      LI_ION_DISCHARGE_VOLTAGE*2,LI_ION_DISCHARGE_VOLTAGE*3,
      LI_ION_DISCHARGE_VOLTAGE*4,LI_ION_DISCHARGE_VOLTAGE*5,
      LI_ION_DISCHARGE_VOLTAGE*6};
    #define LI_FE_DISCHARGE_VOLTAGE 2200
    int LIFE_BATTERY_SERIES_VOLTAGE[] = {
      7200,10800,14400,18000,21600};
    int LIFE_BATTERY_SERIES_SHUTDOWN_VOLTAGE[] = {
      LI_FE_DISCHARGE_VOLTAGE*2,LI_FE_DISCHARGE_VOLTAGE*3,
      LI_FE_DISCHARGE_VOLTAGE*4,LI_FE_DISCHARGE_VOLTAGE*5,
      LI_FE_DISCHARGE_VOLTAGE*6};
    //-------------END OF USER EDITABLE PARAMETER SECTION---------------
    int pwmPin = 0;
    int btnPin = 1;
    int batPin = 1;
    int destDutyCycle = 0;
    int curDutyCycle = 0;

    #define BULB_STATE_OFF 0
    #define BULB_STATE_LOW 1
    #define BULB_STATE_MID 2
    #define BULB_STATE_HIGH 3
    #define BULB_STATE_BOOST 4
    int bulbState = 0;
    #define BUTTON_CLICK 1
    #define BUTTON_DOUBLE_CLICK 2
    #define BUTTON_HOLD 3
    #define BUTTON_LONG_HOLD 4
    /*
    define a = analogRead value
    so battery voltage is:
    a*5000   1      a*5000
    ------*----*120+------
    1023   27       1023
    =
    (5000*120+5000*27)*a
    -------------------
    1023*27
    ~= 26.61*a
    */
    #define VOLTAGE_AMP 26.45
    #define VOLTAGE(analogValue) analogValue*VOLTAGE_AMP
    volatile int batVoltUnderLoad = 0;
    volatile int batVoltWhenIdle = 0;
    int batVoltReadInterval = 500;// read battery voltage every 500ms
    volatile unsigned long lastBatVoltUnderLoadReadTime = 0;
    volatile unsigned long lastBatVoltWhenIdleReadTime = 0;
    boolean batteryUnderVoltage = false;
    boolean needSoftStart = false;
    unsigned long lastDutyCycleSetTime = 0;
    unsigned long lastActivityTime = 0;
    unsigned long lastDutyCycleCheckTime = 0;
    // PWM duty cycle check interval
    #define pwmDutyCycleCheckInterval 100

    #ifdef DEBUG
    SoftwareSerial serial(4, 3); // RX, TX
    #endif
    // Tricks to make ADC read accurate
    // http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
    // There is another way to measure its own voltage and back calculate vcc
    // http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
    // attiny85 timer comp isr
    // read battery voltage when pulse is low, battery is idle
    ISR(TIM0_COMPA_vect){
      if(millis()-lastBatVoltWhenIdleReadTime>batVoltReadInterval){
        batVoltWhenIdle = (analogRead(batPin)+batVoltWhenIdle)/2;
        lastBatVoltWhenIdleReadTime = millis();
      }
    }
    // timer overflow isr
    // read battery voltage when pulse is high, battery is under load
    ISR(TIM0_OVF_vect){
      if(millis()-lastBatVoltUnderLoadReadTime>batVoltReadInterval){
        batVoltUnderLoad = (analogRead(batPin)+batVoltUnderLoad)/2;
        lastBatVoltUnderLoadReadTime = millis();
      }
    }
    void setup(){
      pinMode(pwmPin, OUTPUT);
      pinMode(btnPin, INPUT);
      setDutyCycle(0);
      lastActivityTime = millis();
      batVoltUnderLoad = analogRead(batPin);
      batVoltWhenIdle = batVoltUnderLoad;
      lastBatVoltUnderLoadReadTime = millis();
      lastBatVoltWhenIdleReadTime = millis();
      // auto detect battery in series
      autodetectBatteryInSeries(VOLTAGE(batVoltUnderLoad));
      // TOIE0: Timer/Counter0 Overflow Interrupt Enable
      // used to measure battery voltage when battery is under load
      TIMSK |= (1<<TOIE0);
      // OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable
      // used to measure battery voltage when battery is not under load
      TIMSK |= (1<<OCIE0A);
    #ifdef DEBUG
      serial.begin(9600);
      serial.println("driver board start");
      serial.print("initial volt:");
      serial.println(VOLTAGE(batVoltWhenIdle),DEC);
    #endif
    }
    void loop(){
      if(batteryUnderVoltage){
        if(bulbState!=BULB_STATE_OFF){
          int lowVoltDutyCycle =
            getDutyCycle(BULB_STATE_LOW,SHUTDOWN_VOLTAGE)/2;
          if(destDutyCycle != lowVoltDutyCycle){
            setDutyCycle(lowVoltDutyCycle);
          }
        }
        else{
          digitalWrite(pwmPin,LOW);
          sleepNow();
          return;
        }
      }
      int b = 0;
      if(!needSoftStart)
        b = checkButton();
      switch(b){
      case BUTTON_CLICK:
        switchState();
        break;
      case BUTTON_DOUBLE_CLICK:
        setBulbState(BULB_STATE_HIGH);
        break;
      case BUTTON_HOLD:
        setBulbState(BULB_STATE_BOOST);
        break;
      case BUTTON_LONG_HOLD:
        break;
      default:
        break;
      }
      // check battery under voltage
      // adj pwm duty cycle every interval
      if(bulbState != BULB_STATE_OFF
        && (millis()-lastDutyCycleCheckTime) > pwmDutyCycleCheckInterval){
        int bvLoad = VOLTAGE(batVoltUnderLoad);
    #ifdef DEBUG
        int bvIdle = VOLTAGE(batVoltWhenIdle);
        serial.print("bvIdle:");
        serial.print(bvIdle,DEC);
    #endif
        if(bvLoad<SHUTDOWN_VOLTAGE){
          batteryUnderVoltage = true;
        }
        else{
    #ifdef DEBUG
          serial.print(";bvLoad:");
          serial.print(bvLoad,DEC);
    #endif
          int dc = getDutyCycle(bulbState,bvLoad);
    #ifdef DEBUG
          serial.print(";s:");
          serial.print(bulbState,DEC);
          serial.print(";dc:");
          serial.print(dc,DEC);
    #endif
          if(dc>destDutyCycle){
            destDutyCycle++;
          }
          else{
            if(dc<destDutyCycle)destDutyCycle--;
          }
          lastDutyCycleCheckTime = millis();
    #ifdef DEBUG
          serial.println();
    #endif
        }
      }

      // soft start sort of thing
      if(needSoftStart
        && (curDutyCycle < destDutyCycle)
        && (millis()-lastDutyCycleSetTime)>(SOFT_START_DURATION/destDutyCycle)){
        curDutyCycle ++;
        setDutyCycle(curDutyCycle);
        lastDutyCycleSetTime = millis();
      }
      if(!needSoftStart &&curDutyCycle!=destDutyCycle){
        setDutyCycle(destDutyCycle);
      }
      if(needSoftStart && curDutyCycle >= destDutyCycle){
        needSoftStart = false;
      }
      // sleep thing
      if(bulbState == BULB_STATE_OFF
        && millis()-lastActivityTime>NO_ACTIVITY_SLEEP){
    #ifdef DEBUG
        serial.println("i'm going to sleep");
    #endif
        sleepNow();
      }
    }
    /*
    Number of battery in series autodetection
    */
    void autodetectBatteryInSeries(int v_bat){
      if(SHUTDOWN_VOLTAGE)
        return;
      // set this parameter to a positive integer can make this driver
      // shutdown the flash light before battery reach its discharge
      // end point. By setting it to a negative integer can then make
      // the battery work longer. but doing so may damage your battery.
      // do it at your own risk.
      int adj = 0;
      if(1==BATTERY_TYPE){
        // LiPo, LiIon
        for(int i=0;i<5;i++){
          if(v_bat<=LIION_BATTERY_SERIES_VOLTAGE){
            SHUTDOWN_VOLTAGE = LIION_BATTERY_SERIES_SHUTDOWN_VOLTAGE;
            break;
          }
        }
      }
      else if(2==BATTERY_TYPE){
        // LiFe
        for(int i=0;i<5;i++){
          if(v_bat<=LIFE_BATTERY_SERIES_VOLTAGE){
            SHUTDOWN_VOLTAGE = LIFE_BATTERY_SERIES_SHUTDOWN_VOLTAGE;
            break;
          }
        }
      }
    }
    void switchState(){
      if(bulbState>=BULB_STATE_HIGH){
        setBulbState(BULB_STATE_OFF);
      }
      else{
        int newState = bulbState+1;
        setBulbState(newState);
      }
    }
    void setBulbState(int state){
      if(state>BULB_STATE_BOOST){
        state = BULB_STATE_OFF;
      }
      if(state!=BULB_STATE_OFF && bulbState == BULB_STATE_OFF){
        needSoftStart = true;
      }
      else{
        needSoftStart = false;
      }
      destDutyCycle = getDutyCycle(state,VOLTAGE(batVoltUnderLoad));
      bulbState = state;
      lastActivityTime = millis();
    }
    void setDutyCycle(int dutyCycle){
      curDutyCycle = dutyCycle;
      analogWrite(pwmPin,dutyCycle);
    }
    int getDutyCycle(int state, int voltage){
      if(voltage<=DESIGN_BULB_VOLTAGE && state != BULB_STATE_OFF){
        return 254;
      }
      float Vbulb = 0;
      if(state==BULB_STATE_BOOST){
        Vbulb = (float)BOOST_VOLTAGE;
      }
      else{
        Vbulb = (float)DESIGN_BULB_VOLTAGE;
      }
      if(Vbulb>voltage){
        return 254;
      }
      float dcvrms = Vbulb/voltage;
      dcvrms = dcvrms*dcvrms*254.0*PWM_MUL[state]/100;
      return (int)dcvrms;
    }
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
    * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
    * there is a list of sleep modes which explains which clocks and
    * wake up sources are available in which sleep mode.
    *
    * In the avr/sleep.h file, the call names of these sleep modes are to be found:
    *
    * The 5 different modes are:
    *     SLEEP_MODE_IDLE         -the least power savings
    *     SLEEP_MODE_ADC
    *     SLEEP_MODE_PWR_SAVE
    *     SLEEP_MODE_STANDBY
    *     SLEEP_MODE_PWR_DOWN     -the most power savings
    *
    * For now, we want as much power savings as possible, so we
    * choose the according
    * sleep mode: SLEEP_MODE_PWR_DOWN
    *
    */
    void sleepNow(){
      ACSR |= _BV(ACD);                         //disable the analog comparator
      ADCSRA &= ~_BV(ADEN);                     //disable ADC
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
      sleep_enable();          // enables the sleep bit in the mcucr register
      /* Now it is time to enable an interrupt. We do it here so an
       * accidentally pushed interrupt button doesn't interrupt
       * our running program. if you want to be able to run
       * interrupt code besides the sleep function, place it in
       * setup() for example.
       *
       * In the function call attachInterrupt(A, B, C)
       * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
       *
       * B   Name of a function you want to execute at interrupt for A.
       *
       * C   Trigger mode of the interrupt pin. can be:
       *             LOW        a low level triggers
       *             CHANGE     a change in level triggers
       *             RISING     a rising edge of a level triggers
       *             FALLING    a falling edge of a level triggers
       *
       * In all but the IDLE sleep modes only LOW can be used.
       */
      attachPcInterrupt(1,wakeUpNow,RISING);
      sleep_mode();            // here the device is actually put to sleep!!
      sleep_disable();         // first thing after waking from sleep:
      detachPcInterrupt(1);
      ACSR &= ~_BV(ACD);                         //enable the analog comparator
      ADCSRA |= _BV(ADEN);                     //enable ADC
    }
    void wakeUpNow(){
      lastActivityTime = millis();
    #ifdef DEBUG
      serial.println("i'm woken up");
    #endif
    }

    //=================================================
    //  MULTI-CLICK:  One Button, Multiple Events
    // Button timing variables
    int debounce = 20;          // ms debounce period to prevent flickering when pressing or releasing the button
    int DCgap = 250;            // max ms between clicks for a double click event
    int holdTime = 750;        // ms hold period: how long to wait for press+hold event
    int longHoldTime = 2000;    // ms long hold period: how long to wait for press+hold event
    // Button variables
    boolean buttonVal = LOW;   // value read from button
    boolean buttonLast = LOW;  // buffered value of the button's previous state
    boolean DCwaiting = false;  // whether we're waiting for a double click (down)
    boolean DConUp = false;     // whether to register a double click on next release, or whether to wait and click
    boolean singleOK = true;    // whether it's OK to do a single click
    long downTime = -1;         // time the button was pressed down
    long upTime = -1;           // time the button was released
    boolean ignoreUp = false;   // whether to ignore the button release because the click+hold was triggered
    boolean waitForUp = false;        // when held, whether to wait for the up event
    boolean holdEventPast = false;    // whether or not the hold event happened already
    boolean longHoldEventPast = false;// whether or not the long hold event happened already
    void buttonDown(){
      downTime = millis();
      ignoreUp = false;
      waitForUp = false;
      singleOK = true;
      holdEventPast = false;
      longHoldEventPast = false;
      if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true)  DConUp = true;
      else  DConUp = false;
      DCwaiting = false;
    }
    int buttonUp(){
      int event = 0;
      if (not ignoreUp)
      {
        upTime = millis();
        if (DConUp == false) DCwaiting = true;
        else
        {
          event = 2;
          DConUp = false;
          DCwaiting = false;
          singleOK = false;
        }
      }
      return event;
    }
    int checkButton() {   
      int event = 0;
      buttonVal = digitalRead(btnPin);
      // Button pressed down
      if (buttonVal == HIGH && buttonLast == LOW && (millis() - upTime) > debounce)
      {
        buttonDown();
      }
      // Button released
      else if (buttonVal == LOW && buttonLast == HIGH && (millis() - downTime) > debounce)
      {        
        if(buttonUp()>0){
          event = 2;
        }
      }
      // Test for normal click event: DCgap expired
      if ( buttonVal == LOW && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
      {
        event = 1;
        DCwaiting = false;
      }
      // Test for hold
      if (buttonVal == HIGH && (millis() - downTime) >= holdTime) {
        // Trigger "normal" hold
        if (not holdEventPast)
        {
          event = 3;
          waitForUp = true;
          ignoreUp = true;
          DConUp = false;
          DCwaiting = false;
          //downTime = millis();
          holdEventPast = true;
        }
        // Trigger "long" hold
        if ((millis() - downTime) >= longHoldTime)
        {
          if (not longHoldEventPast)
          {
            event = 4;
            longHoldEventPast = true;
          }
        }
      }
      buttonLast = buttonVal;
      return event;
    }
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-16 11:02 | 显示全部楼层
    成品什么时候公开发售啊?
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-16 15:06 | 显示全部楼层
    Blackbird 发表于 2012-10-16 11:02
    成品什么时候公开发售啊?

    且等吧..
    等我把所有的资料/轿车整理好了发帖上啦.
    然后再抽时间做好TB链接的时候..
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-16 15:50 | 显示全部楼层
    其实arduino直接就可以当isp了,不需要在买编程器了哦
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-16 15:57 | 显示全部楼层
    本帖最后由 daniel_wang 于 2012-10-16 16:06 编辑

    续上篇.. 各种软件驱动安装好之后

    启动Arduino
    启动Arduino.jpg
    粘贴代码, 另存之
    粘贴代码并另存.jpg 设定目标板, 注意不要选错了.

    设定编程器类型, 根据购买的型号设置, 我用的是AVRISP mkII.
    目前最火的还是USBTinyISP, TB搜下很多的, 但是质量比较好的我认为还是ocrobot出品的那款, 红色的, 有过流保护, 反接保护等. 不容易坏, 当然也最贵, 要45元. 不过即使是这个价位也比AVRISP mkII的600多元要便宜很多了.
    功能方面所有的USBTinyISP都一样. 不必纠结.
    选择目标芯片.jpg
    设定灯泡的额定电压和软启动的时间, 注意, 额定电压的单位是毫伏, 如果使用6V的7388 那么这里要写成6000;
    如果是12V的灯泡, 要改成12000, 不要缺0 哦.
    软启动的时间默认是2.5秒, 可以根据自己的需要修改. 如果想改成3秒只需要吧2500换成3000即可.
    调整软启动时长与灯泡额定电压.jpg
    这里修改超频档的灯泡电压, 7388我设定其超频档电压为7V. 左下角是行号, 可见这行代码位于第54行. 这个开发工具比较弱智, 无法输入中文, 也不能显示行号. 网上有很多替代品, 比这功能强大的. 我没时间研究, 就用这个对付了.
    设定超频档电压.jpg
    设定电池类型, 与自动甄别电池节数配合自动设定放电截止电压, 实施放电保护.
    1 代表锂离子或锂聚合物; 2代表磷酸锂铁
    设定电池类型.jpg
    设定高中低档的输出功率百分比(相较于额定功率); 如图所示, 低档为50%, 中档80%,高档100%;
    注意仅这三个数值可以修改, 上下两行不要动.
    设定高中低档输出百分比.jpg
    这行代码, 删掉前面的两个//则表示开启串口调试,此时正确连接串口线, 使用windows的超级终端或者串口调试助手就能看到程序实时传回的电池电压, PWM占空比, 按钮状态等信息.
    开启串口调试.jpg
    改好之后进行编译,测试一下刚刚修改的代码能否通过编译.
    编译.jpg
    如果编译没问题使用这个菜单项将程序写入芯片.
    烧写.jpg

    硬件连接
    编程器与开关板通过一根6芯的编程线相连, 确认6芯线的红色那根对开关板的1脚, PCB上有标注, 另外1脚的焊盘是方形的, 很容易区分. 即使接错了也没关系, 顶多是烧写失败.
    编程器.jpg

    下面两幅图是开关板和USB转TTL板,
    开关板的RX接TTL板的TX
    开关板的TX接TTL板的RX
    即可
    按钮版调试插针.jpg
    USBtoTTL.jpg
    接好之后 电脑上打开串口调试助手, 设定传输速度9600bps, 打开相应的串口, 然后给驱动板上电. 一切正常的话应该能看到下面的输出
    串口调试助手屏拍.JPG




    设定编程器类型.jpg
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2012-10-16 16:00 | 显示全部楼层

    嗯,如果自己有Arduino UNO或者Arduino MEGA的话就不需要另外购买编程器了.
    但是, 想让UNO/MEGA变成编程器也是需要编程器支持的...
    貌似有点先有鸡还是先有蛋的意思啊..
    总之, 还是买个编程器来的方便..
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-6-14 13:55
  • 签到天数: 456 天

    [LV.9]以坛为家II

    发表于 2012-10-20 13:51 来自手机 | 显示全部楼层
    学习      
    回复

    使用道具 举报

    该用户从未签到

    发表于 2012-10-20 14:17 | 显示全部楼层
    楼主这么有精力,为什么不玩LED。泡子PWM调光,感觉比较容易挂掉,不然用调压在控制亮度。
    回复

    使用道具 举报

    本版积分规则

    小黑屋|手机版|Archiver|论坛自带搜索|下载论坛app|手电大家谈-手电筒爱好者之家 ( 备案序号:鲁ICP备05002565号 )
    以上言论纯属个人观点,与手电大家谈立场无关。
    最佳浏览模式:1920*1080


    GMT+8, 2024-4-29 01:31 , Processed in 0.195463 second(s), 62 queries , Gzip On.

    Powered by Discuz! X3.4

    © 2001-2023 Discuz! Team.

    快速回复 返回顶部 返回列表