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.
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
Come posso determinare se il problema è nel timing ? credo di aver fatto tutto correttamente, purtroppo non si può debuggare in realtime :(
picmicro675
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.
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
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.
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
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
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.
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
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
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.
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
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 :(
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