Läsa in RFID taggar [AVR, C, Mega88]

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Läsa in RFID taggar [AVR, C, Mega88]

Inlägg av Snouser »

Jag har sedan en tid tillbaka knappat på en liten kod till en uC (mega88) för att kunna läsa in och bearbeta RFIDtaggar. Problemet är bara det att läsningen och skrivningen från/till minnet inte fungerar särskilt bra, sedan så vet jag inte om den läser in mina taggar riktigt.

Hela idéen är att en RFIDläsare kopplas till en uC. 7 st olika dioder beskriver utåt vad det är som händer. När allt fungerar så är det meningen att den ska kopplas till något vettigare, men nu början så duger dioderna fint.

Koden är skriven som så här.

Användaren har två möjligheter (knapp1 och knapp2). Knapp ett är verifierings processen. När denna knapp är nedtryckt så kan information tas emot från RFID läsaren genom USARTen. Informationen som läses in jämförs sedan bit för bit med informationen som finns i EEPROM minnet. Skulle någon bit vara ogiltig så avbryter den direkt och indikerar genom att tända en diod.

Knapp nummer två är skrivningen till minnet. Det första den gör efter kortet är inläst är att kontrollera så att det inte redan finns i minnet. Om den inte redan existerar så skrivs kortet till minnet.

Som det ser ut nu så skriver den "shit" till minnet.

Så här såg det ut innan jag sparade ett kort i minnet:

Kod: Markera allt

:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:00000001FF
Och så här efter skrivning

Kod: Markera allt

:10000000F8E0F0F0F0F0E0FDF1FFFFFFFFFFFFFF91
:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:00000001FF
Något verkar vara fel.

Lagringen av data i minnet har jag lagt upp så här.

Minnes plats ett används till att lagra antalet kort som finns i minnet.
För varje nytt kort som läggs i i minnet så ökar detta register med ett.

Här är koden till projektet.

Kod: Markera allt

#include <avr/io.h> 
#include <util/delay.h>
#include <avr/iom88.h> 
#define sBit(byte,bit) (byte |= 1<<bit)
#define cBit(byte,bit) (byte &= ~(1<<bit))
#define tBit(byte,bit) (byte & (1<<bit))
#define F_CPU 20000000UL //20Mhz


static unsigned char value_recive[12];

