Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1198 - 1
 
2
/****************************************************************/
3
/*                                                                                                                              */
4
/*                               NG-Video 5,8GHz                                                        */
5
/*                                                                                                                              */
6
/*                              Copyright (C) 2011 - gebad                                              */
7
/*                                                                                                                              */
8
/*  This code is distributed under the GNU Public License               */
9
/*      which can be found at http://www.gnu.org/licenses/gpl.txt       */
10
/*                                                                                                                              */
11
/****************************************************************/
12
 
13
#include <avr/io.h>
14
#include <stdlib.h>
15
#include <avr/interrupt.h>
16
#include <avr/eeprom.h>
17
#include <util/delay.h>
18
 
19
#include "config.h"
20
#include "dogm.h"
21
#include "messages.h"
22
#include "ngvideo.h"
23
#include "menue.h"
24
#include "servo.h"
25
#include "tracking.c"
26
 
27
// LCD selbst definierte Sonderzeichen, RSSI-Balken und wi232 Empfang Daten im Flash 
28
// deshalb in dogm.c lcdPutc(pgm_read_byte(&lcdChr[i]));
29
static SpecialChr7_t lcdSpecialChr PROGMEM = {{32,32,16,16,16,16,32,32},\
30
                                                                                          {32,32,24,24,24,24,32,32},\
31
                                                                                          {32,32,28,28,28,28,32,32},\
32
                                              {32,32,30,30,30,30,32,32},\
33
                                              {32,32,31,31,31,31,32,32},\
34
                                              {6,8,20,19,20,8,6,32},\
35
                                                                                          {4,10,32,14,4,4,14,32}};      // Antenne und Imax
36
 
37
static SpecialChr8_t lcdSpecialChrLs PROGMEM = {{32,1,1,1,1,1,1,32},\
38
                                                                                                {32,31,1,1,1,1,31,32},\
39
                                                                                                {32,31,3,3,3,3,31,32},\
40
                                                                                                {32,31,7,7,7,7,31,32},\
41
                                                                                                {32,31,15,15,15,15,31,32},\
42
                                                                                                {32,31,31,31,31,31,31,32},\
43
                                                                                                {32,16,16,16,16,16,16,32},\
44
                                                                                                {32,31,32,32,32,32,31,32}};
45
 
46
static SpecialChr5_t lcdSpecialChrRs PROGMEM = {{32,1,1,1,1,1,1,32},\
47
                                                                                                {32,31,16,16,16,16,31,32},\
48
                                                                                                {32,31,24,24,24,24,31,32},\
49
                                                                                                {32,31,28,28,28,28,31,32},\
50
                                                                                                {32,31,30,30,30,30,31,32}};
51
 
