Shock Media

Navigatie

rc-5 encoder op ATtiny45 faalt

Forum > Digitaal > rc-5 encoder op ATtiny45 faalt
Naam Bericht
critiacrof

Hallo,

Ik heb een rc-5 decoder gebouwd. Hij doet het niet. Het doel is om op de ATtiny45 een programma te hebben dat bij het indrukken van een bepaalde toets een uitgang laag maakt. Wanneer er geen toets is ingedrukt worden de uitgangen ingangen. Op de ATmega8 stop ik een programma die een HID-keyboard simuleert. Dat programma bestaat al. Op de ingangen van de ATmega8 gaan met pullups de uitgangen van de ATtiny45. Hierdoor kan de ATtiny45 op 5 volt draaien en de ATmega8 op 3.3 volt. Hier is de code van de ATtiny45:
code:
/*
-RC5 encoder for wireless control of media player classic
-30 augustus 2008
-clk=1MHz
-
	2bit keys:
	*+ (up arrow key)
	*- (down arrow key)
	*>|| (space key)
	*nothing
-ouput is high z or 0 to be compatible with 3,3 volt input of usb chip witch has a pullup
-PB1=+
-PB2=-
-PB4=pause/play
-http://www.sbprojects.com/knowledge/ir/rc5.htm
-
*/

#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>//!

#define F_CPU 1000000
#define rx_adress 0 //tv1

bool tick=true; //global, clk for statemachine

ISR(TIMER0_COMPA_vect){
tick=true;
}




int main()
{
int state=0;//state 
int bitteller=0;//bitcounter; used to store bits and to detect end of message.
bool a=false;
bool b=false;
bool end=false;
volatile int i=0;
int bitjes=0;
int address=0;
int command=0;

//timer init:
TCCR0A|=1<<WGM01;//CTC mode
TCCR0B|=1<<CS01;//prescaler=1/8
//OCR0A=444,5/8=56
TCNT0=0;
OCR0A=56;//about 444.4us
TIMSK|=1<<OCIE0A;//interrupt

DDRB&=1<<PINB0;//input pin for tsop

sei();
while(1){

if (tick){
tick=0;

//statemachine:
switch(state){
//-------------------------------------------
case 0:
cli();

while(PINB&(1<<PINB0));//rx=active low

TCNT0=0;//reset for synchronysation
bitteller=0;//start with startbit
bitjes=0;//clear the stored bits
bitjes|=1<<bitteller;//store the startbit	
state=1;//next bit

sei();
break;
//-------------------------------------------
case 1:
//wait 1334us (3/4bit)
//445us have passed so 889us remaining
if (i==2){
i=0;
a=PINB&(1<<PINB0);
state=2;
}
else { 
i++;
}
break;
//-------------------------------------------
case 2:
//wait 889us(1/2bit)
//445us have passed so 445us remaining
if (i==1){
	i=0;
	b=PINB&(1<<PINB0);
	if(a!=b){
		bitteller++;
		bitjes|=a<<bitteller;//10 means 0 and 01 means 1, receiver is inverted

		if (bitteller==13){
			bitteller=0;
			end=true;
			state=1;
		}
		else{
			state=3;
		}

	}

	else { //error!
		cli();
		_delay_ms(25);
		state=0;
		sei();
	}

}
else{ 
i++;
}
break;
//-------------------------------------------
case 3:
if (i==3){
	i=0;
	a=PINB&(1<<PINB0);
	state=2;
}
else { 
	i++;
}

break;
//-------------------------------------------
}//statemachine
}//if(tick==1)
if(end){
	end=false;
	if((bitjes&3)==3){
	address=((bitjes)>>3)&31;	
		if(address==rx_adress){
		command=(bitjes)>>8;
	
		switch(command){
		
		case 12://standby button pressed, standby=12, 12 reversed=12
		//change output:
		DDRB|=1<<PB4;
		break;
		
		case 1://volume+=16, msb=1
		//change output:
		DDRB|=1<<PB1;
		break;
		
		case 17://volume-=17,17 reversed=17
		//change output:
		DDRB|=1<<PB2;
		break;
	
		default: 
		//DDRB&=~((1<<PB1)|(1<<PB2)|(1<<PB4));//clr
		break;
		}
	
	
		}
		else{
		//ignore message
		}

	}
	else{
	//error or extended rc-5
	}


}//if(end)
}//while(1)





return 0;
}