void USART_Init(void) 
{ 
	int MYUBRR = 520;
	UBRR0H = (unsigned char)(MYUBRR>>8); 
	UBRR0L = (unsigned char)MYUBRR; 
	//Aktiverar mottagning
	UCSR0B = (1<<RXEN0); 
	//Sätter en stopbit inget paritet och 8 bitar
	UCSR0C = (0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
}

void EEPROM_write(unsigned int uiAddress, unsigned char ucData) 
{ 
	/* Wait for completion of previous write */ 
	while(EECR & (1<<EEPE)); 
	/* Set up address and Data Registers */ 
	EEAR = uiAddress; 
	EEDR = ucData; 
	/* Write logical one to EEMPE */ 
	EECR |= (1<<EEMPE); 
	/* Start eeprom write by setting EEPE */ 
	EECR |= (1<<EEPE); 
}

unsigned char EEPROM_read(unsigned int uiAddress) 
{ 
	/* Wait for completion of previous write */ 
	while(EECR & (1<<EEPE)) 
	; 
	/* Set up address register */ 
	EEAR = uiAddress; 
	/* Start eeprom read by writing EERE */ 
	EECR |= (1<<EERE); 
	/* Return data from Data Register */ 
	return EEDR; 
}

int read(void)
{
	int counter = EEPROM_read(0); //Läser hur många kort som finns i databasen
	int a; //Deklarerar a
	int b; //Deklarerar b
	int c; //Deklarerar c
	int e; //Deklarerar e
	unsigned char read_value; //Deklarerar read_value
	
	for(a = 0; a < counter; a++) //Loppar så att antalet kort kan läsas av
	{
		c = a*10; //Gångrar antalet kort med 10
		for(b = 1; b < 10; b++)
		{
			e = c+b; //Plusar på antalet gånger forlopen har gått
			read_value = EEPROM_read(e); //Hämtar varje byte ur EEPROM
			
			if(read_value != value_recive[b]) //Om angivna värdet inte stämmer överrens med lästa så hoppar loopen till nästa
			{
				b = 11;
			}
			
			if (b == 10)
			{
				return 1;
			}
		}
	}
	return 0;
}

void write(void)
{
	int counter = EEPROM_read(0); //Läser hur många kort som finns i databasen
	int b; //Ställer in register
	counter++; //Adderar ett till antalkort som finns i databasen
	counter = counter * 10; //Reserverar 10 bytes
	for(b = 1; b < 10; b++) //Loopar 10 gånger, alltså skrivs 10 bytes
	{
		EEPROM_write(counter, value_recive[b]); //Skriver till minnet 
		counter++; //Ökar med en byte efter varje loop
	}
}

void recive(void)
{	
	int b; //Ställer in register
	for(b = 0; b < 10; b++)
	{
		while (!(UCSR0A & (1<<RXC0))); //Väntar på att information ska tas emot	
		value_recive[b] = UDR0; //Sparar data och retunerar allt.. 
	}
}

int main() 
{ 
	USART_Init(); //Ställer in USARTen
	DDRB = 0xFF; //Sätter dioderna som ut
	DDRC = 0b00000100; //Sätter knappar som in och en diod som ut
	unsigned char value[12];
	int knappar1;
	int knappar2;

	while(1) //Loopar i all evighet
	{
		knappar1 = ~PINC & (1<<0); //Hämtar information om första knappen
		knappar2 = ~PINC & (1<<1); //Hämtar information om andra kanppen
		sBit(PORTB,0);
		if  (knappar1) //Kontrollerar kort
		{
			cBit(PORTB,0); //Släcker första dioden för att sedan tända den igen
			sBit(PORTB,1); //Tänder andra dioden för att visa att uC är i läge 1
			recive();
			if (read() == 1) //Allt okej, kortet finns databasen
			{
				sBit(PORTB,2); //Tänder tredje dioden, allt OK
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,2); //Släcker tredje dioden
			}

			else //Kortet finns ej i databasen
			{
				sBit(PORTB,3); //Tänder fjärde dioden, inte OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,3); //Släcker fjärde dioden				
			}			
		}
		
		else if  (knappar2) //Läser in nytt kort och sparar det i minnet
		{
			cBit(PORTB,0); //Släcker första dioden för att sedan tända den igen
			sBit(PORTB,4); //Tänder femte dioden
			recive(); //Hämtar information

			if (read() == 1) //Kontrollerar ifall kortet finns i databasen OM ja -->
			{
				sBit(PORTB,5); //Tänder 6:e dioden, OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,5); //Släcker 6:e dioden
			}
			
			else //Om den inte finns i databasen
			{
				write(); //Hämtar och skriver till minnet
				sBit(PORTC,2); //Tänder 7:e dioden, OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTC,2); //Släcker 7:e dioden
			}		
		}
	}	
}
Här är RFID läsaren jag använder:
http://www.parallax.com/Store/Microcont ... roductName

Här är min uC:
http://www.avrfreaks.net/index.php?modu ... displayDev& objectid=77

Hoppas någon kan ge mig en hint om vad problemet skulle kunna vara.

Tack på förhand
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Utan att ha kollat närmare på din kod så kan du använda de rutiner som finns för skrivning till eeprom i avr-gcc. Börja med att skriva en array till eepromet som du initierar med nåt lämpligt, så du vet att skrivningen fungerar.

http://www.nongnu.org/avr-libc/user-man ... eprom.html
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

Det låter som en bra ide.

Borde inte detta fungera?

Kod: Markera allt

#include <avr/io.h>
#include <avr/eeprom.h> 



int main(void)
{	
		do {} while (!eeprom_is_ready());
		eeprom_write_word (0,'A');
		 do {} while (!eeprom_is_ready());
		eeprom_write_word (1,'B');
		 do {} while (!eeprom_is_ready());
		eeprom_write_word (2,'C');
		 do {} while (!eeprom_is_ready());
		eeprom_write_word (3,'D');
		 do {} while (!eeprom_is_ready());
}
Det händer nämligen ingenting jag har kört koden.
Minnet är precis som innan.
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

Nu fungerar det fint att skriva till EEPROM.
Nu tror jag problemet ligger i att baud inställningen är lite små konstig.

När jag räknade på vilken baud jag skulle använda mig utav så fick jag ett ojämt värde. Enligt de böcker jag har läst så har dom använt sig utav en mer exakt frekvens en den i mitt fall 20Mhz. Kan man ställa in detta någonstans eller spelar det ingen roll om det är lite ojämt.

Här är f.ö min nya kod.

Kod: Markera allt

#include <avr/io.h> 
#include <util/delay.h>
#include <avr/iom88.h>
#include <avr/eeprom.h> 
#define sBit(byte,bit) (byte |= 1<<bit)
#define cBit(byte,bit) (byte &= ~(1<<bit))
#define tBit(byte,bit) (byte & (1<<bit))
#define F_CPU 20000000UL //20Mhz


static unsigned char value_recive[12];

