Subversion Repositories FlightCtrl

Rev

Rev 796 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
796 joko 1
/*
2
 
3
Copyright 2007, Niklas Nold
4
 
5
This program (files compass.c and compass.h) is free software; you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or (at your option) any later version.
8
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License
11
along with this program. If not, see <http://www.gnu.org/licenses/>.
12
 
13
Please note: All the other files for the project "Mikrokopter" by H. Buss are under the license (license_buss.txt) published by www.mikrokopter.de
14
*/
15
 
16
#include "main.h"
17
 
18
struct MM3_calib_struct ee_calib EEMEM;         // Reservierung im EEPROM
19
 
20
struct MM3_working_struct MM3;
21
struct MM3_calib_struct MM3_calib;
22
 
23
 
24
//############################################################################
25
// Initialisierung
26
void init_MM3(void)
27
//############################################################################
28
{
29
        // SPI-Schnittstelle initialisieren
30
        SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);        // Interrupt an, Master, 156 kHz Oszillator
31
 
32
    DDRB |= (1<<PB7)|(1<<PB5)|(1<<PB2); // SCK, MOSI, J8 jeweils als Ausgang
33
 
34
        //Dieser Pin ist weder bei der FC 1.0 noch bei der FC 1.1 verwendet.
35
        //Bei der originalen FC 1.1 ist sogar ein extra Lödpad vorhanden, bei 
36
        //einer originalen FC 1.0 oder auch einer zur 1.1 Umgebauten liegt dieser
37
        //Pin auf "Stecker 4" der Universalschnittstelle
38
        DDRC |= (1<<PC6);               // PC6 (J9) als Ausgang. Ist für den SSNOT Pin beim MM3
39
        PORTC &= ~(1<<PC6);     // PC6 (J9) permanent auf Low. Ist für den SSNOT Pin beim MM3
40
 
41
        // Init Statemachine
42
        MM3.AXIS = MM3_X;
43
        MM3.STATE = MM3_RESET;
44
 
45
        // Kalibrierung aus dem EEprom lesen
46
        eeprom_read_block((uint8_t *) &MM3_calib.X_off, &EEPromArray[EEPROM_ADR_MM3_CALIB], sizeof(MM3_calib)); //Bugfix für sporadisch falsche Zuweisung des Nick-Kanals durch Nick666 EEPROM Verwendung (110308)
47
}
48
 
49
 
50
//############################################################################
51
// Wird in der SIGNAL (SIG_OVERFLOW0) aufgerufen
52
void timer0_MM3(void)
53
//############################################################################
54
{
55
        switch (MM3.STATE)
56
        {
57
        case MM3_RESET:                        
58
                PORTB |= (1<<PB2);      // J8 auf High, MM3 Reset
59
                MM3.STATE = MM3_START_TRANSFER;
60
                return;
61
 
62
        case MM3_START_TRANSFER:
63
                PORTB &= ~(1<<PB2);     // J8 auf Low (war ~125 µs auf High)            
64
 
65
                if (MM3.AXIS == MM3_X) SPDR = 0x31;                     // Schreiben ins SPDR löst automatisch SPI-Übertragung (MOSI und MISO) aus
66
                else if (MM3.AXIS == MM3_Y) SPDR = 0x32;                // Micromag Period Select ist auf 256 (0x30)
67
                else SPDR = 0x33;       //if (MM3.AXIS == MM3_Z)        // 1: x-Achse, 2: Y-Achse, 3: Z-Achse
68
 
69
                MM3.DRDY = SetDelay(8);         // Laut Datenblatt max. Zeit bis Messung fertig (bei PS 256 eigentlich 4 ms)
70
                MM3.STATE = MM3_WAIT_DRDY;
71
                return;
72
 
73
        case MM3_WAIT_DRDY:
74
                if (CheckDelay(MM3.DRDY)) {SPDR = 0x00;MM3.STATE = MM3_DRDY;} // Irgendwas ins SPDR, damit Übertragung ausgelöst wird, wenn Wartezeit vorbei
75
                return;                                         // Jetzt gehts weiter in SIGNAL (SIG_SPI)
76
        }
77
}
78
 
79
 
80
//############################################################################
81
// SPI byte ready
82
SIGNAL (SIG_SPI)
83
//############################################################################
84
{
85
        static char tmp;
86
        int wert;
87
 
88
        switch (MM3.STATE)
89
        {
90
        case MM3_DRDY:          // 1. Byte ist da, zwischenspeichern
91
                tmp = SPDR;
92
                SPDR = 0x00;    // Übertragung von 2. Byte auslösen
93
                MM3.STATE = MM3_BYTE2;
94
                return;
95
 
96
        case MM3_BYTE2:         // 2. Byte der entsprechenden Achse ist da
97
                wert = tmp;
98
                wert <<= 8;             // 1. Byte an MSB-Stelle rücken
99
                wert |= SPDR;   // 2. Byte dranpappen
100
 
101
                if(abs(wert) < Max_Axis_Value)          // Spikes filtern. Zuweisung nur, wenn Max-Wert nicht überschritten
102
                switch (MM3.AXIS)
103
                {
104
                case MM3_X:
105
                        MM3.x_axis = wert;
106
                        MM3.AXIS = MM3_Y;
107
                        break;
108
                case MM3_Y:
109
                        MM3.y_axis = wert;
110
                        MM3.AXIS = MM3_Z;
111
                        break;
112
                default:        //case MM3_Z:
113
                        MM3.z_axis = wert;
114
                        MM3.AXIS = MM3_X;
115
                }
116
 
117
                MM3.STATE = MM3_RESET;
118
        }
119
}
120
 
