25.12.2018
Zdrojový kód zařízení, který je uvedený níže, je též možné si stáhnout. Kód byl vytvořen a přeložen užitím prostředí MPLAB X a překladače XC8.
Na počátku proběhne inicializace. Jednak je nastavena pracovní frekvence 8 MHz a tudíž je 1 instrukce vykonána za 4/8000000 s = 0.5 us. Seriový port je nastaven na přenosovou rychlost 9600 a je povoleno přerušení při přijetí dat - toto přerušení je na počátku jako jediné aktivní. Nastaví se přerušení vyvolané při změně úrovně na vstupu pinu RA2. Časovač Timer0 je nastaven tak, že čítač přeteče každých 128 us. A nakonec se rozsvítí červená dioda na znamení, že proběhla inicializace.
Dále se čeká, než na vstup seriového portu přijde dvojice hodnot 0xAA, 0x55. Tyto hodnoty značí, že program v PC je připravený zpracovávat příchozí data. Jakmile zařízení tyto dva byty zaznamená, zakáže se přerušení na seriovém portu a naopak se povolí přerušení na pinu RA2 (výstup IR přijímače) při změně úrovně z vysoké na nízkou a přerušení generované časovačem Timer0. Taktéž RG dioda změní barvu z červené na zelenou, což signalizuje, že komunikace mezi zařízením a PC je funkční a jsou očekávána data z dálkového ovladače.
Po té, co jsou nastaveny hodnoty některých proměnných, je mikrokontroler uveden do režimu spánku, ze kterého může být aktivován přerušením na pinu RA2 (signál z IR přijímače).
Jakmile je detekována změna úrovně, je zaznamenán čas, po který daná úroveň trvala a režim detekce změny úrovně pomocí přerušení je změněn na opačný (pokud byla nyní detekována změna H->L, bude od teď detekována změna L->H ; a naopak). Je kontrolováno, aby čas, po který je úroveň na pinu RA2 nízká na počátku, byl mezi 8 a 10 ms (má být 9 ms). Pokud je tato podmínka splněna, je to považováno za začátek příchozích dat protokolu NEC.
Konec přenosu je detekován podmínkou, že úroveň signálu je vysoká po dobu delší než 2.56 ms a počet příchozích bitů je větší než 32. V tom případě jsou zakázána všechna přerušení, dioda krátce změní barvu ze zelené na červenou po dobu 50 ms a následně zpět na zelenou. Data jsou odeslána ve formě textového řetězce do PC. Po odeslání jsou všechna přerušení povolena a mikrokontroler je uveden do spánku, ze kterého opět může být probuzen přerušením vyvolaným změnou úrovně na výstupu IR přijímače.
#include <xc.h>
#define _XTAL_FREQ 8000000
// CONFIG1
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG2
#pragma config WRT = OFF
#pragma config PLLEN = OFF
#pragma config STVREN = OFF
//#pragma config BORV = LO
#pragma config LVP = OFF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE;
void sendSerialString(BYTE *s)
{
while (*s)
{
TXREG=*(s++);
while (!TRMT)
;
}
}
#define RED_LED_TRIS TRISCbits.TRISC1
#define RED_LED_LAT LATCbits.LATC1
#define GREEN_LED_TRIS TRISCbits.TRISC0
#define GREEN_LED_LAT LATCbits.LATC0
#define FALLING 0
#define RISING 1
volatile BYTE data;
volatile unsigned int c128us;
volatile BYTE edge;
volatile unsigned int times0[40];
volatile unsigned int times0count;
volatile unsigned int times1[40];
volatile unsigned int times1count;
unsigned int htime;
volatile BYTE dataready;
BYTE s[50];
volatile unsigned int d;
void main(void)
{
OSCCON = 0b01110000;//8 MHz, 0.5 us / 1 instruction
ANSELA=ANSELB=ANSELC=0;
TRISA=TRISB=TRISC=0;
LATA=LATB=LATC=0;
RED_LED_TRIS=0;
GREEN_LED_TRIS=0;
//setup USART
TRISBbits.TRISB5=1;//RX
TRISBbits.TRISB7=0;//TX
SPBRG=51;//9600->51.08
TXSTAbits.BRGH=1;
TXSTAbits.SYNC=0;
RCSTAbits.SPEN=1;
TXSTAbits.TXEN=1;
RCSTAbits.CREN=1;
INTCONbits.PEIE=1;
//timer0
OPTION_REGbits.TMR0CS=0;
OPTION_REGbits.PSA=1;
INTCONbits.TMR0IF=0;
INTCONbits.TMR0IE=0;
//interrupt pin RA2
TRISAbits.TRISA2=1;
INTCONbits.INTF=0;
INTCONbits.INTE=0;
OPTION_REGbits.INTEDG=0;//interrupt pin RA2 rising edge = 1, falling edge = 0
edge=FALLING;
data=0;
d=0;
RED_LED_LAT=1;
PIR1bits.RCIF=0;
PIE1bits.RCIE=1;
INTCONbits.GIE=1;
while (d!=0xAA55)
;
PIE1bits.RCIE=0;
INTCONbits.GIE=0;
RED_LED_LAT=0;
GREEN_LED_LAT=1;
c128us=0;
times0count=0;
times1count=0;
dataready=0;
BYTE x[4];
__delay_ms(200);
INTCONbits.TMR0IF=0;
INTCONbits.TMR0IE=1;
INTCONbits.INTF=0;
INTCONbits.INTE=1;
INTCONbits.GIE=1;
SLEEP();
while (1)
{
if (dataready)
{
INTCONbits.GIE=0;
GREEN_LED_LAT=0;
RED_LED_LAT=1;
__delay_ms(50);
RED_LED_LAT=0;
GREEN_LED_LAT=1;
if ((times0count>=33) && (times1count>=33))
{
memset(x,0,4);
for (BYTE i=0;i<4;i++)
for (BYTE j=0;j<8;j++)
{
if (times1[1+8*i+j]>1400)
x[i]|=(1<<(7-j));
}
sprintf(s,"%02X%02X%02X%02X",x[0],x[1],x[2],x[3]);
sendSerialString(s);
}
times0count=0;
times1count=0;
dataready=0;
edge=FALLING;
OPTION_REGbits.INTEDG=FALLING;
//__delay_ms(1000);
INTCONbits.INTF=0;
INTCONbits.INTE=1;
INTCONbits.TMR0IF=0;
INTCONbits.TMR0IE=1;
INTCONbits.GIE=1;
SLEEP();
}
}
}
void interrupt isr(void)
{
if (INTCONbits.TMR0IE && INTCONbits.TMR0IF)//timer0, 128 us passed
{
++c128us;
if ((edge==FALLING) && (times0count>=33) && (c128us>20))
{
INTCONbits.TMR0IE=0;
INTCONbits.INTE=0;
INTCONbits.INTF=0;
dataready=1;
}
else if (c128us>1000)
{
times0count=0;
times1count=0;
dataready=0;
edge=FALLING;
OPTION_REGbits.INTEDG=FALLING;
}
INTCONbits.TMR0IF=0;
}
if (INTCONbits.INTE && INTCONbits.INTF)//interrupt pin RA2
{
if (edge==FALLING)
{
if (times0count>0)
{
times1[times1count++]=((unsigned int) (TMR0>>1))+(c128us<<7);
}
OPTION_REGbits.INTEDG=RISING;
edge=RISING;
TMR0=0;
c128us=0;
}
else
{
htime=((unsigned int) (TMR0>>1))+(c128us<<7);
if (times0count==0)
{
if ((htime>=8000) && (htime<=10000))
times0[times0count++]=htime;
}
else
{
times0[times0count++]=htime;
}
OPTION_REGbits.INTEDG=FALLING;
edge=FALLING;
TMR0=0;
c128us=0;
}
INTCONbits.INTF=0;
}
if (PIE1bits.RCIE && PIR1bits.RCIF)//UART receive
{
data=RCREG;
switch (data)
{
case 0xAA:
{
if (d==0)
d=(((unsigned int) data)<<8);
else
d=0;
break;
}
case 0x55:
{
if (d==0xAA00)
d|=((unsigned int) data);
else
d=0;
break;
}
default:d=0;
}
PIR1bits.RCIF=0;
}
}