void USART_Init(void) 
{ 
	int MYUBRR = 520;
	UBRR0H = (unsigned char)(MYUBRR>>8); 
	UBRR0L = (unsigned char)MYUBRR; 
	//Aktiverar mottagning
	UCSR0B = (1<<RXEN0); 
	//Sätter en stopbit inget paritet och 8 bitar
	UCSR0C = (0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
}

int read(void)
{
	do {} while (!eeprom_is_ready()); //Väntar på att minnet ska bli klart
	int counter = eeprom_read_byte(0); //Läser hur många kort som finns i databasen
	int a; //Deklarerar a
	int b; //Deklarerar b
	int c; //Deklarerar c
	int e; //Deklarerar e
	unsigned char read_value; //Deklrarerar read_value
	int ok;
	a = 0;
	do //Loppar så att antalet kort kan läsas av
	{
		a++;
		c = a*10; //Gångrar antalet kort med 10
		b = 1;
		ok = 0;
		do
		{
			b++;
			e = c+b; //Plusar på antalet gånger forlopen har gått
			do {} while (!eeprom_is_ready()); //Väntar på att minnet ska bli klart
			read_value = eeprom_read_byte(e); //Hämtar varje byte ur EEPROM
			
			if (b == 10)
			{
				ok = 1;
			}
		}
		while (read_value == value_recive[b] && ok != 1);
	}
	while(a < counter && ok != 1);
	return ok;
}

void write(void)
{
	do {} while (!eeprom_is_ready());
	int counter = eeprom_read_byte (0);; //Läser hur många kort som finns i databasen
	int b; //Ställer in register
	counter++; //Adderar ett till antalkort som finns i databasen
	counter = counter * 10; //Reserverar 10 bytes
	for(b = 1; b < 10; b++) //Loopar 10 gånger, alltså skrivs 10 bytes
	{
		do {} while (!eeprom_is_ready()); //Väntar på att minnet ska bli redo
		eeprom_write_word (counter,value_recive[b]); //Skriver till minnet
		counter++; //Ökar med en byte efter varje loop
	}
}

void recive(void)
{	
	int b; //Ställer in register
	for(b = 0; b < 10; b++)
	{
		while (!(UCSR0A & (1<<RXC0))); //Väntar på att information ska tas emot	
		value_recive[b] = UDR0; //Sparar data och retunerar allt.. 
	}
}

int main() 
{ 
	USART_Init(); //Ställer in USARTen
	DDRB = 0xFF; //Sätter dioderna som ut
	DDRC = 0b00000100; //Sätter knappar som in och en diod som ut
	unsigned char value[12];
	int knappar1;
	int knappar2;

	while(1) //Loopar i all evighet
	{
		knappar1 = ~PINC & (1<<0); //Hämtar information om första knappen
		knappar2 = ~PINC & (1<<1); //Hämtar information om andra kanppen
		sBit(PORTB,0);
		if  (knappar1) //Kontrollerar kort
		{
			cBit(PORTB,0); //Släcker första dioden för att sedan tända den igen
			sBit(PORTB,1); //Tänder andra dioden för att visa att uC är i läge 1
			recive();
			if (read() == 1) //Allt okej, kortet finns databasen
			{
				sBit(PORTB,2); //Tänder tredje dioden, allt OK
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,2); //Släcker tredje dioden
			}

			else //Kortet finns ej i databasen
			{
				sBit(PORTB,3); //Tänder fjärde dioden, inte OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,3); //Släcker fjärde dioden				
			}			
		}
		
		else if  (knappar2) //Läser in nytt kort och sparar det i minnet
		{
			cBit(PORTB,0); //Släcker första dioden för att sedan tända den igen
			sBit(PORTB,4); //Tänder femte dioden
			recive(); //Hämtar information

			if (read() == 1) //Kontrollerar ifall kortet finns i databasen OM ja -->
			{
				sBit(PORTB,5); //Tänder 6:e dioden, OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTB,5); //Släcker 6:e dioden
			}
			
			else //Om den inte finns i databasen
			{
				write(); //Hämtar och skriver till minnet
				sBit(PORTC,2); //Tänder 7:e dioden, OK!
				_delay_ms(300); //Väntar en stund
				cBit(PORTC,2); //Släcker 7:e dioden
			}		
		}
	}	
}
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Använder du 20 MHz och sätter UBRR till 520 så blir felet 0.0% enligt databladet så det verkar ju helt ok, eller har jag missat nåt?

Kolla även upp _delay_ms rutinen i avr libc manualen
"The maximal possible delay is 262.14 ms / F_CPU in MHz"
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

OKej, nu är delaye fixad, men det verkar vara en hel del som är konstigt...

Om vi börjar med mottagningen av koden.

Kod: Markera allt