121
//############################################################################
122
// Kompass kalibrieren
123
void calib_MM3(void)
124
//############################################################################
125
{
126
        signed int x_min=0,x_max=0,y_min=0,y_max=0,z_min=0,z_max=0;
127
        uint8_t measurement=50,beeper=0;
128
        unsigned int timer;
129
 
130
        GRN_ON;
131
        ROT_OFF;
132
 
133
        while (measurement)
134
        {
135
                //H_earth = MM3.x_axis*MM3.x_axis + MM3.y_axis*MM3.y_axis + MM3.z_axis*MM3.z_axis;
136
 
137
                if (MM3.x_axis > x_max) x_max = MM3.x_axis;
138
                else if (MM3.x_axis < x_min) x_min = MM3.x_axis;
139
 
140
                if (MM3.y_axis > y_max) y_max = MM3.y_axis;
141
                else if (MM3.y_axis < y_min) y_min = MM3.y_axis;
142
 
143
                if (MM3.z_axis > z_max) z_max = MM3.z_axis;
144
                else if (MM3.z_axis < z_min) z_min = MM3.z_axis;
145
 
146
                if (!beeper)
147
                {
148
                        ROT_FLASH;
149
                        GRN_FLASH;
150
                        beeptime = 50;
151
                        beeper = 50;
152
                }
153
                beeper--;
154
 
155
                // Schleife mit 100 Hz
156
                timer = SetDelay(10);
157
                while(!CheckDelay(timer));
158
 
159
                // Wenn Gas zurück genommen wird, Kalibrierung mit 1/2 Sekunde Verzögerung beenden
160
                if (PPM_in[EE_Parameter.Kanalbelegung[K_GAS]] < 100) measurement--;
161
        }
162
 
163
        // Wertebereich der Achsen
164
        MM3_calib.X_range = (x_max - x_min);
165
        MM3_calib.Y_range = (y_max - y_min);
166
        MM3_calib.Z_range = (z_max - z_min);
167
 
168
        // Offset der Achsen
169
        MM3_calib.X_off = (x_max + x_min) / 2;
170
        MM3_calib.Y_off = (y_max + y_min) / 2;
171
        MM3_calib.Z_off = (z_max + z_min) / 2;
172
 
173
        // und im EEProm abspeichern
174
        eeprom_write_block((uint8_t *) &MM3_calib.X_off, &EEPromArray[EEPROM_ADR_MM3_CALIB], sizeof(MM3_calib)); //Bugfix für sporadisch falsche Zuweisung des Nick-Kanals durch Nick666 EEPROM Verwendung (110308)
175
}
176
 
177
 
178
//############################################################################
179
// Neigungskompensierung und Berechnung der Ausrichtung
180
int heading_MM3(void)
181
//############################################################################
182
{
183
        signed int sin_nick, cos_nick, sin_roll, cos_roll;
184
        long x_axis, y_axis, z_axis;
185
        long x_corr, y_corr;
186
        signed int heading;
187
        int8_t nicktilt,rolltilt;
188
        unsigned int div_faktor;
189
 
190
        div_faktor = (uint16_t)EE_Parameter.UserParam3 * 8;
191
 
192
        // Berechung von sinus und cosinus
193
        nicktilt = (IntegralNick/div_faktor);
194
        sin_nick = sin_i(nicktilt);
195
        cos_nick = cos_i(nicktilt);
196
 
197
        rolltilt = (IntegralRoll/div_faktor);
198
        sin_roll = sin_i(rolltilt);
199
        cos_roll = cos_i(rolltilt);
200
 
201
        // Offset
202
        x_axis = (MM3.x_axis - MM3_calib.X_off);
203
        y_axis = (MM3.y_axis - MM3_calib.Y_off);
204
        z_axis = (MM3.z_axis - MM3_calib.Z_off);
205
/*
206
        // Normierung Wertebereich
207
        if ((MM3_calib.X_range > MM3_calib.Y_range) && (MM3_calib.X_range > MM3_calib.Z_range))
208
        {
209
                y_axis = (y_axis * MM3_calib.X_range) / MM3_calib.Y_range;
210
                z_axis = (z_axis * MM3_calib.X_range) / MM3_calib.Z_range;
211
        }
212
        else if ((MM3_calib.Y_range > MM3_calib.X_range) && (MM3_calib.Y_range > MM3_calib.Z_range))
213
        {
214
                x_axis = (x_axis * MM3_calib.Y_range) / MM3_calib.X_range;
215
                z_axis = (z_axis * MM3_calib.Y_range) / MM3_calib.Z_range;
216
        }
217
        else //if ((MM3_calib.Z_range > MM3_calib.X_range) && (MM3_calib.Z_range > MM3_calib.Y_range))
218
        {
219
                x_axis = (x_axis * MM3_calib.Z_range) / MM3_calib.X_range;
220
                y_axis = (y_axis * MM3_calib.Z_range) / MM3_calib.Y_range;
221
        }
222
*/     
223
    // Neigungskompensierung
224
        x_corr = x_axis * cos_nick;
225
        x_corr += (((y_axis * sin_roll) / 4096) * sin_nick);
226
        x_corr -= (((z_axis * cos_roll) / 4096) * sin_nick);
227
        x_corr /= 4096;
228
 
229
        y_corr = y_axis * cos_roll;
230
        y_corr += z_axis * sin_roll;
231
        y_corr /= 4096;
232
 
233
        // Winkelberechnung
234
        heading = atan2_i(x_corr, y_corr);
235
 
236
        // Skalieren von +-180° auf 0-360°
237
        if (heading < 0) heading = -heading;
238
        else heading = 360 - heading;  
239
 
240
return (heading);
241
}