|
|
@@ -1,4 +1,6 @@
|
|
1
|
1
|
#include <avr/io.h>
|
|
|
2
|
+#include <avr/interrupt.h>
|
|
|
3
|
+#include <avr/sleep.h>
|
|
2
|
4
|
#include <util/delay.h>
|
|
3
|
5
|
#include <stdint.h>
|
|
4
|
6
|
#include <stdio.h>
|
|
|
@@ -10,10 +12,6 @@
|
|
10
|
12
|
#include "bme280_interface.h"
|
|
11
|
13
|
#include "bme280_defs.h"
|
|
12
|
14
|
|
|
13
|
|
-//#define LED_DDR DDRB //DDRA, DDRB...
|
|
14
|
|
-//#define LED_PORT PORTB //PORTA, PORTB...
|
|
15
|
|
-//#define LED_PORTPIN PB0 //PA0, PA1..., PB0, PB1..., ...
|
|
16
|
|
-//#define time_off 8
|
|
17
|
15
|
|
|
18
|
16
|
/* SPI: */
|
|
19
|
17
|
/* TODO: move to spi.h */
|
|
|
@@ -22,14 +20,46 @@
|
|
22
|
20
|
#define SPI_MOSI_PIN PB3
|
|
23
|
21
|
#define SPI_MISO_PIN PB4
|
|
24
|
22
|
|
|
|
23
|
+/* Debug LED: */
|
|
|
24
|
+#define LED_DDR DDRD
|
|
|
25
|
+#define LED_PORT PORTD
|
|
|
26
|
+#define LED_PIN PD3
|
|
25
|
27
|
|
|
26
|
28
|
|
|
27
|
29
|
char bool_case = 0;
|
|
28
|
30
|
int timer = 0;
|
|
29
|
31
|
int timer_max = 0;
|
|
30
|
32
|
|
|
|
33
|
+volatile uint8_t cycle = 0;
|
|
|
34
|
+
|
|
|
35
|
+volatile uint8_t interruptCounter;
|
|
|
36
|
+volatile uint8_t executionFlag;
|
|
|
37
|
+
|
|
31
|
38
|
|
|
32
|
39
|
void Initialize_SPI(void);
|
|
|
40
|
+void Enter_Power_Save_Mode(void);
|
|
|
41
|
+void Exit_Power_Save_Mode(void);
|
|
|
42
|
+
|
|
|
43
|
+
|
|
|
44
|
+/* TODO Notes for power saving:
|
|
|
45
|
+ * - Power-save-mode needed -> SM2...0 bits written to 011
|
|
|
46
|
+ * - Entering by issuing the SLEEP instruction -> What call in C?
|
|
|
47
|
+ * - Before executing the SLEEP instruction, write bit SE of the SMCR to 1
|
|
|
48
|
+ * - Let Timer/Counter2 run with the necessary period and enable an interrupt.
|
|
|
49
|
+ * -> The Global Interrupt Enable bit in SREG has to be set.
|
|
|
50
|
+ * - asynchronous/synchronous clock source?
|
|
|
51
|
+ * - When waking up
|
|
|
52
|
+ * - Set PRR bits for needed peripherals
|
|
|
53
|
+ * -
|
|
|
54
|
+ */
|
|
|
55
|
+void Set_Up_Power_Save_Mode(void);
|
|
|
56
|
+void Enter_Power_Save_Mode(void);
|
|
|
57
|
+
|
|
|
58
|
+
|
|
|
59
|
+ISR( TIMER2_COMPA_vect )
|
|
|
60
|
+{
|
|
|
61
|
+ /* Do nothing as the interrupt is only used to wake up the MCU. */
|
|
|
62
|
+}
|
|
33
|
63
|
|
|
34
|
64
|
int main (void)
|
|
35
|
65
|
{
|
|
|
@@ -38,7 +68,10 @@ int main (void)
|
|
38
|
68
|
// uint8_t registerContent[5];
|
|
39
|
69
|
// char registerContentString[30];
|
|
40
|
70
|
// uint8_t lengthRead;
|
|
|
71
|
+ uint8_t temp = 0;
|
|
41
|
72
|
|
|
|
73
|
+ /* Enable the debug LED */
|
|
|
74
|
+ LED_DDR |= (1 << LED_PIN);
|
|
42
|
75
|
|
|
43
|
76
|
/* Initialize the SPI */
|
|
44
|
77
|
Initialize_SPI();
|
|
|
@@ -52,21 +85,119 @@ int main (void)
|
|
52
|
85
|
|
|
53
|
86
|
/* Initialize the BME280 */
|
|
54
|
87
|
Initialize_BME280();
|
|
|
88
|
+ Set_Up_Power_Save_Mode();
|
|
55
|
89
|
|
|
56
|
90
|
|
|
|
91
|
+ /* Delay the change of the operating frequency by the function Enter_Power_Save_Mode for the
|
|
|
92
|
+ * first function pass. If it is changed before the ISP can flash the MCU the clocks of the ISP
|
|
|
93
|
+ * and MCU are mismatched and the flashing will fail.
|
|
|
94
|
+ */
|
|
|
95
|
+ _delay_ms(500);
|
|
57
|
96
|
|
|
58
|
97
|
while(1)
|
|
59
|
98
|
{
|
|
60
|
|
- BME280_Get_Measurement(&sensorData);
|
|
61
|
|
- NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
|
|
62
|
|
- _delay_ms(1000);
|
|
|
99
|
+ Enter_Power_Save_Mode(); // The MCU enters the Power Save Mode here.
|
|
|
100
|
+ Exit_Power_Save_Mode(); // The MCU exits the Power Save Mode here.
|
|
|
101
|
+
|
|
|
102
|
+ if (cycle == 0) // TODO cycle == 7 to execute this every 60 s
|
|
|
103
|
+ {
|
|
|
104
|
+ /* Re-Initialize the peripherals */
|
|
|
105
|
+ Set_BME280_Pins();
|
|
|
106
|
+ Set_NRF24L01_Pins();
|
|
|
107
|
+
|
|
|
108
|
+ /* Get measurement and send it */
|
|
|
109
|
+ BME280_Get_Measurement(&sensorData);
|
|
|
110
|
+ NRF24L01_Send_Message((uint8_t*)&sensorData, sizeof(sensorData));
|
|
|
111
|
+
|
|
|
112
|
+ if (temp == 0)
|
|
|
113
|
+ {
|
|
|
114
|
+ LED_PORT |= (1 << LED_PIN);
|
|
|
115
|
+ temp = 1;
|
|
|
116
|
+ }
|
|
|
117
|
+ else
|
|
|
118
|
+ {
|
|
|
119
|
+ temp = 0;
|
|
|
120
|
+ LED_PORT &= ~(1 << LED_PIN);
|
|
|
121
|
+ }
|
|
|
122
|
+
|
|
|
123
|
+ cycle = 0;
|
|
|
124
|
+ }
|
|
|
125
|
+ else
|
|
|
126
|
+ {
|
|
|
127
|
+ cycle ++;
|
|
|
128
|
+ }
|
|
63
|
129
|
}
|
|
64
|
130
|
}
|
|
65
|
131
|
|
|
66
|
132
|
void Initialize_SPI(void)
|
|
67
|
133
|
{
|
|
|
134
|
+ /* TODO: move to spi.h */
|
|
68
|
135
|
/* Set MOSI and SCK output, all others input */
|
|
69
|
136
|
SPI_DDR = (1<<SPI_MOSI_PIN)|(1<<SPI_SCK_PIN);
|
|
70
|
137
|
/* Enable SPI, Master, set clock rate fck/16 */
|
|
71
|
138
|
SPCR = (1<<SPE)|(1<<MSTR);
|
|
72
|
139
|
}
|
|
|
140
|
+
|
|
|
141
|
+void Set_Up_Power_Save_Mode(void)
|
|
|
142
|
+{
|
|
|
143
|
+ // Disable Brown-Out-Detection by setting the BODLEVEL 2:0 Fuses to 0b111 (should be default)
|
|
|
144
|
+ // Disable the on-chip debug system by setting the DWEN Fuse to 1 (should be default)
|
|
|
145
|
+
|
|
|
146
|
+ /* Disable some unused peripherals that are not used during operation of the weather station: */
|
|
|
147
|
+ // The ADC is turned off by default
|
|
|
148
|
+ ACSR &= ~(1<<ACD); // Analog comperator
|
|
|
149
|
+ ACSR &= ~(1<<ACIE); // The interrupt bit has to be cleared after switchin of the analog comperator
|
|
|
150
|
+ /*
|
|
|
151
|
+ * The Internal voltager reference is automatically disabled if the BOD, ADC and Voltage
|
|
|
152
|
+ * Reference are disabled
|
|
|
153
|
+ */
|
|
|
154
|
+
|
|
|
155
|
+ /* Set up Timer/Counter2 */
|
|
|
156
|
+ PRR &= ~(1<<PRTIM2); // Enable the timer 2 in the Power Reduction Register
|
|
|
157
|
+
|
|
|
158
|
+ TCCR2A |= (1<<COM2A1)|(1<<COM2A0)|(1<<WGM21); // Set the timer to ClearTimer on Compare Match with output compare mode for channel A
|
|
|
159
|
+ /* There is a problem: The maximum time until the counter 2 overflows is 262ms at the nominal
|
|
|
160
|
+ * core frquency of 1MHz and a timer prescaler of 1024.
|
|
|
161
|
+ * This can be attenuated by lowering the system frequency to 31.25 kHz via the clock prescaler
|
|
|
162
|
+ * (CLKPS3...0) of the register CLKPR. This gives a overflow time of 8.3s.
|
|
|
163
|
+ * The cycle time of one minute can thus be accomplished by setting the output compare register
|
|
|
164
|
+ * to 229. This spawns an interrupt every 7.5s which means the operation has to be executed
|
|
|
165
|
+ * every 8 interrupt calls.
|
|
|
166
|
+ */
|
|
|
167
|
+
|
|
|
168
|
+ TCCR2B |= (1<<CS22)|(1<<CS21)|(1<<CS20); // Set the timer prescaler to 1/1024
|
|
|
169
|
+ OCR2A = 229; // TODO: calculate this number from the wanted cycle time and the timer frequency.
|
|
|
170
|
+
|
|
|
171
|
+ TIMSK2 |= (1<<OCIE2A); // Enable the Output Compare Match A Interrupt.
|
|
|
172
|
+
|
|
|
173
|
+ /* Enable global interrupts: */
|
|
|
174
|
+ sei();
|
|
|
175
|
+}
|
|
|
176
|
+
|
|
|
177
|
+void Enter_Power_Save_Mode(void)
|
|
|
178
|
+{
|
|
|
179
|
+ PRR |= (1<<PRTWI) | (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRSPI) | (1<<PRUSART0) | (1<<PRADC); /* Only timer 2 is needed for wake-up interrupt */
|
|
|
180
|
+
|
|
|
181
|
+ /* Set the clock prescaler for a frequency of 32.25 kHz*/
|
|
|
182
|
+ CLKPR = (1<<CLKPCE);
|
|
|
183
|
+ CLKPR = (1<<CLKPS3);
|
|
|
184
|
+
|
|
|
185
|
+ TCNT2 = 0;// Reset timer 2
|
|
|
186
|
+ TIMSK2 |= (1<<OCIE2A); // Enable the Output Compare Match A Interrupt.
|
|
|
187
|
+
|
|
|
188
|
+
|
|
|
189
|
+ set_sleep_mode(SLEEP_MODE_PWR_SAVE);
|
|
|
190
|
+ sleep_mode();
|
|
|
191
|
+}
|
|
|
192
|
+
|
|
|
193
|
+void Exit_Power_Save_Mode(void)
|
|
|
194
|
+{
|
|
|
195
|
+ TIMSK2 &= ~(1<<OCIE2A); // Disable the Output Compare Match A Interrupt.
|
|
|
196
|
+
|
|
|
197
|
+ /* Set the normal operating frequency of 1 MHz */
|
|
|
198
|
+ CLKPR = (1<<CLKPCE);
|
|
|
199
|
+ CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
|
|
|
200
|
+
|
|
|
201
|
+ PRR &= ~(1<<PRSPI); // Enable SPI
|
|
|
202
|
+ Initialize_SPI(); // reinitalize SPI
|
|
|
203
|
+}
|