Blame |
Last modification |
View Log
| RSS feed
/****************************************************************/
/* */
/* NG-Video 5,8GHz */
/* */
/* Copyright (C) 2011 - gebad */
/* */
/* This code is distributed under the GNU Public License */
/* which can be found at http://www.gnu.org/licenses/gpl.txt */
/* */
/****************************************************************/
#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include "config.h"
#include "dogm.h"
#include "messages.h"
#include "ngvideo.h"
#include "menue.h"
#include "servo.h"
#include "tracking.c"
// LCD selbst definierte Sonderzeichen, RSSI-Balken und wi232 Empfang Daten im Flash
// deshalb in dogm.c lcdPutc(pgm_read_byte(&lcdChr[i]));
static SpecialChr7_t lcdSpecialChr PROGMEM
= {{32,32,16,16,16,16,32,32},\
{32,32,24,24,24,24,32,32},\
{32,32,28,28,28,28,32,32},\
{32,32,30,30,30,30,32,32},\
{32,32,31,31,31,31,32,32},\
{6,8,20,19,20,8,6,32},\
{4,10,32,14,4,4,14,32}}; // Antenne und Imax
static SpecialChr8_t lcdSpecialChrLs PROGMEM
= {{32,1,1,1,1,1,1,32},\
{32,31,1,1,1,1,31,32},\
{32,31,3,3,3,3,31,32},\
{32,31,7,7,7,7,31,32},\
{32,31,15,15,15,15,31,32},\
{32,31,31,31,31,31,31,32},\
{32,16,16,16,16,16,16,32},\
{32,31,32,32,32,32,31,32}};
static SpecialChr5_t lcdSpecialChrRs PROGMEM
= {{32,1,1,1,1,1,1,32},\
{32,31,16,16,16,16,31,32},\
{32,31,24,24,24,24,31,32},\
{32,31,28,28,28,28,31,32},\
{32,31,30,30,30,30,31,32}};
/************************************************************************************/
/* initialisiert den EEPROM mit default Werten, bzw. liest EEPROM gespeicherte */
/* Werte in gloabale Variablen. */
/* Parameter: */
/* uint8_t ep_reset :0 = zwangsweises Rückstetzen auf default-Werte */
/* */
/************************************************************************************/
void Init_EEPROM
(uint8_t ep_reset
)
{ char ver
[sizeof(VERSION
)];
uint8_t eep_init
;
eep_init
= eeprom_read_byte
(&ep_eep_init
);
eeprom_read_block
(&ver
, &ep_version
, sizeof(VERSION
));
_delay_ms
(1);
if ((eep_init
!= EEP_INITB
) || (ep_reset
== 0) || strcmp(VERSION
, ver
))
{
// nur bei Erstinitialisierung DOGM auf default 3,3V setzen
if ((eep_init
!= EEP_INITB
) || strcmp(VERSION
, ver
)){
eeprom_write_byte
(&ep_eep_init
, EEP_INITB
);
eeprom_write_byte
(&ep_dogm_vers
, DOGM3V
);
eeprom_write_byte
(&ep_contrast
, CONTRAST3V
);
eeprom_write_block
(&VERSION
, &ep_version
, sizeof(VERSION
));
}
eeprom_write_byte
(&ep_light_time
, BACKGR_LIGHT_MAX
);
eeprom_write_byte
(&ep_u_offset
, U_OFFSET
);
eeprom_write_dword
(&ep_u_min
, U_MIN
);
eeprom_write_byte
(&ep_channel
, CHANNEL
);
eeprom_write_byte
(&ep_av_source
, AV_SOURCE
);
eeprom_write_byte
(&ep_language
, NO_LANGUAGE
);
for (uint8_t i
= 0; i
< CHANNEL_MAX
; i
++)
eeprom_write_block
(&udbm
,&ep_udbm
[i
],sizeof(udbm_t
));
eeprom_write_byte
(&ep_sIdxSteps
, STEPS_255
);
eeprom_write_block
(&servo
[0],&ep_servo
[0],sizeof(servo_t
));
eeprom_write_block
(&servo
[1],&ep_servo
[1],sizeof(servo_t
));
eeprom_write_byte
(&ep_servo_frame
, SERVO_PERIODE
);
eeprom_write_byte
(&ep_servo_nr
, 0); // nur bei Test-Servo
eeprom_write_byte
(&ep_single_step
, SINGLE_STEP
); // nur bei Test-Servo
eeprom_write_byte
(&ep_repeat
, REPEAT
); // nur bei Test-Servo
eeprom_write_byte
(&ep_pause
, PAUSE
); // nur bei Test-Servo
eeprom_write_byte
(&ep_pause_step
, PAUSE_STEP
); // nur bei Test-Servo
eeprom_write_byte
(&ep_tracking
, TRACKING_MIN
);
eeprom_write_byte
(&ep_track_hyst
, TRACKING_HYSTERESE
);
eeprom_write_byte
(&ep_track_tx
, 0);
eeprom_write_byte
(&ep_baudrate
, BAUDRATE
);
eeprom_write_block
(¤t
,&ep_current
,sizeof(current_t
));
eeprom_write_byte
(&ep_akku_nr
, AKKU_NR_MIN
);
for (uint8_t i
= 0; i
< AKKU_NR_MAX
; i
++)
eeprom_write_block
(&lipo
,&ep_lipo
[i
],sizeof(lipo_t
));
eeprom_write_byte
(&ep_mk_i_offset
, MK_I_OFFSET
);
eeprom_write_byte
(&ep_mk_i_faktor
, MK_I_FAKTOR
);
eeprom_write_byte
(&ep_mk_w_faktor
, MK_W_FAKTOR
);
sIdxSteps
= STEPS_255
;
}
else
{
light_time
= eeprom_read_byte
(&ep_light_time
);
u_offset
= eeprom_read_byte
(&ep_u_offset
);
u_min
= eeprom_read_dword
(&ep_u_min
);
channel
= eeprom_read_byte
(&ep_channel
);
av_source
= eeprom_read_byte
(&ep_av_source
);
language
= eeprom_read_byte
(&ep_language
);
sIdxSteps
= eeprom_read_byte
(&ep_sIdxSteps
);
eeprom_read_block
(&servo
[0],&ep_servo
[0],sizeof(servo_t
));
eeprom_read_block
(&servo
[1],&ep_servo
[1],sizeof(servo_t
));
servo_frame
= eeprom_read_byte
(&ep_servo_frame
); // nur bei Test-Servo
single_step
= eeprom_read_byte
(&ep_single_step
); // nur bei Test-Servo
repeat
= eeprom_read_byte
(&ep_repeat
); // nur bei Test-Servo
pause
= eeprom_read_byte
(&ep_pause
); // nur bei Test-Servo
pause_step
= eeprom_read_byte
(&ep_pause_step
); // nur bei Test-Servo
tracking
= eeprom_read_byte
(&ep_tracking
);
track_hyst
= eeprom_read_byte
(&ep_track_hyst
);
track_tx
= eeprom_read_byte
(&ep_track_tx
);
baudrate
= eeprom_read_byte
(&ep_baudrate
);
eeprom_read_block
(¤t
,&ep_current
,sizeof(current_t
));
akku_nr
= eeprom_read_byte
(&ep_akku_nr
);
eeprom_read_block
(&lipo
,&ep_lipo
[akku_nr
],sizeof(lipo_t
));
mk_i_offset
= eeprom_read_byte
(&ep_mk_i_offset
);
mk_i_faktor
= eeprom_read_byte
(&ep_mk_i_faktor
);
mk_w_faktor
= eeprom_read_byte
(&ep_mk_w_faktor
);
}
dogm_vers
= eeprom_read_byte
(&ep_dogm_vers
);
contrast
= eeprom_read_byte
(&ep_contrast
);
hyst_u_min
= u_min
;
sw_avx
= av_source
;
for (uint8_t i
= 0; i
< SERVO_NUM_CHANNELS
; i
++) {
servoSet_rev
(i
, servo
[i
].
rev);
servoSet_min
(i
, servo
[i
].
min);
servoSet_max
(i
, servo
[i
].
max);
servoSet_mid
(i
, servo
[i
].
mid);
}
// Vorberechnung von ServoChannels[channel].duty
servoSetDefaultPos
(); // Ausgangsstellung beider Servos
coldstart
= 1;
USART_Init_Baudrate
();
USART_RX_Mode
(tracking
);
}
void servoSetDefaultPos
(void)
{
servoSetPosition
(SERVO_PAN
, ServoSteps
()/2); // Ausgangsstellung SERVO_PAN
servoSetPosition
(SERVO_TILT
, 0); // Ausgangsstellung SERVO_TILT
}
void USART_Init_Baudrate
(void)
{
if (tracking
== TRACKING_MKCOCKPIT
)
USART_Init
(baud
[baudrate
]);
else
USART_Init
(baud
[6]); //57600
}
/************************************************************************************/
/* Zeitanzeige */
/* */
/************************************************************************************/
uint32_t TimeBase60
(char *str
, uint32_t time, uint8_t idx_a
)
{ uint32_t tmp
;
tmp
= time % 60;
time /= 60;
for (int8_t i
= idx_a
; i
>= (idx_a
- 1); i
--) {
str
[i
] = (tmp
% 10) + '0';
tmp
/= 10;
}
return(time);
}
void Displ_TimeMS
(int32_t time)
{ char str
[7];
str
[6] = '\0';
if (time < 0) {
time = abs(time);
str
[0] = '-';
}
else
str
[0] = ' ';
time = TimeBase60
(str
, time, 5);
TimeBase60
(str
, time, 2);
str
[3] = ':';
lcdPuts
(str
);
}
/************************************************************************************/
/* setzt Flag für 3,3V oder 5V DOGM */
/* Parameter: */
/* uint8_t dogm :Version */
/* */
/************************************************************************************/
void Set_DOGM_Version
(void)
{
if(dogm_vers
== DOGM5V
) {
dogm_vers
= DOGM3V
;
contrast
= CONTRAST3V
;
}
else {
dogm_vers
= DOGM5V
;
contrast
= CONTRAST5V
;
}
eeprom_write_byte
(&ep_dogm_vers
, dogm_vers
);
eeprom_write_byte
(&ep_contrast
, contrast
);
}
/************************************************************************************/
/* setzt den RX-Kanal von 1 bis 7 */
/* Parameter: */
/* uint8_t channel :Kanal */
/* */
/************************************************************************************/
void Set_Channel
(uint8_t channel
)
{ uint8_t tmp
;
channel
--;
tmp
= channel
& 0b00000111; // Kanal 1 bis 7 Werte 0 bis 6 setzen
PORTA
|= tmp
;
PORTB
|= tmp
;
tmp
= channel
| 0b11111000;
PORTA
&= tmp
;
PORTB
&= tmp
;
wudbm
= RSSI_Calc_UdBm
(pbar_udbm
); // Vergleichstabelle für dBm-Balken berechnen
}
/************************************************************************************/
/* schaltet den MUX auf AV1 oder AV2 ohne Darstellung und en-/disabled Interrupt */
/* wird nur in main.c (Initialisierung) und Menü Sourceumschaltung eingesetzt */
/* deswegen cli() und sei() nur in Menu_AV_Source(void) */
/* Parameter: */
/* uint8_t src :0-AV1, 1-AV2 */
/* */
/************************************************************************************/
void SetMux0
(void) {
SET_MUX_0
;
mux_X
= 0; // für Erkennung RX Zeitzähler
}
void SetMux1
(void) {
SET_MUX_1
;
mux_X
= 1; // für Erkennung RX Zeitzähler
}
uint8_t Set_AV_Source
(uint8_t src
)
{
switch(src
) {
case AV1
: CLEAR_INT10
; // Interrupt für Sync ausschalten
SetMux0
();
break;
case AV2
: CLEAR_INT10
; // Interrupt für Sync ausschalten
SetMux1
();
break;
case DIVERSITY
: SET_INT10
; // External Interrupt Mask Register ein
SetMux0
();
break;
}
return(src
);
}
/**************************************************************/
/* */
/* LCD-Backlight */
/* */
/**************************************************************/
void lcdSet_BackgrLight_Off
(void)
{
backgr_light
= OFF
;
lcdBacklightOff
();
}
void lcd_BackgrLight_On
(void)
{ // ...&& (light_count < light_time)) ==> sonst wird Beleuchtung laufend wieder eingeschaltet
if ((backgr_light
== OFF
) && (light_time
> BACKGR_LIGHT_MIN
) && (light_count
< light_time
)) {
cli
();
light_count
= 0;
sei
();
backgr_light
= ON
;
lcdBacklightOn
();
}
}
void lcd_BackgrLight
(void)
{
if (backgr_light
== ON
) { // nur wenn Beleuchtung an
if (light_time
== BACKGR_LIGHT_MIN
) // Hintergrundbeleuchtung immer aus?
lcdSet_BackgrLight_Off
();
else
if (light_time
< BACKGR_LIGHT_MAX
) { // Hintergrundbeleuchtung immer an?
cli
();
light_count
++;
sei
();
if (light_count
>= light_time
) lcdSet_BackgrLight_Off
();
}
}
}
/**************************************************************/
/* */
/* ADC */
/* */
/* http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial */
/* */
/**************************************************************/
void ADC_Init
(void)
{
uint16_t result
;
ADMUX
= (0<<REFS1
) | (1<<REFS0
); // AVcc als Referenz benutzen, da an AREF 4,8 V
ADCSRA
= (1<<ADPS2
) | (1<<ADPS1
) | (1<<ADPS0
); // Frequenzvorteiler Prescaler 128
ADCSRA
|= (1<<ADEN
); // ADC aktivieren
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
ADCSRA
|= (1<<ADSC
); // eine ADC-Wandlung
while (ADCSRA
& (1<<ADSC
) ) {} // auf Abschluss der Konvertierung warten
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
result
= ADCW
;
}
/* ADC Einzelmessung */
uint16_t ADC_Read
( uint8_t channel
)
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX
= (ADMUX
& ~
(0x1F)) | (channel
& 0x1F);
ADCSRA
|= (1<<ADSC
); // eine Wandlung "single conversion"
while (ADCSRA
& (1<<ADSC
) ) {} // auf Abschluss der Konvertierung warten
return ADCW
; // ADC auslesen und zurückgeben
}
/* ADC Mehrfachmessung mit Mittelwertbbildung */
adc_avg_t ADC_Read_Avg
(uint8_t channel0
, uint8_t channel1
, uint16_t average
)
{ adc_avg_t result
;
uint32_t u0
= 0;
uint32_t u1
= 0;
for (uint16_t i
= 0; i
< average
; ++i
){
u0
+= ADC_Read
( channel0
);
u1
+= ADC_Read
( channel1
);
_delay_ms
(1);
}
result.
u0 = u0
/average
;
result.
u1 = u1
/average
;
return(result
);
}
/**************************************************************/
/* */
/* Beeper */
/* */
/**************************************************************/
void Beep
(uint8_t time)
{
PORTB
|= (1<<BEEPER
);
_delay_ms
(time);
PORTB
&= ~
(1<<BEEPER
);
}
void Double_Beep
(uint8_t time, uint8_t pause
)
{
Beep
(time);
_delay_ms
(pause
);
Beep
(time);
}
/**************************************************************/
/* */
/* U-Batterie */
/* */
/**************************************************************/
/* Funktion zur Umwandlung einer vorzeichenbehafteten Integer
32-Bit "Festkomma-Zahl"(gedachtes Komma in Integer) in einen String
vereinfacht Variablenübergabe funktion change_value(uint32_t x),
kein printf, double oder float
siehe http://www.mikrocontroller.net/articles/Festkommaarithmetik
Vorz ==> 0 kein '-' trotz negativer Zahl, 1 wenn kein '-' bleibt Stelle leer
len max 11, Vorzeichen wird nicht mitgezählt aber Komma; Vorz 0 oder 1
Festkomma ==> Position der Kommastelle bei Integerwert
Nachkomma ==> angezeigte Nachkommastellen bei Festkomma
makefile derzeit somit auch ohne! Minimalistic printf version
Achtung: keine Fehlerprüfung! */
char* my_itoa
(int32_t zahl
, uint8_t Vorz
, uint8_t len
, uint8_t Festkomma
, uint8_t Nachkomma
)
{
int8_t i
;
uint8_t neg
= 0;
char Komma
; // Sprachversion Deutsch ',' andere '.'
static char str
[13];
Komma
= Msg
(MSG_KOMMA
)[0]; // [0] nur als Char, sonst wäre es ein String
if( zahl
< 0 ) { // ist die Zahl negativ?
zahl
= -zahl
;
neg
= 1;
}
if (Vorz
) str
[0] = '0'; else len
--;
str
[len
+1]='\0'; // String Terminator
if (Nachkomma
> 0) Nachkomma
++;
for(i
=len
; i
>=Vorz
; i
--) {
if ((len
- Festkomma
== i
) && (Festkomma
> 0))
str
[i
]= Komma
; // bei Bedarf Komma einfügen
else { // Integer-Dezimalumrechnung
str
[i
]=(zahl
% 10) +'0'; // Modulo rechnen, dann den ASCII-Code von '0' addieren
zahl
/= 10;
}
// festgelegt Festkomma aber verkleinern der Anzeige Mantisse
if ((Festkomma
> 0) && (Festkomma
>= Nachkomma
) && (len
- Festkomma
+ Nachkomma
== i
)) str
[i
]= '\0';
}
i
=0;
while ((str
[i
+1] != Komma
) && (i
< len
)) {
// Vorzeichen unmittelbar vor Zahl schreiben
if((Vorz
) && (neg
) && ((str
[i
+1] != '0') || (str
[i
+2] == Komma
))) str
[i
] = '-';
// eine 0 vor Komma lassen
if(str
[i
] == '0') str
[i
++] = ' '; else break; // Vornullen entfernen
}
return(str
);
}
// uint32_t u, da bei Displ_Fnct[fu_index](val) der größte Wert UBat gleich 32 Bit
void Displ_1Nk
(uint32_t u
)
{
// 0 kein Vorzeichen, 5 => 2 Ziffern vor Komma + 1 Komma + 2 Mantisse, Festkomma, eine Ziffer Nachkomma darstellen
lcdPuts
(my_itoa
(u
,0,5,2,1));
}
void Displ_U_2Nk
(uint32_t u
)
{
lcdPuts
(my_itoa
(u
,0,5,2,2));
lcdPutc
('V');
}
// uint8_t beep_timer :Akku-leer-Beeper nur mit Task_0_1()-Intervalle bei Menü-Rücksprung
uint32_t U_Messen_cmp
(uint8_t beep_timer
)
{ uint32_t ubat
;
static struct
{ uint8_t time;
uint8_t count
;
} beep_low
;
/* ubat = ((ADC_Read(VBAT) * Vref * (R104 + R103)) /(1024 * R103)) + UD10 (UD10 ist Offset)
Verhältniswert * 100 *8192 ( Verhältniswert = realer Korrekturwert;
mal 100 da alle Werte 2 Nachkommastellen berücksichtigt, aber ohne gerechnet wird
mal 8192 => ohne Bruch gerechnet aber dabei mehr Kommastellen berücksichtigt) */
ubat
= (ADC_Read
(VBAT
) * (uint64_t)43504 + (uint64_t)u_offset
* 8192)/ 8192;
if ( ubat
<= hyst_u_min
)
{
if (bat_low
!= 0) { // nicht laufend Display neu schreiben
hyst_u_min
= u_min
+ 20; // 200mV Hysterese - beruhigt Anzeige
if (tracking
== TRACKING_GPS
)
store_LipoData
(); // wenigstens von GPS-Statisik UsedCapacity, time_on usw. speichern
lcdClear
();
lcdPuts
(Msg
(MSG_ACCU_LOW
));
bat_low
= 0;
Beep
(BEEPBAT
);
// da derzeit Fkt. aller 500ms aufgerufen, mit 2 Min Abstand beginnen
beep_low.
time = BEEP_LOW_TIME
;
beep_low.
count = 0;
}
// Akku leer, in immer kürzeren Intervallen Beep
if ((beep_timer
== 1) && (beep_low.
count++ >= beep_low.
time)){
Beep
(BEEPBAT
);
if (beep_low.
time > 2)
beep_low.
time /= 2;
beep_low.
count = 0;
}
}
else {
if (hyst_u_min
> u_min
) { // falls Anzeige von Batterie leer
bat_low
= 1; // und zurück geschaltet wird,
hyst_u_min
= u_min
; // dann Main_Disp wieder darstellen
Displ_Main_Disp
();
}
}
return(ubat
);
}
void Displ_VBat
(void) // da u_offset globale Variable
{ uint32_t ubat
;
ubat
= U_Messen_cmp
(ENABLE_BTIMER
);
if (bat_low
!= 0) { // würde sonst Anzeige Akku leer überschreiben
lcdGotoXY
(11, 0);
Displ_1Nk
(ubat
);
}
}
/**************************************************************/
/* */
/* RSSI */
/* */
/**************************************************************/
/* RSSI Werte Korrekturfaktor berechnen */
uint16_t RSSI_Calc_Korr
(uint8_t nchannel
, uint16_t u0
, uint16_t u1
)
{ uint16_t u_max
;
// immer nur den kleineren Wert vergrößern
if (u0
< u1
) {
udbm.
korr_1 = (((uint32_t)u1
* UDBM_KORR_FA
) / u0
); // nur mit Integer und 2 Nachkommastellen rechnen
udbm.
korr_2 = UDBM_KORR_FA
;
u_max
= u1
;
}
else {
udbm.
korr_2 = (((uint32_t)u0
* UDBM_KORR_FA
) / u1
); // nur mit Integer und 2 Nachkommastellen rechnen
udbm.
korr_1 = UDBM_KORR_FA
;
u_max
= u0
;
}
eeprom_write_word
(&ep_udbm
[nchannel
- 1].
korr_1, udbm.
korr_1);
eeprom_write_word
(&ep_udbm
[nchannel
- 1].
korr_2, udbm.
korr_2);
return(u_max
);
}
void Displ_Calibr_Aktiv
(uint8_t nchannel
)
{ char str
[LCD_COLS
+ 1];
uint8_t l
;
uint8_t zle
= 1;
// Anzeige für nur einen Kanal oder wenn in Schleife, Kanalnr. des z.Z. kalbrierenden Kanals
lcdClear
();
Displ_Str_mid
(Msg
(MSG_CALIBRATION
),0);
if (nchannel
> 0) { // Anzeige aller RX-Kanäle min. kalibrieren?
strcpy(str
, Msg
(MSG_RX_CHANNEL
));
strcat(str
, ": ");
l
= strlen(str
);
str
[l
] = nchannel
+ 0x30; // gerade zu kalibrierender Kanal, String zusammen stellen
str
[++l
] = '\0';
Displ_Str_mid
(str
,1);
zle
= 2;
}
Displ_Str_mid
(Msg
(MSG_RUNNING
),zle
);
}
void delay_ms100x
(uint8_t delay
)
{
for ( uint8_t i
=0; i
<delay
; i
++)
_delay_ms
(100);
}
void Displ_Error_TX
(uint8_t message
)
{
lcdClear
();
Displ_Str_mid
(Msg
(MSG_ERROR
), 0);
Displ_Str_mid
(Msg
(MSG_TX_NOT
), 1);
Displ_Str_mid
(Msg
(message
), 2);
delay_ms100x
(30);
}
uint8_t RSSI_Min_Calibrate
(uint8_t nchannel
, uint16_t *pbar_udbm
)
{ adc_avg_t rssi_avg
;
uint16_t udbm_min
;
uint8_t one_channel
= !nchannel
;
Displ_Calibr_Aktiv
(nchannel
);
if (one_channel
) nchannel
= channel
;
rssi_avg
= ADC_Read_Avg
(RSSI0
, RSSI1
, 1000 ); //1000 Wiederholungen mit Mittelwertbildung
// Plausibilitätsprüfung ob Sender ausgeschaltet
if (rssi_avg.
u0 + rssi_avg.
u1 > 500) {
udbm_min
= RSSI_Calc_Korr
(nchannel
, rssi_avg.
u0, rssi_avg.
u1); // ist real die größere Spannung, aber der kleinere dbm Wert
eeprom_write_word
(&ep_udbm
[nchannel
- 1].
min, udbm_min
);
if (one_channel
) {
Double_Beep
(DBEEPWR
, DBEEPWRP
);
wudbm
= RSSI_Calc_UdBm
(pbar_udbm
);
}
}
else
if (one_channel
)
Displ_Error_TX
(MSG_TX_OFF
);
else
return(0); // Fehleranzeige wird in menue.c gesammelt ausgewertet
return(1); // kein Fehler, da bei einen Kanal bereits Fehler angezeigt wurde
}
void RSSI_Max_Calibrate
(uint16_t *pbar_udbm
)
{ adc_avg_t rssi_avg
;
uint16_t udbm_max
;
Displ_Calibr_Aktiv
(0);
rssi_avg
= ADC_Read_Avg
(RSSI0
, RSSI1
, 1000 ); //1000 Wiederholungen mit Mittelwertbildung
// Plausibilitätsprüfung ob Sender in der Nähe eingeschaltet
if (rssi_avg.
u0 + rssi_avg.
u1 < 400) {
udbm_max
= RSSI_Calc_Korr
(channel
, rssi_avg.
u0, rssi_avg.
u1); // ist real die kleinere Spannung, aber der größere dbm Wert
eeprom_write_word
(&ep_udbm
[channel
- 1].
max, udbm_max
);
Double_Beep
(DBEEPWR
, DBEEPWRP
);
wudbm
= RSSI_Calc_UdBm
(pbar_udbm
);
}
else Displ_Error_TX
(MSG_TX_ON
);
}
// Vergleichstabelle für RSSI-Bargraph berechnen, vermeidet laufend gleiche Berechnung
uint8_t RSSI_Calc_UdBm
(uint16_t *pbar_udbm
)
{ uint8_t n
;
eeprom_read_block
(&udbm
,&ep_udbm
[channel
- 1],sizeof(udbm_t
));
// -15 um Ende dBm Skala sicher zu erreichen; ohne verfeinerten Bahrgraph war Wert -3
n
= (udbm.
min - udbm.
max -15)/11;
for (uint8_t i
= 0; i
< 12; i
++)
pbar_udbm
[i
] = (udbm.
min - i
* n
);
return(n
/ 5); // da 5 Pixel Breite pro Display-Zeichen; Anzeigebalken pro Pixel differenzieren
}
void Displ_RSSI_Bargraph
(uint16_t *pbar_udbm
, uint8_t wudbm
, uint16_t uadc
)
{ char charBar
[12];
uint8_t i
;
int8_t lz
= 11;
char b
= 4;
// Balken zeichnen - udbm
for (i
= 0; i
< 12; i
++) {
if ((b
!= ' ') && (uadc
> pbar_udbm
[i
])) {
b
= ' ';
lz
= i
- 1;
}
charBar
[i
] = b
;
}
if (lz
>= 0) {
charBar
[lz
] = (pbar_udbm
[lz
] - uadc
) / wudbm
;// Anzeigebalken pro Pixel-"Breite" differenzieren
// bei Teilung 4 wäre richtig und keine Korr. erforderlich, so aber gleichmäßigerer Balkenverlauf
if (charBar
[lz
] > 4) charBar
[lz
] = 4;
}
for (i
= 0; i
< 12; i
++)// lcdPuts (ist auch for) funktioniert hier nicht, da Char'\0' für Zeichen auch Stringende
lcdPutc
(charBar
[i
]);
}
uint8_t RSSI_Diversity
(uint8_t src
, uint16_t *pbar_udbm
, uint8_t visible
)
{ uint16_t u0
, u1
;
static uint8_t div_flag
, ret_div_flag
;
char marker
;
u0
= (ADC_Read
(RSSI0
) * (uint32_t)udbm.
korr_1)/UDBM_KORR_FA
;
u1
= (ADC_Read
(RSSI1
) * (uint32_t)udbm.
korr_2)/UDBM_KORR_FA
;
// falls beide RX gleich gut/schlecht synchronisieren
// Achtung! Niedrigere Spannung - größere Feldstärke
if (src
== DIVERSITY
) {
if (u0
< u1
) {
ret_div_flag
= AV1
;
if ((vscount0
== 255) && (vscount1
== 255)) SetMux0
(); // egal wann RSSI schaltet ==> es ist kein sync vorhanden
}
else {
ret_div_flag
= AV2
;
if ((vscount0
== 255) && (vscount1
== 255)) SetMux1
(); // egal wann RSSI schaltet ==> es ist kein sync vorhanden
}
}
else ret_div_flag
= src
; // sonst leerer Returnwert
if (visible
) {
if (src
== DIVERSITY
) {
// Synchronisation vorrangig zur Feldstärke
if ((vsync0
!= vsync1
) && ((vscount0
& vscount1
) < 255)) {
// ist nur zur Anzeige - Sync-MUX wird über Interrupt gesteuert
if (vsync0
== 0) {
div_flag
= AV1
;
}
else {
div_flag
= AV2
;
}
marker
= MARKER_SYNC
;
}
else {
div_flag
= ret_div_flag
;
marker
= MARKER_RSSI
;
}
}
else marker
= MARKER_AV
;
// wäre unschön - keine RSSI-Anzeige, aber Marker springt
if ((u0
> pbar_udbm
[0]) && (u1
> pbar_udbm
[0])) marker
= ' ';
lcdGotoXY
(2, 1);
Displ_RSSI_Bargraph
(pbar_udbm
, wudbm
, u0
);
lcdGotoXY
(2, 2);
Displ_RSSI_Bargraph
(pbar_udbm
, wudbm
, u1
);
if (src
== DIVERSITY
) Displ_AV_Mark
(div_flag
, marker
);
}
return(ret_div_flag
);
}
/**************************************************************/
/* */
/* Diversity v-Synchronisation Interruptroutinen */
/* */
/**************************************************************/
/* Impulszähler für V-Synchronisation 0 und 1
wird durch Interrupt des jewiligen vSync einzeln zurückgesetzt. 8-bit Timer*/
ISR
(TIMER2_OVF_vect
)
{
TCNT2
= (int8_t)(int16_t)-(F_CPU
/ 64 * 500e-6); // preload
if (vscount0
< 255) ++vscount0
; // Überlauf von vscount vermeiden
if (vscount1
< 255) ++vscount1
; // Überlauf von vscount vermeiden
if (rx_timeout
< RX_TIME_END
) ++rx_timeout
; // veranlasst bei GPS-Tracking MK Datensatz senden
if ((mk_timer
) && (lipo.
time_on < T2PROD_M59S59
)) ++lipo.
time_on; // T2PRODM59S59 = 3599 * 4000
if ((tracking
== TRACKING_GPS
) && (MK_Motor_run
)) { // MK-Motoren müssen laufen
if (mux_X
)
rxcount1
++; // kein Test auf Überlauf ==> Counter groß genug - bis Stunden
else
rxcount0
++;
}
}
/* Messung von Impulsabstand v-Synchronisation 0
Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */
ISR
(INT0_vect
)
{
if ((vscount0
>= 79) && (vscount0
<= 81))
vsync0
= 0;
else {
vsync0
= 1;
if (vsync1
== 0)
SetMux1
();
}
if (vsync0
== vsync1
) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI
if (sw_avx
== AV1
) {
SetMux0
();
}
else
SetMux1
();
}
vscount0
= 0;
}
/* Messung von Impulsabstand v-Synchronisation 1
Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */
ISR
(INT1_vect
)
{
if ((vscount1
>= 79) && (vscount1
<= 81))
vsync1
= 0;
else {
vsync1
= 1;
if (vsync0
== 0)
SetMux0
();
}
if (vsync0
== vsync1
) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI
if (sw_avx
== AV1
) {
SetMux0
();
}
else
SetMux1
();
}
vscount1
= 0;
}
/**************************************************************/
/* */
/* Tasks */
/* ermöglicht unterschiedliche Zeiten f. UBat, Sync... */
/* */
/**************************************************************/
void Task_0_1
(void)
{
if (task_timer0_1
) {
cli
();
task_timer0_1
= 0;
sei
();
Displ_VBat
();
}
}
void Task_0_2
(void)
{
if (task_timer0_2
) {
cli
();
task_timer0_2
= 0;
sei
();
sw_avx
= RSSI_Diversity
(av_source
, pbar_udbm
, bat_low
);
}
}
void Task_0_3
(void)
{
if (task_timer0_3
) {
cli
();
task_timer0_3
= 0;
sei
();
sw_avx
= RSSI_Diversity
(av_source
, pbar_udbm
, 0);
if (tracking
== TRACKING_MKCOCKPIT
) Tracking_MKCockpit
();
}
}
void Task_0_4
(void)
{
if (task_timer0_4
) {
cli
();
task_timer0_4
= 0;
sei
();
if (tracking
== TRACKING_GPS
) Tracking_GPS
();
if (gps_display
== GPS_RX_COUNT
) Displ_RX_Time
(); // aktualisieren der Empfängerzeiten
}
}
void Task_0_5
(void) // Nur für Tasten-Beschleunigung/-Wiederholrate! Hintergrund: Rücksetzung.
{ // Hintergrund: Rücksetzung. Beginnt nach jeden Tastendruck neu zu zählen.
lcd_BackgrLight_On
(); // muss bei beliebiger Taste sofort eingeschaltet werden
if (task_timer0_5
) {
cli
();
task_timer0_5
= 0;
sei
();
lcd_BackgrLight
();
}
}
void Tasks_unvisible
(void)
{
Task_0_3
();
Task_0_4
();
Task_0_5
();
if (tracking
== TRACKING_RSSI
) Tracking_RSSI
();
}