极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 35109|回复: 16

[已解決]電源電壓低下警報--一個無解的問題?

[复制链接]
发表于 2018-3-11 02:51:32 | 显示全部楼层 |阅读模式
本帖最后由 shouzama 于 2018-3-17 11:51 编辑

這兩天在改外甥的玩具車,一時興起想再加個低電壓警報機能,
就是說充電電池電壓原本正常是 4.2V (LI-ION),想要它低於
3.5V 時響警示音,5V=1023的話,那設個 720 當判定值好了。

程式寫了,但一直試到電池電壓低到 3.1V,還是沒能觸發這個
警報機能,修改條件試了一下,居然要 1023 才能觸發警報?!

也就是說,我忽略了一個重要事情:
5V=1023,3.5V=720,是源於電源電壓固定 5V 時的基準,
當 ARDUINO 電源電壓會變動(供電電池電壓在變),這個
基準也會變,給它 3.1V 電源,它就以 3.1V 作為 1023 的基準值...

這表示...根本做不出來偵測電源電壓低下的機能,除非用其他
方法,而不是直接用 ARDUINO 的類比輸入接腳,那...最簡單
的方法是?

請各位先進不吝指導 ^^
回复

使用道具 举报

发表于 2018-3-13 17:19:39 | 显示全部楼层

  1. long readVcc() {
  2.   // Read 1.1V reference against AVcc
  3.   // set the reference to Vcc and the measurement to the internal 1.1V reference
  4.   #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  5.     ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  6.   #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  7.     ADMUX = _BV(MUX5) | _BV(MUX0);
  8.   #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  9.     ADMUX = _BV(MUX3) | _BV(MUX2);
  10.   #else
  11.     ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  12.   #endif  

  13.   delay(2); // Wait for Vref to settle
  14.   ADCSRA |= _BV(ADSC); // Start conversion
  15.   while (bit_is_set(ADCSRA,ADSC)); // measuring

  16.   uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  17.   uint8_t high = ADCH; // unlocks both

  18.   long result = (high<<8) | low;

  19.   result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  20.   return result; // Vcc in millivolts
  21. }
复制代码
回复 支持 1 反对 0

使用道具 举报

发表于 2018-3-13 10:10:10 | 显示全部楼层
最好把原理图和程序发上来这样容易解决问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-13 20:44:26 | 显示全部楼层
本帖最后由 shouzama 于 2018-3-13 20:55 编辑
wuhaoyc 发表于 2018-3-13 10:10
最好把原理图和程序发上来这样容易解决问题

您好:
將 PRO MINI 電源接充電電池(電壓 3.5~4.2V,隨電力而變化),
將 Vcc 直接跳線焊到 A5 進行讀取電壓值,程式:
[kenrobot_code]#define VOLTAGE A5        //定義電池電壓偵測接腳 0~5v=0~1023;3.5~3.7v=716~757

