home | area personale         schemi | tutorial | robotica | pic micro | recensioni         forum | chat irc         faq | contatti         store | Ordina PCB
username
password
cerca

 
FORUM: Pic Micro
Tutto quanto riguarda questi microprocessori... progetti, suggerimenti, aiuti, discussioni...ecc


Decoder Ir NEC con 12F675 - MicroC Pro
     
Autore Messaggio opzioni
tatopower




una ogni 10 livelli una ogni 10 livelli


postato il:
07.01.2019, alle ore 11:25
Decoder Ir NEC con 12F675 - MicroC Pro 

Ciao ragazzi, stavo provando il codice di esempio della Microelettronica basato su un 16F887 modificando alcune impostazione per poterlo usare su un 12F675. Si tratta di un decoder per IR con codifica NEC.

GPIO.3 ingresso IR.
GPIO.1 uscita led.
Oscillatore interno.

Sull\'887 funziona perfettamente impostando T1CON = 0x10 (prescaller 1:2) con quarzo da 8Mhz, sul 12F675 \"nada de nada\"



bit nec_ok;
char text[5];
unsigned short nec_state, command, inv_command, i;
unsigned int address, timer_value;
unsigned long nec_code;


void Interrupt() {
    
    
  if (GPIF_bit && (GPIO.F0 || !GPIO.F0)){         // PORTB change ISR
    GPIF_bit = 0;
    
    if(nec_state != 0){
      timer_value = (TMR1H << 8) + TMR1L;           // Store Timer1 value
      TMR1H = 0;                                    // Reset Timer1
      TMR1L = 0;
    }
    
    switch(nec_state){
     case 0 :                                       // Start receiving IR data (we\'re at the beginning of 9ms pulse)
       TMR1H = 0;                                   // Reset Timer1
       TMR1L = 0;
       TMR1ON_bit = 1;                              // Enable Timer1
       nec_state = 1;                               // Next state: end of 9ms pulse (start of 4.5ms space)
       i = 0;
       break;
       
     case 1 :                                       // End of 9ms pulse
       if((timer_value > 9500) || (timer_value < 8500)){         // Invalid interval ==> stop decoding and reset
         nec_state = 0;                             // Reset decoding process
         TMR1ON_bit = 0;                            // Disable Timer1
       }
       else
         nec_state = 2;                             // Next state: end of 4.5ms space (start of 562µs pulse)
       break;
       
     case 2 :                                       // End of 4.5ms space
       if((timer_value > 5000) || (timer_value < 4000)){
         nec_state = 0;                             // Reset decoding process
         TMR1ON_bit = 0;                            // Disable Timer1
         
         
       }
       else
         nec_state = 3;                             // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
       break;
     case 3 :                                       // End of 562µs pulse
       if((timer_value > 700) || (timer_value < 400)){           // Invalid interval ==> stop decoding and reset
         TMR1ON_bit = 0;                            // Disable Timer1
         nec_state = 0;                             // Reset decoding process
       }
       else
         nec_state = 4;                             // Next state: end of 562µs or 1687µs space
       break;
     case 4 :                                       // End of 562µs or 1687µs space
       if((timer_value > 1800) || (timer_value < 400)){           // Time interval invalid ==> stop decoding
         TMR1ON_bit = 0;                            // Disable Timer1
         nec_state = 0;                             // Reset decoding process
         break;
       }
       if( timer_value > 1000)                           // If space width > 1ms (short space)
         nec_code |= (unsigned long)1 << (31 - i);       // Write 1 to bit (31 - i)
       else                                              // If space width < 1ms (long space)
         nec_code &= ~((unsigned long)1 << (31 - i));    // Write 0 to bit (31 - i)
       i++;
       if(i > 31){                                  // If all bits are received
         nec_ok = 1;                                // Decoding process OK
         GPIE_bit = 0;                              // Disable PORTB change interrupt
         break;
       }
       nec_state = 3;                               // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
    }
  }
  
  if (TMR1IF_bit){                 // Timer1 ISR
    TMR1IF_bit = 0;                // Clear Timer1 overflow flag bit
    nec_state = 0;                 // Reset decoding process
    TMR1ON_bit = 0;                // Disable Timer1
  }
}

