I2C-Chipkarten

aus MariaTheresia, der freien Wissensdatenbank

none
TODO: Bitte Schaltpläne, Layout und Fotos einfügen

I²C – Chipkartenlesegerät

Diese Projekt umfasst die Möglichkeit über I²C von Chipkarten zu lesen, so wie es bei vielen Zeitnehmungssystemen möglich ist.


Zuerst ist einmal ein Wissen über I²C erforderlich.


hier einige hilfreiche Seiten:

www.cc5x.de/I2C.html

www.sprut.de/electronic/pic/grund/i2c.htm

www.hifish.de/sebastian/_LE_DA/node31.html



weiters die benötigten wir Bauteile:

I²C-fähige Chipkarten

... sind bei Conrad erhältlich:


Artikel-Nr.     Größe     Preis
967815 – HK     2kBit     4,99 €
972924 – HK     16kBit    6,95 €
972967 – HK     64kBit    9,95 €  //?könnte das Programm etwas anders sein


zum lesen der Karten wir außerdem ein Kartenleser

... ebenfalls bei Conrad erhältlich: (unter dem Begriff: Chipkarten-Kontaktiereinrichtung)

Artikel-Nr.   Preis
730513 – HK    5,95 
730521 – HK   11,53 

I²C fähiger Prozessor (ich verwendete den 16F877A von [www.microchip.com])

3 x 4k7 Ohm Wiederstände

natürlich ein paar Stecker und Drähte für die Verbindung

---

nun zur Verkabelung: die Informationen finden Sie in hier: I2C_Bauplan.pdf

---

Nun zu meinem Programm

Wenn eine Chipkarte eingesteckt wird, beginnt das Programm. Es fragt einen 4-Stelligen Code ab und vergleicht ihn mit einem der auf der Karte gespeichert wurde. Ein Mastercode (2222) lässt zu dass zugegriffen wird, ohne den Code zu wissen. (z.B. wenn die Karte noch keinen Code hat) Es lassen sich dann Daten von der Karte auslesen oder neue Daten darauf speichern.


der Code: -- chipkarten.c --

///************ Chipkarten über I2C ***********************///
///************ Version 1: Claudia Michalecz **************///

#include <16F877.h>
#include <stdlib.h>

#include <I2C.c>

#fuses hs,nowdt,put,noprotect

#use DELAY(CLOCK=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#define CODE_ADR 0x70 //Speicheradresse des Codes
#define NAME_ADR 0x50 //Speicheradresse eines Namensfeldes
#define CHIP_NR 0xa0  //Device Adresse des genützen Speichers

#define CARD_PIN pin_b0 //Prüfpin des Kartenkontaktes


int read_code (void)	//Liest und überprüft den Code
{
 byte code[4], c_code[4];
 //code … User, c_code … auf der Karte
 int gueltig=0, zz=0, x=0;
 
 for( ;gueltig==0 && zz<3;zz++)
 {
   printf("\r\nBitte geben Sie den Code ein: ");
   for(x=0; x < 4; x++)  
   {
     code[x]=getc();				 //Eingabe des Codes
     if(code[x]>='0' && code[x]<='9')  //nur Zahlen 
     {
       putc('*');
       code[x]-=48;
       x++;
     }
   }
   gueltig=2;
   for(x=0; x<4; x++)  if(code[x]!=2) gueltig=0;
    //Vergleich mit dem Mastercode
   if(gueltig < 2)
   {
     read_i2c_struct(c_code, CODE_ADR, 4, CHIP_NR);
     gueltig=1;
     for(x=0; x<4; x++)  if(code[x]!=c_code[x]) gueltig=0;
	  //lesen und vergleichen mit dem Kartencode
   }
   if(gueltig==0) printf("\n\r Leider der falsche Code. Sie haben noch %d Versuche", 2-zz);
 }
 if(gueltig==2) printf("\n\r MASTERCODE");
 if(gueltig==1) printf("\n\r Code gueltig");
 if(gueltig==0) printf("\n\r Code 3x ungeueltig eingegeben, Karte wird ausgeworfen");

 return (gueltig);
}