52
/************************************************************************************/
53
/*  initialisiert den EEPROM mit default Werten, bzw. liest EEPROM gespeicherte         */
54
/*  Werte in gloabale Variablen.                                                                                                        */
55
/*      Parameter:                                                                                                                                              */
56
/*  uint8_t ep_reset   :0 = zwangsweises Rückstetzen auf default-Werte                          */
57
/*                                                                                                                                                                      */
58
/************************************************************************************/
59
void Init_EEPROM(uint8_t ep_reset)
60
{ char ver[sizeof(VERSION)];
61
  uint8_t eep_init;
62
 
63
  eep_init = eeprom_read_byte(&ep_eep_init);
64
  eeprom_read_block(&ver, &ep_version, sizeof(VERSION));
65
  _delay_ms(1);
66
 
67
  if ((eep_init != EEP_INITB) || (ep_reset == 0) || strcmp(VERSION, ver))
68
  {
69
     // nur bei Erstinitialisierung DOGM auf default 3,3V setzen
70
        if ((eep_init != EEP_INITB) || strcmp(VERSION, ver)){
71
          eeprom_write_byte(&ep_eep_init, EEP_INITB);
72
          eeprom_write_byte(&ep_dogm_vers, DOGM3V);
73
          eeprom_write_byte(&ep_contrast, CONTRAST3V);
74
      eeprom_write_block(&VERSION, &ep_version, sizeof(VERSION));
75
    }
76
        eeprom_write_byte(&ep_light_time, BACKGR_LIGHT_MAX);
77
        eeprom_write_byte(&ep_u_offset, U_OFFSET);
78
        eeprom_write_dword(&ep_u_min, U_MIN);
79
    eeprom_write_byte(&ep_channel, CHANNEL);
80
    eeprom_write_byte(&ep_av_source, AV_SOURCE);
81
        eeprom_write_byte(&ep_language, NO_LANGUAGE);
82
        for (uint8_t i = 0; i < CHANNEL_MAX; i++)
83
          eeprom_write_block(&udbm,&ep_udbm[i],sizeof(udbm_t));
84
    eeprom_write_byte(&ep_sIdxSteps, STEPS_255);
85
        eeprom_write_block(&servo[0],&ep_servo[0],sizeof(servo_t));
86
        eeprom_write_block(&servo[1],&ep_servo[1],sizeof(servo_t));
87
    eeprom_write_byte(&ep_servo_frame, SERVO_PERIODE);
88
    eeprom_write_byte(&ep_servo_nr, 0);                                 // nur bei Test-Servo
89
    eeprom_write_byte(&ep_single_step, SINGLE_STEP);    // nur bei Test-Servo
90
    eeprom_write_byte(&ep_repeat, REPEAT);                              // nur bei Test-Servo
91
    eeprom_write_byte(&ep_pause, PAUSE);                                // nur bei Test-Servo
92
    eeprom_write_byte(&ep_pause_step, PAUSE_STEP);              // nur bei Test-Servo
93
        eeprom_write_byte(&ep_tracking, TRACKING_MIN);
94
        eeprom_write_byte(&ep_track_hyst, TRACKING_HYSTERESE);
95
        eeprom_write_byte(&ep_track_tx, 0);
96
        eeprom_write_byte(&ep_baudrate, BAUDRATE);
97
        eeprom_write_block(&current,&ep_current,sizeof(current_t));
98
        eeprom_write_byte(&ep_akku_nr, AKKU_NR_MIN);
99
        for (uint8_t i = 0; i < AKKU_NR_MAX; i++)
100
          eeprom_write_block(&lipo,&ep_lipo[i],sizeof(lipo_t));
101
    eeprom_write_byte(&ep_mk_i_offset, MK_I_OFFSET);
102
    eeprom_write_byte(&ep_mk_i_faktor, MK_I_FAKTOR);
103
    eeprom_write_byte(&ep_mk_w_faktor, MK_W_FAKTOR);
104
        sIdxSteps = STEPS_255;
105
  }
106
  else
107
  {
108
        light_time = eeprom_read_byte(&ep_light_time);
109
        u_offset = eeprom_read_byte(&ep_u_offset);
110
        u_min = eeprom_read_dword(&ep_u_min);
111
    channel = eeprom_read_byte(&ep_channel);
112
    av_source = eeprom_read_byte(&ep_av_source);
113
        language = eeprom_read_byte(&ep_language);
114
        sIdxSteps = eeprom_read_byte(&ep_sIdxSteps);
115
        eeprom_read_block(&servo[0],&ep_servo[0],sizeof(servo_t));
116
        eeprom_read_block(&servo[1],&ep_servo[1],sizeof(servo_t));
117
        servo_frame = eeprom_read_byte(&ep_servo_frame);        // nur bei Test-Servo
118
        single_step = eeprom_read_byte(&ep_single_step);        // nur bei Test-Servo
119
        repeat = eeprom_read_byte(&ep_repeat);                          // nur bei Test-Servo
120
        pause = eeprom_read_byte(&ep_pause);                            // nur bei Test-Servo
121
        pause_step = eeprom_read_byte(&ep_pause_step);          // nur bei Test-Servo
122
    tracking = eeprom_read_byte(&ep_tracking);
123
    track_hyst = eeprom_read_byte(&ep_track_hyst);
124
        track_tx = eeprom_read_byte(&ep_track_tx);
125
        baudrate = eeprom_read_byte(&ep_baudrate);
126
        eeprom_read_block(&current,&ep_current,sizeof(current_t));
127
        akku_nr = eeprom_read_byte(&ep_akku_nr);
128
        eeprom_read_block(&lipo,&ep_lipo[akku_nr],sizeof(lipo_t));
129
        mk_i_offset = eeprom_read_byte(&ep_mk_i_offset);
130
        mk_i_faktor = eeprom_read_byte(&ep_mk_i_faktor);
131
        mk_w_faktor = eeprom_read_byte(&ep_mk_w_faktor);
132
  }
133
  dogm_vers = eeprom_read_byte(&ep_dogm_vers);
134
  contrast = eeprom_read_byte(&ep_contrast);
135
  hyst_u_min = u_min;
136
  sw_avx = av_source;
137
  for (uint8_t i = 0; i < SERVO_NUM_CHANNELS; i++) {
138
        servoSet_rev(i, servo[i].rev);
139
        servoSet_min(i, servo[i].min);
140
        servoSet_max(i, servo[i].max);
141
        servoSet_mid(i, servo[i].mid);
142
  }
143
  // Vorberechnung von ServoChannels[channel].duty
144
  servoSetDefaultPos(); // Ausgangsstellung beider Servos
145
  coldstart = 1;
146
  USART_Init_Baudrate();
147
  USART_RX_Mode(tracking);
148
}
149
 
150
void servoSetDefaultPos(void)
151
{
152
  servoSetPosition(SERVO_PAN, ServoSteps()/2);  // Ausgangsstellung SERVO_PAN
153
  servoSetPosition(SERVO_TILT, 0);                              // Ausgangsstellung SERVO_TILT
154
}
155
 
