]> www.fi.muni.cz Git - kolektor.git/blob - main.c
schematics.jpg: schema pouzitych soucastek a cest
[kolektor.git] / main.c
1 #include <avr/io.h>
2 #include <util/delay.h>
3 #include <avr/sleep.h>
4 #include <avr/interrupt.h>
5 #include <avr/power.h>
6
7 #include "logging.h"
8
9 // init PLL clock for timer/counter 1
10 // datasheet sekce 12.2.1
11 static void enable_pll_clock()
12 {
13         // async clock
14         PLLCSR = _BV(PLLE) | _BV(LSM); // low-speed mode (32 MHz)
15
16         // Synchronize to the phase lock
17         _delay_us(100);
18         while((PLLCSR & _BV(PLOCK)) == 0)
19                 ;
20         PLLCSR |= _BV(PCKE);
21 }
22
23 // Timer/Counter 1 initialization
24 // datasheet sekce 12
25 static void init_tc1()
26 {
27         power_timer1_enable();
28
29         TCCR1 = _BV(CTC1) // clear on compare match
30                 | _BV(CS10) // clock = PCK (no divisor)
31                 | _BV(COM1A1) // clear output line on compare match
32                 | _BV(PWM1A); // PWM mode
33
34         OCR1C = 255;    // TOP value
35
36         DDRB |= _BV(PB1);
37         OCR1A = 0;      // stride
38         
39         // Tohle pripadne povoli PWM i na OC1B (PB4)
40         // GTCCR = _BV(COM1B1) | _BV(PWM1B);
41         // DDRB |= _BV(PB4);
42         // OCR1B = 0; // stride
43 }
44
45 // Precte synchronne (busy-waitem) jednu hodnotu z A/D prevodniku.
46 // Alternativa je nastavit bit ADSC a ADIE, delat neco jineho,
47 // a pockat az prijde ADC interrupt (viz firmware "step-up" na strance
48 // tinyboard).
49 static uint16_t read_adc_sync()
50 {
51         uint16_t rv;
52
53         ADCSRA |= _BV(ADSC); // start the conversion
54
55         // wait for the conversion to finish
56         while((ADCSRA & _BV(ADIF)) == 0)
57                 ;
58
59         rv = ADCW;
60         ADCSRA |= _BV(ADIF); // clear the IRQ flag
61
62         return rv;
63 }
64
65 // vyber kanalu A/D prevodniku (datasheet tabulka 17-4 v sekci 17.13.1)
66 typedef enum { ADC1, ADC3, ADC4 } adc_channel;
67 static void select_adc_channel(adc_channel c)
68 {
69         switch (c) {
70         case ADC1:
71                 ADMUX = _BV(REFS1) | _BV(MUX0); // ADC1 (PB2), 1.1V ref
72                 break;
73         case ADC3:
74                 ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0); // ADC3 (PB3), 1.1V ref
75                 break;
76         case ADC4:
77                 ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0) // ADC4 (temperature), 1.1V ref
78                 break
79                 ;
80         }
81 }
82
83
84 // analog to digital converter
85 // datasheet sekce 17
86 static void init_adc()
87 {
88         power_adc_enable();
89         ACSR |= _BV(ACD); // enable ADC, disable AC
90
91         ADCSRA = _BV(ADEN) // enable
92                 | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz
93                 ;
94
95         DIDR0 = _BV(ADC1D) | _BV(ADC3D); // disable dig. input on ADC1, ADC3 (PB2, PB3)
96
97         select_adc_channel(ADC4);
98         // do the first conversion, drop the result
99         read_adc_sync();
100 }
101
102 // priklad vselijakych moznosti, co tenhle HW umi
103 int main(void)
104 {
105         unsigned char i;
106
107         init_log(); // viz logging.c - detekce poctu resetu, atd.
108
109         log_byte(0x42); // zkouska logovani
110         log_flush();    // nezapomenout vylit buffer
111
112         power_all_disable(); /* vypneme cele I/O, pak zapneme co bude potreba */
113
114         DDRB |= _BV(DDB4); // PB4 as output (lze misto tohoto pouzit jako PWM)
115
116         PORTB |= _BV(PB0); // PB0 interni pull-up (aby tady byla 1, pokud je plovak rozepnuty)
117
118         enable_pll_clock();
119         init_tc1();
120         init_adc();
121
122         // po skonceni inicializace muzeme i zapnout preruseni,
123         // pokud je budeme potrebovat
124         // cli();
125
126         // priklad prace s A/D prevodnikemo
127         select_adc_channel(ADC4); // interni teplomer na cipu
128         log_word(read_adc_sync()); // nacteme teplotu cipu, zalogujeme
129         // interpretace vysledku: datasheet sekce 17.12
130         log_flush();
131
132         // ve smycce budeme merit jak se meni hodnota na ADC3 (PB3)
133         select_adc_channel(ADC3);
134
135         while(1) {
136                 // PB4 (motor 2) zapínáme podle sepnutí plováku PB0
137                 if (PINB & _BV(PINB0)) { // rozepnuto (1)
138                         PORTB &= ~_BV(PORTB4);
139                 } else { // sepnuto (0)
140                         PORTB |= _BV(PORTB4);
141                 }
142
143                 // hodnota PWM pro PB1 (OC1A)
144                 // jdeme od 128 do 248, napriklad:
145                 OCR1A = 0x80 + (i << 3);
146
147                 // busy-wait, nebo se muzeme nechat casovat
148                 // pomoci watchdogu (WDT, datasheet sekce 7.4.5)
149                 // nebo pomoci Timer/Counter 0 (datasheet sekce 11)
150                 _delay_ms(1500);
151
152                 i++;
153                 i &= 0xF;
154
155                 log_word(read_adc_sync()); // nacteme hodnotu, zalogujeme
156                 log_flush();
157         }
158 }