void read_i2c_data (void) //lesen Daten von der Karte
{
 byte name[30];
 int zz=0;
 read_i2c_struct(name, NAME_ADR, 30, CHIP_NR);
 printf("\n\r DATEN der Chipkarte: ");
 printf("\n\r Name: ");
 for(zz=0; zz<30; zz++) {putc((char)name[zz]);}
	//Ausgabe des abgespeicherten Namens
 getch();
}

void change_i2c_data(void) //Ändern der Daten auf der Karte
{
 byte name[30], code[4];
 int zz=0;

 printf("\n\r Bitte geben Sie den Namen ein: (max. 30 Zeichen) ");
 for(zz=0; zz<30 && (zz==1 || name[zz-1]!= '\r'); zz++) 
 {
   name[zz]=getc();
   putc((char) name[zz]);
 } //Eingabe des Namens durch User
 zz = zz - 1;
 for(; zz<30; zz++) name[zz]=' '; //Auffüllen mit Blanks
 write_i2c_struct(name, NAME_ADR, 30, CHIP_NR);
 //Schreiben auf die Karte

 printf("\n\r Bitte geben Sie einen Code ein: (4 Zahlen) ");
 for(zz=0; zz<4;)  //Codeeingabe, wieder nur Zahlen
 {
   code[zz]=getc();
   if(code[zz]>='0' && code[zz]<='9')
   {
     putc('*');
     code[zz]-=48;
     zz++;
   }
 }
 write_i2c_struct(code, CODE_ADR, 4, CHIP_NR);
 //Schreiben auf die Karte
 printf("\n\n\r Daten wurden gespeichert");
}

int menue (int user) //Auswahlmenü
{
 int next=0;
 while( (next<1 || next>3) && !(user==2 && next==4))
 {
   printf("\n\n\r -- MENUE --");
   printf("\n\r Was wollen Sie tun?");
   printf("\n\r  (1) Daten auslesen"); //read_i2c_data()
   printf("\n\r  (2) Daten eingeben"); //change_i2c_data()
   printf("\n\r  (3) Exit");
   if(user==2) printf("\n\r  (4) Karte auslesen"); 
//read_card() nur vom Master aus möglich
   next=(int)getc()-48; //Eingabe als Zahl in Ascii
 }
 return next;
}

void read_card (void)//lesen was alles gespeichert-für 16kbit!
{
  Byte adr=0x00, text[32];
  int c_nr = 0xa0;
  int zz=0, start=0;

  for (;c_nr<0xb0; c_nr+=0x02) 
  //durchlaufen aller 8 Speicher der Karte
  {
    start=0;
    for (adr=0x00 ; adr>0x00 || start==0 ; adr+=32)
    {
  	  //durchlaufen in 32-Sätzen
      start=1;
      read_i2c_struct(text, adr, 32, c_nr); // 32 Byte lesen
      printf("%04x - %04x ",c_nr,adr);   	 // und ausgeben
      for(zz=0; zz<32; zz++) {putc((char) text[zz]);}
      printf("\n\r");
    }
    delay_ms(800);
  }
  getch();
}

void main (void)
{
  int c=0, next=0;

  init_i2c();

  printf("\r\n\n\n\n\n\n START DER KONSOLE\n\r");
  output_low (CARD_PIN);

  while(TRUE)
  {
    //solange keine Karte eingefügt wurde
    while(!input(CARD_PIN))     {
      printf("\r\n Bitte fuegen Sie eine Karte ein!");
      delay_ms(500);
    }

    printf("\r\n\n Karte wurde eingefuegt");
    c=read_code(); //wenn ungültig 0, gültig 1, mastercode 2
    if(c > 0)
    {
      do
      {
        next=menue(c); //menüfunktion
        switch (next)
        {
	    case 1: read_i2c_data(); break;   //daten lesen
            case 2: change_i2c_data(); break; //daten ändern
            case 3: break;				 //karte auswerfen
            case 4: read_card(); next = 0; break; //karte auslesen
            default: next=0;
        }
      } while(next<3);
    }
      //karte auswerfen, bwz. warten bis entnommen wird
    while(input(CARD_PIN))     {
      printf("\n\r Bitte entnehmen Sie die Karte");
      delay_ms(500);
    }
  }
}