156
void USART_Init_Baudrate(void)
157
{
158
  if (tracking == TRACKING_MKCOCKPIT)
159
    USART_Init(baud[baudrate]);
160
  else
161
    USART_Init(baud[6]);        //57600
162
}
163
 
164
/************************************************************************************/
165
/*  Zeitanzeige                                                                                                                                         */
166
/*                                                                                                                                                                      */
167
/************************************************************************************/
168
 
169
uint32_t TimeBase60(char *str, uint32_t time, uint8_t idx_a)
170
{ uint32_t tmp;
171
 
172
  tmp = time % 60;
173
  time /= 60;
174
  for (int8_t i = idx_a; i >= (idx_a - 1); i--) {
175
    str[i] = (tmp % 10) + '0';
176
        tmp /= 10;
177
  }
178
  return(time);
179
}
180
 
181
void Displ_TimeMS(int32_t time)
182
{ char str[7];
183
 
184
  str[6] = '\0';
185
  if (time < 0) {
186
    time = abs(time);
187
        str[0] = '-';
188
  }
189
  else
190
    str[0] = ' ';
191
  time = TimeBase60(str, time, 5);
192
  TimeBase60(str, time, 2);
193
  str[3] = ':';
194
  lcdPuts(str);
195
}
196
 
197
/************************************************************************************/
198
/*  setzt Flag für 3,3V oder 5V DOGM                                                                                            */
199
/*      Parameter:                                                                                                                                              */
200
/*  uint8_t dogm        :Version                                                                                                                */
201
/*                                                                                                                                                                      */
202
/************************************************************************************/
203
void Set_DOGM_Version(void)
204
{
205
  if(dogm_vers == DOGM5V) {
206
    dogm_vers = DOGM3V;
207
        contrast = CONTRAST3V;
208
  }
209
  else {
210
    dogm_vers = DOGM5V;
211
        contrast = CONTRAST5V;
212
  }
213
  eeprom_write_byte(&ep_dogm_vers, dogm_vers);
214
  eeprom_write_byte(&ep_contrast, contrast);
215
}
216
 
217
/************************************************************************************/
218
/*  setzt den RX-Kanal von 1 bis 7                                                                                                      */
219
/*      Parameter:                                                                                                                                              */
220
/*  uint8_t channel     :Kanal                                                                                                                  */
221
/*                                                                                                                                                                      */
222
/************************************************************************************/
223
void Set_Channel(uint8_t channel)
224
{ uint8_t tmp;
225
 
226
  channel--;
227
  tmp = channel & 0b00000111;   // Kanal 1 bis 7 Werte 0 bis 6 setzen
228
  PORTA |= tmp;
229
  PORTB |= tmp;
230
  tmp = channel | 0b11111000;
231
  PORTA &= tmp;
232
  PORTB &= tmp;
233
  wudbm = RSSI_Calc_UdBm(pbar_udbm); // Vergleichstabelle für dBm-Balken berechnen
234
}
235
 
236
/************************************************************************************/
237
/*  schaltet den MUX auf AV1 oder AV2 ohne Darstellung und en-/disabled Interrupt       */
238
/*  wird nur in main.c (Initialisierung) und Menü Sourceumschaltung eingesetzt          */
239
/*  deswegen cli() und sei() nur in Menu_AV_Source(void)                                                        */
240
/*  Parameter:                                                                                                                                          */
241
/*  uint8_t src :0-AV1, 1-AV2                                                                                                           */
242
/*                                                                                                                                                                      */
243
/************************************************************************************/
244
void SetMux0(void) {
245
  SET_MUX_0;
246
  mux_X = 0;    // für Erkennung RX Zeitzähler
247
}
248
 
249
void SetMux1(void) {
250
  SET_MUX_1;
251
  mux_X = 1;    // für Erkennung RX Zeitzähler
252
}
253
 
254
uint8_t Set_AV_Source(uint8_t src)
255
{
256
  switch(src) {
257
    case AV1:           CLEAR_INT10;    // Interrupt für Sync ausschalten
258
                                        SetMux0();
259
                                        break;
260
    case AV2:           CLEAR_INT10;    // Interrupt für Sync ausschalten
261
                                        SetMux1();
262
                                        break;
263
    case DIVERSITY: SET_INT10;          // External Interrupt Mask Register ein
264
                                        SetMux0();
265
                                        break;
266
  }
267
  return(src);
268
}
269
 
270
 
271
/**************************************************************/
272
/*                                                                                                                        */
273
/*                     LCD-Backlight                                              */
274
/*                                                                                                                        */
275
/**************************************************************/
276
 
277
void lcdSet_BackgrLight_Off(void)
278
{
279
  backgr_light = OFF;
280
  lcdBacklightOff();
281
}
282
 
283
void lcd_BackgrLight_On(void)
284
{ // ...&& (light_count < light_time)) ==> sonst wird Beleuchtung laufend wieder eingeschaltet
285
  if ((backgr_light == OFF) && (light_time > BACKGR_LIGHT_MIN) && (light_count < light_time)) {
286
    cli();
287
        light_count = 0;
288
        sei();
289
        backgr_light = ON;
290
        lcdBacklightOn();
291
  }
292
}
293
 