Ik heb de clock op /8 gezet zodat hij draaid op 1 MHz. De optimalisatie staat uit, omdat hij anders blijft hangen in de interrupt. Wanneer ik simuleer werkt de statemachine en de verwerking van het ontvangen bericht. Ik heb ze los getest. Graag hulp.

mvg Chris
[Bericht gewijzigd door critiacrof op 6 september 2008 12:54:24]
pros

Je kan
code:
bool tick=true;
vervangen door
code:
volatile bool tick=true;
en optimalisatie inschakelen. Zonder die "volatile" bestaat de kans dat de compiler de ganse ISR weg-optimaliseert, en dan loopt alles in het honderd als er een interrupt optreedt.

Verder zou ik
code:
#define F_CPU 1000000
omtoveren naar
code:
#define F_CPU 1000000UL
Wellicht helemaal overbodig, maar het kan nooit kwaad.
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
critiacrof

Bedankt. Ik heb het aangepast. Ik vraag mij af wat die UL doet. Hij werkt nog steeds niet. Ik heb het gedeelte waar het ontvangen bericht wordt verwerkt aangepast dat hij altijd iets doet. Hij doet niets, dus hij komt die lus blijkbaar niet in. Ik ga handmatig eerst een compleet bericht simuleren om te zien wat er mis kan gaan. Ik hoop niet dat het aan mijn afstandsbediening van 1,50 van de action ligt. Ik heb namelijk geen scoop om hem te checken in de rc-5stand. Op de tv op een ander protocol werkt hij wel.

edit2: het eerste probleem na de optimalisatie ben ik al tegengekomen. bool b wordt namelijk weggeoptimaliseerd. Van a en b maak ik eerst maar een volatile.

edit2: Het opslaan van een bericht gaat prima. De timing heb ik niet gecontroleerd, maar dat zit wel goed denk ik. Hij gaat na het opslaan van een bericht keurig naar de verwerkingslus, maar hij herkend het command niet.
De variabele command kon ik niet zien met de watch dus heb ik die global gemaakt. Nu herkend hij command wel. Waarom dat zo is weet ik niet.

edit3: Blijkbaar heeft avrstudio na een vastloper de optimizer weer uitgezet. Nu gaat hij wel in de lus, maar hij gaat standaard naar case 12.
[Bericht gewijzigd door critiacrof op 5 september 2008 16:19:39]
Sphere

quote:
Op 5 september 2008 15:43:14 schreef critiacrof:
Bedankt. Ik heb het aangepast. Ik vraag mij af wat die UL doet.


Unsigned Long
[Bericht gewijzigd door Sphere op 5 september 2008 16:47:19]
maartenbakker

Even voor de duidelijkheid, ik denk dat dit een decoder is en geen encoder, of heb ik het verkeerd?
pros

Ik heb je code even gecompileerd, en kreeg onmiddelijk klachten over F_CPU. Met reden, want die moet vóór "#include <util/delay.h>" geplaatst worden.

Een 2e klacht:
code:
z.c:30: warning: 'TIMER0_COMPA_vect' appears to be a misspelled signal handler
z.c:39: warning: function declaration isn't a prototype

De eerste opgelost door "TIMER0_COMPA_vect" te vervangen door "TIM0_COMPA_vect"
De tweede door "int main()" te vervangen door "int main(void)"
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
critiacrof

quote:
Op 5 september 2008 16:52:58 schreef maartenbakker:
Even voor de duidelijkheid, ik denk dat dit een decoder is en geen encoder, of heb ik het verkeerd?

Ja klopt. Ik heb door wat ctrl+c ctrl+v deze fout gemaakt. Maar de titel is correct. De afstandbediening(de encoder) werkt niet op de avr.
@pros:
Ik krijg 0 foutmeldingen en 0 warnings. Ik heb avr studio versie 4.14. De "misspelled signal handler" wordt bij mij wel herkend en hij werkt ook.
Ik denk dat er iets mis is met de timing, maar ik kan zo niets vinden. Ik heb helaas geen scoop, dus ik kan niet op de ingangspin van mijn avr meten.
[Bericht gewijzigd door critiacrof op 6 september 2008 12:58:31]
Marcel
Golden Member

Wat betreft de F_CPU, die heb je dan blijkbaar al in AVR studio opgegeven. Laat hem dan uit de code. Twee keer opgeven geeft uiteindelijk verwarring. Zeker als de waarden ook nog eens van elkaar afwijken. Want dat zou de oorzaak kunnen zijn van je timing probleem.