void loop()
{
  //檢測電池電壓是否低下
  int VOLTAGE = analogRead( VOLTAGE );
  if ( VOLTAGE < 720 )                    //讀取電池電壓 0~5v=0~1023;3.5~3.7v=716~757
    MELODY = 0;                             //若電池電壓 < 3.5V 則響嗶嗶聲提示電壓低下

  switch ( MELODY)
  {
   * case 0:   //0.BEEP
      sz_play( 3, NOTE_BEEP+1, DURATION_BEEP, NOTE_BEEP[0] );
      break; */

     case 1:   //1.PRAYER_CUT
      sz_play( 3, NOTE_PRAYER_CUT+1, DURATION_PRAYER_CUT, NOTE_PRAYER_CUT[0] );
      break;
.....(略)[/kenrobot_code]
就是一台遙控車,電源吃 DC3.5~4.2V 的 LI-ION 電池,
由震動開關觸發播放音樂的程式,音樂曲目會自動輪流,
但當偵測到低電壓時,曲目 MELODY =0 強制只能播放
"嗶嗶"聲警示電壓低下
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-13 21:10:59 | 显示全部楼层

感謝指導!
好像是直接參考 ADC 內部的值(1.1V)來判定?
這段程式對我而言難度有點高...

不過這倒給了我一個靈感,假設我將 Vcc 接一顆
10k電阻,再串一顆順向二極體接到 GND,不論 Vcc
是多少(3.5~4.2V),理論上在二極體兩端的電壓差
不會變(約為 0.7V)

若我從二極體拉一條線到 A4,由 A4 取得 0.7V 的
讀值,Vcc 接到 A5 取得 Vcc 讀值,當
" A5 讀值 < A4 讀值*5 "時,大致上就可以判定
Vcc < 3.5V 而進行低電壓警報

當然,實際判斷值可能要 TRY & ERROR 來微調,
依我的水準這樣應該是最簡單的吧?
回复 支持 反对

使用道具 举报

发表于 2018-3-15 12:51:34 | 显示全部楼层
直接調用readVcc()便可得出Vcc值。
  1.   
  2.   long voltage = readVcc();
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-17 11:49:56 | 显示全部楼层
本帖最后由 shouzama 于 2018-3-17 11:56 编辑
rayyee 发表于 2018-3-15 12:51
直接調用readVcc()便可得出Vcc值。


您好: 今天總算有空測試、搞懂這個函式片段了

根據上網查到的資料,這個函式應該存在已久,只是我不知道怎麼去找來用,
經您分享提示,測試可以用,我當然也想知道它倒底做了什麼? 最後依我的
理解再加上註解(變數名稱則依個人習慣更改),分享給站友們:  (有錯請不吝指正)
[kenrobot_code]
long readVcc()
//讀取 Vcc 電源電壓(絕對值)並回傳一長整數
{
/*
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
      #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
        ADMUX = _BV(MUX3) | _BV(MUX2);
      #else
        ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif
*/

  //根據 AVcc 為參考電壓,讀取 1.1V 內部電壓值
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); //REFS0=使用AVcc(=Vcc)為參考電壓;MUX1~3 ON=量測內部 1.1V 參考電壓
  delay(2);                         //等待參考電壓 AVcc(+)~AREF(-) 備妥
  ADCSRA |= _BV(ADSC);              //ADC控制狀態暫存器A(ADCRSA)=開始 ADC 量測
  while (bit_is_set(ADCSRA,ADSC));  //直到完成 10bit 的讀取

  uint8_t LOW_BIT = ADCL;           //讀取 ADC 量測結果低位元組(bit0~7)
  uint8_t HIGH_BIT = ADCH;          //讀取 ADC 量測結果高位元組(bit8~9)
  long RESULT = ( HIGH_BIT<<8 ) | LOW_BIT;  //使用長整數 RESULT 將高低位元整數組合

  RESULT = 1125300L / RESULT;       //計算 Vcc 讀值(mV)
  /* 計算說明:
  ~.1.1*1000(轉mV)*1023(AVcc參考電壓讀值)=1125300,L=長整數指定
  ~.假設 AVcc=4V(讀值1023),1.1V測得 1.1*1023/4=281之值( AVcc=3.5V時,1.1V測得321之值 )
  ~.反換算=1125300/281=4004(mV)之結果,即為 Vcc 之值 (AVcc=3.5V時,反換算=1125300/321=3505) */
  
  return RESULT;                    //傳回 Vcc 讀值(mV)
}
[/kenrobot_code]
因為大致上搞懂了暫存器設定的意義,所以 PRO MINI(基於 ATmega328p) 我就直接用一行
程式取代掉開頭的那一大段判定程式
回复 支持 反对

使用道具 举报

发表于 2018-4-22 22:46:34 | 显示全部楼层
这是汇编语言吗?
我没学过汇编,看不懂啊!!
能说下大概的工作原理吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 22:39:38 | 显示全部楼层
最帅的老饼 发表于 2018-4-22 22:46
这是汇编语言吗?
我没学过汇编,看不懂啊!!
能说下大概的工作原理吗?

嗯,我也沒學過,但我有上網找了些資料,
那種程式寫法類似 MACRO 巨集程式的方式
(語法都是官方認可的),編譯器會自行將它們
編譯成較正式的程式

程式查出來的"作用"我都寫在 //註解 了,
這程式不是我寫的,我只是去搞懂它們做了
些什麼工作,讓輸出結果可以直接取得電源
電壓的絕對值
回复 支持 反对

使用道具 举报

发表于 2018-4-24 10:56:27 | 显示全部楼层
我还个想法,不知可否?
外部电池电压是4.2V 你用 Arduino pro mini 3.3V版做主控
把外部电压 接到两个 5K的串联电阻上,
把两个串联电阻中间点接到 Arduino A0 上读取数值,
电阻是串联的,中间点的电压理论是2.1V
当它是1.75V 时相当于外部电压是3.5V
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-24 23:00:03 | 显示全部楼层
最帅的老饼 发表于 2018-4-24 10:56
我还个想法,不知可否?
外部电池电压是4.2V 你用 Arduino pro mini 3.3V版做主控
把外部电压 接到两个 5 ...

也就是電源電壓 4.2V→3.3V,取得電源電壓 100% 的絕對穩定值,
然後再分壓計算量測值?

這點邏輯上可行,但有個問題,為了達到"省電"的作用,
我讓 ARDUINO 隨時進入 POWER DOWN 模式,
外部用震動開關→硬體中斷喚醒→響音樂→響完休眠,
喚醒時若發現電源電壓低下則不響音樂,響警告音

如果是用 3.3V 的穩壓電路+開發板,就算 POWER DOWN
休眠了,穩壓電路的靜態耗電量也是很可觀的,所以我選擇
用 4.2V 去驅動 5V 的開發板,才產生了這個主題 ^^a
回复 支持 反对

使用道具 举报

发表于 2018-4-25 13:10:55 | 显示全部楼层
shouzama 发表于 2018-4-24 23:00
也就是電源電壓 4.2V→3.3V,取得電源電壓 100% 的絕對穩定值,
然後再分壓計算量測值?

我测试了pro mini 3.3V版 睡眠时功耗 1.6mA  uno睡眠时功耗 40+mA
如果是考虑功耗,当然是选 pro mini  
我做过两个10K电阻串联的测试,可以达到功能要求,但读值变化有点大 反应有点慢。
改用两个5K电阻串联和并联一只电容出来的效果很不错,它的理论功耗才 0.33mA 。
应该可以接受吧。
还有,谢谢你的振动开关唤醒,点子很好。我不问盗取了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-25 23:02:54 | 显示全部楼层
最帅的老饼 发表于 2018-4-25 13:10
我测试了pro mini 3.3V版 睡眠时功耗 1.6mA  uno睡眠时功耗 40+mA
如果是考虑功耗,当然是选 pro mini   ...

對了,不知您的 PRO MINI 供應電源電壓多少?
4.2V? 5V?

如果是 4.2V 的電源,理論上調壓後 -1.25V,
PRO MINI 的電源電壓最高 4.2-1.25=2.95V,
電壓低下時 3.7-1.25=2.45V,以這 2.45~2.95V
當 100% 基礎,也是會變動的 ^^"

我當時在自製遙控器時有量過 PRO MINI 進入
POWER DOWN 的電流好像是 0.2mA (我砍了
電源指示燈,5V 穩壓 IC 因為電源電壓 3.7~4.2V
未達作動電壓,沒有靜態耗電流的問題)
回复 支持 反对

使用道具 举报

发表于 2018-4-26 20:00:10 | 显示全部楼层
shouzama 发表于 2018-4-25 23:02
對了,不知您的 PRO MINI 供應電源電壓多少?
4.2V? 5V?

pro mini 有两个版本,一个是5V 一个是 3.3 V  你可以用3.3V版 。
锂电池接在 pro mini 的 RAW脚 这脚最高可以接受12V.
锂电池是 4.2V 用两只电阻串联后取中间电压理论是 2.1 V
3.3V版的pro mini 可以正常读取 2.1V 电压值。
这个电压读数乘以2就是外部电压了。


你测量出0.2mA时外部电压是多少?
我测量出pro mini 正常工作时是 9mA 睡眠时是 1.6 mA
我相信 pro mini 的功耗是与外部输入电压有关,
刚好前几天买了个可调压电源,等会去求证一下,

回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-26 22:22:30 | 显示全部楼层
最帅的老饼 发表于 2018-4-26 20:00
pro mini 有两个版本,一个是5V 一个是 3.3 V  你可以用3.3V版 。
锂电池接在 pro mini 的 RAW脚 这脚最 ...

您可能沒看懂我的意思,分壓的理論我懂,但 PRO MINI
之所以能接受某範圍的高電源電壓,是因為它有內建
穩壓晶片,一般穩壓晶片的特性至少會有 1.25V 的壓降

用了 3.3V 的 PRO MINI,你接 4.2V 的鋰電池給它,理論上
它就只能獲得 2.95V 的電源電壓(未達 3.3V),且隨著電池
電壓的下降,PRO MINI 的電源電壓也會下降,除了這個問題
之外,就是穩壓電路的靜態耗電了(就算只降 1.25V 還是有
工作電流,POWER DOWN 時或許很小,但不經過穩壓晶片
的電流可更小)



您可以試試接 4.2V 到 3.3V PRO MINI 的 RAW 腳位上,去
量測經穩壓晶片後, VCC 變成多少電壓,是真的固定 3.3V?
還是掉到 3V 以下並且成為變動狀態?

我說的是理論(查過穩壓晶片的 DATASHEET),因為我也沒用過
3.3V 的 PRO MINI

P.S.當時量測靜態耗電流(0.2mA)時,電池電壓應該有 4V 以上
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 22:26 , Processed in 0.053971 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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