294
void lcd_BackgrLight(void)
295
{
296
  if (backgr_light == ON) {                                     // nur wenn Beleuchtung an
297
    if (light_time == BACKGR_LIGHT_MIN)         // Hintergrundbeleuchtung immer aus?
298
      lcdSet_BackgrLight_Off();
299
        else
300
          if (light_time < BACKGR_LIGHT_MAX) {  // Hintergrundbeleuchtung immer an?
301
            cli();
302
                light_count++;
303
                sei();
304
                if (light_count >= light_time) lcdSet_BackgrLight_Off();
305
          }
306
  }
307
}
308
 
309
/**************************************************************/
310
/*                                                                                                                        */
311
/*                           ADC                                                      */
312
/*                                                                                                                        */
313
/*      http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial  */
314
/*                                                                                                                        */
315
/**************************************************************/
316
 
317
void ADC_Init(void)
318
{
319
  uint16_t result;
320
 
321
  ADMUX = (0<<REFS1) | (1<<REFS0);              // AVcc als Referenz benutzen, da an AREF 4,8 V
322
  ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);        // Frequenzvorteiler Prescaler 128
323
  ADCSRA |= (1<<ADEN);                                  // ADC aktivieren
324
 
325
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
326
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
327
 
328
  ADCSRA |= (1<<ADSC);                                  // eine ADC-Wandlung 
329
  while (ADCSRA & (1<<ADSC) ) {}                // auf Abschluss der Konvertierung warten
330
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
331
     Wandlung nicht übernommen. */
332
  result = ADCW;
333
}
334
 
335
/* ADC Einzelmessung */
336
uint16_t ADC_Read( uint8_t channel )
337
{
338
  // Kanal waehlen, ohne andere Bits zu beeinflußen
339
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
340
  ADCSRA |= (1<<ADSC);                          // eine Wandlung "single conversion"
341
  while (ADCSRA & (1<<ADSC) ) {}                // auf Abschluss der Konvertierung warten
342
  return ADCW;                                  // ADC auslesen und zurückgeben
343
}
344
 
345
/* ADC Mehrfachmessung mit Mittelwertbbildung */
346
adc_avg_t ADC_Read_Avg(uint8_t channel0, uint8_t channel1, uint16_t average )
347
{ adc_avg_t result;
348
  uint32_t u0 = 0;
349
  uint32_t u1 = 0;
350
 
351
  for (uint16_t i = 0; i < average; ++i){
352
    u0 += ADC_Read( channel0 );
353
    u1 += ADC_Read( channel1 );
354
        _delay_ms(1);
355
  }
356
  result.u0 = u0/average;
357
  result.u1 = u1/average;
358
  return(result);
359
}
360
 
361
/**************************************************************/
362
/*                                                                                                                        */
363
/*                         Beeper                                                         */
364
/*                                                                                                                        */
365
/**************************************************************/
366
 
367
void Beep(uint8_t time)
368
{
369
  PORTB |= (1<<BEEPER);
370
  _delay_ms(time);
371
  PORTB &= ~(1<<BEEPER);
372
}
373
 
374
void Double_Beep(uint8_t time, uint8_t pause)
375
{
376
  Beep(time);
377
  _delay_ms(pause);
378
  Beep(time);
379
}
380
 
381
/**************************************************************/
382
/*                                                                                                                        */
383
/*                        U-Batterie                                              */
384
/*                                                                                                                        */
385
/**************************************************************/
386
 
387
/* Funktion zur Umwandlung einer vorzeichenbehafteten Integer
388
   32-Bit "Festkomma-Zahl"(gedachtes Komma in Integer) in einen String
389
   vereinfacht Variablenübergabe funktion change_value(uint32_t x),
390
   kein printf, double oder float
391
   siehe http://www.mikrocontroller.net/articles/Festkommaarithmetik
392
   Vorz ==> 0 kein '-' trotz negativer Zahl, 1 wenn kein '-' bleibt Stelle leer
393
   len max 11, Vorzeichen wird nicht mitgezählt aber Komma; Vorz 0 oder 1
394
   Festkomma ==> Position der Kommastelle bei Integerwert
395
   Nachkomma ==> angezeigte Nachkommastellen bei Festkomma
396
 
397
   makefile derzeit somit auch ohne! Minimalistic printf version
398
   Achtung: keine Fehlerprüfung! */
399
 
