成为订阅者(免费)

加入29,000名其他订阅者以获得用户销售折扣和 其他免费资源。
:
:
大学教师'担心 - 您的邮件地址完全是 安全的。我保证使用它 只要 to send you MicroZine.

arduino.电池充电器 Project

ARDUINO电池充电器:如何一次保存行星一个电池! 你知道所有的单身电池(碱性人)都有吗? 他们的标签说"Do Not Recharge"事实上是收费!

当然有些不会,有些人会收取比这一点更好 其他。但即使正在从抛弃电池中再使用似乎是一个 better way to go.

 无论是不是的标准 电池是重新收费的,而不是首先给它一个目视检查。如果 它有粉状残留物,然后它已经死了,所以在当地重新循环它 电池重新循环。

确定重新收费的下一件事是电池是否 电压下降到0.8V以下。如果它太低,那么你不太可能得到 任何地方。您可以用伏特计或仅使用项目来衡量这一点 下面这会自动为您(我将级别设置为0.75 电压测量不是绝对准确的(电压regs通常有一个 ±10%调节,所以你不'T井完全一下 - 也是参考电压i 使用的是使用两个分隔电阻器'另外10%)。它不是 对充电碱性电池绝对关键。

笔记: 这种碱性电池充电器项目是 不是 suitable 用于重新充电NiMH,NICD或李电池。锂 电池(LI)需要至少1%的电压调节和绝对 精确切断电压,否则存在爆炸的风险。只是用来 项目代表碱性电池(标准一次性电池 标称电压1.5V)。
警告: 一些电池会泄漏,所以先检查他们 (最好戴手套)。如果你看到他们的白色粉末处理它们 电池再循环中心。

arduino.电池充电器 Schematic

Arduionodry电池充电器电路图

笔记: If you don'有一个串行液晶显示只需使用并行 connections shown 这里 and 相应地调整代码。您只需要调整初始方法(for 由于图书馆基于相同的代码,因此因此将运行 使用相同的说明。对于lcd.print等。
笔记: 您可以使用任何通用低压PNP晶体管 for this circuit.

arduino.电池 充电器电路操作

首先,当CHRG和HCHRG浮动时,R1拉动晶体管 基础高,因此没有电流流量=关闭。

将CHRG降低导致21.3mA的恒定电流,然后拉动 HCRG低导致33mA的充电电流增加。

笔记: 这些是标称值,并会随着 使用电阻和环境温度的容差。对于这些干燥 细胞确切值并不重要。

基本操作是开始在低电流下对电池充电 期间,然后充电在一个高电流中另一个时期。如果电池 电压增加,在高电荷期间,然后进行充电,如果没有,那么 充电完成(只要电池在可接受的电压内 limits).

arduino.电池 充电器充电电流

当克拉被拉出时,r2,r2和r3形成电阻 将基极电压设置的分频器

3.28V:5 *((1E3 + 560)/(1E3 + 560 + 820))

因此,晶体管基部的电压,即R1,是:

1.722:5 - 3.26

基础发射极二极管下降为0.7V,因此叶1V掉落在R4上。 因此,这允许您定义充电电流即47R 电阻显示的电阻将是

21.3MA:1.0 / 47

arduino.电池 充电器高电流充电

当HCHRG被拉低时(无论克格),电阻器R3短路 出台。因此,现在跨越(仅)R2的电压是:

2.74V:5 *((1E3)/(1E3 + 820)))

这跨越晶体管基部的电压,即R1,是:

2.25V:5 - 2.74

现在R1上的电压降是:

1.55:2.25 - 0.7

这导致充电电流:

33MA:1.55 / 47

ISF外部电压

由R8和R9形成的分压器将用于ADC的电压减半 参考,因此ADC可以读取的最大值是2.5V,因为我们 只需要测量高达约1.6V。还具有较低的ISF电压 意味着ADC的每个位具有较低的值i.e.更精细的分辨率 - 而不是4.88mv它为每位2.44mV,因此ADC可以看到较小的电压 电池的变化。

显示

