//**********************************************************************
// program pro rizeni TRXu
//**********************************************************************
// (c) OK1XGL 2005
// verze 1.0.0 - uvodni verze
// verze 1.0.1 - prechod 16F877 a usazeni sibnalu na porty
// verze 1.0.2 = odladeni zakladnich funkci - muzeme delat tistak
// verze 1.0.3 - definitivni usazeni signalu - hotovy DPS
// verze 1.0.4 - prvni pouzitelna verze
// verze 1.1.0 - SIGNAL ATN1 PRESUNUT NA RE0 A SIGNAL ATN2 PRESUNUT NA RC0 !!!!!
// verze 1.2.0 - doprobramovan jednopakovy klic
// verze 1.3.0 - elbug zmenen na dvoupakovy a cely presunut do preruseni
// verze 1.4.0 - po zapnuti se RX naladi na QRP kmitocet na danem pasmu
// - PSV se povazuje za platne jen kdyz je skutecne zaklicovano
// verze 1.5.0 - upraven zpusob cteni dat z AD prevodniku
// - pwm rozsirena na 157 kroku
// - doplneno ALC pro vykon a nastaveni vykonu v 0.5W jednotkach
// verze 1.6.0 - provedena kalibrace S-metru
// Poznamky:
// zobrazeni kmitoctu na LCD trva 30ms !!!
// pri rychlosti klicovani 200zn/s je sirka impulzu (tecka) cca 30ms
// timer2 vyhrazen na generovani tonu a ma nastaven kmitocet 800Hz, ton se generuje PWM, rizeni vykonu tez PWM 800Hz je baze
// timer 1 vyhrazen pro elbug
//DODELAT: - pri BK provozu je treba, aby se pri prepnuti na prjem mezi elementy znacky nezobrazoval S-metr, protoze
// se to tak rychle nestiha zobrazovat a je lepsi,aby se zobrazovalo stale psv a vykon. Nyni je toho dosazeno tak,
// ze pokud je aktivni elbug, tak se zobrazeni nedela ovsem toto reseni nebude fungovat pri externim elbugu
// spravne reseni je timerem, ktery bude vykryvat cas mezi znackami
// - projit kod a nektere veci ucesat
#include "vfo.h"
#include <lcd.c>
//#define ADC_LCD // misto obvyklych udaju zobrazuje hodnoty AD prevodniku
//#define NO_FILTER_CONTROL // vyrazuje prubeznou kontrolu pritomnosti filtru pro prislusne pasmo
/////////// FUNKCE PRO ZOBRAZOVANI NA LCD /////////
// podpora zobrazeni RIT
// POZOR: pred pouzitim je nutno vynulovat promennou lcd_pos !!!
void rit_lcd_putc(int8 c)
{
lcd_pos++;
if(lcd_pos==2) lcd_putc('.'); // prida tecku za KHZ
lcd_putc(c);
} // rit_lcd_putc
// podpora zobrazeni kmitoctu VFO
// POZOR: pred pouzitim je nutno vynulovat promennou lcd_pos !!!
void vfo_lcd_putc(int8 c)
{
lcd_pos++;
// za MHz dopln pismenko VFO
if(lcd_pos==3)
if(vfo_index)
if(bit_test(_SPLIT)) lcd_putc('\21'); // vyplnene b
else lcd_putc('b');
else if(bit_test(_SPLIT)) lcd_putc('\22'); // vyplnene a
else lcd_putc('a');
// za KHz dopln tecku
if(lcd_pos==6)
if(step_index) lcd_putc(':'); // hrube ladeni
else lcd_putc('.'); // jemne ladeni
lcd_putc(c);
} //vfo_lcd_putc
// podpora zobrazeni vykonu a psv
// POZOR: pred pouzitim je nutno vynulovat promennou lcd_pos !!!
void pwr_lcd_putc(int8 c)
{
lcd_pos++;
if(lcd_pos==2) lcd_putc('.');
lcd_putc(c);
} // pwr_lcd_putc
// podpora zobrazeni napeti baterie
// POZOR: pred pouzitim je nutno vynulovat promennou lcd_pos !!!
void batt_lcd_putc(int8 c)
{
lcd_pos++;
if(lcd_pos==3) lcd_putc('.');
lcd_putc(c);
} // batt_lcd_putc
/////////// FUNKCE PRO PRACI S DDS /////////
// odesle 16 bitovy zaznam do DDS
//
void dds_send(int16 record)
{
int8 i;
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
output_low(DDS_FSYNC); // zacatek komunikace s DDS
i=16;
do
{
if(bit_test(record,15)) output_high(DDS_SDATA); // vystav datovy bit, zaciname MSB
else output_low(DDS_SDATA);
output_low(DDS_SCK); // hodinovy impulz
output_high(DDS_SCK);
record=record<<1; // na dalsi bit
} while(--i);
output_high(DDS_FSYNC); // konec komunikace s DDS
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
#use standard_io(D)
} // dds_send
// naplni registr0 pro kmitocet v DDS (28 bitu)
//
void dds_freq0(int32 freq)
{
int16 record;
// posli ridici slovo
dds_send(CTRL_FREQ0);
// zapis pozadovane frekvence
// zapis LSB
record=(int16)freq;
bit_set(record,14); // zapis do frekvencniho registru 0
bit_clear(record,15);
dds_send(record);
// zapis MSB
record=(int16)((freq<<2)>>16); // divny zapis, ale >> 14 dava hrozny vysledek
bit_set(record,14); // zapis do frekvencniho registru 0
bit_clear(record,15);
dds_send(record);
} // dds_freq0
/////////// FUNKCE PRO RIZENI PRIPOSLECHU /////////
// vypne generovani tonu priposlechu
//
#inline
void tone_off()
{
int8 a;
a=input(TONE);
} // tone_off()
// zapne generovani tonu priposlechu
//
#inline
void tone_on()
{
output_low(TONE);
} // tone_on
/////////////////////////////////
// Prerusovaci rutiny
/////////////////////////////////
// rezie preruseni je cca 30+30 cyklu
// preruseni od zmeny polohy kroutitka
#int_EXT
void Encoder_handler()
{
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
int1 dir;
dir=input(ENCODER_DIR); // zapamatuj si smer krouceni
bit_set(_ENC_CHNG); // oznam zmenu polohy kroutitka
if(dir) enc_delta++; // pridej
else enc_delta--; // uber
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
} // Encoder_handler
// periodicke tiky, granularita TICK_TIME
// citace/ casovace se granularitou TICK_TIME
#INT_TIMER0
void Tick_handler()
{
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
set_timer0(TICK_TIME); // znovu natahni timer
// mereni napeti z prevodniku
if(bit_test(_ADC_START))
{
read_adc(ADC_START_ONLY); // spust prevod
bit_clear(_ADC_START); // priste budeme cist vysledek
} else
{
adc_val=read_adc(ADC_READ_ONLY); // vyzvedni vysledek
if(bit_test(_KEYING)) // hodnoty vykonu aktualizuj jen pokud je zaklicovano
{
if(adc_ch==1) fwd_val=adc_val;
if(adc_ch==0) rev_val=adc_val;
}
if(adc_ch==2) batt_val=adc_val;
else if(adc_ch==3) smtr_val=adc_val;
else if(adc_ch==4) bnd_val=adc_val;
if(adc_ch>=4) adc_ch=0; // mame 5 kanalu
else adc_ch++;
set_adc_channel(adc_ch); // priste nasledujici kanal
bit_set(_ADC_START); // priste budeme spoustet prevod
}
// klicovani
if(bit_test(_TXDELAY)) // jen pokud tx_delay vyprsel
{
if(!bit_test(_ELBUG_ON))
keyer=(~input_b()) & 0b10000000; // pokud neni zapnut elbug, zavzorkuj stav klice
if((keyer!=0 && !bit_test(_ELBUG_ON)) || // pri vypnutem elbugu rizeno stavem pak
(bit_test(_ELBUG_OUT) && bit_test(_ELBUG_ON))) // pri zapnutem elbugu rizeno stavem _ELBUG_ON
{
// zaklicuj
output_high(KEYING);
tone_on();
bit_clear(_RUN_VOX);
bit_set(_KEYING);
adc_ch=0; // zacneme merit dopredny vykon
set_adc_channel(adc_ch);
bit_set(_ADC_START); // priste spustime prevod ADC
} else
{
// prestan klicovat
output_low(KEYING);
vox_timer=vox_time; // natahni vox_timer
bit_set(_RUN_VOX);
tone_off();
bit_clear(_KEYING);
}
bit_clear(_TXDELAY);
}
// periodicky timer na aktualizaci kde ceho
if(update_timer==0xFF) update_timer=UPDATE_TIME;
else update_timer--;
// vox timer
if(bit_test(_RUN_VOX))
if(vox_timer!=0) vox_timer--;
else
{
// vox vyprsel
bit_clear(_RUN_VOX);
output_low(RXTX); // prepni zpet na prijem
bit_clear(_TRANSMIT);
bit_set(_DDS_UPDATE);
}
// timer pro zjisteni dlouheho stisku tlacitek
if(key_timer!=0) key_timer--;
// periodicke cteni tlacitek
#use fast_io(C)
keys_work=(~input_c()) & KEY_MASK; // precti stav tlacitek
#use standard_io(C)
if(keys_work!=keys_old) keys_old=keys_work; // neshoda zapamatuj si novy stav
else
{
// shoda
if(keys_work!=0)
{
// tlacitko je STISKNUTO
if(keys==0)
{
// akceptujeme jen pokud bylo zpracovano vse predchozi
keys=keys_work; // zapamatuj si nove tlacitko
key_timer=KEY_LONG; // natahni casovac pro zjisteni dlouheho stisku
} else
{
// neco je jeste ke zpracovani
if(key_timer==0 && !bit_test(_KEYS_RELEASE))
{
// jde o dlouhy stisk tlacitka
bit_set(_KEYS_LONG);
bit_set(_KEYS_VALID);
}
}
} else
{
// tlacitko je UVOLNENO
if(key_timer!=0)
{
// jde o kratky stisk tlacitka
bit_set(_KEYS_VALID);
key_timer=0;
} else if(bit_test(_KEYS_RELEASE))
{
keys_flags=0; // jde o klidovy stav - tlacitka zpracovana
keys=0;
}
}
}
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
} // Tick_handler
// periodicke tiky kazdych 5ms
// vyuzito pro rizeli LCD_LED
//
#INT_TIMER2
void led_handler()
{
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
flash_timer++;
// rizeni LED
// pri prijmu bez attenuatoru sviti zelena
// pri prijmu s attenuatorem sviti zluta
// pri vysilani sviti cervena
// pri vybite baterii pri prijmu led blika
if(bit_test(_TRANSMIT))
{
// vysilani - rozsvid cervenou LED
if(bit_test(_LED_UPDATE)) output_high(LCD_LED1);
else output_low(LCD_LED1);
output_low(LCD_LED2);
} else
{
if(bit_test(_BATT_LOW) && bit_test(flash_timer,7))
{
// zhasni led
output_low(LCD_LED1);
output_low(LCD_LED2);
} else
{
// prijem - rozsvid zelenou nebo zlutou led
if(bit_test(_LED_UPDATE))
{
output_high(LCD_LED2);
output_low(LCD_LED1);
} else
{
output_low(LCD_LED2);
if(bit_test(_ATTN)) output_high(LCD_LED1);
else output_low(LCD_LED1);
}
}
}
if(bit_test(_LED_UPDATE)) bit_clear(_LED_UPDATE);
else bit_set(_LED_UPDATE);
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
} // led_handler
// cteni pak, klice
#INT_RB
void paddle_handler()
{
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
keyerb=(~input_b()); // precti stav pak
if(bit_test(_ELBUG_ON)) keyerb=keyerb & 0b11000000; // platne jsou obe paky
else keyerb=keyerb & 0b10000000; // platna je paka tecek
if(!bit_test(_TXDELAY)) // reagujeme jen kdyz nebezi TXDELAY
{
if(!bit_test(_ELBUG_ON))
{
// RUCNI KLICOVANI
set_timer0(TICK_TIME); // txdelay je dano jednim zakladnim tikem, natahni tik
_T0IF=0;
bit_set(_TXDELAY); // spustime TXDELAY
} else
{
// ELBUG
// nastav priznaky pak
if(bit_test(_ELBUG_REV))
{
if(bit_test(keyerb,6)) bit_set(_ELBUG_DOT);
if(bit_test(keyerb,7)) bit_set(_ELBUG_DASH);
} else
{
if(bit_test(keyerb,7)) bit_set(_ELBUG_DOT);
if(bit_test(keyerb,6)) bit_set(_ELBUG_DASH);
}
if(!bit_test(_ELBUG_BSY))
{
// spusteni elbugu
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); // spust casovac
_TMR1IF=1;
}
}
if(!bit_test(_TRANSMIT) && keyerb!=0) // pri stisku pak prejdeme na vysilani pokud tomu jiz tak neni
{
bit_set(_TRANSMIT); // priznak stavu vysilani
output_high(RXTX); // prepni TRX na vysilani
bit_set(_DDS_UPDATE); // nastav vysilaci kmitocet
}
}
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
} // paddle_handler
// elbug
//
#int_timer1
void elbug_handler()
{
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
if(bit_test(_ELBUG_SP))
{
// odvysilali jsem tecku nebo carku - musime dovysilat mezeru
bit_clear(_ELBUG_SP); // priste budeme vysilat podle stavu pak
bit_clear(_ELBUG_OUT);
set_timer1(elbug_dot_sp); // natahni casovac na mezeru
set_timer0(TICK_TIME); // txdelay je dano jednim zakladnim tikem, natahni tik
_T0IF=0;
bit_set(_TXDELAY); // spustime TXDELAY
return;
}
if(bit_test(_ELBUG_BSY))
{
// odvysilali jsme posloupnost tecka-mezera nebo carka-mezera
// nuluj priznak prave dovysilaneho elementu
if(bit_test(_ELBUG_LAST)) bit_clear(_ELBUG_DASH);
else bit_clear(_ELBUG_DOT);
// dale se rozhodujeme podle stavu pak
keyer=(~input_b()) & 0b11000000; // precti stav pak
// nastav priznak pak podle stisknute paky
if(bit_test(_ELBUG_REV))
{
if(bit_test(keyer,6)) bit_set(_ELBUG_DOT);
if(bit_test(keyer,7)) bit_set(_ELBUG_DASH);
} else
{
if(bit_test(keyer,7)) bit_set(_ELBUG_DOT);
if(bit_test(keyer,6)) bit_set(_ELBUG_DASH);
}
if(bit_test(_ELBUG_REAL) && keyer==0) // nestisknuto nic
{
// pri realnem klicovani po uvolneni pak se uz dal nic nevysila
bit_clear(_ELBUG_DOT);
bit_clear(_ELBUG_DASH);
}
}
// prepnuti na vysilani pokud tomu uz tak neni
if(!bit_test(_TRANSMIT) &&
(bit_test(_ELBUG_DOT) || bit_test(_ELBUG_DASH)))
{
bit_set(_TRANSMIT); // priznak stavu vysilani
output_high(RXTX); // prepni TRX na vysilani
bit_set(_DDS_UPDATE); // nastav vysilaci kmitocet
}
// nastav hodnotu casovace podle stisknute paky
if(bit_test(_ELBUG_DOT))
{
if(bit_test(_ELBUG_DASH))
{
// stisknuty obe paky - vysilej opak priznaku LAST
if(bit_test(_ELBUG_LAST))
{
bit_clear(_ELBUG_LAST);
set_timer1(elbug_dot_sp); // natahni casovac na tecku
} else
{
bit_set(_ELBUG_LAST);
set_timer1(elbug_dash); // natahni casovac na carku
}
} else
{
bit_clear(_ELBUG_LAST);
set_timer1(elbug_dot_sp); // natahni casovac na tecku
}
} else if(bit_test(_ELBUG_DASH))
{
bit_set(_ELBUG_LAST);
set_timer1(elbug_dash); // natahni casovac na carku
} else
{
// NENI CO VYSILAT -KONCIME
bit_clear(_ELBUG_BSY);
setup_timer_1(T1_DISABLED); // zastav casovac
return;
}
bit_set(_ELBUG_BSY); // elbug bezi
bit_set(_ELBUG_SP); // priste musime vysilat mezeru
bit_set(_ELBUG_OUT);
set_timer0(TICK_TIME); // txdelay je dano jednim zakladnim tikem, natahni tik
_T0IF=0;
bit_set(_TXDELAY); // spustime TXDELAY
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
} // elbug_handler
/////////// FUNKCE PRO OVLADANI UTLUMU /////////
// natavi utlum
//
void Attn_0dB()
{
output_low(ATN1);
output_low(ATN2);
output_high(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
delay_ms(RELE_PULSE);
input(ATN1);
input(ATN2);
}
// natavi utlum
//
void Attn_6dB()
{
output_high(ATN1);
output_low(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
output_low(ATN2);
output_high(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
delay_ms(RELE_PULSE);
input(ATN1);
input(ATN2);
}
// natavi utlum
//
void Attn_12dB()
{
output_low(ATN1);
output_high(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
output_high(ATN2);
output_low(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
delay_ms(RELE_PULSE);
input(ATN1);
input(ATN2);
}
// natavi utlum
//
void Attn_18dB()
{
output_high(ATN1);
output_high(ATN2);
output_low(ATNC);
delay_ms(RELE_PULSE);
input(ATNC); // prepni ANTC zpet do tretiho stavu (vstup)
delay_ms(RELE_PULSE);
input(ATN1);
input(ATN2);
}
/*
// precte z prevodnihu hornich 8 bitu
//
int8 adc()
{
return(read_adc()>>8) ;
} // adc
*/
/////////// FUNKCE PRO PRACI S EEPROM /////////
// aktualizuje kontrolni soucet
//
void update_eeprom()
{
int8 i;
int8 crc;
crc=0;
for(i=0;i<EE_ADR_CRC;i++) crc+=read_eeprom(i);
crc=0-crc;
write_eeprom(EE_ADR_CRC,crc);
} // update_eeprom
// zkontroluje obsah pameti eeprom a pokud je poskozen, nAstavi defaultni parametry
//
void check_eeprom()
{
int8 i;
int8 crc;
crc=0;
for(i=0;i<=EE_ADR_CRC;i++) crc=crc+read_eeprom(i);
if(crc!=0)
{
i=EE_ADR_POWER;
while(i<BAND_NUM) write_eeprom(i++,PAR_LIMIT[PAR_POWER][0]); // minimalni vykon na vsech pasmech
write_eeprom(EE_ADR_KEYER,20); // nastaveno 20 WPM
write_eeprom(EE_ADR_VOX,6); // vox 300ms
write_eeprom(EE_ADR_BATT,0); // konstantni hodntota,dale se nemeni
write_eeprom(EE_ADR_KEYER_REV,0); // nereverzuj paky
write_eeprom(EE_ADR_KEYER_MODE,0); // doplnkove klicovani
write_eeprom(EE_ADR_ATTN,PAR_LIMIT[PAR_VOX][0]); // utlum vypnut
update_eeprom(); // aktualizuj kontorlni soucet
}
} // check_eeprom
/////////////////////////////////////
// VYKONNE FUNKCE HLAVNI SMYCKY
/////////////////////////////////////
// zpracovani zmeny polohy kroutitka
// trva max 600cyklu (600us)
//
// CHELO BY TO UCESAT POMOCI KONSTRUKCE IF - RETURN
#inline
void enc_chng()
{
int32 freq_dds;
signed int32 delta_freq;
signed int16 delta_rit;
if(bit_test(_MNU) || bit_test(_MNU2))
{
// NASTAVUJEME PARAMETRY
if(enc_delta<ENC_HISTEREZE && enc_delta>-ENC_HISTEREZE) return; // zmeny pod minimum si nevsimej
if(enc_delta>0)
{
// nastala zmena +1
if(bit_test(_MNU2))
{
if(par_index<PAR_NUM-3)
{
par_index++; // zmena typu parametru pokud projde kontrola horni meze
bit_set(_LCD2_UPDATE);
}
} else if(par[par_index]<PAR_LIMIT[par_index][1]) // zmena hodnoty parametru pokud projde kontrola horni meze
{
par[par_index]++;
bit_set(_PAR_UPDATE); // pozadavek aktualizace parametru
}
} else
{
// nastala zmena -1
if(bit_test(_MNU2))
{
if(par_index>0)
{
par_index--; // zmena typu parametru pokud projde kontrola dolni meze
bit_set(_LCD2_UPDATE);
}
} else if(par[par_index]>PAR_LIMIT[par_index][0]) // zmena hodnoty parametru pokud projde kontrola dolni meze
{
par[par_index]--;
bit_set(_PAR_UPDATE); // pozadavek aktualizace parametru
}
}
enc_delta=0; // zmena provedena
} else
{
// LADIME KMITOCET
if(bit_test(_RIT))
{
// ladime RIT
delta_rit=enc_delta*RIT_STEP;
enc_delta=0;
if(freq_rit+delta_rit <=RIT_LIMIT[1] &&
freq_rit+delta_rit >=RIT_LIMIT[0]) freq_rit+=delta_rit;
} else
{
// ladime VFO
delta_freq=enc_delta*FREQ_STEP[step_index];
enc_delta=0;
freq_dds=freq_vfo[vfo_index]+delta_freq;
if(freq_dds <=BAND_LIMIT[band_index][1] &&
freq_dds >=BAND_LIMIT[band_index][0]) freq_vfo[vfo_index]+=delta_freq;
}
bit_set(_DDS_UPDATE); // pozadujeme zmenu kmitoctu v DDS
}
bit_clear(_ENC_CHNG); // zmena polohy kroutitka zpracovana
} // enc_chng
// aktualizuje parametry
//
#inline
void par_update()
{
// int16 power;
bit_clear(_PAR_UPDATE);
switch(par_index)
{
case PAR_ATTN:
bit_set(_ATTN); // pri utlumu bude misto zelene led svitit zluta
switch(par[PAR_ATTN])
{
case 1: Attn_6dB();
break;
case 2: Attn_12dB();
break;
case 3: Attn_18dB();
break;
default:Attn_0dB();
bit_clear(_ATTN); // zadny utlum, zpet zelena led
break;
}
break;
case PAR_POWER:
// set_pwm2_duty(par[PAR_POWER]);
// power=par[PAR_POWER];
// set_pwm2_duty(power<<1);
//!!!!!
power=par[PAR_POWER]*5; // vykon je v nasobcich 0.5W
break;
case PAR_KEYER:
if(par[PAR_KEYER]<=PAR_LIMIT[PAR_KEYER][0]) bit_clear(_ELBUG_ON); ///elbug_flags=0; // vypni elbug
else
{
// zapni elbug a nastav rychlost
bit_set(_ELBUG_ON);
elbug_dot_sp=~(ELBUG_CONST/par[PAR_KEYER]); // preved na hodnotu citace TMR1
elbug_dot_sp++;
elbug_dash=(elbug_dot_sp<<1)+elbug_dot_sp; // *3, ale rychleji
}
break;
case PAR_VOX:
vox_time=par[PAR_VOX];
if(vox_time!=0) vox_time=vox_time*10; // cas je ve 50ms jednotkach
else vox_time=1; // minimalni vox je 5ms
break;
case PAR_KEYER_REV:
if(par[PAR_KEYER_REV]) bit_set(_ELBUG_REV); //
else bit_clear(_ELBUG_REV);
break;
case PAR_KEYER_MODE:
// if(par[PAR_KEYER_MODE]) bit_set(_ELBUG_REAL); //
// else bit_clear(_ELBUG_REAL);
break;
}
bit_set(_LCD2_UPDATE); // pozadujeme update 2. radku dispeje
} // par_update()
// aktualizuje kmitocet v dds
// trva max. cca 2500cyklu (2.5ms)
//
#inline
void dds_update()
{
int32 freq_dds;
signed int32 delta_freq;
signed int32 freq_rit2;
if(!bit_test(_TRANSMIT))
{
// PRIJEM
if(band_index>=SUB_IF_INDEX) freq_dds=freq_vfo[vfo_index]-FREQ_IF; // pri prijmu na 14MHz se odecita kmitocet mezifrekvence
else freq_dds=freq_vfo[vfo_index]+FREQ_IF; // pri prijmu pod 14MHz se pricita kmitocet mezifrekvence
if(bit_test(_RIT))
{
freq_rit2=freq_rit; // prevod na signed int32, chyba v C, neumi int32 + signed int16
freq_dds=freq_dds+freq_rit2; // je-li zapnut RIT, udelej korekci kmitoctu
}
bit_set(_LCD1_UPDATE); // pozadujeme zmenit kmitocet na lcd
} else
{
// VYSILANI
if(bit_test(_SPLIT)) // pri split se pouzije opacne vfo
freq_dds=freq_vfo[(~vfo_index)];
else freq_dds=freq_vfo[vfo_index];
}
dds_freq0((int32)((float)freq_dds*CONVERT_CONST)); // odesli jej do DDS trva to cca 2050 cylklu (2.05ms)
bit_clear(_DDS_UPDATE); // kmitocet v dds zmenen
// bit_set(_LCD1_UPDATE); // pozadujeme zmenit kmitocet na lcd
} // dds_update
// aktualizuje zobrazeni na lcd - 1.radek
// trva max. 3000cyklu (30ms) !!!!!!
//
//#inline
#separate
int8 lcd1_update()
{
int16 rit_val;
lcd_gotoxy(1,1);
bit_clear(_LCD1_UPDATE);
if(bit_test(_MNU2)) printf(lcd_putc,"PARAM: "); // zobraz ze vybirame typ parametru
else if(bit_test(_MNU))
{
// zobraz nazev parametru
switch(par_index)
{
case PAR_ATTN: printf(lcd_putc,"ATTN: ");
break;
case PAR_POWER: printf(lcd_putc,"POWER: ");
break;
case PAR_KEYER: printf(lcd_putc,"KEYER: ");
break;
case PAR_VOX: printf(lcd_putc,"DELAY: ");
break;
case INF_BATT: printf(lcd_putc,"BATTERY:");
break;
case PAR_KEYER_MODE: printf(lcd_putc,"MODE: ");
break;
case PAR_KEYER_REV: printf(lcd_putc,"REVERSE:");
break;
}
} else if(bit_test(_RIT))
{
// POZN: fce printf spatne zachazi se znaminkovimi cisly, proto je znamenko
// zobrazeno samostatne a rit je preveden na neznamenkove cislo
printf(lcd_putc,"RIT:");
if(freq_rit<0) lcd_putc('+');
else lcd_putc('-');
rit_val=abs(freq_rit);
lcd_pos=0;
printf(rit_lcd_putc,"%04LU",rit_val); // zobraz RIT na LCD
} else
{
lcd_pos=0;
printf(vfo_lcd_putc,"%8LD",freq_vfo[vfo_index]); // zobraz kmitocet na LCD
}
} // lcd1_update
// pomocna funkce pro zobrazeni vykonu a psv na lcd
//
#separate
void lcd_pwr_psv()
{
#ifdef ADC_LCD
printf(lcd_putc,"F%2X R%2X",pwr_val,psv_val);
#else
// vysilani - zobrazujeme vykon a psv
if(pwr_val>99) printf(lcd_putc,">10");
else
{
lcd_pos=0;
printf(pwr_lcd_putc,"%02U",pwr_val);
}
printf(lcd_putc,"W ");
if(psv_val>99) printf(lcd_putc,">10");
else
{
lcd_pos=0;
printf(pwr_lcd_putc,"%02U",psv_val);
}
#endif
} // lcd_pwr_psv
// aktualizuje zobrazeni na lcd - 2.radek
// trva max 2000 cyklu (2ms)
//
//#inline
#separate
void lcd2_update()
{
int8 i;
int16 vox;
int16 batt;
bit_clear(_LCD2_UPDATE);
lcd_gotoxy(1,2);
if(bit_test(_MNU2))
{
// zobraz vybrany parametr
switch(par_index)
{
case PAR_POWER: printf(lcd_putc,"POWER ");
break;
case PAR_VOX: printf(lcd_putc,"DELAY ");
break;
case INF_BATT: printf(lcd_putc,"BATTERY ");
break;
case PAR_KEYER_MODE: printf(lcd_putc,"MODE ");
break;
case PAR_KEYER_REV: printf(lcd_putc,"REVERSE ");
break;
}
} else if(bit_test(_MNU))
{
// zobraz hodnotu parametru
switch(par_index)
{
case PAR_ATTN: printf(lcd_putc,"-%2U dB ",par[PAR_ATTN]*6); // krok je po 6dB
break;
case PAR_POWER: if(!bit_test(_TRANSMIT))
{
lcd_pos=0;
printf(pwr_lcd_putc,"%02UW PTT",power); // prijem - zobraz pozadovany vykon a vyzvu k vysilani
} else lcd_pwr_psv(); // vysilani - zobraz vykon a psv
break;
case PAR_KEYER: if( par[PAR_KEYER]<=PAR_LIMIT[PAR_KEYER][0]) printf(lcd_putc,"OFF ");
else printf(lcd_putc,"%2U ",par[PAR_KEYER]);
break;
case PAR_VOX:
vox=par[PAR_VOX];
vox=vox*50; // ve 50ms jednotkach
printf(lcd_putc,"%4LU ms ",vox);
break;
case INF_BATT:
#ifdef ADC_LCD
printf(lcd_putc,"%3X V ",batt_val);
#else
// zobraz napeti baterie na desetiny voltu
batt=batt_val;
batt=(batt*10)/16;
lcd_pos=0;
printf(batt_lcd_putc,"%03UV ",(int8)batt);
#endif
break;
case PAR_KEYER_MODE:
if(par[PAR_KEYER_MODE]) printf(lcd_putc,"B ");
else printf(lcd_putc,"A ");
break;
case PAR_KEYER_REV:
if(par[PAR_KEYER_REV]) printf(lcd_putc,"YES ");
else printf(lcd_putc,"NO ");
break;
}
} else if(bit_test(_TRANSMIT)) lcd_pwr_psv(); // vysilani - zobraz vykon a psv
else if(!bit_test(_ELBUG_BSY)) // v mezerach mezi znackami elbugu S-metr nezobrazuj
{
// prijem - zobrazujeme S-metr
#ifdef ADC_LCD
printf(lcd_putc,"SMTR:%2X ",smtr_val);
#else
if(smtr_val<=S_METER[0]) lcd_putc('2');
else lcd_putc(' ');
if(smtr_val<=S_METER[1]) lcd_putc('3');
else lcd_putc(' ');
if(smtr_val<=S_METER[2]) lcd_putc('4');
else lcd_putc(' ');
if(smtr_val<=S_METER[3]) lcd_putc('5');
else lcd_putc(' ');
if(smtr_val<=S_METER[4]) lcd_putc('6');
else lcd_putc(' ');
if(smtr_val<=S_METER[5]) lcd_putc('7');
else lcd_putc(' ');
if(smtr_val<=S_METER[6]) lcd_putc('8');
else lcd_putc(' ');
if(smtr_val<=S_METER[8]) lcd_putc('\23');
else if(smtr_val<=S_METER[7]) lcd_putc('9');
else lcd_putc(' ');
#endif
}
} // lcd2_update()
// nastavi pasmo podle pripojeneho filtru
//
//#inline
void set_band()
{
// int8 adc_band;
set_adc_channel (BND_CH); // prepni ADC na vstup signalu BAND
delay_ms(20);
// opakuj dokud neni pripojen vhodny filtr
for(;;)
{
bnd_val=read_adc() & BAND_ADC_MASK;
// prohlidni tabulku moznych filtru
band_index=BAND_NUM;
while(band_index--)
{
if(bnd_val==BAND_ADC[band_index]) return; // platny filtr pritomen
}
printf(lcd_putc,"\rCONNECT\n");
printf(lcd_putc," FILTER");
delay_ms(500);
}
} // set_band
// mereni analogovych vstupu
//
// doba trvani max 3000 cyklu (3ms)
#separate
void analog_inputs()
{
static int8 count;
int16 k;
int32 pom32,pom32_2; // pro vypocet dopredneho vykonu
int16 pom16,pom16_2; // pro vypocet PSV
signed int8 delta;
#ifndef NO_FILTER_CONTROL // vyrazuje prubeznou kontrolu pritomnosti filtru pro prislusne pasmo
if((bnd_val & BAND_ADC_MASK)!=BAND_ADC[band_index]) reset_cpu(); // fittr byl odpojen
#endif
// mereni napeti baterie
if(batt_val+5<=BATT_MIN) bit_set(_BATT_LOW); // baterie je vybita
// vypocti aktualni vykon a psv a reguluj vykon
if(bit_test(_TRANSMIT))
{
#ifdef ADC_LCD // vypina zpracovani - zobrazuje prime hodnoty z prevodniku
pwr_val=fwd_val;
psv_val=rev_val;
#else
// vypocti vykon na desetiny watu
pom32=fwd_val;
pom32=pom32*pom32; // vykon je umerny kvadratu napeti
// vynasobime *10 - vykon bude 100mW jednotkach
// realizuje *10, je vyrazne casove kratsi ( o cca 500cyklu)
pom32_2=pom32<<3;
pom32_2=pom32_2+pom32;
pom32_2=pom32_2+pom32;
pwr_val=pom32_2/PWR_FWD_CONST; // vydelime kalibracni konstantou pro dopredny vykon
// vypocti PSV na desetinu
if(fwd_val>=0 && rev_val==0) psv_val=10; // psv je 1.0 pokud je odrazeny vykon nulovy
else
{
pom16=fwd_val;
pom16=pom16<<4; // vynasobime *16 pro vetsi presnost
k=pom16/rev_val; // pomer odpovidajici ciniteli odrazu
if(k<=16) psv_val=250; // PSV se blizi nekonecnu
else if(k>337) psv_val=10; // psv je lepsi jak 1.1 tedy ho povazujeme za 1.0
else
{
// toto realizuje vyraz (k+16)*10
pom16=k+16;
pom16_2=pom16<<3;
pom16_2=pom16_2+pom16;
pom16_2=pom16_2+pom16;
// vypocet psv
psv_val=pom16_2/(k-16);
}
}
// rizeni vykonu (ALC)
if(psv_val>BAD_PSV) delta=PWR_LIM-pwr_val; // pri spatnem PSV omez vykon
else delta=power-pwr_val;
if(delta<-PWR_HIST_HI && pwm_val>PWM_MIN)
{
if(delta<-10) pwm_val=pwm_val-4;
else pwm_val--;
pom16=pwm_val;
set_pwm2_duty(pom16<<1);
} else if(delta>PWR_HIST_LO && pwm_val<PWM_MAX)
{
if(delta>10) pwm_val=pwm_val+4;
else pwm_val++;
pom16=pwm_val;
set_pwm2_duty(pom16<<1);
}
#endif
}
// zobrazeni na LCD delame mene casto
if(count>4)
{
bit_set(_LCD2_UPDATE);
count=0;
} else count++;
}// analog_inputs
/*
void pwr_control()
{
int16 aaa;
signed int8 delta;
if(bit_test(_TRANSMIT))
{
delta=power-pwr_val;
if(delta<-1 && pwm_val>27)
{
if(delta<-10) pwm_val=pwm_val-4;
else
pwm_val--;
aaa=pwm_val;
set_pwm2_duty(aaa<<1);
} else if(delta>2 && pwm_val<157)
{
if(delta>10) pwm_val=pwm_val+4;
else
pwm_val++;
aaa=pwm_val;
set_pwm2_duty(aaa<<1);
}
}
} // pwr_control
*/
/////////////////////////////////
///// HLAVNI FUNKCE /////
/////////////////////////////////
void main()
{
int8 ee_adr;
int8 a;
int8 b;
signed int8 c;
// inicializace LCD
lcd_init();
// definice specialnich znaku
lcd_define_char(2,LCD_CHAR_a_FILL);
lcd_define_char(1,LCD_CHAR_b_FILL);
lcd_define_char(3,LCD_CHAR_9_FILL);
// nastaveni smeru signalu a jejich klidovych stavu
port_b_pullups(TRUE);
output_high(DDS_FSYNC); // zapis_so DDS neaktivni
output_low(DDS_SDATA); // data do 0
output_high(DDS_SCK); // hodiny do neaktivniho stavu
output_low(RXTX); // prepni na prijem
output_low(KEYING); // neklicuj
output_low(LCD_LED2); // zhasni led
output_low(LCD_LED1); // zhasni led
input(TONE); // vypni priposlech
output_low(PWR_CTRL); // nulovy vykon
output_low(ATN1);
output_low(ATN2);
output_low(ATNC);
// inicializace DDS
dds_send(CTRL_RESET); // pozadujeme reset
dds_send(CLR_PHASE0);
dds_send(CLR_PHASE1);
// zakladni nastaveni ridicich promennych programu
update_timer=UPDATE_TIME; // natahni periodicky timer pro LCD
flags=0; // nuluj priznaky ridici program
elbug_flags=0; // nuluj priznaky pro elbug
keys_flags=0;
adc_flags=0;
adc_ch=0;
pwm_val=PWM_MIN;
enc_delta=0; // zadna zmena od kroutitka
keys=0; // zadna tlacitka nejsou stisknuta
freq_rit=0; // nuluj RIT
// uvodni hlaseni programu
lcd_gotoxy(1,1);
printf(lcd_putc,NAME);
lcd_gotoxy(1,2);
printf(lcd_putc,VERSION);
delay_ms(1000);
// nastaveni AD prevodniku
setup_adc(ADC_CLOCK_DIV_8);
setup_adc_ports(AN0_AN1_AN2_AN3_AN4); // povoleny porty AN0-AN4
set_band(); // nastav pasmo podle pripojeneho filtru nebo cekej na jeho pripojeni
check_eeprom(); // kontrola platnosti obsahu eeprom, pri poruse nastav defaultni parametry
// obnoveni a nastaveni parametru programu
par[PAR_POWER]=read_eeprom(EE_ADR_POWER+band_index); // vyzvedni nastaveny vykon pro dane pasmo
power=par[PAR_POWER]*5;
par[PAR_KEYER]=read_eeprom(EE_ADR_KEYER); // vyzvedni rychlost klice
if(par[PAR_KEYER]<=PAR_LIMIT[PAR_KEYER][0]) elbug_flags=0; // vypni elbug
else
{
// zapni elbug a nastav rychlost
bit_set(_ELBUG_ON);
elbug_dot_sp=~(ELBUG_CONST/par[PAR_KEYER]); // preved na hodnotu citace TMR1
elbug_dot_sp++;
elbug_dash=(elbug_dot_sp<<1)+elbug_dot_sp; // *3, ale rychleji
}
par[PAR_VOX]=read_eeprom(EE_ADR_VOX); // vyzvedni vox
vox_time=par[PAR_VOX];
if(vox_time!=0) vox_time=vox_time*20; // cas je ve 100ms jednotkach
else vox_time=2;
par[PAR_KEYER_REV]=read_eeprom(EE_ADR_KEYER_REV); // vyzvedni chapani pak
if(par[PAR_KEYER_REV]) bit_set(_ELBUG_REV); //
else bit_clear(_ELBUG_REV);
par[PAR_KEYER_REV]=read_eeprom(EE_ADR_KEYER_REV); // vyzvedni mod elbugu
// if(par[PAR_KEYER_REV]) bit_set(_ELBUG_REAL); //
// else bit_clear(_ELBUG_REAL);
bit_clear(_ELBUG_REAL); // mod elbugu je zatim vzdy doplnkovy
par[PAR_ATTN]=PAR_LIMIT[PAR_ATTN][0]; // attenuator vzdy vypnut
Attn_0dB();
freq_vfo[0]=START_FREQ[band_index]; // QRP volaci kmitocet BAND_LIMIT[band_index][0] ; // po zapnuti ma VFO nejmensi kmitocet pasma
freq_vfo[1]=START_FREQ[band_index]; // QRP volaci kmitocet BAND_LIMIT[band_index][0] ; // po zapnuti ma VFO nejmensi kmitocet pasma
bit_set(_DDS_UPDATE); // pozadujeme nastavit kmitocet v dds
step_index=0; // defaultne jemny krok ladeni
vfo_index=0; // defaultne vfoA
// nastaveni zakladniho tiku
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
set_timer0(TICK_TIME);
// nastaveni pro generovani priposlechu, rizeni LCD_LED a PWM pro rizeni vykonu
setup_timer_2(T2_DIV_BY_16,TONE_SET,4); // zajisti pro PWM rozliseni 8.28 bitu
setup_ccp1(CCP_PWM); // pro generovani tonu
set_pwm1_duty((TONE_SET+1)/2); // strida cca 1:1
tone_off(); // priposlech vypnut
setup_ccp2(CCP_PWM); // pro rizeni vykonu
set_pwm2_duty((int16)27); //
setup_timer_1(T1_DISABLED); // elbug je v klidu
#use fast_io(b)
keyer=(~input_b()) & 0b11000000; // precti stav pak
#use standard_io(b)
if(bit_test(keyer,6)) bit_clear(_ELBUG_ON); // pokud je ori zapnuti stisknuta paka carek, je pripojen rucni klic
// povoleni preruseni
enable_interrupts(INT_EXT); // preruseni od zmeny polohy kroutitka
enable_interrupts(INT_TIMER0); // zakadni tik
enable_interrupts(INT_TIMER2); // preruseni pro rizeni vykonu, LED a generovani priposlechu
enable_interrupts(INT_TIMER1); // preruseni pro elbug
enable_interrupts(INT_RB); // preruseni od stavu pak klice
enable_interrupts(GLOBAL);
//#define TEST
#ifdef TEST
bit_set(_TRANSMIT);
//bit_set(_MNU);
fwd_val=150;
rev_val=10;
smtr_val=150;
bnd_val=0x20;
a=50;
b=5;
// testovaci smycka pro zjistovani doby behu testovane funkce
setup_timer_1(T1_INTERNAL|RTCC_DIV_1);
set_timer1(0);
//Analog_inputs();
c=b-a;
setup_timer_1(T1_DISABLED);
lcd_gotoxy(1,1);
printf(lcd_putc,"T:%LU",get_timer1());
lcd_gotoxy(1,2);
printf(lcd_putc,"%D",c);
for(;;);
#else
// HLAVNI SMYCKA
for(;;)
{
/////////////////
// pozadavek na zmenu kmitoctu (max. 2,5ms)
if(bit_test(_DDS_UPDATE)) dds_update();
////////////////
// nastala zmena polohy kroutitka
if(bit_test(_ENC_CHNG)) enc_chng();
/////////////////
// zmena parametru
if(bit_test(_PAR_UPDATE)) par_update();
/////////////////
// pozadavek zmeny kmitoctu na lcd - 1.radek (zabere 30ms !!!!!)
// PODMINKU NUTNO UPRAVIT
if(bit_test(_LCD1_UPDATE) && update_timer==0 && !bit_test(_ELBUG_BSY)) lcd1_update();
/////////////////
// pozadavek na zmenu informaci na lcd - 2.radek (max 2ms)
if(bit_test(_LCD2_UPDATE) && update_timer==0)
{
lcd2_update();
update_timer=0xFF; // ukonci okno,kdy je timer vyprseny
}
/////////////////
// periodicka mereni (max 3ms)
if(update_timer==0)
{
analog_inputs();
update_timer=0xFF; // ukonci okno,kdy je timer vyprseny
}
/////////////////
// stisknuta tlacitka
if(bit_test(_KEYS_VALID)) // stisknuto nejake tlacitko
{
// kratky stisk libovolneho tlacitka ukonci nastavovani
if(bit_test(_MNU) && !bit_test(_KEYS_LONG))
{
bit_clear(_MNU); // vypni nastavovani
enc_delta=0; // zahod nacitane zbyle impulzy korutitka
if(bit_test(_ELBUG_ON_TMP)) bit_set(_ELBUG_ON); // obnov zapnuti elbugu pokud byl zapnut
if(par_index!=PAR_ATTN) // stav attenuatoru se neuklada do eeprom
{
ee_adr=EE_ADDR[par_index];
if(par_index==PAR_POWER) ee_adr=ee_adr+band_index; // pro parametr vykonu urci adresu eeprom pro dane pasmo
if(read_eeprom(ee_adr)!=par[par_index]) // pokud doslo ke zmene parametru, aktualizuj ho v eeprom
{
write_eeprom(ee_adr,par[par_index]);
update_eeprom();
}
}
bit_set(_LCD1_UPDATE);
bit_set(_LCD2_UPDATE);
} else
{
// ktere tlacitko je stisknuto?
if(keys==KEY_SPLIT) // SPLIT/MNU
{
if(bit_test(_KEYS_LONG))
{
// dlouhy stisk - vstup do MENU
bit_set(_MNU2); // prvni stisk - vyber parametr
par_index=PAR_POWER;
bit_set(_LCD1_UPDATE);
bit_set(_LCD2_UPDATE);
} else
{
// kratky stisk - pokracovani v MENU
if(bit_test(_MNU2))
{
if(par_index==PAR_POWER)
{
// zapamatuj si , zda je elbug zapnut nebo vypnut
if(bit_test(_ELBUG_ON)) bit_set(_ELBUG_ON_TMP);
else bit_clear(_ELBUG_ON_TMP);
bit_clear(_ELBUG_ON); // pri nastavovani vykonu je elbug vypnut
}
bit_clear(_MNU2); // druhy stisk - prejdi do vybraneho parametru
bit_set(_MNU);
} else
{
// kratky stisk - funkce SPLIT
if(bit_test(_SPLIT)) bit_clear(_SPLIT);
else bit_set(_SPLIT);
}
bit_set(_LCD1_UPDATE);
}
} // KEY_SPLIT
// ostani tlacitka jsou aktivni jen kdyz nejsme ve vyberu parametru
if(!bit_test(_MNU2))
{
if(keys==KEY_RIT) // RIT/STEP
{
if(bit_test(_KEYS_LONG))
{
// dlouhy stisk - funkce STEP
if(step_index) step_index=0;
else step_index=1;
bit_set(_LCD1_UPDATE);
} else
{
// kratky stisk - funkce RIT
if(bit_test(_RIT))
{
bit_clear(_RIT);
freq_rit=0; // pri vypnuti RIT vynuluj
} else bit_set(_RIT);
bit_set(_DDS_UPDATE);
}
} // KEY_RIT
if(keys==KEY_CHNGVFO) // prepni VFO/srovnej VFO
{
if(bit_test(_KEYS_LONG))
{
// dlouhy stisk - funkce srovnej VFO
if(vfo_index) freq_vfo[0]=freq_vfo[1];
else freq_vfo[1]=freq_vfo[0];
} else
{
// kratky stisk - funkce prepni VFO
if(vfo_index) vfo_index=0;
else vfo_index=1;
bit_set(_DDS_UPDATE);
}
} // KEY_CHNGVFO
if(keys==KEY_ATTN) // ATTN/ELBUG
{
if(bit_test(_KEYS_LONG))
{
// dlouhy stisk - funkce ELBUG
par_index=PAR_KEYER;
bit_set(_MNU);
bit_set(_LCD1_UPDATE);
bit_set(_LCD2_UPDATE);
} else
{
// kratky stisk - funkce ATTN - mozne jen pokud se nevysila
par_index=PAR_ATTN;
bit_set(_MNU);
bit_set(_LCD1_UPDATE);
bit_set(_LCD2_UPDATE);
}
} // KEY_ATTN
}
}
bit_clear(_KEYS_VALID); // tlacitko zpracovano
bit_set(_KEYS_RELEASE); // budeme cekat na uvolneni tlacitek
}
} // hlavni smycka
#endif
}
// End of File