400
char* my_itoa(int32_t zahl, uint8_t Vorz, uint8_t len, uint8_t Festkomma, uint8_t Nachkomma)
401
{
402
  int8_t i;
403
  uint8_t neg = 0;
404
  char Komma;                                   // Sprachversion Deutsch ',' andere '.'
405
  static char str[13];
406
 
407
  Komma = Msg(MSG_KOMMA)[0];    // [0] nur als Char, sonst wäre es ein String
408
  if( zahl < 0 ) {                              // ist die Zahl negativ?
409
    zahl = -zahl;
410
    neg = 1;
411
  }
412
  if (Vorz) str[0] = '0'; else len--;
413
  str[len+1]='\0';                              // String Terminator
414
  if (Nachkomma > 0) Nachkomma++;
415
 
416
  for(i=len; i>=Vorz; i--) {
417
    if ((len - Festkomma == i) && (Festkomma > 0))
418
                str[i]= Komma;                  // bei Bedarf Komma einfügen
419
        else {                                          // Integer-Dezimalumrechnung
420
          str[i]=(zahl % 10) +'0';      // Modulo rechnen, dann den ASCII-Code von '0' addieren
421
      zahl /= 10;
422
        }
423
        // festgelegt Festkomma aber verkleinern der Anzeige Mantisse
424
        if ((Festkomma > 0) && (Festkomma >= Nachkomma) && (len - Festkomma + Nachkomma == i)) str[i]= '\0';
425
  }
426
  i=0;
427
  while  ((str[i+1] != Komma) && (i < len))  {
428
        // Vorzeichen unmittelbar vor Zahl schreiben
429
        if((Vorz) && (neg) && ((str[i+1] != '0') || (str[i+2] == Komma))) str[i] = '-';
430
    // eine 0 vor Komma lassen
431
        if(str[i] == '0') str[i++] = ' '; else break; // Vornullen entfernen
432
  }
433
  return(str);
434
}
435
 
436
// uint32_t u, da bei Displ_Fnct[fu_index](val) der größte Wert UBat gleich 32 Bit 
437
void Displ_1Nk(uint32_t u)
438
{
439
  // 0 kein Vorzeichen, 5 => 2 Ziffern vor Komma + 1 Komma + 2 Mantisse, Festkomma, eine Ziffer Nachkomma darstellen
440
  lcdPuts(my_itoa(u,0,5,2,1));
441
}
442
 
443
void Displ_U_2Nk(uint32_t u)
444
{
445
  lcdPuts(my_itoa(u,0,5,2,2));
446
  lcdPutc('V');
447
}
448
 
449
// uint8_t beep_timer :Akku-leer-Beeper nur mit Task_0_1()-Intervalle bei Menü-Rücksprung
450
uint32_t U_Messen_cmp(uint8_t beep_timer)
451
{ uint32_t ubat;
452
  static struct
453
  { uint8_t time;
454
        uint8_t count;
455
  } beep_low;
456
 
457
/*       ubat = ((ADC_Read(VBAT) * Vref * (R104 + R103)) /(1024 * R103)) + UD10 (UD10 ist Offset)
458
         Verhältniswert * 100 *8192 ( Verhältniswert = realer Korrekturwert;
459
         mal 100 da alle Werte 2 Nachkommastellen berücksichtigt, aber ohne gerechnet wird
460
         mal 8192 => ohne Bruch gerechnet aber dabei mehr Kommastellen berücksichtigt) */
461
  ubat = (ADC_Read(VBAT) * (uint64_t)43504 + (uint64_t)u_offset * 8192)/ 8192;
462
  if ( ubat <= hyst_u_min )
463
  {
464
    if (bat_low != 0) {         // nicht laufend Display neu schreiben
465
          hyst_u_min = u_min + 20;      // 200mV Hysterese - beruhigt Anzeige
466
          if (tracking == TRACKING_GPS)
467
            store_LipoData();           // wenigstens von GPS-Statisik UsedCapacity, time_on usw. speichern
468
          lcdClear();
469
          lcdPuts(Msg(MSG_ACCU_LOW));
470
          bat_low = 0;
471
          Beep(BEEPBAT);
472
          // da derzeit Fkt. aller 500ms aufgerufen, mit 2 Min Abstand beginnen
473
          beep_low.time = BEEP_LOW_TIME;
474
          beep_low.count = 0;
475
        }
476
        // Akku leer, in immer kürzeren Intervallen Beep
477
        if ((beep_timer == 1) && (beep_low.count++ >= beep_low.time)){
478
          Beep(BEEPBAT);
479
          if (beep_low.time > 2)
480
            beep_low.time /= 2;
481
          beep_low.count = 0;
482
        }
483
  }
484
  else {
485
    if (hyst_u_min > u_min) {   // falls Anzeige von Batterie leer
486
          bat_low = 1;                          // und zurück geschaltet wird,
487
          hyst_u_min = u_min;           // dann Main_Disp wieder darstellen
488
          Displ_Main_Disp();
489
        }
490
  }
491
  return(ubat);
492
}
493
 
494
void Displ_VBat(void) // da u_offset globale Variable
495
{ uint32_t ubat;
496
 
497
  ubat = U_Messen_cmp(ENABLE_BTIMER);
498
  if (bat_low != 0) { // würde sonst Anzeige Akku leer überschreiben
499
    lcdGotoXY(11, 0);
500
    Displ_1Nk(ubat);
501
  }
502
}
503
 
