Mastering the SiLabs C8051 Microcontroller

External Interrupt (EXTI) – RFID Card Reader

C8051F330D microcontroller does not have pin-change interrupt capability but like many other 8051 microcontrollers, it sports two external interrupts – EXTI0 and EXTI1. In combination, these interrupts can be used for a number of applications. Here I used these interrupts for decoding a Wiegand 26 RFID card reader.

To know more about Weigand 26, RFIDs and their working principle be sure to check the following links:

Code

Waveshare_RGB_LCD.h

 sbit Soft_I2C_Scl at P1_7_bit;
sbit Soft_I2C_Sda at P1_6_bit;
 
#define LCD_I2C_address             0x7C
#define RGB_I2C_address             0xC0
 
/*    Colour Definitions    */
#define REG_RED                     0x04
#define REG_GREEN                   0x03
#define REG_BLUE                    0x02
#define REG_MODE_1                  0x00
#define REG_MODE_2                  0x01
#define REG_OUTPUT                  0x08
 
/*    LCD Definitions    */
#define LCD_CLEAR_DISPLAY           0x01
#define LCD_RETURN_HOME             0x02
#define LCD_ENTRY_MODE_SET          0x04
#define LCD_DISPLAY_CONTROL         0x08
#define LCD_CURSOR_SHIFT            0x10
#define LCD_FUNCTION_SET            0x20
#define LCD_SET_CGRAM_ADDR          0x40
#define LCD_SET_DDRAM_ADDR          0x80
 
/*    flags for display entry mode    */
#define LCD_ENTRY_RIGHT             0x00
#define LCD_ENTRY_LEFT              0x02
#define LCD_ENTRY_SHIFT_INCREMENT   0x01
#define LCD_ENTRY_SHIFT_DECREMENT   0x00
 
/*    flags for display on/off control    */
#define LCD_DISPLAY_ON              0x04
#define LCD_DISPLAY_OFF             0x00
#define LCD_CURSOR_ON               0x02
#define LCD_CURSOR_OFF              0x00
#define LCD_BLINK_ON                0x01
#define LCD_BLINK_OFF               0x00
 
/*    flags for display/cursor shift    */
#define LCD_DISPLAY_MOVE            0x08
#define LCD_CURSOR_MOVE             0x00
#define LCD_MOVE_RIGHT              0x04
#define LCD_MOVE_LEFT               0x00
 
/*    flags for function set    */
#define LCD_8_BIT_MODE              0x10
#define LCD_4_BIT_MODE              0x00
#define LCD_2_LINE                  0x08
#define LCD_1_LINE                  0x00
#define LCD_5x8_DOTS                0x00
 
/*   Data / Command selection   */
#define DAT                         0x40
#define CMD                         0x80
 
void RGB_LCD_init(void);
void I2C_bus_write(unsigned char address, unsigned char value_1, unsigned char value_2);
void LCD_I2C_write(unsigned char value, unsigned char mode);
void RGB_I2C_write(unsigned char reg, unsigned char value);
void set_RGB(unsigned char R, unsigned char G, unsigned char B);
void LCD_goto(unsigned char x_pos, unsigned char y_pos);
void LCD_clear_home(void);
void LCD_putchar(char chr);
void LCD_putstr(char *lcd_string);

Waveshare_RGB_LCD.c

 #include "Waveshare_RGB_LCD.h"
 
void RGB_LCD_init(void)
{
    Soft_I2C_Init();
    delay_ms(20);
   
    LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);
    delay_ms(5);
   
    LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);
    delay_ms(5);
   
    LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);
    delay_ms(5);
   
    LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);
    LCD_I2C_write((LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINK_OFF), CMD);
   
    LCD_clear_home();
   
    LCD_I2C_write((LCD_ENTRY_MODE_SET | LCD_ENTRY_LEFT | LCD_ENTRY_SHIFT_DECREMENT), CMD);
   
    RGB_I2C_write(REG_MODE_1, 0x00);
    RGB_I2C_write(REG_OUTPUT, 0xFF);
    RGB_I2C_write(REG_MODE_2, 0x20);
   
    set_RGB(127, 127, 127);
}
 
void I2C_bus_write(unsigned char address, unsigned char value_1, unsigned char value_2)
{
    Soft_I2C_Start();
    Soft_I2C_Write(address);
    Soft_I2C_Write(value_1);
    Soft_I2C_Write(value_2);
    Soft_I2C_Stop();
}
 
