1 | /*
|
2 | * _2_Punktregler_Temp_SMT_160_30.c
|
3 | *
|
4 | * Created: 19.09.2013 10:48:00
|
5 | * Author: Administrator
|
6 | */
|
7 |
|
8 |
|
9 | #include <avr/io.h>
|
10 | #include <avr/interrupt.h>
|
11 | #include "icp.h"
|
12 |
|
13 | /* Atmega8 Portdefinitionen */
|
14 | #define ICP_PIN PINB /* ICP1 GPIO Wert */
|
15 | #define ICP_PORT PORTB /* ICP1 GPIO Port */
|
16 | #define ICP_DDR DDRB /* ICP1 GPIO DDR */
|
17 | #define ICP_BIT PB0 /* ICP1 GPIO Pin */
|
18 | /*Timerdefinitionen*/
|
19 | #define ICP_OCR OCR1A /* ICP1 Ausgabe Vergleichsregister */
|
20 | #define ICP_OC_IE OCIE1A /* ICP1 Timer Ausgabe Vergleich EIN */
|
21 | #define ICP_OC_IF OCF1A /* ICP1 Timer Ausgabe Vergleichs Flag */
|
22 | #define ICP_IE TICIE1 /* ICP1 Unterbrechung EIN */
|
23 | #define ICP_IF ICF1 /* ICP1 Unterbrechungs Flag */
|
24 | #define ICP_CTL_A TCCR1A /* ICP1 Timer Kontrollreg */
|
25 | #define ICP_CTL TCCR1B /* ICP1 Unterbrechungs Kontrollreg */
|
26 | #define ICP_SENSE ICES1 /* ICP1 Unterbrechung bei (steigend/fallend) */
|
27 | #define ICP_PRESCALE ((0 << CS12) | (0 << CS11) | (1 << CS10)) /* Vorteiler /1 */
|
28 |
|
29 | #define ICP_START_SENSE (1 << ICP_SENSE) /* starte mit steigender Flanke */
|
30 | /*Demodulationsvaraiblen*/
|
31 | typedef unsigned int icp_timer_t; /* von der selben Bitlänge wie TCNT1 */
|
32 | icp_timer_t icp_start_time, icp_stop_time;
|
33 | icp_timer_t icp_period;
|
34 |
|
35 | /*speichert demodulierte Abtatswerte*/
|
36 | icp_sample_t icp_rx_q[ICP_RX_QSIZE];
|
37 |
|
38 | void icp_init(void)
|
39 | {
|
40 | /*
|
41 | * Nothing interesting to set in TCCR1A
|
42 | */
|
43 | ICP_CTL_A = 0;
|
44 |
|
45 | /*
|
46 | * Setting the OCR (timeout) to 0 allows the full TCNT range for
|
47 | * the initial period.
|
48 | */
|
49 | ICP_OCR = 0;
|
50 |
|
51 | /*
|
52 | * Set the interrupt sense and the prescaler
|
53 | */
|
54 | ICP_CTL = ICP_START_SENSE | ICP_PRESCALE;
|
55 |
|
56 | /*
|
57 | * Enable both the Input Capture and the Output Capture interrupts.
|
58 | * The latter is used for timeout (0% and 100%) checking.
|
59 | */
|
60 | TIMSK |= (1 << ICP_IE) | (1 << ICP_OC_IE);
|
61 |
|
62 | return;
|
63 | }
|
64 |
|
65 | /**
|
66 | * icp_rx_tail, icp_rx_head
|
67 | *
|
68 | * Queue state variables for icp_rx_q.
|
69 | *
|
70 | * The rx_head and rx_tail indices need to be wide enough to
|
71 | * accomodate [0:ICP_RX_QSIZE). Since QSIZE should generally
|
72 | * not be very large, these are hard-coded as single bytes,
|
73 | * which gets around certain atomicity concerns.
|
74 | */
|
75 | unsigned char icp_rx_tail; /* icp_rx_q insertion index */
|
76 | #if !ICP_ANALOG /* ICP_DIGITAL */
|
77 | unsigned char icp_rx_head; /* icp_rx_q retrieval index */
|
78 | #endif
|
79 |
|
80 |
|
81 | /**
|
82 | * icp_enq()
|
83 | *
|
84 | * Stores a new sample into the Rx queue.
|
85 | */
|
86 | #if __GCC__
|
87 | __inline__
|
88 | #else /* assume IAR */
|
89 | #pragma inline /* for next function */
|
90 | #endif
|
91 | static void icp_enq(icp_sample_t sample)
|
92 | {
|
93 | unsigned char t;
|
94 |
|
95 | t = icp_rx_tail;
|
96 | #if ICP_ANALOG
|
97 | icp_total += sample - icp_rx_q[t];
|
98 | #endif
|
99 | icp_rx_q[t] = sample;
|
100 | if (++t >= ICP_RX_QSIZE)
|
101 | t = 0;
|
102 | #if !ICP_ANALOG
|
103 | if (t != icp_rx_head) /* digital: Check for Rx overrun */
|
104 | #endif
|
105 | icp_rx_tail = t;
|
106 | return;
|
107 | }
|
108 |
|
109 | /**
|
110 | * icp_duty_compute()
|
111 | *
|
112 | * This function computes the value of (ICP_SCALE*pulsewidth)/period.
|
113 | * It is effectively a divide function, but uses a successive-approximation
|
114 | * (moral equivalent of long division) method which:
|
115 | * 1) Doesn't require 32-bit arithmetic (the numerator is 24+ bits nominal).
|
116 | * 2) For an 8-bit result, only needs 8 loops (instead of 16 for general 16/16).
|
117 | * 3) Compiles nicely from C.
|
118 | * We get away with this because we know that pulsewidth <= period, so
|
119 | * no more than log2(ICP_SCALE) bits are relevant.
|
120 | */
|
121 | #if __GCC__
|
122 | __inline__
|
123 | #else /* assume IAR */
|
124 | #pragma inline /* for next function */
|
125 | #endif
|
126 | static icp_sample_t icp_duty_compute(icp_timer_t pulsewidth, icp_timer_t period)
|
127 | {
|
128 | icp_sample_t r, mask;
|
129 |
|
130 | mask = ICP_SCALE >> 1;
|
131 | r = 0;
|
132 | do
|
133 | {
|
134 | period >>= 1;
|
135 | if (pulsewidth >= period)
|
136 | {
|
137 | r |= mask;
|
138 | pulsewidth -= period;
|
139 | }
|
140 | mask >>= 1;
|
141 | } while (pulsewidth != 0 && mask != 0);
|
142 | return(r);
|
143 | }
|
144 |
|
145 |
|
146 | ISR(TIMER1_CAPT_vect)
|
147 | {
|
148 | icp_timer_t icr, delta;
|
149 | unsigned char tccr1b;
|
150 |
|
151 | /*
|
152 | * Capture the ICR and then reverse the sense of the capture.
|
153 | * These must be done in this order, since as soon as the
|
154 | * sense is reversed it is possible for ICR to be updated again.
|
155 | */
|
156 | icr = ICR1; /* capture timestamp */
|
157 |
|
158 | do
|
159 | {
|
160 | tccr1b = ICP_CTL;
|
161 | ICP_CTL = tccr1b ^ (1 << ICP_SENSE); /* reverse sense */
|
162 |
|
163 | /*
|
164 | * If we were waiting for a start edge, then this is the
|
165 | * end/beginning of a period.
|
166 | */
|
167 | if ((tccr1b & (1 << ICP_SENSE)) == ICP_START_SENSE)
|
168 | {
|
169 | /*
|
170 | * Beginning of pulse: Compute length of preceding period,
|
171 | * and thence the duty cycle of the preceding pulse.
|
172 | */
|
173 | icp_period = icr - icp_start_time; /* Length of previous period */
|
174 | delta = icp_stop_time - icp_start_time; /* Length of previous pulse */
|
175 | icp_start_time = icr; /* Start of new pulse/period */
|
176 |
|
177 | /*
|
178 | * Update the timeout based on the new period. (The new period
|
179 | * is probably the same as the old, give or take clock drift.)
|
180 | * We add 1 to make fairly sure that, in case of competition,
|
181 | * the PWM edge takes precedence over the timeout.
|
182 | */
|
183 | ICP_OCR = icr + icp_period + 1; /* Move timeout window */
|
184 | TIFR = (1 << ICP_OC_IF); /* Clear in case of race */
|
185 |
|
186 | /*
|
187 | * Compute the duty cycle, and store the new reading.
|
188 | */
|
189 | icp_enq(icp_duty_compute(delta,icp_period));
|
190 |
|
191 | /*
|
192 | * Check for a race condition where a (very) short pulse
|
193 | * ended before we could reverse the sense above.
|
194 | * If the ICP pin is still high (as expected) OR the IF is
|
195 | * set (the falling edge has happened, but we caught it),
|
196 | * then we won the race, so we're done for now.
|
197 | */
|
198 | if ((ICP_PIN & (1 << ICP_BIT)) || (TIFR & (1 << ICP_IF)))
|
199 | break;
|
200 | }
|
201 | else
|
202 | {
|
203 | /*
|
204 | * Falling edge detected, so this is the end of the pulse.
|
205 | * The time is simply recorded here; the final computation
|
206 | * will take place at the beginning of the next pulse.
|
207 | */
|
208 | icp_stop_time = icr; /* Capture falling-edge time */
|
209 |
|
210 | /*
|
211 | * If the ICP pin is still low (as expected) OR the IF is
|
212 | * set (the transition was caught anyway) we won the race,
|
213 | * so we're done for now.
|
214 | */
|
215 | if ((!(ICP_PIN & (1 << ICP_BIT))) || (TIFR & (1 << ICP_IF)))
|
216 | break;
|
217 | }
|
218 | /*
|
219 | * If we got here, we lost the race with a very short/long pulse.
|
220 | * We now loop, pretending (as it were) that we caught the transition.
|
221 | * The Same ICR value is used, so the effect is that we declare
|
222 | * the duty cycle to be 0% or 100% as appropriate.
|
223 | */
|
224 | } while (1);
|
225 |
|
226 | return;
|
227 | }
|
228 |
|
229 |
|
230 | int main(void)
|
231 | {
|
232 |
|
233 | while(1)
|
234 | {
|
235 | //(Hier steht noch nichts!)
|
236 |
|
237 | }
|
238 | }
|