您只能使用LCD显示器或仅使用LED。你会得到一个绿色 (通过)或红色(失败)光线充电结束。 LCD显示更多 电池电压电压等信息,起始电压 电池和经过的时间。它还显示了状态变量(真的 对于debug),可以让您知道代码在哪里。此外,串口 输出显示发生的事情的短信。所以液晶液晶不是真的 对于操作至关重要,但如果您单独使用单位,则是有用的。

串行显示器

您可以使用串行监视器(在Arduino IDE中)观察操作 还报告串行数据显示状态机操作,ADC值和 voltages.

软件库和版本

arduino. IDE版本

版本:1.8.3.

图书馆

用于普通的库 Hitachi HD44780. display is called 液晶和下面的过程将用不同的代码替换它 这样你就可以使用一个串行驱动的液晶显示器 74HC595. 串行到平行芯片。

在原始库中,您需要以下代码以初始化液晶类的实例化:

    LiquidCrystal lcd(lcd_rs,lcd_e,lcd_d4,lcd_d5,lcd_d6,lcd_d7);

这是一个4位接口,通常用作默认值 并行接口(可以使用8位接口但是 没有很大的优势)。所以在该界面中,您需要共6个 引脚驱动芯片。

当您使用SPI版本的LiquincryStal接口时,初始方法是:

    LiquidCrystal lcd(spi_ss_pin.);

这看起来只使用一个引脚,但实际上它使用标准SPI引脚:

  •     MOSI
  •     SCK

spi_ss_pin.只是用户定义的从属选择引脚 其他人是在Arduino Board上的固定销。所以通过添加一个 74HC595以驾驶那些原始的针脚,在第一个初始化者中看到,你 可以节省三个引脚。不仅如此,这些SPI引脚可用于驱动 其他SPI设备(具有不同的SS信号)。 

提示: 您可以使用带有不同的SS控制引脚的其他SPI设备。

如果你不't have an 74HC595. 然后,您可以使用与下面的相同的草图,但如图所示加入LCD 这里 (4位并行接口) - 和唐't更改图书馆(下面)。这 SPI库使用与正常库相同的功能,因此代码 素描不会改变。

笔记: 如果您是使用液晶SPI库 使用串行SPI LCD。

取代液体库

液晶库被替换为允许SPI操作:

从以下方式下载(SPI)SpilectcryStal库:

//playground.arduino.cc/Main/LiquidCrystal#Download

然后转到您的图书馆位置:

C:\用户\<username>\ documents \ arduino \图书馆

重命名Directory tumpercrystal to silitercrystal_orig。

然后解压缩下载的文件,这应该导致新文件夹

液晶

笔记: 此库指定LCD的引脚和44HC595必须 match the schematic:

您可以在此处找到原理图(接线图74HC595至HITACHI HD44780):

//playground.arduino.cc/Main/LiquidCrystal#Connections

那里'没有改变引脚的工具(你可以改变图书馆 代码虽然要将其更改为您自己的74HC595 - HD44780连接 desired).

代码操作状态机

arduino.电池充电器代码由简单的状态机形成。 这些是主要国家:

闲置,蝙蝠,充电,upd_charge,测试,完成,失败,等待_start

您可以或多或少地从左到右阅读这些,看看代码是什么 doing.

闲置的

首先在空闲状态中,系统设置为充电。

蝙蝠队

然后在BATFND状态下,检查电压(在低电荷期间)查看 如果存在有效电池。

如果超出范围,则状态将失败。

如果在范围内,则状态设置为充电。

收费

在充电状态下,低电荷电流持续30秒。在末尾 ADC读数存储在变量LowChRGADC中。

30秒后,状态设置为High_charge和高电流输出 activated.

状态在30秒后更改为High_charge。

另外两次测试是(一直)。

电池达到最大电压

1.状态设置为完成。

电池超出范围

2.状态设置为失败。

HIGH_CHARGE.

30秒后,状态设置为测试

状态在30秒后改变了测试。

另外两次测试是(一直)。

电池达到最大电压

1.状态设置为完成。

电池超出范围

2.状态设置为失败。

测试

