ฉันสร้างตัวระบุตำแหน่งไฟฉายขนาดเล็กซึ่งใช้ ATtiny85 ขับเคลื่อนจากปุ่มเซลล์ (CR2032) ดูเหมือนว่านี้:
ด้านอื่น ๆ:
ที่ปัจจุบันมีน้ำหนัก 5.9 กรัม ที่ใส่แบตเตอรี่มีน้ำหนัก 1.6 กรัมดังนั้นคุณสามารถประหยัดได้โดยใช้ที่ยึดที่มีน้ำหนักเบามากขึ้น (อาจเป็นพลาสติกสำหรับฉนวนกันความร้อนและบัดกรีกับแบตเตอรี่โดยตรง) ซ็อกเก็ตชิปมีน้ำหนักอย่างน้อย 0.5 กรัมดังนั้นคุณสามารถบันทึกได้ด้วยการบัดกรีที่ขาโปรเซสเซอร์ ดังนั้นเราจึงลดลงเหลือ 3.8 กรัม
ATtiny85 มี EEPROM 512 ไบต์ซึ่งคุณสามารถใช้เพื่อบันทึกการอ่าน ฉันไม่แน่ใจเกี่ยวกับนาฬิกาถ้าคุณพยายามที่จะลดน้ำหนัก แต่ถ้าคุณเริ่มต้นในเวลาที่รู้จักกันคุณสามารถประเมินเวลาได้อย่างสมเหตุสมผลโดยใช้millis()
ฟังก์ชั่นเพื่อค้นหา miliiseconds ตั้งแต่เริ่มต้น
ฉันทำอีกหนึ่งในขณะที่แฟลช LED ทุกสองสามวินาที:
นั่นคือที่คล้ายกัน โปรเซสเซอร์มี (คว่ำลงใต้ซ็อกเก็ตชิป) และแบตเตอรี่อยู่ด้านล่าง ที่มีน้ำหนัก 6 กรัม แบตเตอรี่ใช้งานได้สองสามปีและนั่นทำให้ 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