Ik denk dat ik het al weet: IOCBF0_Bit zal het moeten zijn
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Tja, waarom?...
Omdat ze nu eenmaal dat bit zo genoemd hebben (IOCBNx_bit en IOCBPx_bit)
Dit vind ik ook even een lastige, om onderstaand (Arduino) om te zetten naar een PIC:
// 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
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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.
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.
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:
bitSet(nec_code, (31 - i)) ' Write 1 to bit (31 - i)
of het zou iets moeten zijn van:
For x1 = 0 to 31-i
nec_code.x1 = 1
Next
Ik ben al een eind verder. Maar wat ik nog niet snap is de functie met de timer:
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:
'================================================================================
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?)
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Timer 2 is een auto-reload timer, je hoeft waarschijnlijk niks te doen verder...
Maar de waarde (TCNT2) wordt ergens opgeslagen.
Ik heb TCNT2 maar als integer gedefinieerd en in de Interrupt routine verhoog ik hem:
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%)]
Dan heb ik nog het volgende opgenomen:
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:
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?
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..
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
PR2 is de auto-reload counter.
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:
if((timer_value > 19000) OR (timer_value < 17000)) Then
Dat zijn hoge waarden. Dan klopt er toch iets niet?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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... )
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:
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
T2CON = %01111100
Echter: de werkelijke frequentie wordt ca 48.500 Hz, ca 3 keer minder.
Hier maak ik blijkbaar een denkfout?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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)
800 Mhz is idd overdreven...
Tikfout dus.
Met 8 Mhz bedoel ik de oscillator frequentie (zoals die wordt ingesteld in het project en met
OSCCON = %01110000 '8MHz internal
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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)
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:
T2CON = %00011000
Dit levert 50.000 Hz op, 10 keer te weinig..
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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.
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
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..
Of kan dat wellicht slimmer op een andere manier?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
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.
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.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Aanzetje:
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
Dank wederom. Mooie basis!
Ik ben nu als eerste bezig de timer goed te zetten:
IK heb nu:
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...