void main() {
  nec_ok = 0;
  nec_state = 0;
  
  
  
  ADCON0 = 0;                      // Configure all PORTB pins as digital
  CMCON=0x7;
  TMR1IF_bit = 0;                  // Clear Timer1 overflow interrupt flag bit
  GPIF_bit = 0;                    // Clear PORTB change interrupt flag bit
  TMR1IE_bit = 1;                  // Enable Timer1 overflow interrupt
  
  T1CON = 0;                    // Set Timer1 clock source to internal with 1:1 prescaler (Timer1 clock = 1MHz)
  INTCON = 0xC8;                  // Enable global, peripheral and PORTB change interrupts
  IOC3_bit = 1;        //abilita cambio stato su gpio3

  
  INTE_bit = 1;                   // Enable RB0 pin change interrupt
  VRCON= 0;
  
  ANSEL  = 0x00000000; // All ports are digital
  TRISIO = 0b00001000; //Tutti i pin in OUT tranne gpio3
  GPIO = 0;

  while(1) {
    while(!nec_ok);                // Wait until NEC code receiver
    nec_ok = 0;                    // Reset decoding process
    nec_state = 0;
    TMR1ON_bit = 0;                // Disable Timer1
    address = nec_code >> 16;
    address = nec_code;
   
   
    if (address==6897){
    GPIO.F1 = 1; //LED ON
    }
  }
tatopower




una ogni 10 livelli una ogni 10 livelli


postato il:
07.01.2019, alle ore 21:35
Come posso determinare se il problema è nel timing ? credo di aver fatto tutto correttamente, purtroppo non si può debuggare in realtime :(
picmicro675




una ogni 10 livelli


postato il:
08.01.2019, alle ore 06:48
Ho fatto lo stesso lavoro con proton basic. L' ho solo provato con il simulatore e direi che risponde alle specifiche.
Vorrei andare a provare in hardware, ma son sempre lì a procrastinare
Se vuoi provare con proton basic, lo trovi free per i due micro che citi.
Questo il sorgente basic di Protonbasic, per il trasmettitore. Invia numeri casuali.
Device 12F675
Declare Xtal 4
Config INTRC_OSC_NOCLKOUT, WDT_OFF, MCLRE_ON, BODEN_OFF, PWRTE_ON


Symbol TMR1IE = PIE1.0       ' TMR1 Overflow Interrupt Enable
Symbol TMR1IF = PIR1.0       ' TMR1 Overflow Interrupt Flag
Symbol TMR1ON = T1CON.0         ' Timer1 ON
Symbol GPIF = INTCON.0       ' Port Change Interrupt Flag
Symbol T0IF = INTCON.2       ' TMR0 Overflow Interrupt Flag
Symbol T0IE = INTCON.5       ' TMR0 Overflow Interrupt Enable
Symbol PEIE = INTCON.6
Symbol GIE = INTCON.7        ' Global Interrupt Enable
Symbol GPIE = INTCON.3       ' GP Interrupt Enable
Symbol TXDPIN 0              ' Trasmitting pin
Symbol RXDPIN 1              ' Receiving pin
Symbol IN0PIN 3              ' input 0 pin definition
Symbol IN1PIN 5              ' input 1 pin definition
Symbol OUT0PIN 2             ' output 0 pin definition
Symbol OUT1PIN 4             ' output 1 pin definition
Symbol IOCPIN0 = IOC.IN0PIN  ' Interrupt-on-Change
Symbol IOCPIN1 = IOC.IN1PIN  ' Interrupt-on-Change
Symbol TRUE = 1              ' Boolean value
Symbol FALSE = 0             ' Boolean value
Symbol _ON = 1               ' Boolean value
Symbol _OFF = 0              ' Boolean value
Symbol TMRSET = 99           ' Setting for internal clock
Symbol BUFLEN = 4            ' The buffer where to store the received command
Symbol BUFSPACE BUFLEN -1
Symbol TXD GPIO.TXDPIN       ' pin assigned for trasmission
Symbol RXD GPIO.RXDPIN       ' pin assigned for reception
Symbol IN0 GPIO.IN0PIN       ' first limit switch on first relay
Symbol IN1 GPIO.IN1PIN       ' second limit switch on second relay
Symbol OUT0 GPIO.OUT0PIN
Symbol OUT1 GPIO.OUT1PIN
Symbol StartHigh        ($ffff-9000)
Symbol StartLow         ($ffff-4500)
Symbol burstHigh        ($ffff-562)
Symbol burstlowShort    ($ffff-562)
Symbol burstlowLong     ($ffff-1688)

Dim address As Word
Dim command As Word
Dim flags As Byte
Dim ovrflw As flags.0
Dim x As Byte
Dim i As Byte
Dim z As Byte
Dim pass As Bit
Dim Timer1 As TMR1L.Word
Declare Serial_Data 9
Declare Serial_Baud 9600
Declare Rsout_Pin TXD
Declare Rsout_Mode 0
Declare Rsin_Mode 0

On_Hardware_Interrupt GoTo Isr

'============================Main program=======================================
Set_OSCCAL                   ' recover the calibration
OPTION_REG = 0
Clear ANSEL
Clear flags
CMCON = 7
INTCON = 0
T1CON = 1
Set PEIE
Set GIE
Set TMR1IE
Set GPIE
High OUT0
For i = 0 To 20
    Timer1 = ($ffff-62500)
    Clear ovrflw
    While ovrflw = FALSE: Wend
Next i

address = Random
command = Random
RSOut "\rSending address code = ", Hex address
RSOut "\rSending command code = ", Hex command

Clear OUT0
Timer1 = StartHigh
Clear ovrflw
While ovrflw = FALSE: Wend
Set OUT0
Timer1  = StartLow
Clear ovrflw
While ovrflw = FALSE: Wend
x = address.LowByte
GoSub sendbyte
x = address.HighByte
GoSub sendbyte
x = command.LowByte
GoSub sendbyte
x = command.HighByte
GoSub sendbyte
Clear OUT0
Timer1  = burstHigh
While ovrflw = FALSE: Wend
Set OUT0

End

sendbyte:
    Clear z
    Repeat
        Asm-
        Clrf _i
        Clrc
        Rrf     _x,F
        Bcf     _i,0
        Skpnc
        Bsf     _i,0
        Endasm-
        Clear OUT0
        Timer1 = burstHigh
        Clear ovrflw
        While ovrflw = FALSE: Wend
        Set OUT0
        Clear ovrflw
        If i.0 = 1 Then
            Timer1 = burstlowLong
        Else
            Timer1 = burstlowShort
        End If
        While ovrflw = FALSE: Wend
        Inc z
    Until z > 7
Return
End

Isr:                         ' Interrupt Service Routine
    Context Save
    If TMR1IF = TRUE Then
        Set ovrflw
        Clear TMR1IF
    End If
    Context Restore

Collegando al ricevitore, si può simulare con `quel simulatore`. Se usi il mikrobasic lo puoi simulare col suo debugger, oppure con `quel simulatore`, basta che compili con il coff.
Per il pacchetto dei miei esperimenti lo trovi
http://www.grix.it/UserFiles/picmicro675/File/TransitFiles/N…
Non è tanto commentato, spero riesci a venire a capo.
Comunque per il tuo caso, dovresti almeno attivare una seriale su un piedino disponibile e fare i debug mandando messaggi alla seriale. Tanto hai ancora dei piedini liberi.
Se noti il mio programma ne fa uso.



Anno nuovo, forum nuovo.
Mi sa che lascio.
picmicro675




una ogni 10 livelli


postato il:
08.01.2019, alle ore 07:09
Alcuni link del mio cercare
https://www.sbprojects.net/knowledge/ir/nec.php . La bibbia
Con compilatore CCS
http://ccspicc.blogspot.com/2016/07/nec-ir-remote-control-de…
http://ccspicc.blogspot.com/2016/09/nec-ir-transmitter-recei…
Piccola differenza di librerie, ma lo stesso concetto.

Questo con un 12F615
https://www.circuitvalley.com/2013/09/nec-protocol-ir-infrar…
Che non usa l' interrupt.
Il mio progetto vengono usati gli interrupts per catturare il fronte dell'inizio trasmissione. Non viene considerata la condizione di ripetizione.



Anno nuovo, forum nuovo.
Mi sa che lascio.
tatopower




una ogni 10 livelli una ogni 10 livelli


postato il:
08.01.2019, alle ore 10:54
Grazie PicMicro sei sempre molto disponibile e gentile.
Ho provato la simulazione e non ho problemi sul teorico funzionamento, nella pratica mi sorge il dubbio che l'hardware non sia all'altezza del compito... ma è praticamente impossibile a meno che il micro non sia bacato.
Decoder fatto con il 16F84 e mikrobasic perfettamente funzionante.
Decoder fatto con il 12F675 e MikroC non va manco a spingerlo...

Volevo passare a MikroC in quanto più performante ma il primo approccio lascia una nota amara.

Proverò a verificare tramite seriale cosa accade.
Purtroppo di esempi in MikroC sulla decodifica NEC nei piccoli pic ne ho contati davvero pochi e spesso c'è solo il file hex e non si può studiare il sorgente per capire le scelte di programmazione fatte. Sgrunt.
picmicro675




una ogni 10 livelli


postato il:
08.01.2019, alle ore 11:02
Ho cercato di convertire il programma NecIRrx02.bas in mikroC.
Purtroppo, i geni della mikroE usano i float per calcolare la velocità della seriale, che non ci sta nel 12F675.
Comunque, fai tesoro delle routine e tieni conto che command contiene il comando e address l' indirizzo dispositivo.
Utilizzando queste due variabili comincerai a confrontare se è il codice corrispondente a quello desiderato di indirizzo 6897.

Ma di solito l' indirizzo è a 1, per un telecomando di televisore, poi trovi gli altri valori del comandi che può dare anche più di una uscita.

#define TXDPIN B0                    // Trasmitting pin
#define RXDPIN B1                    // Receiving pin
#define IN0PIN B3                    // input 0 pin definition
#define IN1PIN B5                    // input 1 pin definition
#define OUT0PIN B2                   // output 0 pin definition
#define OUT1PIN B4                   // output 1 pin definition
#define TXDP 0                      // Trasmitting pin
#define RXDP 1                      // Receiving pin
#define IN0P 3                      // input 0 pin definition
#define IN1P 5                      // input 1 pin definition
#define OUT0P 2                     // output 0 pin definition
#define OUT1P 4                     // output 1 pin definition
#define TMRSET  99                  // Setting for internal clock
#define BITMASK (1<<RXDPIN)

unsigned int address;
unsigned int command;
unsigned char bitcnt = 0;
unsigned char GPIOcopy;
unsigned char GPIOtmp;
unsigned int y;
unsigned char ticks = 0;
unsigned char flags;
sbit TXD at GPIO.TXDPIN;             // pin assigned for trasmission
sbit RXD at GPIO.RXDPIN;             // pin assigned for reception
sbit RXerror at flags.B0;
sbit codeOK at flags.B1;
sbit RXstart at flags.B2;
sbit zeroX  at flags.B6;
const char OKmsg[] = "OK\r";
const char msg1[] = "\rtime = ";
const char msg2[] = "\rcommand code = ";
const char msg3[] = "\raddress code = ";

void tidy()
{
    if (zeroX) {
       zeroX = 0;
       Soft_UART_Write(OKmsg);
    }
    flags = flags & 0xf8;
    address = 0;
    command = 0;
    bitcnt = 0;
    zeroX = 0;
    TMR1H = 0;                      // Reset Timer1
    TMR1L = 0;
    while (!zeroX);                 // short pause to wait for a new correct code
}

void ckstart() {
    if (RXD) {                      // falling edge, inverted by the TSOP38
        if ((y < 9499) && (y > 8500)) {
            bitcnt.B0 = 1;
        } else {
            RXerror = 1;
            RXstart = 0;
        }
    } else {                         // raising edge
        if ((y < 4950) && (y > 4050)) {
            if (bitcnt.B0) {
                RXstart = 1;
                bitcnt = 0;
            } else {
                RXstart = 1;
            }
        }
    }
}

void ckbits() {
    if (RXD) {                      // raising edge half bit received
       if ((y < 620) && (y > 506)) {
           bitcnt.B7 = 1;
       } else {
            RXerror = 1;
       }
    } else {                        // falling edge, start a new bit
        if (bitcnt.B7 = 1) {
            bitcnt.B7 = 0;
             if (y > 1855) {
                RXerror = 1;
            } else if ((y < 1855) && (y > 1675)) {
                asm Bsf    _command+1,7 ;
            } else if ((y < 620) && (y > 506)) {
                asm Bcf     _command+1,7 ;
            } else {
                RXerror  = 1;
            }
            asm{    bcf    STATUS,0
                    Rrf    _command+1,F
                    Rrf    _command+0,F
                    Rrf    _address+1,F
                    Rrf    _address+0,F
            };
            ++bitcnt;
            if (bitcnt > 30) {
                RXerror = 0;
                codeOK = 1;
            }
        }
    }
}

void Interrupt()                    // Interrupt Service Routine
{
    if (INTCON.T0IF) {                     // the timer0 overflowed ?
        TMR0 = TMRSET;              // then reload its count
        INTCON.T0IF = 0;                   // remove the flag
        if (ticks < 101) {          // when ticks reaches 100, it's reset to zero
            ++ticks;                // else it'll increase
        } else {
            ticks = 0;              // reset
            zeroX = 1;              // it records when one second is past
        }
    }

    // Verifying if the status of the are changed
    if (INTCON.GPIF) {
        GPIOtmp = GPIO & BITMASK;   // mask out unneeded signals
        INTCON.GPIF = 0;
        y = (TMR1H << 8) + TMR1L;
        TMR1H = 0;                  // Reset Timer1
        TMR1L = 0;
        GPIOcopy = GPIOcopy ^ GPIOtmp;
        if (GPIOcopy.RXDPIN) {
            if ( !RXstart) {
                ckstart();
            } else {
                ckbits();
            }
        }
        GPIOcopy = GPIOtmp;
    }
}

void main()
{
    // resume the Oscillator calibration
    asm {   call 0x3FF              ; load calibration bits
            bsf STATUS,5            ; select the correct bank
            movwf OSCCAL            ; save them
            bcf STATUS,5            ; select the correct bank
    };
    Soft_UART_Init(&GPIO,RXD,TXD,2400,0);
    // Setting the IO according to the wanted conditions
    TRISIO = 1<<RXDP | 1<<IN0P | 1<<IN1P;
    IOC.IN0PIN = 1;
    WPU.RXDPIN = 1;                 // pullup for RX Serial
    OPTION_REG = 5;                 // options to set timer0 with 64 prescaler
    ANSEL = 0;                      // no analog inputs
    flags = 0;                      // all flags cleared
    CMCON = 7;                      // no comparators
    INTCON = 0b11101000;            // GIE, PEIE, T0IE and GPIE set to Interrupt
    T1CON = 1;
    GPIOtmp = GPIO & BITMASK;       // initial condition
    TMR1H = 0;
    INTCON.GPIF = 0;

    while (1) {
        if (RXerror) {
            Soft_UART_Write(msg1);
            //, Dec y
            tidy();
        }
        if (codeOK) {
        Soft_UART_Write(msg3);
        //, Hex address
        Soft_UART_Write(msg2);
        //, Hex command, 13
         tidy();
        }
    }
}




Anno nuovo, forum nuovo.
Mi sa che lascio.
tatopower




una ogni 10 livelli una ogni 10 livelli


postato il:
09.01.2019, alle ore 00:38
Questo codice che hai convertito decodifica la trasmissione NEC e la invia sulla seriale. A questo punto basterebbe eliminare la parte di trasmissione alla seriale usando uno o più operatori di confronto e azionando l'uscita desiderata.
Corretto ? Ho visto che usi gpio.0 per la ricezione dell'IR
picmicro675




una ogni 10 livelli


postato il:
09.01.2019, alle ore 02:14
Sì, corretto. Ma senza seriale è come scrivere un programma con gli occhi chiusi.
Il programma riceve sia command che address. Poi ci fai quello che ti serve. A te serviranno le sole routines, quello che si vuol fare in main() è qualcosa plus-ultra.
Io non avendo finito con la seriale, ieri non ho potuto nemmeno compilare. Se trovo un attimo di tempo vedo di finirlo.

Per la seriale si può lasciar perdere quella di mikroE che è assurda. Si trova una molto più snella.
http://saeedsolutions.blogspot.com/2012/10/pic16f84a-i2c-bit…
Oppure quella di Diego Bincoletto
http://www.grix.it/viewer.php?page=10942



Anno nuovo, forum nuovo.
Mi sa che lascio.
picmicro675




una ogni 10 livelli


postato il:
09.01.2019, alle ore 02:17
Ah, poi non serve la parte del timer0 in ISR, che ho utilizzato per fare un piccolo uso per ritardi.


Anno nuovo, forum nuovo.
Mi sa che lascio.
tatopower




una ogni 10 livelli una ogni 10 livelli


postato il:
09.01.2019, alle ore 09:39
Tutta la codifica del mio telecomando l'ho rilevata con un Arduino, conosco quindi la corrispondenza di command e address rispetto al tasto premuto.
Ecco quindi che mi sono inchiodato sul timing nel 12f675 non riuscendo a capire da dove arrivava l'errore o il mancato riconoscimento del codice ricevuto :(
segui questo thread con grixFC, per questa funzione devi aver installato il software grixFC

torna su
     

Come utente anonimo puoi leggere il contenuto di questo forum ma per aprire una discussione
o per partecipare ad una discussione esistente devi essere registrato ed accedere al sito




 







 
 
indietro | homepage | torna su copyright © 2004/2024 GRIX.IT - La community dell'elettronica Amatoriale