Ik denk dat ik het al weet: IOCBF0_Bit zal het moeten zijn
Dit topic is gesloten
Golden Member
Ik denk dat ik het al weet: IOCBF0_Bit zal het moeten zijn
Special Member
Tja, waarom?...
Omdat ze nu eenmaal dat bit zo genoemd hebben (IOCBNx_bit en IOCBPx_bit)
Golden Member
Dit vind ik ook even een lastige, om onderstaand (Arduino) om te zetten naar een PIC:
c code:
// Timer1 module configuration
TCCR1A = 0;
TCCR1B = 0; // Disable Timer1 module
TCNT1 = 0; // Set Timer1 preload value to 0 (reset)
TIMSK1 = 1; // enable Timer1 overflow interrupt
Wat zijn hiervan nu de equivalenten? Ik haal dat niet zo uit de Datasheet
Special Member
pic basic code:
TMR2ON_bit = 0 'Disable timer2 module
PR2 = ... 'Preload value
TMR2IE = 1 'Enable timer2 interrupt
Timer 2, 4, of 6 zijn hier beter geschikt voor als timer 1
Je moet wel de post en prescaler voor de betreffende timer zetten.
Golden Member
Ik ben nu bezig om een werkend C-programma (arduino) om te zetten naar MikroBasic.
Dit programma werkt met een NEC-remote (die ik heb) en heeft geen ingewikkelde .h includes etc.
c code:
char text[5];
boolean nec_ok = 0;
byte i, nec_state = 0, command, inv_command;
unsigned int address;
unsigned long nec_code;
void setup() {
// set up the LCD's number of columns and rows
Serial.begin(9600);
Serial.print("Start Ontvangst");
Serial.println("Address:0x0000");
Serial.println("Com:0x00 In:0x00");
// Timer1 module configuration
TCCR1A = 0;
TCCR1B = 0; // Disable Timer1 module
TCNT1 = 0; // Set Timer1 preload value to 0 (reset)
TIMSK1 = 1; // enable Timer1 overflow interrupt
attachInterrupt(0, remote_read, CHANGE); // Enable external interrupt (INT0)
}
void remote_read() {
unsigned int timer_value;
if(nec_state != 0){
timer_value = TCNT1; // Store Timer1 value
TCNT1 = 0; // Reset Timer1
}
switch(nec_state){
case 0 : // Start receiving IR data (we're at the beginning of 9ms pulse)
TCNT1 = 0; // Reset Timer1
TCCR1B = 2; // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
nec_state = 1; // Next state: end of 9ms pulse (start of 4.5ms space)
i = 0;
return;
case 1 : // End of 9ms pulse
if((timer_value > 19000) || (timer_value < 17000)){ // Invalid interval ==> stop decoding and reset
nec_state = 0; // Reset decoding process
TCCR1B = 0; // Disable Timer1 module
}
else
nec_state = 2; // Next state: end of 4.5ms space (start of 562µs pulse)
return;
case 2 : // End of 4.5ms space
if((timer_value > 10000) || (timer_value < 8000)){
nec_state = 0; // Reset decoding process
TCCR1B = 0; // Disable Timer1 module
}
else
nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
return;
case 3 : // End of 562µs pulse
if((timer_value > 1400) || (timer_value < 800)){ // Invalid interval ==> stop decoding and reset
TCCR1B = 0; // Disable Timer1 module
nec_state = 0; // Reset decoding process
}
else
nec_state = 4; // Next state: end of 562µs or 1687µs space
return;
case 4 : // End of 562µs or 1687µs space
if((timer_value > 3600) || (timer_value < 800)){ // Time interval invalid ==> stop decoding
TCCR1B = 0; // Disable Timer1 module
nec_state = 0; // Reset decoding process
return;
}
if( timer_value > 2000) // If space width > 1ms (short space)
bitSet(nec_code, (31 - i)); // Write 1 to bit (31 - i)
else // If space width < 1ms (long space)
bitClear(nec_code, (31 - i)); // Write 0 to bit (31 - i)
i++;
if(i > 31){ // If all bits are received
nec_ok = 1; // Decoding process OK
detachInterrupt(0); // Disable external interrupt (INT0)
return;
}
nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
}
}
ISR(TIMER1_OVF_vect) { // Timer1 interrupt service routine (ISR)
nec_state = 0; // Reset decoding process
TCCR1B = 0; // Disable Timer1 module
}
void loop() {
if(nec_ok){ // If the mcu receives NEC message with successful
nec_ok = 0; // Reset decoding process
nec_state = 0;
TCCR1B = 0; // Disable Timer1 module
address = nec_code >> 16;
command = nec_code >> 8;
inv_command = nec_code;
sprintf(text, "%04X", address);
Serial.println(text); // Display address in hex format
sprintf(text, "%02X", command);
Serial.println(text); // Display command in hex format
sprintf(text, "%02X", inv_command);
Serial.println(text); // Display inverted command in hex format
attachInterrupt(0, remote_read, CHANGE); // Enable external interrupt (INT0)
}
}
Ik denk dat ik wel een eind kom. De timer Pre- en Postcaler moet ik nog uitrekenen ahv het commentaar
// Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
Wat nog een lastige is:
c code:
bitSet(nec_code, (31 - i)) ' Write 1 to bit (31 - i)
of het zou iets moeten zijn van:
pic basic code:
For x1 = 0 to 31-i
nec_code.x1 = 1
Next
Golden Member
Ik ben al een eind verder. Maar wat ik nog niet snap is de functie met de timer:
pic basic code:
if(nec_state <> 0) Then
timer_value = TCNT1 ' Store Timer1 value
TCNT1 = 0 ' Reset Timer1
End If
Select Case nec_state
case 0 ' Start receiving IR data (we're at the beginning of 9ms pulse)
TCNT1 = 0 ' Reset Timer1
TCCR1B = 2 ' Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
TCNT1 kent het programma niet.
De timer wordt 'gereset' en de 'Timer_value' wordt opgeslagen.
Maar wie/ wat bepaalt de waarde van die Timer_value nu?
Ik heb de interrupt routine nu zo:
pic basic code:
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
If TMR2IF_bit Then 'See if timer2 irq
'Wat moet ik hier nu doen?
TMR2IF_bit = 0
End If
IF IOCBF0_Bit = 1 then 'See if PORTB.0 Change
Remote_Read()
IOCBF0_Bit = 0
End If
End Sub
Of is dat soms een simpele Inc(Timervalue?)
Special Member
Timer 2 is een auto-reload timer, je hoeft waarschijnlijk niks te doen verder...
Golden Member
Maar de waarde (TCNT2) wordt ergens opgeslagen.
Ik heb TCNT2 maar als integer gedefinieerd en in de Interrupt routine verhoog ik hem:
pic basic code:
if(nec_state <> 0) Then
timer_value = TCNT2 ' Store Timer2 value
TCNT2 = 0 ' Reset Timer2
End If
Select Case nec_state
case 0 ' Start receiving IR data (we're at the beginning of 9ms pulse)
TCNT2 = 0 ' Reset Timer2
TMR2ON_bit = 1 ' Enable Timer2 module with 1/8 prescaler ( 2 ticks every 1 us)
nec_state = 1 ' Next state: end of 9ms pulse (start of 4.5ms space)
---
'================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'================================================================================
If TMR2IF_bit Then 'See if timer2 irq
'Wat moet ik hier nu doen?
Inc(TCNT2)
TMR2IF_bit = 0
End If
IF IOCBF0_Bit = 1 then 'See if PORTB.0 Change
Remote_Read()
IOCBF0_Bit = 0
End If
End Sub
Maar ik weet niet of dat wel zo goed gaat..
Want anders heb ik geen actie als er een timer-overflow interrupt komt, toch?
[Bericht gewijzigd door Bavelt op maandag 9 november 2020 23:04:23 (22%)
Golden Member
Dan heb ik nog het volgende opgenomen:
pic basic code:
T2CON = 0x10 'Set Timer1 clock source to internal with 1:2 prescaler (Timer1 clock = 1MHz)
Want blijkbaar heb je een algemene instelling (met Post en prescale) maar je kan kennelijk ook kiezen uit een interne oscillator als bron voor de timer.
Het is nu:
pic basic code:
T2CON = %00100110 'Post:5 - Pre:16
PR2 = 249 'Timer load value
T2CON = 0x10 'Set Timer1 clock source to internal with 1:2 prescaler (Timer1 clock = 1MHz)
Of is dit dubbel op?
Golden Member
Die TCNT2 wordt in Arduino gebruikt. Het schijnt een register te zijn die als counter fungeert voor de timer.
In de PIC16F1847 kan ik geen counter ontdekken die eea bijhoudt..
Special Member
PR2 is de auto-reload counter.
Golden Member
Op 10 november 2020 03:48:51 schreef Arco:
PR2 is de auto-reload counter.
Ok, maar PR2 is een register, 1 byte dus.
In het programma wordt echter gevraagd:
pic basic code:
if((timer_value > 19000) OR (timer_value < 17000)) Then
Dat zijn hoge waarden. Dan klopt er toch iets niet?
Special Member
Kan zijn dat er inderdaad een losse variabele voor wordt gebruikt.
(geen zin om die C boel door te vlooien als het niet hoeft; dat maakt je depressief... )
Golden Member
Op 10 november 2020 11:58:47 schreef Arco:
Kan zijn dat er inderdaad een losse variabele voor wordt gebruikt.
(geen zin om die C boel door te vlooien als het niet hoeft; dat maakt je depressief... )
Dat was ik idd al aardig aan het worden. Het is een worsteling.
Maar de aanhouder wint..
Ik heb het inderdaad met een variabele gedaan.
Dan ben ik nog met die timer bezig.
Blijkbaar wil 'men' iedere uS twee overflow tikken van de timer:
c code:
TCCR1B = 2; // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
Ok, dat zou dus betekenen 500.000 Hz.
Ik kan dat regelen door de Pre- en Postscaler.
Daarvoor is het T2CON register:
De klokfrequentie is 8 Mhz.
Dus dacht ik in mijn onschuld:
PR2 = 0
f = Fosc/4/pre/post/(PR2+1)
= 8.0000.0000/4/1/16/(0+1) = 125.000
ik kom dan op
pic basic code:
T2CON = %01111100
Echter: de werkelijke frequentie wordt ca 48.500 Hz, ca 3 keer minder.
Hier maak ik blijkbaar een denkfout?
Special Member
Die 8.0000.0000 zal (hopelijk) wel een typo zijn? (800MHz is wat snel... )
Wat bedoel je met 8MHz klok? De oscillator clock (Fosc) of de instruction cycle clock? (Tcy)
Golden Member
800 Mhz is idd overdreven...
Tikfout dus.
Met 8 Mhz bedoel ik de oscillator frequentie (zoals die wordt ingesteld in het project en met
pic basic code:
OSCCON = %01110000 '8MHz internal
Special Member
Met een oscillatorfrequentie van maar 8MHz is een timerinterrupt op 500kHz niet mogelijk, dat is veel en veel te snel.
Je houdt dan 2.000.000/500.000 = 4 instructies over per interrupt cycle, en die zijn al op aan de interrupt call (2 cy) en de return (ook 2 cy)
En dat is nog in het allergunstigste geval. (er gebeurt verder niets in main of in de interrupt)
Golden Member
Maar om uiteindelijk 500.000H z te krijgen zou de Postscale dus 4 moeten zijn en de Pre 1:
8.000.000 / 4 /4 / 1
ofwel:
pic basic code:
T2CON = %00011000
Dit levert 50.000 Hz op, 10 keer te weinig..
Special Member
Zoals gezegd, zelfs als het lukt heb je er niets aan.
Op 2MHz cycle clock is de processor 100% van de tijd bezig met van en naar de interrupt te gaan en heeft 0% 'vrije tijd' om iets zinvols te doen.
Golden Member
Op 10 november 2020 13:14:42 schreef Arco:
Met een oscillatorfrequentie van maar 8MHz is een timerinterrupt op 500kHz niet mogelijk, dat is veel en veel te snel.
Je houdt dan 2.000.000/500.000 = 4 instructies over per interrupt cycle, en die zijn al op aan de interrupt call (2 cy) en de return (ook 2 cy)En dat is nog in het allergunstigste geval. (er gebeurt verder niets in main of in de interrupt)
Dan bedoelen ze met
c code:
TCCR1B = 2; // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
Blijkbaar wat anders..
Dat TCCR1B is typisch iets van de Arduino. Ik weet ook niet met welke klok dat draait.
Maar terug naar af:
Waar het uiteindelijk om draait, is om de onderstaande info te vangen.
About the NEC protocol:
The complete extended NEC protocol message is started by 9ms burst followed by 4.5ms space which is then followed by the Address and Command. The address is 16-bit length and the command is transmitted twice (8 bits + 8 bits) where in the second time all bits are inverted and can be used for verification of the received message. The following drawing shows an extended NEC message example.
The NEC protocol uses pulse distance encoding of the bits. Each pulse is a 562.5µs long with carrier frequency of 38KHz. Logic bits are transmitted as follows:
Logic 0: 562.5µs pulse burst followed by 562.5µs space, with a total transmit time of 1125µs (562.5 x 2).
Logic 1: a 562.5µs pulse burst followed by a 1687.5µs (562.5 x 3) space, with a total transmit time of 2250µs (562.5 x 4).
Er worden 32 bits gestuurd. het begint met een 9 ms blok. Een 0 of een 1 moet worden gehaald uit de tijd die tussen de pulsen zit.
Tja, en hoe dat te vangen, daarvoor zul je toch de timer nodig hebben..
Golden Member
Of kan dat wellicht slimmer op een andere manier?
Special Member
Je kunt een timerinterrupt gebruiken op bijv. 10kHz (dan heb je wat meer tijd in de interrupts)
Ik zou wel de clock op 32MHz zetten (PLL aan). Je hebt dan 800 instructies 'ruimte' in een interrupt.
Je hoeft dan alleen bij iedere interrupt te kijken of de pin hoog of laag is, en dat kan vrij ruim.
Tussen de 4 en 8 keer hoog? (400...800uS). Dan is het een 'hoog' puls.
Tussen de 8 en 14 keer laag? (0.8...1.4mS). Dan is het een 'laag' puls.
Verder alleen een kwestie van die pulsjes interpreteren.
Bij een hoog of laag van > 14 keer weet je dat er een nieuwe pulstrein start.
Je kunt het inverted address/command desgewenst overslaan, dan blijven er maar 24 pulsjes over...
Je kunt ook de CCP module gebruiken om de lengte van pulsjes te meten, maar dat is weer een heel andere benadering.
Golden Member
Dank Arco, ik ga daar maar eens mee bezig.
Ik begin gewoon opnieuw.
Is eigenlijk ook veel beter dan een C-programma proberen om te schrijven, waarbij ik veelal eigenlijk ook niet weet wat er precies gebeurt.
Dan is het vaak meer gokken dan de logica bevatten.
Ik moet dan wel het eerste 'blok' van 9ms zien te vangen. Dat moet op zich kunnnen. De codes zijn 'inverted'. De TSOP is standaard hoog.
Special Member
Aanzetje:
pic basic code:
HMIN = 4 'Min value pulse high
HMAX = 8 'Max value pulse high
LMIN = 4 'Min value pulse low
L1 = 8 'Max value for '1' in pulse low
LMAX = 14 'Max value pulse low
TIMEOUT = 25 'Max count value
Dim OldState As Byte
HiCnt As Byte
LoCnt As Byte
interrupt:
If Pin = 1 Then
If OldState <> Pin Then
OldState = Pin
If (HiCnt > HMIN) And (HiCnt < HMAX) And
(LoCnt > LMIN) And (LoCnt < LMAX) Then
If LoCnt < L1 Then
'valid pulse '1' found...
Else
'valid pulse '0' found
End If
HiCnt = 0
LoCnt = 0
End If
End If
If HiCnt < HMAX Then Inc(HiCnt) End If
Else
OldState = Pin
If LoCnt < LMAX Then Inc(LoCnt) End If
End If
End If
Golden Member
Dank wederom. Mooie basis!
Ik ben nu als eerste bezig de timer goed te zetten:
IK heb nu:
pic basic code:
OSCCON = %11110000 '32MHz internal, 4x PLL On
T2CON = %00000110 'Pre: 16- Post:1
PR2 = 49 'Timer load value
Dus ik dacht: FOsc / 4 / Pre / Post / (PR2 + 1) =
32.000.000 / 4 / 16 / 1 / 50 = 10.000.
Mis, het wordt 5.000...
Dit topic is gesloten