void LCD_I2C_write(unsigned char value, unsigned char mode)
{
    I2C_bus_write(LCD_I2C_address, mode, value);
}
 
void RGB_I2C_write(unsigned char reg, unsigned char value)
{
    I2C_bus_write(RGB_I2C_address, reg, value);
}
 
void set_RGB(unsigned char R, unsigned char G, unsigned char B)
{
    RGB_I2C_write(REG_RED, R);
    RGB_I2C_write(REG_GREEN, G);
    RGB_I2C_write(REG_BLUE, B);
}
 
void LCD_goto(unsigned char x_pos, unsigned char y_pos)
{
    if(y_pos == 0)
    {
        x_pos |= 0x80;
    }
    else
    {
        x_pos |= 0xC0;
    }
   
    I2C_bus_write(LCD_I2C_address, 0x80, x_pos);
}
 
void LCD_clear_home(void)
{
    LCD_I2C_write(LCD_CLEAR_DISPLAY, CMD);
    LCD_I2C_write(LCD_RETURN_HOME, CMD);
    delay_ms(2);
}
 
void LCD_putchar(char chr)
{
    if((chr >= 0x20) && (chr <= 0x7F))
    {
        LCD_I2C_write(chr, DAT);
    }
}
 
void LCD_putstr(char *lcd_string)
{
    do
    {
        LCD_putchar(*lcd_string++);
    }while(*lcd_string != '\0') ;
}

lcd_print_rgb.h

 #define no_of_custom_symbol     1
#define array_size_per_symbol   8
#define array_size              (array_size_per_symbol * no_of_custom_symbol)
 
void load_custom_symbol(void);
void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index);
void print_C(unsigned char x_pos, unsigned char y_pos, signed int value);
void print_I(unsigned char x_pos, unsigned char y_pos, signed long value);
void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points);
void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points);

lcd_print_rgb.c

 #include "lcd_print_rgb.h"
 
void load_custom_symbol(void)
{
    unsigned char s = 0;
 
    const unsigned char custom_symbol[array_size] =
    {
        0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00
    };
 
    LCD_I2C_write(0x40, CMD);
 
    for(s = 0; s < array_size; s++)
    {
         LCD_I2C_write(custom_symbol[s], DAT);
    }
 
    LCD_I2C_write(0x80, CMD);
}
 
void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index)
{
    LCD_goto(x_pos, y_pos);
    LCD_I2C_write(symbol_index, DAT);
}
 
void print_C(unsigned char x_pos, unsigned char y_pos, signed int value)
{
     char ch[5] = {0x20, 0x20, 0x20, 0x20, '\0'};
 
     if(value < 0x00)
     {
        ch[0] = 0x2D;
        value = -value;
     }
     else
     {
        ch[0] = 0x20;
     }
 
     if((value > 99) && (value <= 999))
     {
         ch[1] = ((value / 100) + 0x30);
         ch[2] = (((value % 100) / 10) + 0x30);
         ch[3] = ((value % 10) + 0x30);
     }
     else if((value > 9) && (value <= 99))
     {
         ch[1] = (((value % 100) / 10) + 0x30);
         ch[2] = ((value % 10) + 0x30);
         ch[3] = 0x20;
     }
     else if((value >= 0) && (value <= 9))
     {
         ch[1] = ((value % 10) + 0x30);
         ch[2] = 0x20;
         ch[3] = 0x20;
     }
 
     LCD_goto(x_pos, y_pos);
     LCD_putstr(ch);
}
 
