Sterrenhemel

Dit topic is gesloten

Bavelt

Golden Member

Ik denk dat ik het al weet: IOCBF0_Bit zal het moeten zijn

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Tja, waarom?...

Omdat ze nu eenmaal dat bit zo genoemd hebben (IOCBNx_bit en IOCBPx_bit)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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

Fouten zijn het bewijs dat je het probeert..
Arco

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.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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
Fouten zijn het bewijs dat je het probeert..
Bavelt

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?)

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Timer 2 is een auto-reload timer, je hoeft waarschijnlijk niks te doen verder...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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%)

Fouten zijn het bewijs dat je het probeert..
Bavelt

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?

Fouten zijn het bewijs dat je het probeert..
Bavelt

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..

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

PR2 is de auto-reload counter.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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?

Fouten zijn het bewijs dat je het probeert..
Arco

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... ;) )

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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?

Fouten zijn het bewijs dat je het probeert..
Arco

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)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

800 Mhz is idd overdreven...:P
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
Fouten zijn het bewijs dat je het probeert..
Arco

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)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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..

Fouten zijn het bewijs dat je het probeert..
Arco

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.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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..

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Of kan dat wellicht slimmer op een andere manier?

Fouten zijn het bewijs dat je het probeert..
Arco

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.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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.

Fouten zijn het bewijs dat je het probeert..
Arco

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



Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

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...

Fouten zijn het bewijs dat je het probeert..

Dit topic is gesloten