PIC16F877A & infrarood RC5

Alleen berichten met de trefwoorden “interrupt picbasic” worden getoond. Alle berichten tonen

Heeft iemand van jullie wel eens een RC5 infrarood ontvanger gemaakt voor de pic16f877a? De programma's die ik op internet vind zijn vaak asm, hetgeen van picbasic is alleen voor volledige versie van de proton compiler. Ik gebruik zelf de mikroC compiler.

De bedoeling is om een paar functies van de ab te kunnen gebruiken op een via I2C aangesloten IC.

Zelf schrijven is ook een optie alleen vraag ik me af wat de beste manier is om dit op te lossen.

Ik heb er twee gemaakt, een voor de ti83+ om tekst te typen met de afstandsbediening en eentje om een motor aan te sturen. Ik raad je aan om het in een interrupt te zetten. Je zou eventueel een stuk asm in de code zetten als dat kan.
Het ontvangen van de code gaat als volgt.
-Je leest deze pagina door.
-Je maakt een interrupt als de ontvanger output laag wordt
-Je maakt een vertraging subroutine
-Je wacht tot de uitgang weer hoog wordt en je registreert hoeveel vertragingen dat heeft geduurd.
Nu komt een lus die pas eindigt als de pauze tussen aan/uit langer dan 255 vertragingen is
-Je zet de huidige status van de lijn op bit 0 van de ontvangst byte. denk aan or logica, bit 0 moet dan wel 0 zijn gemaakt van te voren (denk aan and logica.
-Je wacht tot de lijn veranderd, als dit langer dan 255 vertragingen duurt is het signaal voorbij.
-Je maakt een for loop die de vertraging subroutine net zo vaak herhaald als eerder opgenomen in het begin, liefst iets meer.
-Je draait de onvang byte naar links.
einde while loop
je draait de onvangen byte naar rechts en doet and %11000000, omdat alleen de laatste 6 bits een opdracht bevatten.

Dit kan wat vaag overkomen, dus je kunt het natuurlijk altijd vragen.

Uiteraard via een interrupt werken, maar als ik het goed begrijp is de ontvanger IC via i2c uit te lezen?

Dan zal hij ook het ontvangen signaal al hebben omgezet voor je denk ik.

Heb je een link naar de datasheet van de IC?

Koop hier uw kristallen bol - in 2008 ga ik m'n projecten afmaken, echt waar ....... nouja in 2009 dan ..... ehh 2010 ....

Nou ik heb een eerste programmatje geschreven waarin ik op m'n lcd een tekst wil laten weergeven bij een binnenkomend ir-signaal. Dit werkt helaas nog niet, misschien ziet iemand van jullie wat er anders moet zodat er tekst op mijn scherm komt te staan wanneer ik op een willekeurige knop op de ab druk.

code:


/*
  Project: RC5 infraroodbesturing
  MCU: PIC16F877A
*/

void main()
{
 LCD_Init(&PORTB);         // Initialize LCD connected to PORTB
 INTCON = 0x10;             //INTE hoog (RB0 external interrupt)
 PORTB = 0x01;              //PORTB.0 hoog

}

void interrupt()
 {
  while(1)
  {
  Delay_ms(100);
  LCD_Cmd(LCD_CLEAR);       // Clear display
  LCD_Cmd(LCD_CURSOR_OFF);  // Turn cursor off
  Delay_ms(100);
  LCD_Out(1,1, "Inter");
  }
 }

zoals je code nu staat blijft je programma eeuwig in je interrupt. de correcte manier is;

code:


void main (){


 while (1){
  
 // eeuwige lus
 }

}

void interrupt(){

//handel interrupt af

}

houd je interrupts zo klein/snel mogelijk.

verstandiger is dus om je lcd routines buiten je interrupts te houden en alleen in je interrupt een globale variabele te laten veranderen en deze dan in de eeuwige lus te gebruiken.

[Bericht gewijzigd door Fixation op maandag 16 april 2007 21:43:49

Nou ik ben er vandaag weer even aan verder gegaan met het volgende resultaat. Ik krijg nog steeds geen text op m'n lcd. Op de scoop zie ik mooi de bitstroom langskomen, dus ik zou zeggen dat de interrupt in werking treedt, helaas niet. Iemand een idee??

code:


/*
  Project: RC5 infraroodbesturing
  MCU: PIC16F877A
  TSOP aangesloten op RB0
*/

void main()
{
 while(1)
 {
  LCD_Init(&PORTB);         // Initialize LCD connected to PORTB
  Delay_ms(100);
  INTCON = 0x90;             //GIE & INTE hoog (RB0 external interrupt)
  PORTB = 0x01;              //PORTB.0 van begin hoog
 };
}

void interrupt()
 {
  LCD_Cmd(LCD_CLEAR);       // Clear display
  LCD_Cmd(LCD_CURSOR_OFF);  // Turn cursor off
  LCD_Out(1,1, "Inter");
 }

Wanneer ik de lcd_cmd in m'n main zet dan compiled hij niet.

Het kan aan mij liggen, ik heb nog nooit een PIC in C geprogrammeerd.
In PicBasic moet je eerst de interrupt functie aangeven, je moet de compiler dus vertellen naar welke functie de PIC toe moet springen bij een interrupt.
Vervolgens moet je de GlobalInterruptEnable (GIE) flag aanzetten (welk register dat is weet ik niet meer, but 0 uit mn hoofd), vervolgens moet je de interrupt voor een bepaalde gebeurtenis, [doorstreep]in jouw geval de INT pin (denk ik??)[/doorstreep] (ik had niet goed gelezen) inschakelen, die zit in dezelfde register, samen met een vlag die aangeeft op welke flank ie moet triggeren. Hiervoor kun je ook nog even de manual van je PIC raadplegen )
Ik denk dat je PORTB.0 wel even als input in moet stellen, hoewel ik dat niet zeker weet....

Wanneer ik de lcd_cmd in m'n main zet dan compiled hij niet.

Foutmelding ??????

Alleen de LCD_Cmd in de main routine zetten is niet voldoende, je moet in de interrupt in een variabele zetten wat er moet gebeuren, in de loop van de main routine deze variabele uitlezen, doen wat er gedaan moet worden, en de variabele resetten.

Succes!

[Bericht gewijzigd door UFO op donderdag 19 april 2007 17:07:57

Op 19 april 2007 17:04:14 schreef UFO:
Foutmelding ??????

Reentrancy not allowed: function [Lcd_Cmd] called in both main and interrupt threads.

Dat van die variabelen zal ik eens bekijken.

Je kan de LCD functies niet in de interrupt gebruiken.

Wat je moet doen is de info klaar zetten in je interrupt en in je main lus die info oppakken en weergeven.

Persoonlijk zal ik niet steeds de lcd opnieuw schrijven maar enkel bij wisselingen.

Koop hier uw kristallen bol - in 2008 ga ik m'n projecten afmaken, echt waar ....... nouja in 2009 dan ..... ehh 2010 ....

Endless loop in een interrupt..?

hou je interrupt routine zo 'schoon' en kort mogelijk.
in jouw geval

zou ik doen

code:


volatile unsigned char ieSet;

void interrupt( void ) {
  if ( intcon ( 1 << RBIE ) ) {
     ieSet= 1; 
     intcon &= (RBIF^0xff);   // reset interrupt flag!
     }

  return;
}

void main ( void ) {
  ieSet= 0;
  // init code

  while ( 1 ) {
     if ( ieSet == 1 ) {
         ieSet= 0;
         // lcd output code
     }
  }
}

En zo hou je alle lcd call's automatisch uit je interrupt..

[Bericht gewijzigd door fredvr op vrijdag 20 april 2007 16:20:18

Op 20 april 2007 09:30:09 schreef Red_Arrow:
[...]

Reentrancy not allowed: function [Lcd_Cmd] called in both main and interrupt threads.

Dat van die variabelen zal ik eens bekijken.

Het lijkt erop dat je de Lcd_Cmd aanroep zowel in de interrupt, als de main routine hebt staan... in PicBasic is dat geen probleem, volgens de C aanpak blijkbaar wel.

Wat een deftig woord voor een PIC, "threads"...

Ik ben even verder gegaan met frrrd z'n programma, na een kleine wijziging in de interrupt functie vond de compiler hem goed, maar helaas in de praktijk werkt het nog niet.

code:


volatile unsigned char ieSet;

void interrupt( void ) {
  if ( INTCON.RBIE ) {
     ieSet= 1;
     INTCON &= (RBIF^0xff);   // reset interrupt flag!
     }

  return;
}

void main ( void ) {
  ieSet= 0;
  // init code
  TRISB = 0;                // PORTB is output
  Lcd_Init(&PORTB);         // Initialize LCD connected to PORTB
  Lcd_Cmd(Lcd_CLEAR);       // Clear display
  Lcd_Cmd(Lcd_CURSOR_OFF);  // Turn cursor off

  while ( 1 ) {
     if ( ieSet == 1 ) {
         ieSet= 0;
         // lcd output code
         Lcd_Out(1, 1, "Inter");
     }
  }
}

Even ter info, het lcd werkt wel gewoon zonder interrupt functie!

Ik heb ook nog
if ( INTCON.RBIE == 1 )
geprobeert, helaas ook zonder resultaat. Als ik de probe van de scoop op RB0 zet dan zit ik wel gewoon 'n treintje langskomen.

Iemand een idee???

Even m'n programma aangepast om te kijken of ik wel in m'n main kom, echter zie ik met onderstaand programma nog niets op m'n lcd. Er zit dus een rare fout in.

code:


volatile unsigned char ieSet;

void interrupt( void ) {
  if ( INTCON.RBIE == 1 ) {
     ieSet= 1;
     INTCON &= (RBIF^0xff);   // reset interrupt flag!
     }

  return;
}

void main ( void ) {
  ieSet= 0;
  // init code
  //TRISB = 0;                // PORTB is output
  Lcd_Init(&PORTB);         // Initialize LCD connected to PORTB
  Delay_ms(100);
  Lcd_Cmd(Lcd_CLEAR);       // Clear display
  Lcd_Cmd(Lcd_CURSOR_OFF);  // Turn cursor off
  Lcd_Out(1,1, "POWER ON");
  Delay_ms(200);
  Lcd_Cmd(Lcd_CLEAR);

  while ( 1 ) {
     if ( ieSet == 1 ) {
         ieSet= 0;
         // lcd output code
         Lcd_Out(1, 1, "Inter");
     }
  }
}

edit: Red_arrow gaat zich schamen, had de fuses bij dit project niet ingesteld :-) ik krijg nu wel power on te zien! Ik ga nu weer verder kijken naar de interrupt functie.

[Bericht gewijzigd door Red_Arrow op donderdag 10 mei 2007 09:53:06

Arco

Special Member

Hoe wou je in hemelsnaam een interrupt op Port B krijgen, als alle pinnen als outputs staan gedefinieerd?

(TRISB = 0x00)

Je moet ook eerst wel de interrupts aanzetten (GIE, PEIE, RBIE)

Ook moet:

code:

if ( INTCON.RBIE == 1 ) {

zijn:

code:

if ( INTCON.RBIF == 1 ) {

[Bericht gewijzigd door Arco op donderdag 10 mei 2007 16:20:35

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

Changed:

code:


volatile unsigned char ieSet;

void interrupt( void ) {
  if ( INTCON.RBIF == 1 ) {
     ieSet= 1;
     INTCON &= (RBIF^0xff);   // reset interrupt flag!
     }

  return;
}

void main ( void ) {
  ieSet= 0;
  // init code
  TRISB = 0x01;              // PORT RB0 is input
  INTCON = 0xD0;             //GIE, PEIE & INTE hoog (RB0 external interrupt)
  Lcd_Init(&PORTB);          // Initialize LCD connected to PORTB
  Delay_ms(100);
  Lcd_Cmd(Lcd_CLEAR);       // Clear display
  Lcd_Cmd(Lcd_CURSOR_OFF);  // Turn cursor off
  Lcd_Out(1,1, "POWER ON");
  Delay_ms(200);
  Lcd_Cmd(Lcd_CLEAR);

  while ( 1 ) {
     if ( ieSet == 1 ) {
         ieSet= 0;
         // lcd output code
         Lcd_Out(1, 1, "Inter");
     }
  }
}

Maar nog geen interrupt.

Arco

Special Member

RBIF is de flag voor changes op alle port B pinnen.
INTF is de interrupt vlag voor externe interrupt op RB0 (die je met INTE hebt aangezet)

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

Je moet denk ik ook nog aangeven op wat voor een soort signaalwisseling de interrupt gegeven moet worden. in geval van IR is dat van hoog ('rust') naar laag.

code:


OPTION_REG |= INTEDG;   	// int on falling edge

Kun je niet even een ledje aan een poortje aansluiten? Weet je zeker dat het niet in je LCD routines zit. Misschien krijg je wel een interrupt maar laat ie het om die reden niet zien...