void print_I(unsigned char x_pos, unsigned char y_pos, signed long value)
{
    char ch[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, '\0'};
 
    if(value < 0)
    {
        ch[0] = 0x2D;
        value = -value;
    }
    else
    {
        ch[0] = 0x20;
    }
 
    if(value > 9999)
    {
        ch[1] = ((value / 10000) + 0x30);
        ch[2] = (((value % 10000)/ 1000) + 0x30);
        ch[3] = (((value % 1000) / 100) + 0x30);
        ch[4] = (((value % 100) / 10) + 0x30);
        ch[5] = ((value % 10) + 0x30);
    }
 
    else if((value > 999) && (value <= 9999))
    {
        ch[1] = (((value % 10000)/ 1000) + 0x30);
        ch[2] = (((value % 1000) / 100) + 0x30);
        ch[3] = (((value % 100) / 10) + 0x30);
        ch[4] = ((value % 10) + 0x30);
        ch[5] = 0x20;
    }
    else if((value > 99) && (value <= 999))
    {
        ch[1] = (((value % 1000) / 100) + 0x30);
        ch[2] = (((value % 100) / 10) + 0x30);
        ch[3] = ((value % 10) + 0x30);
        ch[4] = 0x20;
        ch[5] = 0x20;
    }
    else if((value > 9) && (value <= 99))
    {
        ch[1] = (((value % 100) / 10) + 0x30);
        ch[2] = ((value % 10) + 0x30);
        ch[3] = 0x20;
        ch[4] = 0x20;
        ch[5] = 0x20;
    }
    else
    {
        ch[1] = ((value % 10) + 0x30);
        ch[2] = 0x20;
        ch[3] = 0x20;
        ch[4] = 0x20;
        ch[5] = 0x20;
    }
 
    LCD_goto(x_pos, y_pos);
    LCD_putstr(ch);
}
 
void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points)
{
    char ch[5] = {0x2E, 0x20, 0x20, 0x20, 0x20};
 
    ch[1] = ((value / 100) + 0x30);
 
    if(points > 1)
    {
        ch[2] = (((value / 10) % 10) + 0x30);
 
        if(points > 1)
        {
            ch[3] = ((value % 10) + 0x30);
        }
    }
 
    LCD_goto(x_pos, y_pos);
    LCD_putstr(ch);
}
 
void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points)
{
    signed long tmp = 0x00000000;
 
    tmp = value;
    print_I(x_pos, y_pos, tmp);
    tmp = ((value - tmp) * 1000);
 
    if(tmp < 0)
    {
       tmp = -tmp;
    }
 
    if(value < 0)
    {
        value = -value;
        LCD_goto(x_pos, y_pos);
        LCD_putchar(0x2D);
    }
    else
    {
        LCD_goto(x_pos, y_pos);
        LCD_putchar(0x20);
    }
 
    if((value >= 10000) && (value < 100000))
    {
        print_D((x_pos + 6), y_pos, tmp, points);
    }
    else if((value >= 1000) && (value < 10000))
    {
        print_D((x_pos + 5), y_pos, tmp, points);
    }
    else if((value >= 100) && (value < 1000))
    {
        print_D((x_pos + 4), y_pos, tmp, points);
    }
    else if((value >= 10) && (value < 100))
    {
        print_D((x_pos + 3), y_pos, tmp, points);
    }
    else if(value < 10)
    {
        print_D((x_pos + 2), y_pos, tmp, points);
    }
}

main.c

 #include "Waveshare_RGB_LCD.c"
#include "lcd_print_rgb.c"
 
unsigned char count = 0;
unsigned long raw_card_data = 0;
 
void PCA_Init(void);
void Timer_Init(void);
void Port_IO_Init();
void Oscillator_Init(void);
void Interrupts_Init(void);
void Init_Device(void);
 
void EXTI_0_ISR(void)
iv IVT_ADDR_EX0
ilevel 0
ics ICS_AUTO
{
    raw_card_data <<= 1;
    count++;
}
 
void EXTI_1_ISR(void)
iv IVT_ADDR_EX1
ilevel 0
ics ICS_AUTO
{
    raw_card_data <<= 1;
    raw_card_data |= 1;
    count++;
}
 
void main(void)
{
    unsigned char facility_code = 0;
    unsigned int card_number = 0;
   
    Init_Device();
    RGB_LCD_init();
    LCD_clear_home();
   
    LCD_goto(0, 0);
    LCD_putstr("Facility:");
 
    LCD_goto(0, 1);
    LCD_putstr("Card I.D:");
   
    while(1)
    {
        if(count >= 25)
        {
            card_number = (raw_card_data & 0xFFFF);
            facility_code = (0xFF & (raw_card_data >> 0x10));
            print_C(12, 0, facility_code);
            print_I(10, 1, card_number);
            raw_card_data = 0;
            count = 0;
        }
    };
}
 
void PCA_Init(void)
{
    PCA0MD &= ~0x40;
    PCA0MD = 0x00;
}
 
void Timer_Init(void)
{
    TCON = 0x05;
}
 