电池电压 增加高电荷

这是决定终止过程的地方或 继续。首先,如果当前的ADC值(在高电荷结束时 与低电流充电期结束时的ADC值相比)不是 high enough (<9.77mv)然后电池被认为是充电的 状态设置为完成。

自从它已经在此处测试了电池(超出范围)的状态 在各州收费和High_charge中不断测试。

检测最终费用:test_avg()

一些电池在最终值周围悬停,但改变其电压输出 在高电荷时足够,以便算法可以'停下来。检测这一点 状态(超过几次充电和高电荷周期)需要存储ADC值 因此,包含最后10个低充电ADC值的滚动移位寄存器是 used for detection.

在函数test_avg()中,测试阵列prevadc []以查看是否存在 值全部在10个读数的平均值的值范围内。如果它们是, 然后,状态机进入了消费的状态I.E.这表明有 been no 'real'在最后几个充电周期内更换电池电压。

在每个测试阶段之后,阵列移位,最新的低电荷ADC value is inserted.

如果上述情况都不是真的,那么状态机就会返回 IDLE.

下一个州是:

完成(如果电池电压足够高)或

完成了没有平均电池的变化或

闲置(如果其他人不是真的)。

完成的

设置控制和LED :(绿色LED点亮以指示成功)和 充电已关闭。

下一个状态是wait_start。

失败

设置控件和LED :(红色LED点亮以指示故障)和 充电已关闭。

下一个状态是wait_start。

wait_start.

这是允许重启检测按钮按下的唯一状态 输入引脚。按下时,初始化各种变量以进行完整 restart.

按下状态时,状态设置为空闲。

arduino.电池充电器 Sketch

// AA and AAA charger
// Could use for others with different charge currents
// i.e. different emitter resistors.
//
// LiquidCrystal library used here is not the original
// download an enhanced version from
// //playground.arduino.cc/Main/LiquidCrystal
// LiquidCrystal_1.zip allows SPI operation.
//
// V1.00
// Copyright John Main
// Free for non-commercial use.
//
#include <SPI.h>
#include <LiquidCrystal.h> // Enhanced for SPI operation.

#define START_PIN 12
#define RLED_PIN A4
#define GLED_PIN A5

#define VBATT_PIN A0
#define CHRG_PIN 2
#define HIGH_PIN 3
#define spi_ss_pin. 10

#define 收费_ON  pinMode(CHRG_PIN,OUTPUT);digitalWrite(CHRG_PIN,LOW);
#define 收费_OFF pinMode(CHRG_PIN,INPUT);
#define HIGH_ON    pinMode(HIGH_PIN,OUTPUT);digitalWrite(HIGH_PIN,LOW);
#define HIGH_OFF   pinMode(HIGH_PIN,INPUT);
#define RLED_ON    digitalWrite(RLED_PIN,HIGH);
#define RLED_OFF   digitalWrite(RLED_PIN,LOW);
#define GLED_ON    digitalWrite(GLED_PIN,HIGH);
#define GLED_OFF   digitalWrite(GLED_PIN,LOW);
#define SPC        Serial.print(' ');

#define VBATMAX 1.60 // Maximum and minimum acceptable battery.
#define VBATMIN 0.75 // voltage to allow charging to start.
#define VREFANA 2.50 // Reference voltage (AREF). Measure this with DMM.
#define CHRG_ms 30000 // Time period of normal charging time (ms).
#define HIGH_ms 30000 // Time period of normal higher power charging time (ms).

#define PREV_ADC 10  // Number of nearly same ADC readings to declare done.

typedef enum { 闲置的, 蝙蝠队, 收费, HIGH_CHARGE., 测试,
               完成的, 失败, wait_start. } state_t;

enum { BATTFULL, BATTAVGSTABLE, BATTBAD, BATTNORISE };

// Initialize for SPI with sspin, also known as RCLK or LATCH.
// For the lcd other pins are the standard SPI pins.
液晶 LCD(SPI_SS_PIN);

///////////////////////////////////////////////////
void setup() {

   pinMode(VBATT_PIN,INPUT);
   pinMode(START_PIN,INPUT_PULLUP);

   pinMode(CHRG_PIN,OUTPUT);
   pinMode(HIGH_PIN,OUTPUT);
   pinMode(GLED_PIN,OUTPUT);
   pinMode(RLED_PIN,OUTPUT);

   收费_OFF
   HIGH_OFF
   RLED_OFF
   GLED_OFF
   analogReference(EXTERNAL);

   // set up the LCD's number of columns and rows:
   lcd.begin(16, 2);



   Serial.begin(57600);
   Serial.println("Battery Charger ");
    showStartVolts();
}

///////////////////////////////////////////////////
// Print start volts to LCD & serial(for reference).
void showStartVolts(void) {

  float v = getVana( analogRead(VBATT_PIN) ) ;

  lcd.setCursor(11, 0);
  lcd.print( v,3 );
  Serial.print("\nStart volts: ");
  Serial.println( v,3 );
}

///////////////////////////////////////////////////
void reason(uint8_t c) {
   Serial.print("End reason: ");
   switch(c) {
      case BATTFULL       : Serial.println("Max volts."); break;
      case BATTAVGSTABLE  : Serial.println("No avg change."); break;
      case BATTBAD        : Serial.println("Out of range.");
      case BATTNORISE     : Serial.println("No Hchrg rise.");
   }
}
///////////////////////////////////////////////////
void loop() {
  static uint32_t loop_time = 0;

  if (millis()-loop_time>250) {  // No need execute too fast
     action();
     loop_time = millis();
  }
}

///////////////////////////////////////////////////
float getVana(uint16_t adc) {
    return adc * VREFANA / 1024;
}

///////////////////////////////////////////////////
uint8_t checkBattBad(float Vana) {
   if ( Vana<VBATMIN || Vana>VBATMAX ) return 1;
   return 0;
}

///////////////////////////////////////////////////
uint8_t checkBattFinished(float Vana) {
   if ( Vana>=VBATMAX-0.1 ) return 1;
   return 0;
}

///////////////////////////////////////////////////
void showSerialElapsedTime(uint32_t r_time) {
   Serial.print("Time:");
   Serial.print(r_time/1000/60);
   Serial.println(" mins.");
}

///////////////////////////////////////////////////
void showState(state_t state) {

   // This state has no text, to leave FINISHED or FAIL on LCD.
   if (state == wait_start.) return;

   // Show current state
   lcd.setCursor(0, 0);
   lcd.print("           "); // 11 chars clear debug area.
   lcd.setCursor(0, 0);
   switch( state) {
     case 闲置的 : lcd.print("IDLE");break;
     case 蝙蝠队 : lcd.print("BATFND");break;
     case 收费 : lcd.print("CHRG");break;
     case HIGH_CHARGE. : lcd.print("H-CHRG");break;
     case 测试 : lcd.print("TEST");break;
     case 完成的 : lcd.print  ("FINSHD");break;
     case 失败 : lcd.print("FAIL");break;
//     case WAIT_START : lcd.print("WAIT");break;
    default: break;
   }
}

///////////////////////////////////////////////////
void showTime(uint32_t timeVal_ms) { // could use sprinf - this = less memory.
  uint8_t lcdpos;
  uint16_t tmin,tsec;
  uint32_t t;

    t = timeVal_ms;
    tmin = (t/1000/60); // Could use sprintf but smaller code using:

    if (tmin >= 1) { // Print minutes since reset
       lcdpos = 12;
       if (tmin>99) lcdpos = 10;
          else if (tmin>9) lcdpos = 11;
       lcd.setCursor(lcdpos, 1);

       lcd.print(tmin);
       lcd.print(':');
    }

    // Print seconds since reset.
    tsec = (t/1000) % 60;

    lcd.setCursor(14, 1);
    if (tsec<10)
       lcd.print('0');
    lcd.print(tsec);
}

///////////////////////////////////////////////////
// -1 resets the store
//
uint8_t test_avg(uint16_t adc) {
uint8_t i,match,allmatch;
static uint16_t prevADC[PREV_ADC];
uint16_t avg;

   if (adc==-1) {
      for(i=0;i<PREV_ADC;i++) prevADC[i]=0;
      return;
   }

   // Get average value
      avg = 0;
      Serial.print("AVG:");
      for (i=0;i<PREV_ADC;i++) {
         Serial.print(prevADC[i]); SPC;
         avg+=prevADC[i];
      }
      avg += 5;  // =0.5 after division by 10
      avg /=10;
      Serial.print("Avg ");Serial.println(avg);

      // If any are zero then not filled: set avg zero to stop err. match
      for (i=0;i<PREV_ADC;i++) {
          if (prevADC[i]==0) {
             avg = 0;
             Serial.println("Avg zet ZERO");
             break;
          }
      }

      // Check if has not increased over last n readings - if so exit.
      allmatch = 1;

      for (i=0;i<PREV_ADC;i++) {
         match = 0;
         // Detect close matches: lowChrgADC+/-2 (+/-4.88mV)
         if ( avg-1 <= prevADC[i] && prevADC[i] <= avg+1 ) match=1;

         // Here if the value is one of 3: lowChrgADC+/-1, then match is high
         if (!match) { allmatch = 0; break; }
      }

      // Update rolling store. // Array indices 0 ~ (n-1) shift.
      for (i=0;i<PREV_ADC-1;i++) prevADC[i]=prevADC[i+1];
      prevADC[PREV_ADC-1] = adc;

      // allmatch is 1 if all have matched for all elements.
      if (allmatch && avg!=0) { // Zero is a special case.
         reason(BATTAVGSTABLE);
         return 1; // All the same so indicate finished.
      }
      return 0;
}



///////////////////////////////////////////////////
void action(void) {
   static uint32_t s_time = millis();
   static uint32_t r_time = s_time; // Relative, start times.
   static uint32_t timewas = 0, timewas_state=r_time;
   static state_t state = 闲置的;
   static uint16_t lowChrgADC=0;
   static uint8_t timer_on=1;
   uint16_t adc=0;
   float Vana;
   static uint8_t done_once = 0;

   if (!done_once) {
      test_avg(-1); // Reset store.
      done_once=1;
   }

   r_time = millis() - s_time; // Use time relative to start
   if (timer_on) showTime(r_time); // Time since start: to LCD.

   adc = analogRead(VBATT_PIN);
   lcd.setCursor(0, 1);
   lcd.print("Vb:");
   lcd.print(Vana=getVana(adc),3);

   switch( state) {

   case 闲置的 :
       state = 蝙蝠队;
       Serial.println("IDLE>BATFND");

       收费_ON   // Start charge to detect battery.
       HIGH_OFF

       RLED_OFF
       GLED_OFF

       showSerialElapsedTime(r_time);

       break;

   case 蝙蝠队 : // Battery ok?
       Serial.println("BATFND>CHARGE");

       if ( checkBattBad(Vana) ) {
          state = 失败; // Battery is dead or not present.
          Serial.println("FAIL in BATFND");
       } else if (Vana>=VBATMIN && Vana<=VBATMAX) {
           state = 收费;
       }
       break;

   case 收费 :
      if ( checkBattBad(Vana) )      { reason(BATTBAD) ; state = 失败; }
      if ( checkBattFinished(Vana) ) { reason(BATTFULL); state = 完成的; }
      else if (r_time - timewas_state>CHRG_ms) {
         Serial.println("CHARGE>HCHARGE");

         lowChrgADC = adc; // Store value just before high charge time.

         HIGH_ON
         state = HIGH_CHARGE.;
         timewas_state = r_time;
      }
      break;

   case HIGH_CHARGE. :
      if ( checkBattBad(Vana) )      { reason(BATTBAD) ; state = 失败; }
      if ( checkBattFinished(Vana) ) { reason(BATTFULL); state = 完成的; }
      else if ( r_time - timewas_state>HIGH_ms) {
         Serial.println("HCHARGE>TEST");
         state = 测试;
         timewas_state = r_time;
      }
      break;

   case 测试 :
      Serial.println("TEST>IDLE/FINISHED");
      Serial.println("Cur adc,lowChrgADC");
      Serial.print(adc);       SPC; Serial.println(getVana(adc),3);
      Serial.print(lowChrgADC);SPC;Serial.println(getVana(lowChrgADC),3);

      if ( adc > (lowChrgADC+4) ) {  // Gone up by > (2.5/1024)*4=9.77mV
         state= 闲置的;
      } else { // No rise so batery charge maxed out.
         reason(BATTNORISE);
         state = 完成的;
      }

      if ( test_avg(lowChrgADC) ) state = 完成的;

      break;

   case 失败 : // Error condition so stop charging battery.
      Serial.println("FAIL");
      收费_OFF
      HIGH_OFF
      timer_on = 0;
      RLED_ON
      GLED_OFF
      state = wait_start.;
      break;

   case 完成的 :
      Serial.print("FINISHED:");
      Serial.println(Vana);
      showSerialElapsedTime(r_time);

      收费_OFF
      HIGH_OFF
      RLED_OFF
      GLED_ON
      timer_on = 0;
      state = wait_start.;
      break;

   case wait_start. :
      if ( digitalRead(START_PIN)==0) {
         state = 闲置的;

         s_time = millis();
         r_time  = millis()-s_time;
         timewas_state = r_time;

         timer_on = 1;
         test_avg(-1); // Reset store.
         lcd.clear();
         showStartVolts();
      }
      break;
   }

   showState(state);

   // Show raw adc value
   lcd.setCursor(7, 0);
   lcd.print(adc);lcd.print(' ');
}

