]> www.average.org Git - sensor-light.git/blob - msp430/main.c
fa802dd68292ffb5ef9abbbbe17f1a744b02305c
[sensor-light.git] / msp430 / main.c
1 #include <msp430.h> 
2
3 static volatile unsigned int ADC_Result;
4 static volatile unsigned int irq_events = 0;
5 enum {ev_btn1 = 0, ev_btn2, ev_pir1, ev_pir2, ev_tmr, ev_adc, ev_MAX};
6
7 #define PWM_ORDER 10
8 #define PWM_HALF 5
9 #define LIGHT_THRESHOLD 900
10 #define TIME_ON 320
11         
12 #ifdef ADCSC /* Let us hope that this is a "new" model */
13 # define BIT_RL BIT0
14 # define BIT_GL BIT1
15 # define PBTN(x) P2##x
16 # define BIT_BTN BIT3
17 # define HAVE_BTN2
18 # define BIT_BTN2 BIT7
19 #else
20 # define BIT_RL BIT0
21 # define BIT_GL BIT6
22 # define PBTN(x) P1##x
23 # define BIT_BTN BIT3
24 # define BIT_BTN2 0
25 #endif
26
27 static int expon2(int duty)
28 {
29         int shift = duty>>1;
30         int comp = 1<<shift;
31         int extra = (duty & 1) ? comp>>1 : 0;
32         return (duty ? comp|extra : 0);
33 }
34
35 int main(void)
36 {
37         int Duty_Cycle = 0;
38         int Increment = 1;
39         unsigned int Time_Left = 50;
40         unsigned int Time_Indicate = 2;
41
42         WDTCTL = WDTPW | WDTHOLD;       // stop watchdog timer
43         // Configure GPIO Out
44         P1DIR |= BIT_RL|BIT_GL|BIT2;    // Set LEDs & PWM to output direction
45         P1OUT &= ~(BIT_RL|BIT_GL);      // LEDs off
46 #ifdef P1SEL1
47         P1SEL1 |= BIT2;                 // PWM out
48 #else
49         P1SEL |= BIT2;                  // PWM out
50 #endif
51
52         // Configure GPIO In
53         PBTN(DIR) &= ~(BIT_BTN|BIT_BTN2);       // Buttons
54         PBTN(OUT) |= BIT_BTN|BIT_BTN2;          // Pull up
55         PBTN(REN) |= BIT_BTN|BIT_BTN2;          // Enable pull-up
56         PBTN(IES) |= BIT_BTN|BIT_BTN2;          // INT on Hi->Lo edge
57         PBTN(IE)  |= BIT_BTN|BIT_BTN2;          // INT enable
58
59         P2DIR &= ~(BIT4|BIT5);          // PIR Sensors
60         P2OUT &= ~(BIT4|BIT5);          // Pull down
61         P2REN |= BIT4|BIT5;             // Enable pull-down
62         P2IES &= ~(BIT4|BIT5);          // INT on Lo->Hi edge
63         P2IE  |= BIT4|BIT5;             // INT enable
64
65         // Configure ADC10
66
67 #ifdef ADCPCTL4 /* Newer model */
68         SYSCFG2 |= ADCPCTL4|ADCPCTL5;   // disconnect pin 4 and 5 from GPIO
69         ADCCTL0 |= ADCSHT_2 | ADCON;    // ADCON, S&H=16 ADC clks
70         ADCCTL1 |= ADCSHP;              // ADCCLK = MODOSC; sampling timer
71         ADCCTL2 |= ADCRES;              // 10-bit conversion results
72         ADCMCTL0 |= ADCINCH_4;          // A4 ADC input select; Vref=AVCC
73         ADCIE |= ADCIE0;                // Enable ADC conv complete interrupt
74         // channel 5 is unused, reserved for measuring current
75 #else
76         ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADCON, S&H=16 ADC clks
77         ADC10CTL1 = INCH_4;             // A4 ADC input select
78         // channel 5 is unused, reserved for measuring current
79 #endif
80
81         // Timer and PWM
82
83 #ifndef TASSEL__SMCLK
84 # define TASSEL__SMCLK TASSEL_2
85 # define MC__UP MC_1
86 # define MC__CONTINUOUS MC_2
87 # define TA0CCR2 TA0CCR1
88 # define TA0CCTL2 TA0CCTL1
89 #endif
90
91         // Configure timer A0 for PWM
92         TA0CCR0 = 1 << PWM_ORDER;       // PWM Period 2^10 ca. 1 kHz
93         TA0CCR2 = 0;                    // CCR1 PWM duty cycle
94         TA0CCTL2 = OUTMOD_7;            // CCR1 reset/set
95         TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;// SMCLK, up mode
96                 // SMCLK, no divider, up mode, no interrupt, clear TAR
97
98         //Configure timer A1 for counting time
99         TA1CTL |= TASSEL__SMCLK | MC__CONTINUOUS | TACLR | TAIE;
100                 // SMCLK, no divider, continuous mode, interrupt enable
101
102 #ifdef LOCKLPM5
103         // Disable the GPIO power-on default high-impedance mode to activate
104         // previously configured port settings
105         PM5CTL0 &= ~LOCKLPM5;
106 #endif
107
108         while(1)
109         {
110                 unsigned int events;
111
112                 _disable_interrupts();
113                 events = irq_events;
114                 irq_events = 0;
115                 _enable_interrupts();
116
117                 // Button 2 or PIR events initiate light measurement
118                 // and tuns on green or red led
119                 if (events & (1<<ev_btn2|1<<ev_pir1|1<<ev_pir2)) {
120                         if (events & 1<<ev_pir1)
121                                 P1OUT |= BIT_GL;        // Set green LED on
122                         if (events & 1<<ev_pir2)
123                                 P1OUT |= BIT_RL;        // Set red LED on
124                         // Sampling and conversion start
125 #ifdef ADCENC
126                         ADCCTL0 |= ADCENC | ADCSC;
127 #else
128                         ADC10CTL0 |= ENC + ADC10SC;
129 #endif
130                 }
131
132                 // End of light measurement. Set new Duty_Cycle,
133                 // zero increment and turn off green led
134                 if (events & 1<<ev_adc) {
135                         P1OUT ^= (BIT_GL|BIT_RL); // Flip green and red LEDs
136                         Time_Indicate = 5;
137                         if (ADC_Result < LIGHT_THRESHOLD)
138                                 continue;
139                         Time_Left = TIME_ON;
140                         Increment = 1;
141                 }
142
143                 // Button 1 sets non-zero increment (and toggles it)
144                 if (events & 1<<ev_btn1) {
145                         P1OUT |= (BIT_GL|BIT_RL); // Set green and red LEDs on
146                         Time_Indicate = 5;
147                         if (Duty_Cycle > PWM_HALF) {
148                                 Time_Left = 0;
149                                 Increment = -1;
150                         } else {
151                                 Time_Left = TIME_ON;
152                                 Increment = 1;
153                         }
154                 }
155
156                 // Timer event (100 ms) changed duty cycle and flashes red led
157                 if (events & 1<<ev_tmr) {
158                         if (Time_Indicate) {
159                                 Time_Indicate--;
160                                 if (!Time_Indicate)
161                                         P1OUT &= ~(BIT_RL|BIT_GL); // LEDs off
162                         }
163                         if (Time_Left) {
164                                 Time_Left--;
165                                 if (!Time_Left)
166                                         if (Duty_Cycle)
167                                                 Increment = -1;
168                         }
169                         if (Increment > 0) {
170                                 if (++Duty_Cycle >= (PWM_ORDER<<1)) {
171                                         Duty_Cycle = PWM_ORDER<<1;
172                                         Increment = 0;
173                                 }
174                         } else if (Increment < 0) {
175                                 if (--Duty_Cycle < 1) {
176                                         Duty_Cycle = 0;
177                                         Increment = 0;
178                                 }
179                         } else // Increment _was_ zero - no change!
180                                 continue;
181
182                         TA0CCR2 = expon2(Duty_Cycle);
183                 }
184                 __bis_SR_register(LPM0_bits | GIE);
185                 __no_operation();
186         }
187         return 0; /* not reached */
188 }
189
190 // TIMER interrupt routine
191 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
192 #pragma vector = TIMER1_A1_VECTOR
193 __interrupt void Timer_A (void)
194 #elif defined(__GNUC__)
195 void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer_A (void)
196 #else
197 #error Compiler not supported!
198 #endif
199 {
200         switch(__even_in_range(TA1IV,TA1IV_TAIFG))
201         {
202                 case TA1IV_NONE:
203                         break;  // No interrupt
204                 case TA1IV_TACCR1:
205                         break;  // CCR1 not used
206                 case TA1IV_TACCR2:
207                         break;  // CCR2 not used
208                 case TA1IV_TAIFG:
209                         irq_events |= 1<<ev_tmr;
210                         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
211                         break;
212                 default:
213                         break;
214         }
215 }
216
217 #ifndef ADC_VECTOR
218 # define ADCMEM0 ADC10MEM
219 # define ADC_VECTOR ADC10_VECTOR
220 #endif
221
222 // ADC interrupt service routine
223 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
224 #pragma vector=ADC_VECTOR
225 __interrupt void ADC_ISR(void)
226 #elif defined(__GNUC__)
227 void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
228 #else
229 #error Compiler not supported!
230 #endif
231 {
232 #ifdef ADCIV_NONE
233         switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
234         {
235                 case ADCIV_NONE:
236                         break;
237                 case ADCIV_ADCOVIFG:
238                         break;
239                 case ADCIV_ADCTOVIFG:
240                         break;
241                 case ADCIV_ADCHIIFG:
242                         break;
243                 case ADCIV_ADCLOIFG:
244                         break;
245                 case ADCIV_ADCINIFG:
246                         break;
247                 case ADCIV_ADCIFG:
248 #endif
249                         ADC_Result = ADCMEM0;
250                         irq_events |= 1<<ev_adc;
251                         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
252 #ifdef ADCIV_NONE
253                         break;
254                 default:
255                         break;
256         }
257 #endif
258 }
259
260 // GPIO interrupt service routine
261 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
262 #pragma vector=PORT2_VECTOR
263 __interrupt void Port_2(void)
264 #elif defined(__GNUC__)
265 void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
266 #else
267 #error Compiler not supported!
268 #endif
269 {
270         if (P2IFG & BIT4) {
271                 irq_events |= 1<<ev_pir1;
272                 P2IFG &= ~BIT4; // Clear P2.4 IFG
273         }
274         if (P2IFG & BIT5) {
275                 irq_events |= 1<<ev_pir2;
276                 P2IFG &= ~BIT5; // Clear P2.5 IFG
277         }
278 #if (PBTN() == P1)
279         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
280 }
281 // GPIO interrupt service routine
282 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
283 #pragma vector=PORT1_VECTOR
284 __interrupt void Port_1(void)
285 #elif defined(__GNUC__)
286 void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
287 #else
288 #error Compiler not supported!
289 #endif
290 {
291 #endif /* (PBTN() == P1) */
292         if (PBTN(IFG) & BIT_BTN) {
293                 irq_events |= 1<<ev_btn1;
294                 PBTN(IFG) &= ~BIT_BTN;  // Clear button IFG
295         }
296 #ifdef HAVE_BTN2
297         if (PBTN(IFG) & BIT_BTN2) {
298                 irq_events |= 1<<ev_btn2;
299                 PBTN(IFG) &= ~BIT_BTN2; // Clear button 2 IFG
300         }
301 #endif
302         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
303 }