program GeneHF_90MHz;
{===============================================================================
par Silicium628
versions: voir plus bas dans la partie "const" - derniere mise à jour 22 aout 2008
================================================================================
PRINCIPE:
--------------------------------------------------------------------------------
================================================================================
La carte electronique répond aux signaux d'une télécommande TV infrarouge universelle
Beaucoup de modèles conviennent, il faudra adapter les codes des touches dans ce
programme le cas écheant (voir les 'case octet_IR of') dans la partie "main"
Pour ma part, j'utilise une PHILIPS type 'UNIVERSAL SBC RU 252 II'
================================================================================
}
{ $W+ Warnings} {Warnings off}
Device = mega8, VCC = 5;
Import SysTick, LCDport, {RTclock,} {TickTimer,} RC5Rxport, { FreqCount,} ADCPort;
// From RTclock Import RTCtimer;
From System Import Int64, float;
Define
ProcClock = 16000000; {Hertz}
SysTick = 10, Timer0; {msec} // ATTENTION: necessaire pour l'horloge RTC et LCD
// RTclock = iData, DateTime; {Time, DateTime}
// RTCsource = SysTick {, adj}; { adj = +/-100}
// RTCtimer = 4; // 4 cannaux
// FreqTimer = Timer1; // (used 16bit Timer}
StackSize = 256, iData; // (voir affi en runtime)
FrameSize = 128, iData;
LCDport = PortB, 0, PortC, 0; // control port, bit, Data port, bit ; voir le docuDriver.pdf (3.4.3 LCD-Split)
//The first parameter defines the control port with its first used bit. The order of the bits are fixed but
//different to the non-split driver: RS, RW, E (, Enable2 optional).
LCDtype = 44780;
LCDrows = 4; {rows}
LCDcolumns = 20; {columns per line}
RC5Rxport = PinC, 4, negative; {Port, Pin#, polarity}
RC5mode = rc_6bit; {command bit count}
ADCchans = [6], iData; {use only 1 Channel, ADC5}
ADCpresc = 16;
Implementation
//==============================================================================
{$IDATA}
type
const
version : string = '4.0';
{ Type Declarations }
//==============================================================================
{$IDATA}
var
// delay : SysTimer8;
ticked : boolean;
// timeout1 : boolean; // pour RTCtimer
// timeout2 : boolean; // pour RTCtimer
// timeout3 : boolean; // pour RTCtimer
// timeout4 : boolean; // pour RTCtimer
stk1 : word;
itps : word;
OCR2_real : float;
rxAdr : byte;
rxCmd : byte;
adr1 : integer;
cmd1 : integer;
octet_IR : byte; //octet recu par le recepteur IR
bitsix : byte;
memobitsix : byte;
nouveau : boolean; // pour l'anti rebond signaux IR
acqui_ADC : word;
pos_bt : byte;
memo_pos_bt : byte;
digit_x : byte;
increment : word;
puiss10 : array[1..4] of word;
pos_cur : array[1..4] of byte;
// Frequence : longword;
// F_affi : longword;
F_base1 : word;
consigne_F : longword;
gamme : byte;
memo_gamme : byte;
manuel : boolean;
{--------------------------------------------------------------}
{functions }
procedure init_ports; // ports perso
// 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
begin
PortB:= %00000000;
DDRB:= DDRB or %00001000; // portB[3] = sortie (OC2)
DDRC:= DDRC and %001111; //PC4 en entree (IR)
portD:= %00100001;
DDRD:= %11111111;
end;
procedure interroge_IR;
begin
if RecvRC5(rxAdr, rxCmd) then // interroge IR
adr1:= integer(rxAdr);
cmd1:= {%00111111 and} integer(rxCmd);
octet_IR:= byte(cmd1); // le bit6 (=64 decimal) est=1 un appui de touche de la zapette sur deux
memobitsix:= bitsix;
bitsix:= octet_IR and %01000000;
if bitsix <> memobitsix then
nouveau:= true;
else nouveau:= false;
endif;
octet_IR:= octet_IR and %00111111; // on supprime l'info de repetition de l'octet
// portx:= portx or ......; // allume LED
else
octet_IR:= $FF;
// portx:= portx and %......; // eteint LED
endif;
if nouveau = false then octet_IR:= $FF; endif; // pas de repetition auto dans cette application
end;
procedure InitINTs; // A ADAPTER au ATmega8
begin
{ TCCR2:
wgm21,20 =11 ->Fast PMW
com21,com20=11 ->Set OC2 on Compare Match, clear OC2 at TOP ;
bits2,1,0: prescaler = 1/256
TCCR2:= %01111110;
}
TCCR2:= %00000000; // Timer2 non utilisé. OC2 = sortie (portB,3) normale
TIMSK := TIMSK or %00000000; // INT Timer2 comp disable; INT Timer2 overflow disable;
GICR := GICR or %00000000; // gere les INTs voir page 67 du pdf
MCUCR := MCUCR or %00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
end;
procedure Affiche_STACK_free; // attention: ne pas appeller depuis une INT sinon fait planter
begin
LCDxy(16, 3);
Write(LCDout, IntToStr(stk1 : 3 : '0') );
// LCDxy(16, 3);
// Write(LCDout, IntToStr(fram_free : 3 : '0') ); fonction bugguée? chaque lecture consomme 1 octet!
end;
(*
procedure RTCtickSecond; // CallBack from RTClock
begin
LCDxy(8, 0);
LCDclrEOL;
Write(LCDout, IntToStr(F_base1));
LCDxy(0, 0);
// LCDclrEOL;
Write(LCDout, ByteToStr(pos_bt : 2));
end;
*)
procedure active_ENB;
begin
portD:= portD and %11011111; // ENB/=0 (active le transfert entre le uC et le MC145170)
udelay(1); // 10us
end;
procedure desactive_ENB;
begin
portD:= portD or %00100000; // ENB/=1 (desactive ENB/ ce qui effectue le transfert dans les registres internes)
mdelay(1);
end;
procedure init_variables;
begin
puiss10[1]:= 1;
puiss10[2]:= 10;
puiss10[3]:= 100;
puiss10[4]:= 1000;
pos_cur[1]:= 0;
pos_cur[2]:= 1;
pos_cur[3]:= 3;
pos_cur[4]:= 4;
gamme:= 0;
manuel:= false;
end;
procedure clk_PLL;
begin
portD:= portD or %01000000;
udelay(1); // 10us
portD:= portD and %10111111;
udelay(1); // 10us
end;
procedure out_registre_C(C_data : byte);
//c'est le nombre de clocks qui determine le registre de destination
// en envoie le bit de poids fort en premier
var
n, p : byte;
begin
active_ENB;
for n:= 7 downto 0 do // 8 bits
// p:= 1 shl (n - 1);
// if (C_data and p) <> 0 then
if bit(C_data, n) then
portD:= portD or %10000000;
else
portD:= portD and %01111111;
endif;
clk_PLL;
endfor;
desactive_ENB;
end;
procedure out_registre_N(N_data : word); // vers la PLL MC145170
//c'est le nombre de clocks qui determine le registre de destination
// en envoie le bit de poids fort en premier
var
n : byte;
p : word;
begin
active_ENB;
for n:= 15 downto 0 do // 16 bits
if bit(N_data, n) then
portD:= portD or %10000000;
else
portD:= portD and %01111111;
endif;
clk_PLL;
endfor;
desactive_ENB;
end;
procedure out_registre_R(R_data : word); // vers la PLL MC145170
//c'est le nombre de clocks qui determine le registre de destination
// en envoie le bit de poids fort en premier
var
n : byte;
p : word;
begin
active_ENB;
for n:= 14 downto 0 do // 15 bits
if bit(R_data, n) then
portD:= portD or %10000000;
else
portD:= portD and %01111111;
endif;
clk_PLL;
endfor;
desactive_ENB;
end;
procedure init_registre_C; // de la PLL
{-------------------------------------------------------------------------------------------------------------
RAPPEL: programmation du registre C (8 bits) de la PLL MC145170:
C7 - POL:Select the output polarity of the phase/frequency detectors.
When set high, this bit inverts PDout and interchanges the fR function with fV as depicted in Figure 19.
Also see the phase detector output pin descriptions for more information. This bit is cleared low at power up.
C6 - PDA/B:Selects which phase/frequency detector is to be used.
When set high, enables the output of phase/frequency detector A (PDout) and disables phase/frequency detector B
by forcing fR and fV to the static high state.
When cleared low, phase/frequency detector B is enabled (fR and fV) and phase/frequency detector A is disabled
with PDout forced to the high-impedance state. This bit is cleared low at power up.
C5 - LDE:Enables the lock detector output when set high.
When the bit is cleared low, the LD output is forced to a static low level.
This bit is cleared low at power up.
C4 - C2, OSC2 - OSC0: Reference output controls which determines the REFout characteristics as shown below.
C4 C3 C2 REFout Frequency ; Upon power up, the bits are initialized such that OSCin/8 is selected.
000dc (Static Low)
001 OSCin
010 OSCin /2
011 OSCin /4
100 OSCin /8 (par Defaut)
101 OSCin /16
110 OSCin /8
111 OSCin /16
C1 - fVE:Enables the fV output when set high.
When cleared low, the fV output is forced to a static low level.
The bit is cleared low upon power up.
C0 - fRE:Enables the fR output when set high. When cleared low, the fR output is forced to a static low level.
The bit is cleared low upon power up.
-------------------------------------------------------------------------------------------------------------}
begin
// bits 76543210
out_registre_C(%01110011);
end;
procedure test_IR;
var
chr1 : char;
begin
LCDclr;
LCDxy(0, 0);
Write(LCDout, 'GeneHF 90MHz ' + version );
LCDxy(0, 1);
Write(LCDout, 'Test IR ok = out' );
repeat
interroge_IR;
if nouveau = true then
chr1:= '*';
else chr1:= ' ';
endif;
if octet_IR <> 255 then
LCDxy(0, 0);
LCDclrEOL;
Write(LCDout, ByteToStr(octet_IR : 3 : ' ') + ' ' + chr1);
mdelay(200);
endif;
until (octet_IR = 0) or (octet_IR = 23);
end;
procedure acqui_pos_btn;
// lit la position d'un potentiometre à resistances CMS discretes (63k au total)
begin
// LCDclr;
acqui_ADC:= GetADC; // resolution 10bits
case acqui_ADC of
881..900 : pos_bt:= 0; // 884
|
875..880 : pos_bt:= 1; // 878
|
869..874 : pos_bt:= 2; // 871
|
860..868 : pos_bt:= 3; // 862
|
851..859 : pos_bt:= 4; // 854
|
839..850 : pos_bt:= 5; // 844
|
826..838 : pos_bt:= 6; // 831
|
811..825 : pos_bt:= 7; // 819
|
791..810 : pos_bt:= 8; // 804
|
776..790 : pos_bt:= 9; // 787
|
756..775 : pos_bt:= 10; // 768
|
736..755 : pos_bt:= 11; // 744
|
701..735 : pos_bt:= 12; // 717
|
671..700 : pos_bt:= 13; // 683
|
631..670 : pos_bt:= 14; // 639
|
551..630 : pos_bt:= 15; // 585
|
451..550 : pos_bt:= 16; // 512
|
350..450 : pos_bt:= 17; // 409
|
200..300 : pos_bt:= 18; // 255
|
0..100 : pos_bt:= 19; // 0
|
endcase;
// LCDxy(0, 1);
// Write(LCDout, ByteToStr(n : 3));
end;
procedure commute_selfs(gamme1 : byte);
// gamme = 1..7
// chaque bit commute une des trois selfs. Les selfs peuvent donc etre utilisees en //
begin
portD:= portD and %11111000;
portD:= portD or (gamme1 and %00000111);
end;
procedure select_gamme;
// a finaliser, sans trous, apres avoir ajuste toutes les selfs
begin
memo_gamme:= gamme;
case F_base1 of
8001..9000 : gamme:= 7;
|
7301..8000 : gamme:= 6;
|
6801..7300 : gamme:= 5;
|
6301..6800 : gamme:= 4;
|
5501..6300 : gamme:= 3;
|
4800..5500 : gamme:= 2;
|
3200..3800 : gamme:= 1;
|
endcase;
// if gamme <> memo_gamme then
commute_selfs(gamme);
LCDxy(7, 2);
Write(LCDout, ByteToStr(gamme));
// endif;
end;
procedure increment_F;
begin
F_base1:= F_base1 + increment;
LCDxy(4, 0);
LCDclrEOL;
Write(LCDout, IntToStr(F_base1 : 3 : 2) + ' MHz');
LCDxy(8 - digit_x, 0);
out_registre_N(F_base1);
if not(manuel) then
select_gamme;
endif;
end;
procedure decrement_F;
begin
F_base1:= F_base1 - increment;
LCDxy(4, 0);
LCDclrEOL;
Write(LCDout, IntToStr(F_base1 : 3 : 2) + ' MHz');
LCDxy(8 - digit_x, 0);
out_registre_N(F_base1);
if not(manuel) then
select_gamme;
endif;
end;
procedure affiche_increment;
begin
case digit_x of
1 : LCDxy(4, 1);
Write(LCDout, ' 10 kHz');
|
2 : LCDxy(4, 1);
Write(LCDout, '100 kHz');
|
3 : LCDxy(4, 1);
Write(LCDout, ' 1 MHz');
|
4 : LCDxy(4, 1);
Write(LCDout, ' 10 MHz');
|
endcase;
end;
//==============================================================================
{ Main Program }
{$IDATA}
begin
init_variables;
init_ports;
InitINTs;
init_registre_C;
out_registre_R(400); // 4MHz/400 = 10kHz (ref)
out_registre_N(7000);
ticked := true;
LCDclr; { clear display }
LCDcursor(false, false); { display on, cursor off & no blink }
Write(LCDout, 'RESET');
mdelay(300);
LCDclr;
Write(LCDout, 'GeneHF 90MHz ' + version );
mdelay(1000);
LCDclr;
LCDxy(0, 0);
Write(LCDout, 'Out');
LCDxy(0, 1);
Write(LCDout, 'pas');
LCDxy(0, 2);
Write(LCDout, 'gamme');
// SetFreqCountMode(TFreqBase1MHz); // mode frequencemetre TFreqBase1MHz Frequ = 100Hz...6.5535MHz gate time = 10msec
octet_IR:= 255;
F_base1:= 7000;
gamme:= 1;
commute_selfs(gamme);
LCDxy(7, 2);
Write(LCDout, ByteToStr(gamme));
EnableInts;
digit_x:= 3;
increment := puiss10[digit_x];
affiche_increment;
loop
memo_pos_bt:= pos_bt;
acqui_pos_btn;
if (pos_bt < memo_pos_bt) and (pos_bt + memo_pos_bt <> 19) then
decrement_F;
elsif (pos_bt > memo_pos_bt)and (pos_bt + memo_pos_bt <> 19) then
increment_F;
elsif (( pos_bt = 0) and (memo_pos_bt = 19) ) then
increment_F;
elsif (( pos_bt = 19) and (memo_pos_bt = 0) ) then
decrement_F;
endif;
interroge_IR;
if octet_IR <> 255 then
case octet_IR of
0 : manuel:= false;
LCDxy(10, 2);
Write(LCDout, '( auto )');
|
1..8 : manuel:= true;
gamme:= octet_IR;
commute_selfs(gamme);
LCDxy(7, 2);
Write(LCDout, ByteToStr(gamme));
LCDxy(10, 2);
Write(LCDout, '(manuel)');
|
9 : test_IR
|
12 : system_reset;
|
17 : LCDcursor(true, false);
if digit_x < 4 then // (fleche <)
inc(digit_x);
LCDxy(8 - pos_cur[digit_x], 0);
increment := puiss10[digit_x];
affiche_increment;
endif;
|
16 : if digit_x > 1 then // (fleche >)
dec(digit_x);
LCDxy(8 - pos_cur[digit_x], 0);
increment := puiss10[digit_x];
affiche_increment;
endif;
|
32 : increment_F; // (fleche haut)
|
33 : decrement_F; // (fleche bas)
|
43 : nop; // (<< rouge)
|
46 : nop; //(>> bleue)
|
47 : nop; // (.)
|
56 : nop; // (lecture >)
|
23 : nop; // (Ok)
|
endcase;
endif;
// Frequence:= 16 * GetFreqCounterL;
mdelay(2);
endloop;
// RTCtimer_Stop(0);
end GeneHF_90MHz.