定义vrefana是 名义上2.5V,但我使用数字万用表测量并放置 代码中的值,给出更准确的阅读。如果你不't 想要这样做,留下价值为2.5。


新的! Comments

让你说到你刚刚阅读的东西!留下下面的框中的评论。




隐私政策 | 接触 | 关于我

网站地图 | 使用条款


ezoic.报告此广告

访问我们的Facebook页面:

   点击这里



最近的文章

  1. 如何使用ADS1115

    使用ADS1115精度16位ADC进行教程进行低功耗。

    阅读更多

  2. arduino.模拟输出...易模拟输出生成

    arduino.模拟输出:如何创建最精确的PWM模拟输出以及如何创建模拟PWM正弦波。

    阅读更多

  3. 数号和等效的快速宏。加快代码!

    了解DigitalWrite()的工作原理......现在使用17倍宏宏!

    阅读更多

  4. TCS230颜色传感芯片:如何运作以及如何使用它。

    如何使用TCS230(/ TCS3200)彩色检测器芯片并轻松将其添加到您的任何项目中。

    阅读更多

  5. 如何使用ADXL345进行运动感测等。

    使用ADXL345 Acellerometer,您可以检测到16G!您还可以了解如何使用它来点击检测等。

    阅读更多

  6. HMC5883L 3轴数字MAGENTOMTER如何运作

    HMC5883L - 如何制作数字罗盘,了解HMC5883L和QMC5883L之间的差异以及它们是否兼容。

    阅读更多



读者 Comments

"I wanted to thank
你这么好
对于所有信息
你已经提供了
你的网站's

高超极好的."

- 逃亡Potthath.

"This site really is
最好的和我最喜欢的。
我发现这里有很多很有用
项目和提示。"

- 米兰

Bursach.<at>gmail.com<

"Awesome site,
非常,非常容易和好
导航!"


-
镭_tr.<at>
wolf359.cjb.net.


学习微控制器

"Interested in
微控制器?"

注册
免费7天指南:

自由 GUIDE : CLICK HERE


"I am a newbie to PIC
我想说
 how great your
网站一直在为我。"


- 戴夫

de_scott.<at>bellsouth.net

"Your site is a great
和完美的工作。
恭喜。"


- SURESH.

IntegratedInfosys.<at>
Yahoo.com.

"I couldn't find the correct
要定义的词语
你的网页。

非常有用,揭开,
诚实明确。

非常感谢
你的时间和作品。
问候。"


- Anon.

回到顶部