0,0 → 1,855 |
|
/****************************************************************/ |
/* */ |
/* 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 <string.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 "tools.h" |
#include "keys.h" |
#include "usart.h" |
#include "tracking.h" |
|
// LCD selbst definierte Sonderzeichen, RSSI-Balken und wi232 Empfang Daten im Flash |
// deshalb in dogm.c lcdPutc(pgm_read_byte(&lcdChr[i])); |
SpecialChr_t lcdSpecialChr[7] 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 |
|
SpecialChr_t lcdSpecialChrLs[8] 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}}; |
|
SpecialChr_t lcdSpecialChrRs[5] 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}}; |
|
/**************************************************************/ |
/* */ |
/* EEPROM */ |
/* */ |
/**************************************************************/ |
uint8_t ep_eep_init EEPROM; |
char ep_version[sizeof(VERSION)] EEPROM; |
uint8_t ep_dogm_vers EEPROM; |
uint8_t ep_contrast EEPROM; |
uint8_t ep_light_time EEPROM; |
uint8_t ep_u_offset EEPROM; |
uint16_t ep_u_min EEPROM; |
uint8_t ep_rssi_inv EEPROM; |
uint8_t ep_channel EEPROM; |
uint8_t ep_av_source EEPROM; |
uint8_t ep_language EEPROM; |
udbm_t ep_udbm[CHANNEL_MAX] EEPROM; |
uint16_t ep_tx_value_on EEPROM; |
uint16_t ep_tx_value_off EEPROM; |
uint8_t ep_sIdxSteps EEPROM; |
servo_t ep_servo[SERVO_NUM_CHANNELS] EEPROM; |
uint8_t ep_servo_frame EEPROM; |
uint8_t ep_servo_nr EEPROM; |
uint8_t ep_single_step EEPROM; |
uint8_t ep_repeat EEPROM; |
uint8_t ep_pause EEPROM; |
uint8_t ep_pause_step EEPROM; |
uint8_t ep_tracking EEPROM; |
uint8_t ep_track_hyst EEPROM; |
uint8_t ep_track_tx EEPROM; |
uint8_t ep_baudrate EEPROM; |
mk_current_t ep_mk_current EEPROM; |
uint8_t ep_mk_akku_nr EEPROM; |
mk_lipo_t ep_mk_lipo[AKKU_NR_MAX+1] EEPROM; |
uint8_t ep_mk_i_offset EEPROM; |
uint8_t ep_mk_i_faktor EEPROM; |
uint8_t ep_mk_w_faktor EEPROM; |
|
/**************************************************************/ |
// Working variables of EEPROM contents |
uint8_t dogm_vers; |
uint8_t contrast; |
uint8_t light_time = BACKGR_LIGHT_MAX; |
uint8_t backgr_light = OFF; |
uint8_t u_offset = U_OFFSET; |
uint16_t u_min = U_MIN; |
uint8_t rssi_inv = RSSI_INV; |
uint8_t channel = CHANNEL; |
uint8_t av_source = AV_SOURCE; |
uint8_t language = NO_LANGUAGE; |
udbm_t udbm = {UDBM_MIN, UDBM_MAX, UDBM_KORR_FA, UDBM_KORR_FA}; |
uint16_t tx_value_on = TX_VALUE_ON; |
uint16_t tx_value_off = TX_VALUE_OFF; |
uint16_t hyst_u_min; |
servo_t servo[SERVO_NUM_CHANNELS] = {{SERVO_REV, SERVO_I0_RIGHT, SERVO_I0_LEFT, SERVO_I0_MIDDLE},\ |
{SERVO_REV, SERVO_I0_RIGHT, SERVO_I0_LEFT, SERVO_I0_MIDDLE}}; |
uint8_t servo_frame = SERVO_PERIODE; |
uint8_t single_step = SINGLE_STEP; |
uint8_t repeat = REPEAT; |
uint8_t pause = PAUSE; |
uint8_t pause_step = PAUSE_STEP; |
uint8_t baudrate = BAUDRATE; |
|
/**************************************************************/ |
uint8_t coldstart; // Flag erstmaliger MK-Start(Motore) nur nach GPS-Fix |
uint8_t ch_stored; // Flag zur Speicherung, wenn Wert im Hauptdisplay geändert |
|
uint8_t gps_display = 0; |
uint8_t gps_disp_clear; |
|
uint16_t bar_udbm[12]; // RSSI-Bargraph |
uint8_t wudbm; // Differenz/Abstand benachbarter udbm[i] für differenzierteren Bargraphen |
uint8_t bat_low = 0; |
uint8_t sw_avx; // steuert über Set_AV_Source() oder rssi_diversity(av_source) Marker-Position und RX-Umschaltung |
uint8_t mux_X; // berücksichtigt Schaltung auf Grund Synchronisation und RSSI (sw_avx meist RSSI) RX-Zählung |
uint8_t MK_Motor_run = 0; // Flag für RX Time-Counter Start/Stop |
uint8_t mk_timer = 0; // Zeitzähler lipo.time_on auf aus |
|
const uint16_t PROGMEM baud[8] = {4800, 7200, 9600, 14400, 19200, 38400, 57600}; |
|
volatile uint8_t vsync0; |
volatile uint8_t vsync1; |
volatile uint8_t vscount0; |
volatile uint8_t vscount1; |
volatile uint32_t rxcount0 = 0; |
volatile uint32_t rxcount1 = 0; |
|
|
/************************************************************************************/ |
/* 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_word(&ep_u_min, U_MIN); |
eeprom_write_byte(&ep_rssi_inv, RSSI_INV); |
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_word(&ep_tx_value_on, TX_VALUE_ON); |
eeprom_write_word(&ep_tx_value_off, TX_VALUE_OFF); |
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(&mk_current,&ep_mk_current,sizeof(mk_current_t)); |
eeprom_write_byte(&ep_mk_akku_nr, AKKU_NR_MIN); |
for (uint8_t i = 0; i <= AKKU_NR_MAX; i++) |
eeprom_write_block(&mk_lipo,&ep_mk_lipo[i],sizeof(mk_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_word(&ep_u_min); |
rssi_inv = eeprom_read_byte(&ep_rssi_inv); |
channel = eeprom_read_byte(&ep_channel); |
av_source = eeprom_read_byte(&ep_av_source); |
language = eeprom_read_byte(&ep_language); |
tx_value_on = eeprom_read_word(&ep_tx_value_on); |
tx_value_off = eeprom_read_word(&ep_tx_value_off); |
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(&mk_current,&ep_mk_current,sizeof(mk_current_t)); |
mk_akku_nr = eeprom_read_byte(&ep_mk_akku_nr); |
eeprom_read_block(&mk_lipo,&ep_mk_lipo[mk_akku_nr],sizeof(mk_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); |
mk_dUsedCapacity = mk_lipo.UsedCapacity; |
} |
|
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 || tracking == TRACKING_NMEA) |
USART_Init(getBaud(baudrate)); |
else |
USART_Init(57600); |
} |
|
/************************************************************************************/ |
/* 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(bar_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_count < light_time)) { |
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 |
} |
|
/* falls Rx mit invertierter RSSI-Spannung eingesetzt wird */ |
uint16_t ADC_Read_inv( uint8_t channel ) |
{ uint16_t result; |
|
result = ADC_Read(channel); |
if (rssi_inv) |
result = 0x1ff - result; // 10 bit ADC, 1bit Vorzeichen; 9bit Wert |
return result; |
} |
|
/* 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_inv( channel0 ); |
u1 += ADC_Read_inv( channel1 ); |
_delay_ms(1); |
} |
result.u0 = u0/average; |
result.u1 = u1/average; |
return(result); |
} |
|
/**************************************************************/ |
/* */ |
/* Beeper */ |
/* */ |
/* Bei AVR-Studio 5 ist in delay.h */ |
/* #define __DELAY_BACKWARD_COMPATIBLE__ */ |
/* zu setzen */ |
/* */ |
/**************************************************************/ |
|
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 */ |
/* */ |
/**************************************************************/ |
|
// uint16_t u, da bei Displ_Fnct[fu_index](val) der größte Wert UBat gleich 16 Bit |
void Displ_1Nk(uint16_t u) |
{ |
// 4 => 2 Ziffern vor Komma + 1 Komma + eine Ziffer Nachkomma darstellen, 2 Festkomma |
lcdPuts(my_itoa(u,4,2,1)); |
} |
|
void Displ_U_2Nk(uint16_t u) |
{ |
lcdPuts(my_itoa(u,5,2,2)); |
lcdPutc('V'); |
} |
|
// uint8_t beep_timer :Akku-leer-Beeper nur mit Task_0_1()-Intervalle bei Menü-Rücksprung |
uint16_t U_Messen_cmp(uint8_t beep_timer) |
{ uint16_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) { // 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 = 1; |
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 = 0; // 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 |
{ uint16_t ubat; |
|
ubat = U_Messen_cmp(ENABLE_BTIMER); |
if (!bat_low) { // 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(); |
lcdPutStrMid(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'; |
lcdPutStrMid(str,1); |
zle = 2; |
} |
lcdPutStrMid(Msg(MSG_RUNNING),zle); |
} |
|
void Displ_Error_TX(uint8_t message) |
{ |
lcdClear(); |
lcdPutStrMid(Msg(MSG_ERROR), 0); |
lcdPutStrMid(Msg(MSG_TX_NOT), 1); |
lcdPutStrMid(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 > tx_value_off) { |
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 < tx_value_on) { |
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_inv(RSSI0) * (uint32_t)udbm.korr_1)/UDBM_KORR_FA; |
u1 = (ADC_Read_inv(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 |
div_flag = vsync0 == 0? AV1: 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) && (mk_lipo.time_on < T2PROD_M59S59)) ++mk_lipo.time_on; // T2PRODM59S59 = 3599 * 4000 |
if (((tracking == TRACKING_GPS) && (MK_Motor_run)) || ((tracking == TRACKING_NMEA) && !coldstart)) { // 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; |
if ((mux_X) && (vscount1 == 255)) { |
SetMux0(); |
vsync1 = 1; |
} |
} |
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; |
if (!(mux_X) && (vscount0 == 255)) { |
SetMux1(); |
vsync0 = 1; |
} |
} |
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, bar_udbm, !bat_low); |
} |
} |
|
void Task_0_3(void) |
{ |
if (task_timer0_3) { |
cli(); |
task_timer0_3 = 0; |
sei(); |
sw_avx = RSSI_Diversity(av_source, bar_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(); |
else if (tracking == TRACKING_NMEA) |
Tracking_NMEA(); |
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_invisible(void) // wird in main.c und menue.c aufgerufen |
{ |
Task_0_3(); |
Task_0_4(); |
Task_0_5(); |
if (tracking == TRACKING_RSSI) Tracking_RSSI(); |
} |