Card detect

beckhj

Neues Mitglied
29. Nov. 2010
27
0
1
Rheinstetten
Sprachen
  1. ANSI C
Zunächst mal zu meinem Problem.

In meiner Firma brauche ich zu mehr und mehr Applikation meinen Firmenausweis, da dieser auch meine Schlüsselinformationen auf diesem gespeichert sind. Das heißt, er steckt häufig in meinem Kartenleser (ich nutze einen externen, der ist einfach praktischer).

Nun kommt es dann aber leider öfters vor, dass ich morgens in die Firma komme und feststellen muss, dass mein Ausweis immer noch vom letzten Tag her im Leser steckt und schon habe ich das Problem - wir komme ich rein (auch dafür brauche ich meinen Ausweis.


Also suchte ich nach einer Möglichkeit. mich an das erinnern zu lassen. Windows-Mittel greifen da leider nicht mehr (seit Windows-Vista kann man den PowerDown Event nicht mehr abfangen und verzögern). Also musste ich da zu einer anderen Lösung greifen.


Ich habe nun eine kleine Gabellichtschranke auf meinen Ausweisleser geklebt und die beiliegende Schaltung da dran gehängt.

CardDetect.PNG
Ich messe mit dem uP die USB-Spannung und überwache auch, ob die Karte steckt. Wenn die Karte steckt leuchtet eine rote LED, eine grüne leuchtet ohne gesteckte Karte, um die Betriebsbereitschaft zu symbolisieren.

Wenn ich nun einen Spannungseinbruch von 10% unterhalb der Maximalspannung erkenne UND der Ausweis steckt, aktiviere ich einen Piezo-Summer.

Da hatte ich in der 1. Version das Problem, dass der bei den ca. 4,3V sehr leise war. Daher habe ich nun in der 2. Version eine kleine Ladungspumpe eingebaut, die auch durch den uP versorgt wird. Der C2 wird darüber so auf ca. 8,5V geladen und damit ist der Piezo gut hörbar.


Tja, eigentlich alles andere als komplex - aber mal wieder eine schöne Anwendung für einen Tiny. Die 1. Version hatte einen TINY13 drin, aber mit der Ladungspumpe und der grünen LED (in der 1. Version hatte ich nur die rote) gingen mit dann die IO-Pins aus. Daher nun der TINY44.
 
Mit "eigentlich alles andere als komplex" hast Du ja des wesentliche gesagt - eigentlich sollte sich das auch ohne µC mit ein paar Logicgattern realisieren lassen, ABER natürlich sind wir hier ein Mikrocontrollerforum, und da sind für solche kleinen Sachen die Tinies erste Wahl.
(In meiner Datenbank gibts auch keine Tinies mit mehr als 8, weniger als 14 Beinen).

Wie ist das mit der Ladungspumpe, wäre die nicht über einen PWM-Pin sinniger gewesen?

Ansonsten wieder ein typischer Fall von "Ich brauche ein xyz das uvw kann. Was, sowas gibts nicht? Dann mach ich's eben selbst";)
 
Hallo LotadaC

das mit den wenigen Logicgattern stimmt, aber die bekommst Du nicht alle in einem 14-Pin Gehäuse.

PWM - stimmt vollkommen, aber ich gebe es zu, daran hatte ich nicht gedacht.
 
Hi,

schöne kleine Lösung für ein kleines Problemchen. :) Gegenüber Logikgattern ist das mit nem Tiny natürlich wesentlich einfacher zu löten. Weniger Chips und die Pins werden so verdrahten wie man sie ohne Kreuzungen haben will. Den Rest macht das Programm :D

Sieht auch sehr Anfängergeeignet aus. Wär klasse wenn du für diese Fraktion noch den Quellcode in diesen Thread packen könntest. ;)
Wäre für nen gestandenen Bascomer kein Problem das selber zusammenzutippen (bischen ADC, nen bischen IO, ...) die Funktionsbeschreibung gibt dafür eigentlich alles her. Aber grade Anfänger haben da immer Probleme rauszufinden wie man das am besten anpackt. ;)

Gruß
Dino
 
Hallo!

Gerne, anbei der Quellcode:


CodeBox C

#define F_CPU 8000000

#include <avr/wdt.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <stdbool.h>

#define LED_RED  (1<<PORTA7)
#define LED_GREEN (1<<PORTA6)
#define Buzzer (1<<PORTA3)
#define ChargPump (1<<PORTA2)