504
 
505
/**************************************************************/
506
/*                                                                                                                        */
507
/*                          RSSI                                                          */
508
/*                                                                                                                        */
509
/**************************************************************/
510
 
511
/* RSSI Werte Korrekturfaktor berechnen */
512
uint16_t  RSSI_Calc_Korr(uint8_t nchannel, uint16_t u0, uint16_t u1)
513
{ uint16_t u_max;
514
 
515
  // immer nur den kleineren Wert vergrößern
516
  if (u0 < u1) {
517
    udbm.korr_1 = (((uint32_t)u1 * UDBM_KORR_FA) / u0); // nur mit Integer und 2 Nachkommastellen rechnen
518
        udbm.korr_2 = UDBM_KORR_FA;
519
        u_max = u1;
520
  }
521
  else {
522
    udbm.korr_2 = (((uint32_t)u0 * UDBM_KORR_FA) / u1); // nur mit Integer und 2 Nachkommastellen rechnen
523
    udbm.korr_1 = UDBM_KORR_FA;
524
        u_max = u0;
525
  }
526
  eeprom_write_word(&ep_udbm[nchannel - 1].korr_1, udbm.korr_1);
527
  eeprom_write_word(&ep_udbm[nchannel - 1].korr_2, udbm.korr_2);
528
  return(u_max);
529
}
530
 
531
void Displ_Calibr_Aktiv(uint8_t nchannel)
532
{ char str[LCD_COLS + 1];
533
  uint8_t l;
534
  uint8_t zle = 1;
535
 
536
  // Anzeige für nur einen Kanal oder wenn in Schleife, Kanalnr. des z.Z. kalbrierenden Kanals
537
  lcdClear();
538
  Displ_Str_mid(Msg(MSG_CALIBRATION),0);
539
  if (nchannel > 0) {                   // Anzeige aller RX-Kanäle min. kalibrieren?
540
    strcpy(str, Msg(MSG_RX_CHANNEL));
541
    strcat(str, ": ");
542
    l = strlen(str);
543
    str[l] = nchannel + 0x30;   // gerade zu kalibrierender Kanal, String zusammen stellen
544
    str[++l] = '\0';
545
    Displ_Str_mid(str,1);
546
        zle = 2;
547
  }
548
  Displ_Str_mid(Msg(MSG_RUNNING),zle);
549
}
550
 
551
void delay_ms100x(uint8_t delay)
552
{
553
  for ( uint8_t i=0; i<delay; i++)
554
    _delay_ms(100);
555
}
556
 
557
void Displ_Error_TX(uint8_t message)
558
{
559
  lcdClear();
560
  Displ_Str_mid(Msg(MSG_ERROR), 0);
561
  Displ_Str_mid(Msg(MSG_TX_NOT), 1);
562
  Displ_Str_mid(Msg(message), 2);
563
  delay_ms100x(30);
564
}
565
 
566
uint8_t RSSI_Min_Calibrate(uint8_t nchannel, uint16_t *pbar_udbm)
567
{ adc_avg_t rssi_avg;
568
  uint16_t udbm_min;
569
  uint8_t  one_channel = !nchannel;
570
 
571
  Displ_Calibr_Aktiv(nchannel);
572
  if (one_channel) nchannel = channel;
573
  rssi_avg = ADC_Read_Avg(RSSI0, RSSI1, 1000 ); //1000 Wiederholungen mit Mittelwertbildung
574
  // Plausibilitätsprüfung ob Sender ausgeschaltet
575
  if (rssi_avg.u0 + rssi_avg.u1 > 500) {
576
    udbm_min = RSSI_Calc_Korr(nchannel, rssi_avg.u0, rssi_avg.u1); // ist real die größere Spannung, aber der kleinere dbm Wert
577
    eeprom_write_word(&ep_udbm[nchannel - 1].min, udbm_min);
578
        if (one_channel) {
579
          Double_Beep(DBEEPWR, DBEEPWRP);
580
          wudbm = RSSI_Calc_UdBm(pbar_udbm);
581
        }
582
  }
583
  else
584
    if (one_channel)
585
          Displ_Error_TX(MSG_TX_OFF);
586
        else
587
          return(0);    // Fehleranzeige wird in menue.c gesammelt ausgewertet
588
  return(1);            // kein Fehler, da bei einen Kanal bereits Fehler angezeigt wurde
589
}
590
 
591
void RSSI_Max_Calibrate(uint16_t *pbar_udbm)
592
{ adc_avg_t rssi_avg;
593
  uint16_t udbm_max;
594
 
595
  Displ_Calibr_Aktiv(0);
596
  rssi_avg = ADC_Read_Avg(RSSI0, RSSI1, 1000 ); //1000 Wiederholungen mit Mittelwertbildung
597
  // Plausibilitätsprüfung ob Sender in der Nähe eingeschaltet
598
  if (rssi_avg.u0 + rssi_avg.u1 < 400) {
599
    udbm_max = RSSI_Calc_Korr(channel, rssi_avg.u0, rssi_avg.u1); // ist real die kleinere Spannung, aber der größere dbm Wert
600
    eeprom_write_word(&ep_udbm[channel - 1].max, udbm_max);
601
        Double_Beep(DBEEPWR, DBEEPWRP);
602
    wudbm = RSSI_Calc_UdBm(pbar_udbm);
603
  }
604
  else Displ_Error_TX(MSG_TX_ON);
605
}
606
 