void receive(void)
{	
	int b = 0;
	do
	{
		while (!(UCSR0A & (1<<RXC0))); //Väntar på att information ska tas emot	
		value_recive[b] = UDR0; //Sparar data och returnerar.. 
		b++;
	}
	while(UDR0 != 0x0D);
}
Enligt databladet för läsaren så är den sista biten som skickas 0x0D.
Av någon anledning så är ingen bit 0x0D vilket gör att loopen aldrig tar slut.

Det är väll så man skriver koden, eller har jag gjort fel någonstans?
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

Bör du inte kolla om b > 12 så avbryt också?
Nu fyller du bara på , bufferten kan bli överfull

Sen läser du UDR0 på 2 ställen
först när du sätter value_recieve och därefter i While loopen
Vet inte om detta kan vara ett problem.
Jag hade istället läst UDR0 till en temp variabel.
Å andra sidan kör jag inte C. så möjligt att det funkar ändå

Swech
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

Ja, det borde absolut kunna spela roll. Varje gång dataregistert läses så läser man ut ett nytt tecken (om det finns). Så det skall definitivat bara läsas en gång per tecken. Skulle det köas upp inkommande tecken så får du definitivt problem annars.
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

För att göra det enklare att felsöka min kod så har jag gjort om den lite...

Så här ser den ut nu.

Kod: Markera allt

#include <avr/io.h> 
#include <util/delay.h>
#include <avr/iom88.h>

#define sBit(byte,bit) (byte |= 1<<bit)
#define cBit(byte,bit) (byte &= ~(1<<bit))
#define tBit(byte,bit) (byte & (1<<bit))

void USART_Init(void) 
{ 
	int MYUBRR = 520;
	UBRR0H = (unsigned int)(MYUBRR>>8); 
	UBRR0L = (unsigned int)MYUBRR; 
	//Aktiverar mottagning
	UCSR0B = (1<<RXEN0); 
	//Sätter en stopbit inget paritet och 8 bitar
	UCSR0C = (0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
}

int receive(void)
{   
   int b = 0;
   unsigned char frog;
   unsigned char value[12];

   do
   {
      while (!(UCSR0A & (1<<RXC0)));   
      frog = UDR0;
      value[b] = frog;
      b++;
      if (b > 11) return -1;
   }
   while(frog != 0x0D);
	return 1;
}

int main(void)
{
    USART_Init(); //Ställer in USARTen
	DDRB = 0xFF;
	while(1)
	{
		if (receive() == 1)
		{
			sBit(PORTB,1);
			_delay_ms(50);
			cBit(PORTB,1);
		}
		
		else
		{
			sBit(PORTB,2);
			_delay_ms(50);
			cBit(PORTB,2);
		}
	}
}

Hur jag än gör så blir aldrig sista biten 0x0D.
Den hinner alltid bli avbruten, vilket i detta fall gör att den returnerar -1.

Någon som ser vad felet är?
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

Snouser skrev:Hur jag än gör så blir aldrig sista biten 0x0D.
Sista byten eller sista tecknet. Inte biten. :)

Jag kan inte säga på rak arm varför. Det är iallafall bättre att använda en variabel att läsa ut i, som du gör nu, istället för att läsa registret flera ggr.
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

Jag tror jag vet vad felet är.
Felet är att jag kör på en intern kristall, jag tror jag ska köra på en extern kristall så att jag få lite mer exakt frekvens.

Vad jag har förstått så kan man koppla in en kristall och två kondensatorer för att få det att fungera. Enligt databladet så jag man välja två kondensatorer mellan 12 och 20 (my). Spelar det ingen roll vad jag väljer? Kan jag välja en 15 utan problem?

Kan man seriekoppla kondensatorer precis som man kan föra med resistorer?
Jag har nämligen 10st 10 (my:are) liggandes. Då kanske man slipper köpa in ett par extra.

Sedan så har Jag har hittat en kristall på 11.0592Mhz vilket ger mig ett exakt UDDR värde på 287, vilket borde fungera f.ö.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> (my)

pF ?

> Kan man seriekoppla kondensatorer precis som man kan föra med resistorer?

Ja, men jag tror inte resultatet blir vad du tror...

http://www.elektronikforumet.com/wiki/i ... ondensator
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

Du kan ju testa att kalibrera den interna oscillatorn istället

Det finns ett fabrikskalibreringsvärde som du kan läsa av och
använda - då brukar det bli noggrant så det räcker till...

Swech
Snouser
Inlägg: 107
Blev medlem: 15 november 2006, 22:07:55
Ort: Göteborg

Inlägg av Snouser »

Nu har jag inhandlat lite kondensatorer.

Finns det någon trevlig guide för hur man kopplar in en kristall och vilka värden man ska ha på kondensatorn? Databandet är nämligen lite svår läst..
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Länk till datablad för kristallen?

Hur du kopplar kristall finns på sidan 33 i Atmegans datablad.
Skriv svar