void Port_IO_Init()
{
    // P0.0  -  Skipped,     Open-Drain, Digital
    // P0.1  -  Skipped,     Open-Drain, Digital
    // P0.2  -  Unassigned,  Open-Drain, Digital
    // P0.3  -  Unassigned,  Open-Drain, Digital
    // P0.4  -  Unassigned,  Open-Drain, Digital
    // P0.5  -  Unassigned,  Open-Drain, Digital
    // P0.6  -  Unassigned,  Open-Drain, Digital
    // P0.7  -  Unassigned,  Open-Drain, Digital
 
    // P1.0  -  Unassigned,  Open-Drain, Digital
    // P1.1  -  Unassigned,  Open-Drain, Digital
    // P1.2  -  Unassigned,  Open-Drain, Digital
    // P1.3  -  Unassigned,  Open-Drain, Digital
    // P1.4  -  Unassigned,  Open-Drain, Digital
    // P1.5  -  Unassigned,  Open-Drain, Digital
    // P1.6  -  Skipped,     Push-Pull,  Digital
    // P1.7  -  Skipped,     Push-Pull,  Digital
 
    P1MDOUT = 0xC0;
    P0SKIP = 0x03;
    P1SKIP = 0xC0;
    XBR1 = 0x40;
}
 
void Oscillator_Init(void)
{
    OSCICN = 0x82;
}
 
void Interrupts_Init(void)
{
    IE = 0x85;
    IP = 0x05;
    IT01CF = 0x10;
}
 
void Init_Device(void)
{
    PCA_Init();
    Timer_Init();
    Port_IO_Init();
    Oscillator_Init();
    Interrupts_Init();
}

Schematic

Explanation

In Wiegand 26 protocol, there are 26 bits which define unique card identification (B) and facility code (A) as shown below:  

Bits 0 to 25 are either ones or zeroes and are defined by the D0 and D1 outputs of the Wiegand 26 RFID reader. Normally D0 and D1 remain in the high logic state. When there is a high to low transition in D0 output, a zero is read and similarly when there is such a transition in D1, a one is read. Detecting 26 such transitions results in decoding the card number. 

External interrupts EXTI0 (P0.0) and EXTI1 (P0.1) are configured to detect high-to-low or falling edge transitions. These pins are configured as open-drain inputs.

 void Interrupts_Init(void)
{
    IE = 0x85;
    IP = 0x05;
    IT01CF = 0x10;
}
 
 
void Timer_Init(void)
{
    TCON = 0x05;
}

EXTI0 is connected to D0 and EXTI1 is connected to D1 of the RFID reader respectively and so when interrupts are triggered bit info is processed. When EXTI0 is triggered, it means that the bit in the card code is zero. Similarly, when EXTI1 is triggered, it means that the bit in the card code is one. The variable raw_card_data contains the card info and upon every interrupt, this variable is shifted while the bit count is stored in the variable count. A “one” is added to the variable raw_card_data when EXTI1 is triggered. For “zero”, nothing is needed to be done.

 void EXTI_0_ISR(void)
iv IVT_ADDR_EX0
ilevel 0
ics ICS_AUTO
{
    raw_card_data <<= 1;
    count++;
}
 
void EXTI_1_ISR(void)
iv IVT_ADDR_EX1
ilevel 0
ics ICS_AUTO
{
    raw_card_data <<= 1;
    raw_card_data |= 1;
    count++;
}

Inside the main code, the peripherals are initialized first. The bit count is checked to see if all 26 bits (0 to 25) have been read. If read so then the raw card info is processed and displayed. After displaying, bit count and raw card data variables are reset to zeroes.

 void main(void)
{
    unsigned char facility_code = 0;
    unsigned int card_number = 0;
   
    Init_Device();
    RGB_LCD_init();
    LCD_clear_home();
   
    LCD_goto(0, 0);
    LCD_putstr("Facility:");
 
    LCD_goto(0, 1);
    LCD_putstr("Card I.D:");
   
    while(1)
    {
        if(count >= 25)
        {
            card_number = (raw_card_data & 0xFFFF);
            facility_code = (0xFF & (raw_card_data >> 0x10));
            print_C(12, 0, facility_code);
            print_I(10, 1, card_number);
            raw_card_data = 0;
            count = 0;
        }
    };
}

Demo

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

Related Posts

3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *