我组成了一个小的火炬定位器,它使用了由纽扣电池(CR2032)供电的ATtiny85。看起来像这样:
另一边:
目前重量为5.9克。电池座的重量为1.6克,因此您可以通过制造重量更轻的电池座(也许用一点塑料进行绝缘,然后直接焊接到电池上)来节省重量。芯片插槽的重量至少为0.5g,因此您也可以通过焊接到处理器引脚上来节省重量。因此我们降至3.8克。
ATtiny85具有512字节的EEPROM,可用于记录读数。我不确定时钟是否要减轻重量,但是如果在已知时间启动时钟,则可以使用该millis()
函数查找自启动以来的毫秒数,从而可以合理地估算时间。
前一阵子我又做了一个,每隔几秒钟就会闪烁一个LED:
那是相似的。处理器在那里(倒置在芯片插槽下面),电池在下面。重量为6克。电池已经使用了几年,每隔几秒钟就会闪烁一个LED!
可以使用热敏电阻代替LED来读取温度,而不是LED。
您可以将其编程为每隔几个小时读取一次,然后将其保存到EEPROM。然后,根据指示(例如通过连接几个引脚),它可以将读数输出到另一个引脚(通过串行)。
使用SMD(表面安装)设备可以节省更多的重量,也许还可以使用组成很小的电路板来节省重量。
码
我的火炬定位器的代码如下。有趣的是,它大部分时间处于休眠状态。它还在ADC采样期间休眠。尽管在我的情况下,我正在测量LDR(光敏电阻),但用于测量热敏电阻的代码却与此类似。您只需要在最后进行一些计算即可将读数转换为温度。
// ATtiny85 torch detector
// Author: Nick Gammon
// Date: 25 February 2015
// ATMEL ATTINY 25/45/85 / ARDUINO
// Pin 1 is /RESET
//
// +-\/-+
// Ain0 (D 5) PB5 1| |8 Vcc
// Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1
// Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1
// GND 4| |5 PB0 (D 0) pwm0
// +----+
/*
Pin 2 (PB3) <-- LDR (GL5539) --> Pin 7 (PB2) <----> 56 k <----> Gnd
Pin 5 (PB0) <---- LED ---> 100 R <-----> Gnd
*/
#include <avr/sleep.h> // Sleep Modes
#include <avr/power.h> // Power management
#include <avr/wdt.h> // Watchdog timer
const byte LED = 0; // pin 5
const byte LDR_ENABLE = 3; // pin 2
const byte LDR_READ = 1; // Ain1 (PB2) pin 7
const int LIGHT_THRESHOLD = 200; // Flash LED when darker than this
// when ADC completed, take an interrupt
EMPTY_INTERRUPT (ADC_vect);
// Take an ADC reading in sleep mode (ADC)
float getReading (byte port)
{
power_adc_enable() ;
ADCSRA = bit (ADEN) | bit (ADIF); // enable ADC, turn off any pending interrupt
// set a2d prescale factor to 128
// 8 MHz / 128 = 62.5 KHz, inside the desired 50-200 KHz range.
ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2);
if (port >= A0)
port -= A0;
#if defined(__AVR_ATtiny85__)
ADMUX = (port & 0x07); // AVcc
#else
ADMUX = bit (REFS0) | (port & 0x07); // AVcc
#endif
noInterrupts ();
set_sleep_mode (SLEEP_MODE_ADC); // sleep during sample
sleep_enable();
// start the conversion
ADCSRA |= bit (ADSC) | bit (ADIE);
interrupts ();
sleep_cpu ();
sleep_disable ();
// reading should be done, but better make sure
// maybe the timer interrupt fired
// ADSC is cleared when the conversion finishes
while (bit_is_set (ADCSRA, ADSC))
{ }
byte low = ADCL;
byte high = ADCH;
ADCSRA = 0; // disable ADC
power_adc_disable();
return (high << 8) | low;
} // end of getReading
// watchdog interrupt
ISR (WDT_vect)
{
wdt_disable(); // disable watchdog
} // end of WDT_vect
#if defined(__AVR_ATtiny85__)
#define watchdogRegister WDTCR
#else
#define watchdogRegister WDTCSR
#endif
void setup ()
{
wdt_reset();
pinMode (LED, OUTPUT);
pinMode (LDR_ENABLE, OUTPUT);
ADCSRA = 0; // turn off ADC
power_all_disable (); // power off ADC, Timer 0 and 1, serial interface
} // end of setup
void loop ()
{
// power up the LDR, take a reading
digitalWrite (LDR_ENABLE, HIGH);
int value = getReading (LDR_READ);
// power off the LDR
digitalWrite (LDR_ENABLE, LOW);
// if it's dark, flash the LED for 2 mS
if (value < LIGHT_THRESHOLD)
{
power_timer0_enable ();
delay (1); // let timer reach a known point
digitalWrite (LED, HIGH);
delay (2);
digitalWrite (LED, LOW);
power_timer0_disable ();
}
goToSleep ();
} // end of loop
void goToSleep ()
{
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts (); // timed sequence coming up
// pat the dog
wdt_reset();
// clear various "reset" flags
MCUSR = 0;
// allow changes, disable reset, clear existing interrupt
watchdogRegister = bit (WDCE) | bit (WDE) | bit (WDIF);
// set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
watchdogRegister = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0); // set WDIE, and 2 seconds delay
sleep_enable (); // ready to sleep
interrupts (); // interrupts are required now
sleep_cpu (); // sleep
sleep_disable (); // precaution
} // end of goToSleep