/
TinySensor_InternalTemperatureSensor.ino
217 lines (182 loc) · 6.19 KB
/
TinySensor_InternalTemperatureSensor.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
//--------------------------------------------------------------------------------------
// Internal temperature measurement of Attiny84 based TinySensor
// harizanov.com
// GNU GPL V3
//--------------------------------------------------------------------------------------
#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU 1000000 // 1 MHz
#include <JeeLib.h> // https://github.com/jcw/jeelib
#include "pins_arduino.h"
ISR(WDT_vect) { Sleepy::watchdogEvent(); } // interrupt handler for JeeLabs Sleepy power saving
#define myNodeID 18 // RF12 node ID in the range 1-30
#define network 210 // RF12 Network group
#define freq RF12_868MHZ // Frequency of RFM12B module
#define LEDpin PB0
#define TEMPERATURE_ADJUSTMENT 26-43
#define EXTREMES_RATIO 5
#define MAXINT 32767
#define MININT -32767
int offset=TEMPERATURE_ADJUSTMENT;
float coefficient=1;
int readings[30];
int pos=0;
//########################################################################################################################
//Data Structure to be sent
//########################################################################################################################
typedef struct {
int temp; // Temperature reading
int supplyV; // Supply voltage
} Payload;
Payload temptx;
static void setPrescaler (uint8_t mode) {
cli();
CLKPR = bit(CLKPCE);
CLKPR = mode;
sei();
}
void setup() {
setPrescaler(1); // div 1, i.e. 4 MHz
pinMode(LEDpin,OUTPUT);
digitalWrite(LEDpin,LOW);
delay(1000);
digitalWrite(LEDpin,HIGH);
rf12_initialize(myNodeID,freq,network); // Initialize RFM12 with settings defined above
// Adjust low battery voltage to 2.2V UNTESTED!!!!!!!!!!!!!!!!!!!!!
rf12_control(0xC040);
rf12_sleep(0); // Put the RFM12 to sleep
// Serial.begin(9600);
PRR = bit(PRTIM1); // only keep timer 0 going
}
void loop() {
pinMode(LEDpin,OUTPUT);
digitalWrite(LEDpin,LOW);
setPrescaler(3); // div 8, i.e. 1 MHz
bitClear(PRR, PRADC); // power up the ADC
ADCSRA |= bit(ADEN); // enable the ADC
Sleepy::loseSomeTime(16); // Allow 10ms for the sensor to be ready
int_sensor_init();
// sprint();
temptx.temp = in_c() * 100; // Convert temperature to an integer, reversed at receiving end
temptx.supplyV = readVcc(); // Get supply voltage
ADCSRA &= ~ bit(ADEN); // disable the ADC
bitSet(PRR, PRADC); // power down the ADC
digitalWrite(LEDpin,HIGH);
rfwrite(); // Send data via RF
for(int j = 0; j < 1; j++) { // Sleep for 5 minutes
Sleepy::loseSomeTime(60000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms)
}
}
//--------------------------------------------------------------------------------------------------
// Send payload data via RF
//--------------------------------------------------------------------------------------------------
static void rfwrite(){
setPrescaler(1); // div 1, i.e. 4 MHz
bitClear(PRR, PRUSI); // enable USI h/w
rf12_sleep(-1); //wake up RF module
while (!rf12_canSend())
rf12_recvDone();
rf12_sendStart(0, &temptx, sizeof temptx);
rf12_sendWait(2); //wait for RF to finish sending while in standby mode
rf12_sleep(0); //put RF module to sleep
bitSet(PRR, PRUSI); // disable USI h/w
setPrescaler(4); // div 4, i.e. 1 MHz
}
//--------------------------------------------------------------------------------------------------
// Read current supply voltage
//--------------------------------------------------------------------------------------------------
long readVcc() {
long result;
// Read 1.1V reference against Vcc
ADMUX = _BV(MUX5) | _BV(MUX0);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate Vcc in mV
return result;
}
void sprint() {
Serial.print( "> R:" );
Serial.print( raw(), DEC );
Serial.print( " L:" );
Serial.print( in_lsb(), DEC );
Serial.print( " K:" );
Serial.print( in_k(), DEC );
Serial.print( " C:" );
Serial.print( in_c(), DEC );
Serial.print( " F:" );
Serial.print( in_f(), DEC );
Serial.println( " # " );
}
void int_sensor_init() {
//analogReference( INTERNAL1V1 );
// Configure ADMUX
ADMUX = B00100010; // Select temperature sensor
ADMUX &= ~_BV( ADLAR ); // Right-adjust result
ADMUX |= _BV( REFS1 ); // Set Ref voltage
ADMUX &= ~( _BV( REFS0 ) ); // to 1.1V
// Configure ADCSRA
ADCSRA &= ~( _BV( ADATE ) |_BV( ADIE ) ); // Disable autotrigger, Disable Interrupt
ADCSRA |= _BV(ADEN); // Enable ADC
ADCSRA |= _BV(ADSC); // Start first conversion
// Seed samples
int raw_temp;
while( ( ( raw_temp = raw() ) < 0 ) );
for( int i = 0; i < 30; i++ ) {
readings[i] = raw_temp;
}
}
int in_lsb() {
int readings_dup[30];
int raw_temp;
// remember the sample
if( ( raw_temp = raw() ) > 0 ) {
readings[pos] = raw_temp;
pos++;
pos %= 30;
}
// copy the samples
for( int i = 0; i < 30; i++ ) {
readings_dup[i] = readings[i];
}
// bubble extremes to the ends of the array
int extremes_count = 6;
int swap;
for( int i = 0; i < extremes_count; ++i ) { // percent of iterations of bubble sort on small N works faster than Q-sort
for( int j = 0;j<29;j++ ) {
if( readings_dup[i] > readings_dup[i+1] ) {
swap = readings_dup[i];
readings_dup[i] = readings_dup[i+1];
readings_dup[i+1] = swap;
}
}
}
// average the middle of the array
int sum_temp = 0;
for( int i = extremes_count; i < 30 - extremes_count; i++ ) {
sum_temp += readings_dup[i];
}
return sum_temp / ( 30 - extremes_count * 2 );
}
int in_c() {
return in_k() - 273;
}
int in_f() {
return in_c() * 9 / 5 + 32;
}
int in_k() {
return in_lsb() + offset; // for simplicty I'm using k=1, use the next line if you want K!=1.0
//return (int)( in_lsb() * coefficient ) + offset;
}
int raw() {
if( ADCSRA & _BV( ADSC ) ) {
return -1;
} else {
int ret = ADCL | ( ADCH << 8 ); // Get the previous conversion result
ADCSRA |= _BV(ADSC); // Start new conversion
return ret;
}
}