-- I2C.c --
Das Grundgerüst zu diesem Programm habe ich von Andreas Pirker – vielen Dank
///************ I²C Funktionen ****************************///
///************ Version 1: Andreas Pirker *****************///
///************ Überarbeitung: Claudia Michalecz **********///

//für pic16f877a
#define I2C_SDA  pin_C4	//SDA -- Datenleitung
#define I2C_SCL  PIN_C3	//SCL -- Clock, Tackt

#use DELAY(CLOCK=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use I2C(MASTER, SDA=I2C_SDA, SCL=I2C_SCL, FORCE_HW, FAST)  
//Master, festlegung der Leitungen, HW-Steuerung, Fast-Mode



//Initialisieren des I2C-Buses
void init_i2c()
{
  output_float(I2C_SCL);
  output_float(I2C_SDA);
}

//Schreiben von einem Byte über I2C
void write_i2c(Byte address, BYTE data, int c_nr)
{
  short int status;

  i2c_start();          //Belegen des Buses
  i2c_write(0xfe & c_nr);  //schreiben der Deviceadresse
  i2c_write(address);   //Datenadresse
  i2c_write(data);	     //1 Byte Daten
  i2c_stop();           //Busfreigabe

  //Warten bis die Daten verarbeitet und Gerät wieder bereit
  i2c_start();	
  status=i2c_write(c_nr); 
  //Statusabfrage, 0-Gerät reagiert, 1-Gerät reagiert nicht
  while(status==1) //Warten bis es reagiert
  {
    i2c_start();
    status=i2c_write(0xa0 | c_nr);
  }
  i2c_stop();
}

BYTE read_i2c(Byte address, int c_nr) //Lesen eines Bytes
{
  BYTE data;

  i2c_start();          //Belegen des Buses
  i2c_write(0xfe & c_nr);  //schreiben der Deviceadresse
  i2c_write(address);   //Datenadresse

  i2c_start();          //Restarten des Buses
  i2c_write(0xa1 | c_nr);	//1 steht für Lesezugriff
  data=i2c_read(0);	//1 Byte lesen
  i2c_stop();			//Freigeben des Buses

  return(data);
}


//Schreiben von beliebig vielen Bytes
void write_i2c_struct(byte *ptr,byte address,int size,int c_nr)
{
  int i = (int) address, start=0;
  byte status;
  //schreiben nur innerhalb eines Blocks (max 256 Bytes)
  for(; i < (size + (int)address && i < 256 ;)
  {
    start=0;
    i2c_start();          //Belegen des Buses
    i2c_write(0xfe & c_nr);  //schreiben der Deviceadresse
    i2c_write(address);   //Datenadresse

    //Daten werden in 16er Blöcke geschrieben
    for (; i<size && i<256 && start == 0 || (i%16) > 0; i++) 
    {
       i2c_write(ptr[i]);
       start=1;
    }
    i2c_stop(); //vorläufige Freigabe			
 //Warten bis die Daten verarbeitet und Gerät wieder bereit     
    i2c_start();			
    status=i2c_write(c_nr);

    while(status==1)
    {
      i2c_start();
      status=i2c_write(c_nr);
    }
    i2c_stop();
    address+=16; //Beginnpunkt der nächsten 16 Bytes
  }
}
//Lesen von beliebig vielen Bytes
void read_i2c_struct(byte *ptr, byte address, int size, int c_nr)
{
  int i = 0;

  i2c_start();          //Belegen des Buses
  i2c_write(0xfe & c_nr);  //schreiben der Deviceadresse
  i2c_write(address);   //Datenadresse
  i2c_start();          //Restarten des Buses
  i2c_write(0xa1 | c_nr);	//1 steht für Lesezugriff

  for (; i < size - 1; i++)	//1 … noch weitere Bytes bitte
  {
     ptr[i] = i2c_read(1);
  }

  ptr[i] = i2c_read(0);	//0 … keine weiteren Bytes mehr
  i2c_stop();			//Busfreigabe
}