Versie van AVR Studio is minder van belang dan de versie van de AVRGCC compiler. Welke versie van AVRGCC gebruik je?
Can you decode my avatar? | AVR C tutorial http://expand.xs4all.nl/avr
critiacrof

Waar kan ik zien welke versie ik heb? Ik heb namelijk overal gezocht(eigenlijk niet).
Jammer dan ik niet kan zien wat er gebeurd in het echt(heb geen scoop). Is er een soort simulator voor de avr waar je net als bij modelsim de signalen in de tijd kunt zien ed?
pros

Op een Linux-bak tik je gewoon "avr-gcc -v" in, waarna je zoiets te zien krijgt:
code:
Using built-in specs.
Target: avr
....
gcc version 4.1.3 20070724 (prerelease) (SUSE Linux)


Misschien eens in een dos-shell proberen?

[Vreselijk lange regel verwijderd]
[Bericht gewijzigd door pros op 5 september 2008 21:59:29]
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
Marcel
Golden Member

Type op de commandline 'avr-gcc --version' (zonder quotes) en je krijgt het versienummer te zien.

Het timing probleem ga je helaas niet op in, maar geef je in AVR Studio ook 1.000.000 Hz op?
Can you decode my avatar? | AVR C tutorial http://expand.xs4all.nl/avr
critiacrof

Ik heb via plug-in manager de versie gevonden. Het is een oude versie namelijk 1,0,0,9 2005. Kan dit de oorzaak zijn van het probleem?
pros

Oudere versies van avr-gcc waren heel tolerant wat foutmeldingen betrof. Telkens ik iets aan een ouder programma wil wijzigen, krijg ik een boel warnings over me heen.

Dat hoeft echter niet de oorzaak van je probleem te zijn...
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
Marcel
Golden Member

quote:
Op 5 september 2008 21:59:29 schreef critiacrof:
Ik heb via plug-in manager de versie gevonden. Het is een oude versie namelijk 1,0,0,9 2005. Kan dit de oorzaak zijn van het probleem?

Nee, dat is de versie van de plugin zelf. Je zal het echt even op de commandline in moeten typen. Heb je inmiddels de timing in AVR Studio gechecked?
Can you decode my avatar? | AVR C tutorial http://expand.xs4all.nl/avr
critiacrof

"gcc version 4.3.0 (WinAVR 20080610)"

Ik heb nu alle variabelen op volatile gezet. Wanneer ik optimaliseer slaat hij de complete eerste state over. Pas na een hele lange tijd komt hij er pas in. Dit allemaal ondanks de variabele state 0 was bij het initialiseren. Wanneer ik niet optimaliseer lijkt het of hij doet wat ik zeg dat hij moet doen. Wanneer ik wel optimaliseer gaat hij alles in de verkeerde volgorde doen(begint bij state 3). Wanneer ik niet optimaliseer werkt de 25ms wachtfunctie niet meer correct(warning). Ik ga nu de timing checken in ongeoptimaliseerde toestand.
Hoe voorkom ik dat de optimizer gekke dingen doet?

edit: Ik merk dat mijn methode niet erg netjes is. Als de timing iets afwijkt dan is aan het einde van de pulstrein het effect natuurlijk groter. Ik heb het programma herschreven door een edge detectie in te bouwen. Dat had ik met een interrupt kunnen doen, maar daar heb ik even geen zin in. Gewoon lekker ouderwets de hele tijd naar de ingang kijken. Hier is de code:
code:
Verbeterd

Hij doet het nog steeds niet. Wanneer ik niet optimaliseer wordt het programma veel te groot. Wanneer ik wel optimaliseer gaat hij alles in een hele rare volgorde doen. Hoe kalmeer ik de optimizer?

edit2:
Ik heb een foutje ontdekt in de flankdetectie waar hij een valse flank kan genereren. Dat heb ik verbeterd.

edit3:
He cool. Er is een ingangssimulator voor avr studio...


edit4:
leen nooit een varabele! Ik had de variabele a(eerste bithelfd) voor een ander process gebruikt. Dit op zo'n manier dat a het omgekeerde van a werd. a werd gebruikt als oude waarde om halverwege het bit een flank te detecteren. Daarom werd er geen flank gedetecteerd. Ook heb ik een paar timingproblemen verwijderd. Nu werkt hij in de simulator.
In het echt werkt hij ook! Alleen dat komt omdat ik het verwerkingslusje zodanig heb aangepast dat hij altijd iets doet. Nu heb ik dus of een verkeerd bericht ontvangen of extendend rc-5. Hier is de code:
code:
verbeterd


