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
|
//v0 5/1/2014 by Everett
//initial version
//simple flashlight controller. mode change on power cycle
//v1 5/3/2014 by Everett
//adapted to momentary switch
#include <htc.h>
#include <pic10f322.h>
#define _XTAL_FREQ 8000000
__CONFIG(CP_OFF & BOREN_OFF & LVP_OFF & MCLRE_OFF & WDTE_OFF & PWRTE_OFF & FOSC_INTOSC & WRT_HALF);
#define pwm PWM1DCH
unsigned char mode;
enum mode{
max=0,
med=1,
low=2,
off=3,
};
#define max_mode 3
#define default_mode 0
unsigned int v_timer;
bit v_sample;
#define voltage_rate 100 //milliseconds
bit pressed;
bit new_press;
char switch_count;
void delayms(int milliseconds);
void configure(void);
unsigned char read_voltage(void);
void initialize_mode(void);
void debounce(void);
void shutdown(void);
void interrupt isr(void)
{
if(TMR0IF){ //fires at 1kHz
TMR0IF=0;
debounce();
if(++v_timer==voltage_rate){v_timer=0; v_sample=1;}
}
}
void main(void)
{
configure(); //set up hardware peripherals
mode=default_mode;
initialize_mode();
pressed=0; new_press=0; switch_count=10;
GIE=1; //turn on interrupts
while(1){
if(v_sample){
v_sample=0;
if(mode==max){ //if battery goes below 3.0V in max mode, force down to medium mode
if(read_voltage()>87){
mode=med;
initialize_mode();
}
}
}
if(new_press){
new_press=0;
mode++;
if(mode>max_mode) mode=0;
initialize_mode();
}
if(mode==off)
{
shutdown(); //shutdown will lock up here until a press wakes the device
}
}
}
void shutdown(void)
{
INTCON=0b00001000; //interrupt on pin change only
PWM1DCH=0; //zero output
PWM1CON=0; //turn off pwm
LATA=0; //ensure pin is low
FVRCON=0; //fvr off
ADCON=0; //adc off
while(1) //make this a loop so we stay here until sure the switch went down
{
do{
debounce();
delayms(1);
}while(pressed); //ensure switch is up
IOCAP=0;
IOCAN=0b00001000; //interrupt on fall of ra3
IOCAF=0; //clear flags
SLEEP();
pressed=0; switch_count=10;
for(char i=0; i<40; i++){ //watch for up to 40ms for a solid press
debounce();
delayms(1);
if(pressed) break; //if pressed break out of for loop
}
if(pressed) break; //if pressed break out of sleep loop
}
configure(); //set up hardware for operation
GIE=1; //turn on interrupts
}
void debounce(void)
{
static char port_copy=0xff;
#define switch_mask 0b00001000 //this selects RA3 as the switch
if((PORTA&switch_mask)==port_copy) //if the current state matches previous state
{
if(--switch_count==0) //count down samples. if 10 consecutive samples matched
{
switch_count=10; //reset sample counter
if(PORTA&switch_mask) pressed=0; //if the state is high, switch is up
else //else switch is down. check for new press
{
if(pressed==0) new_press=1; //if last state of pressed was 0, this is a new press
pressed=1; //switch is now down
}
}
}
else //state doesn't match,
{
switch_count=10; //reset sample counter
port_copy=(PORTA&switch_mask); //get new sample
}
}
void initialize_mode(void)
{
switch(mode){ //initialize current mode
default:
case max:
pwm=255;
break;
case med:
pwm=25;
break;
case low:
pwm=1;
break;
case off:
pwm=0;
break;
}
}
unsigned char read_voltage(void)
{
//fvr is at 1.024V. ADRES = 1.024/Vin*255. Vin = 1.024/(ADRES/255). voltage limit set to 3.0V -> 87. values below this correspond to voltage above 3.0V
GO_nDONE=1;
while(GO_nDONE);
return ADRES;
}
void delayms(int milliseconds)
{
while(milliseconds!=0){ __delay_ms(1); milliseconds--;}
}
void configure(void)
{
INTCON=0b00100000; //tmr0 only
T2CON=0b00000100; //on, no prescale
PR2=255;
TMR2=0;
LATA=0;
TRISA=0b11111110; //GP0 output
ANSELA=0b11110000; //
WPUA=0b11111110;
OSCCON=0b01100000; //8MHz
OPTION_REG=0b00000010; //8 prescale for 1ms interrupts
FVRCON=0b10000001; //1.024v to adc
ADCON=0b10111101; // fvr
PWM1DCH=0;
PWM1CON=0b11000000; //on, output
}
|