607
// Vergleichstabelle für RSSI-Bargraph berechnen, vermeidet laufend gleiche Berechnung
608
uint8_t RSSI_Calc_UdBm(uint16_t *pbar_udbm)
609
{ uint8_t n;
610
 
611
  eeprom_read_block(&udbm,&ep_udbm[channel - 1],sizeof(udbm_t));
612
  // -15 um Ende dBm Skala sicher zu erreichen; ohne verfeinerten Bahrgraph war Wert -3
613
  n = (udbm.min - udbm.max -15)/11;
614
  for (uint8_t i = 0; i < 12; i++)
615
    pbar_udbm[i] = (udbm.min - i * n);
616
  return(n / 5); // da 5 Pixel Breite pro Display-Zeichen; Anzeigebalken pro Pixel differenzieren
617
}
618
 
619
void Displ_RSSI_Bargraph(uint16_t *pbar_udbm, uint8_t wudbm, uint16_t uadc)
620
{ char charBar[12];
621
  uint8_t i;
622
  int8_t lz = 11;
623
  char b = 4;
624
 
625
  // Balken zeichnen - udbm
626
  for (i = 0; i < 12; i++) {
627
        if ((b != ' ') && (uadc > pbar_udbm[i])) {
628
          b  = ' ';
629
          lz = i - 1;
630
        }
631
    charBar[i] = b;
632
  }
633
  if (lz >= 0) {
634
        charBar[lz] = (pbar_udbm[lz] - uadc) / wudbm ;// Anzeigebalken pro Pixel-"Breite" differenzieren
635
        // bei Teilung 4 wäre richtig und keine Korr. erforderlich, so aber gleichmäßigerer Balkenverlauf
636
    if (charBar[lz] > 4) charBar[lz] = 4;
637
  }
638
  for (i = 0; i < 12; i++)// lcdPuts (ist auch for) funktioniert hier nicht, da Char'\0' für Zeichen auch Stringende
639
    lcdPutc(charBar[i]);
640
}
641
 
642
uint8_t RSSI_Diversity(uint8_t src, uint16_t *pbar_udbm, uint8_t visible)
643
{ uint16_t u0, u1;
644
  static uint8_t div_flag, ret_div_flag;
645
  char marker;
646
 
647
  u0 = (ADC_Read(RSSI0) * (uint32_t)udbm.korr_1)/UDBM_KORR_FA;
648
  u1 = (ADC_Read(RSSI1) * (uint32_t)udbm.korr_2)/UDBM_KORR_FA;
649
 
650
  // falls beide RX gleich gut/schlecht synchronisieren
651
  // Achtung! Niedrigere Spannung - größere Feldstärke
652
  if (src == DIVERSITY) {
653
    if (u0 < u1) {
654
          ret_div_flag = AV1;
655
          if ((vscount0 == 255) && (vscount1 == 255)) SetMux0();        // egal wann RSSI schaltet ==> es ist kein sync vorhanden
656
    }
657
    else {
658
          ret_div_flag = AV2;
659
          if ((vscount0 == 255) && (vscount1 == 255)) SetMux1();        // egal wann RSSI schaltet ==> es ist kein sync vorhanden
660
    }
661
  }
662
  else ret_div_flag = src; // sonst leerer Returnwert
663
 
664
  if (visible) {
665
    if (src == DIVERSITY) {
666
          // Synchronisation vorrangig zur Feldstärke
667
      if ((vsync0 != vsync1) && ((vscount0 & vscount1) < 255)) {
668
            // ist nur zur Anzeige - Sync-MUX wird über Interrupt gesteuert
669
        if (vsync0 == 0) {
670
              div_flag = AV1;
671
            }
672
            else {
673
              div_flag = AV2;
674
            }
675
            marker = MARKER_SYNC;
676
      }
677
          else {
678
            div_flag = ret_div_flag;
679
                marker = MARKER_RSSI;
680
          }
681
    }
682
    else marker = MARKER_AV;
683
        // wäre unschön - keine RSSI-Anzeige, aber Marker springt
684
        if ((u0 > pbar_udbm[0]) && (u1 > pbar_udbm[0])) marker = ' ';
685
        lcdGotoXY(2, 1);
686
    Displ_RSSI_Bargraph(pbar_udbm, wudbm, u0);
687
    lcdGotoXY(2, 2);
688
        Displ_RSSI_Bargraph(pbar_udbm, wudbm, u1);
689
        if (src == DIVERSITY) Displ_AV_Mark(div_flag, marker);
690
  }
691
  return(ret_div_flag);
692
}
693
 