#define Lichschranke_Sender    (1 << PORTB2)
#define Lichschranke_Empfaenger    (1 << PORTB1)


volatile uint8_t sleep_interval=0;
uint16_t Analog_Max,AnalogResult;
uint8_t CardPresent;

void init_wdt();

void delay(uint16_t ms);
void sleep(uint8_t s);
void slow_clock();
void fast_clock();
void ADC_Init();
uint16_t ADC_Read( uint8_t );


int main() 
{
        delay(10); // delay before clock slows down, 1000ms * 64

        init_wdt();
       
        DDRA |= LED_GREEN | LED_RED | Buzzer | ChargPump;
        PORTA |=  LED_GREEN;
        PORTA &= ~(Buzzer| LED_RED);

        DDRB |=  Lichschranke_Sender;
        PORTB |= Lichschranke_Empfaenger | ChargPump;    //Pullup Ein
        PORTB &= ~Lichschranke_Sender;

        ADC_Init();
       
        slow_clock();
        //fast_clock();
       
        sei();

        while (1) 
        {
            PORTB &= ~Lichschranke_Sender;
            AnalogResult=ADC_Read(0);
            if (AnalogResult > Analog_Max)
                Analog_Max=AnalogResult;
            CardPresent=PINB & Lichschranke_Empfaenger;
            PORTB |=  Lichschranke_Sender;
            if (CardPresent != 0)
            {
                PORTA |= LED_GREEN;
                PORTA &= ~LED_RED;
            }
            else
            {
                PORTA &= ~LED_GREEN;
                PORTA |= LED_RED;
            }
            if (AnalogResult < (Analog_Max - (Analog_Max/10)))
            {
                if (CardPresent != 0)
                {
                    PORTA &= ~(LED_GREEN | LED_RED);

                    while (1)
                    {
                        PORTA |=  Buzzer;
                        sleep(1);
                        PORTA &=  ~Buzzer;
                        sleep(1);
                    }
                }
                else
                {
                    while (1)
                        PORTA |= (LED_GREEN | LED_RED);
                }
            }   

            PORTA ^= ChargPump;
        }
               
}

/* ADC initialisieren */
void ADC_Init(void)
{
  // die Versorgungsspannung AVcc als Referenz wählen:
  //ADMUX |= ~(1<<REFS0);    //Versorgungsspannung als Referenz
  ADMUX = 0;    //Versorgungsspannung als Referenz

  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
  // schon auf 0, also single conversion
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */

  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der Konvertierung warten
  }
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  (void) ADCW;
}

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
  }
  return ADCW;                    // ADC auslesen und zurückgeben
}

void delay(uint16_t ms) {
        while(ms) {
                _delay_ms(1); // this function must be called with a compile-time CONST, otherwise it pulls in float-math (huge)
                ms--;
        }
}


// Puts MCU to sleep for specified number of seconds using
// WDT to wake every second and track number of seconds
void sleep(uint8_t s)
{
        sleep_interval = 0;
        while (sleep_interval < s) {
               wdt_reset();
               set_sleep_mode(SLEEP_MODE_PWR_DOWN);
               sleep_mode();
        }
}


// Enable watchdog interrupt, set prescaling to 1 sec
void init_wdt()
{
        // Disable interrupts
        cli();

        _WD_CONTROL_REG |= (1<<WDCE);

        _WD_CONTROL_REG = (1<<WDIE)|(1<<WDP1)|(1<<WDP0); //250ms
        //_WD_CONTROL_REG = (1<<WDIE)|(1<<WDP2)|(0<<WDP0); //250ms
        //_WD_CONTROL_REG = (1<<WDIE)|(1<<WDP2)|(1<<WDP0); //500ms
        //_WD_CONTROL_REG = (1<<WDIE)|(1<<WDP2)|(1<<WDP1); //1s
}



void fast_clock()
{
        CLKPR = (1<<CLKPCE);
        CLKPR = 0; // scale = 1
        }

void slow_clock()
{

    CLKPR = (1<<CLKPCE);
    CLKPR = (1<<CLKPS2)|(1<<CLKPS1); // scale = /64
}

ISR(WATCHDOG_vect)
{
        sleep_interval++;
        wdt_reset();
        // Re-enable WDT interrupt. Normally we wouldn't do that here,
        // But we're using this routine purely as a timeout; 
        // WDT is never used for reset
        _WD_CONTROL_REG |= (1<<WDIE);          
        return;
}

 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)