edit 5:
Ik heb de aanpassing ongedaan gemaakt en een paar bugs verwijderd. Hij doet hij nu soms. Na een reset maakt hij na het indrukken van het standbyknopje op de ab de goede uitgang van zwevend naar laag. Daarna een knopje indrukken maakt die uitgang voor altijd weer zwevend(ingang). Als na een reset een ander knopje wordt ingedrukt dan wordt hij ook nooit meer laag. Het probleem zit hem dus in het herhalen. Na 1 bericht blijft hij blijkbaar ergens hangen...
Conclusie hij doet het half; dus nu lekker slapen.
oja hier is de nieuwste versie van de code:

code:
verbeterd

[Bericht gewijzigd door critiacrof op 7 september 2008 11:48:46]
critiacrof

Ik had een stomme fout gemaakt. Het bericht voor plus is 16 dat is binair 010000. Omgedraaid is dat 000010 dus 2. Ik was die nul vergeten dus ik had 1 ingevuld. Zo had ik bij - (17) 17 ingevuld. Dat had 34 moeten zijn. Bij het simuleren werkt de plus ook gelukkig. Nu moet ik er voor zorgen dat hij na het eerste bericht nog een bericht kan ontvangen. Ik zie dat hij na het bericht een raar gaat doen in de flankdetectie. Hij gaat
code:
if(new0!=old0){
gewoon door ondanks dat de uitspraak niet waar is. Na een paar keer op en neer springen komt hij weer terug in de flank detectie lus waar hij blijft hangen. Ik denk dat ik dat heb opgelost door de tick uit te zetten. Dan slaat hij namelijk de lus over. Dan is alles namelijk weer hetzelfde als aan het begin. De code werkt nu soms. Hij werkt dus prima, maar het duurt soms even voordat hij een bericht oppakt. Iemand nog tips voor stabiliteit? Hier is de versie van vandaag:

code:
verbeterd


edit: Ik heb met een laagdoorlaatfilter en een klein c-tje de ontvanger gestabiliseerd. Dit helpt niet. Wanneer ik mijn hand voor de zender houd dan doet hij het beter. Ik denk dat hij iets te hard zend. Ook zie ik dat in de zender het indicatielampje paralel zit aan het ir ledje.

edit 2:
zoals ik al dacht zat er een probleem in de foutenafhandeling. Bij een fout ging hij gewoon vrolijk door met ontvangen. Dit totdat de fout was opgeschoven en hij weer was hersteld. Dit heb ik opgelost door een simpele delay van 25 ms. Nu werkt hij perfect!!!
Hier is de code:
code:
/*
-Chris Idema(aka critiacrof)
-RC5 decoder for wireless control of media player classic
-6 september 2008
-version 3.0
-clk=1MHz
-keys:
	*+ (up arrow key)  PB1
	*- (down arrow key)PB2
	*>|| (space key)   PB4
	*nothing
-ouput is high z or 0 to be compatible with 3,3 volt input of usb chip wich has a pullup
-http://www.sbprojects.com/knowledge/ir/rc5.htm
*/
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>

#define rx_adress 0 //tv1





int main()
{
volatile bool new0=true, old0=true;//old and new values of input for edge detection
volatile bool tick=false;//edge  

volatile int state=0;

volatile int bitteller=13;//bitcounter; used to store bits and to detect end of message.
volatile int bitjes=0;//message

volatile bool a=true, b=true;//first half and second half of bit

volatile bool end=false;//condition when message is finished

volatile int address=0;//adress(reversed)

volatile int command=0;//commmand(reversed)


//PORTB=0
DDRB&=1<<PINB0;//input pin for tsop

//-------------------------------------------
while(1){

//edge detection:
old0=a;//edge must be detected after first half of bit
while (tick==false){
new0=PINB&(1<<PINB0);
if(new0!=old0){
	tick=true;//edge detected
}

}
tick=false;//reclear



//statemachine:
switch(state){
//-------------------------------------------
case 0:
//wait 444us:
_delay_us(444);

bitteller=13;//start with startbit
bitjes=0;//clear the stored bits
bitjes|=((PINB&(1<<PINB0))^(1<<PINB0))<<bitteller;//store the startbit	
state=1;//next bit
tick=true;//no need to wait for edge

break;
//-------------------------------------------
case 1:
//wait 889us:
_delay_us(444);
_delay_us(445);

a=PINB&(1<<PINB0);//store first half of bit 
state=2;//go to second half

break;
//-------------------------------------------
case 2:
//wait 444us:
_delay_us(444);

b=PINB&(1<<PINB0);
if(a!=b){//bit is correct
	tick=true;//no need to wait for edge
	bitteller--;//next bit
	bitjes|=a<<bitteller;//10 means 0 and 01 means 1, receiver is inverted

	if (bitteller==0){//done
			bitteller=13;//reclear
			end=true;
			state=0;//reset
			a=true;//for edge detection
			tick=false;//reclear
		}
		else{
			state=1;//next bit
		}

	}

else { //error!
	_delay_ms(25);//message is 25 ms long
	state=0;//reset
	a=true;//for edge detection
	tick=false;//wait for edge again
	end=false;//message is not complete
}

break;
//-------------------------------------------
}//statemachine



if(end){
	
	end=false;//reclear
	if((bitjes>>12)==3){//start bits are one's
	address=((bitjes)>>6)&31;	
		if(address==rx_adress){
	
		command=(bitjes)&63;
		
			
			switch(command){
		
			case 12://standby button pressed, standby=12
			//change output:
			DDRB|=1<<PB4;
			_delay_ms(200);
			DDRB&=~(1<<PB4);//clr
			break;
			
			case 16://volume+=16
			//change output:
			DDRB|=1<<PB1;
			_delay_ms(200);
			DDRB&=~(1<<PB1);//clr
			break;
		
			case 17://volume-=17
			//change output:
			DDRB|=1<<PB2;
			_delay_ms(200);
			DDRB&=~(1<<PB2);//clr
			break;
			}
	
		}
		else{
		//ignore message
		_delay_ms(25);//message is 25 ms long
		}

	}
	else{
	//error or extended rc-5
	_delay_ms(25);//message is 25 ms long
	}


}//if(end)
}//while(1)



return 0;
}

[Bericht gewijzigd door critiacrof op 8 september 2008 22:12:05]
critiacrof

Ik zit met een probleem. Ik wil dus een atmega8 microcontroller gebruiken als keyboard emulator. Op http://www.obdev.at/products/avrusb/index.html staan heel veel voorbeelden. Mijn oog viel op deze: http://www.obdev.at/products/avrusb/hidkeys.html . Ik heb al een atmega8 in mijn bezit dus deze wil ik ook gaan gebruiken. Ik heb het software-archiefje gedownload. De code hiervan was makkelijk aan te passen. Hij kan namelijk 17 toetsen gebruiken en daar was een simpele tabel voor gemaakt(toets 1 is A enz.). Deze heb ik aangepast dat toets 1 gelijk staat aan spatie en toets 2 aan pijl omhoog en toets 3 pijl omlaag. Dat zijn namelijk de toetsen die ik wil gebruiken. Maar nu komt het. Hij gaat niet zomaar compileren. Er moeten eerst tig programmatjes worden gedownload en geïnstalleerd( http://www.nongnu.org/avr-libc/user-manual/install_tools.html ). Wie heeft een alternatief of wil mijn code compileren?
Wanneer dit werkt wil ik in de toekomst misschien mijn ontwerp met deze: http://www.obdev.at/products/avrusb/easylogger.html in 1 chip maken, maar dat lijkt mij nu nog te ingewikkeld.
pros

Als je op een Windows-machine werkt, moet je WinAvr hebben. Da's een port van avr-gcc naar een Windows-omgeving, waarbij de buld al uitgevoerd is.
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
critiacrof

Ik heb WinAvr, maar van je laatste zin kan ik niets maken.
pros

gcc is de GNU C-compiler, geschikt voor een brede waaier aan microprocessors.
avr-gcc is daarvan afgeleid, specifiek voor AVR's.
WinAvr is de Windows-versie van die laatste.

Hoe dan ook, als je WinAvr hebt, zou je de broncode moeten kunnen compileren. Lukt dat niet, mail dan de broncode even door (e-mail adres staat in m'n profiel) dan doe ik het wel even.
Een stijgtijd van 1V/nS komt overeen met 3600000000000V/h. Pros Robaer (1995)
Zoeken in topic