694
/**************************************************************/
695
/*                                                                                                                        */
696
/*      Diversity v-Synchronisation Interruptroutinen             */
697
/*                                                                                                                        */
698
/**************************************************************/
699
 
700
/* Impulszähler für V-Synchronisation 0 und 1
701
   wird durch Interrupt des jewiligen vSync einzeln zurückgesetzt. 8-bit Timer*/
702
ISR(TIMER2_OVF_vect)
703
{
704
  TCNT2 = (int8_t)(int16_t)-(F_CPU / 64 * 500e-6);  // preload
705
  if (vscount0 < 255) ++vscount0; // Überlauf von vscount vermeiden
706
  if (vscount1 < 255) ++vscount1; // Überlauf von vscount vermeiden
707
  if (rx_timeout < RX_TIME_END) ++rx_timeout; // veranlasst bei GPS-Tracking MK Datensatz senden
708
  if ((mk_timer) && (lipo.time_on < T2PROD_M59S59)) ++lipo.time_on; // T2PRODM59S59 = 3599 * 4000
709
  if ((tracking == TRACKING_GPS) && (MK_Motor_run)) { // MK-Motoren müssen laufen
710
    if (mux_X)
711
          rxcount1++;   // kein Test auf Überlauf ==> Counter groß genug - bis Stunden
712
        else
713
          rxcount0++;
714
  }
715
}
716
 
717
/* Messung von Impulsabstand v-Synchronisation 0
718
   Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */
719
ISR(INT0_vect)
720
{
721
  if ((vscount0 >= 79) && (vscount0 <= 81))
722
    vsync0 = 0;
723
  else {
724
    vsync0 = 1;
725
        if (vsync1 == 0)
726
          SetMux1();
727
  }
728
  if (vsync0 == vsync1) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI 
729
    if (sw_avx == AV1) {
730
          SetMux0();
731
        }
732
        else
733
          SetMux1();
734
  }
735
  vscount0 = 0;
736
}
737
 
738
/* Messung von Impulsabstand v-Synchronisation 1
739
   Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */
740
ISR(INT1_vect)
741
{
742
 if ((vscount1 >= 79) && (vscount1 <= 81))
743
    vsync1 = 0;
744
  else {
745
    vsync1 = 1;
746
    if (vsync0 == 0)
747
          SetMux0();
748
  }
749
  if (vsync0 == vsync1) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI
750
    if (sw_avx == AV1) {
751
          SetMux0();
752
        }
753
        else
754
          SetMux1();
755
  }
756
  vscount1 = 0;
757
}
758
 
759
/**************************************************************/
760
/*                                                                                                                        */
761
/*                          Tasks                                                         */
762
/*        ermöglicht unterschiedliche Zeiten f. UBat, Sync...     */
763
/*                                                                                                                        */
764
/**************************************************************/
765
 
766
void Task_0_1(void)
767
{
768
  if (task_timer0_1) {
769
    cli();
770
        task_timer0_1 = 0;
771
        sei();
772
    Displ_VBat();
773
   }
774
 }
775
 
776
void Task_0_2(void)
777
{
778
  if (task_timer0_2) {
779
    cli();
780
        task_timer0_2 = 0;
781
        sei();
782
        sw_avx = RSSI_Diversity(av_source, pbar_udbm, bat_low);
783
  }
784
}
785
 
786
void Task_0_3(void)
787
{
788
  if (task_timer0_3) {
789
    cli();
790
        task_timer0_3 = 0;
791
        sei();
792
    sw_avx = RSSI_Diversity(av_source, pbar_udbm, 0);
793
        if (tracking == TRACKING_MKCOCKPIT) Tracking_MKCockpit();
794
  }
795
}
796
 
797
void Task_0_4(void)
798
{
799
  if (task_timer0_4) {
800
    cli();
801
        task_timer0_4 = 0;
802
        sei();
803
    if (tracking == TRACKING_GPS) Tracking_GPS();
804
        if (gps_display == GPS_RX_COUNT) Displ_RX_Time(); // aktualisieren der Empfängerzeiten
805
  }
806
}
807
 
808
void Task_0_5(void)                     // Nur für Tasten-Beschleunigung/-Wiederholrate! Hintergrund: Rücksetzung.
809
{                                                       // Hintergrund: Rücksetzung. Beginnt nach jeden Tastendruck neu zu zählen.
810
  lcd_BackgrLight_On();         // muss bei beliebiger Taste sofort eingeschaltet werden
811
  if (task_timer0_5) {
812
    cli();
813
        task_timer0_5 = 0;
814
        sei();
815
        lcd_BackgrLight();
816
  }
817
}
818
 
819
void Tasks_unvisible(void)
820
{
821
  Task_0_3();
822
  Task_0_4();
823
  Task_0_5();
824
  if (tracking == TRACKING_RSSI) Tracking_RSSI();
825
}