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:
- https://en.wikipedia.org/wiki/Wiegand_interface
- https://getsafeandsound.com/blog/26-bit-wiegand-format
- https://www.securityinfowatch.com/access-identity/access-control/article/10537302/understanding-26bit-wiegand
- https://www.techtarget.com/iotagenda/definition/RFID-radio-frequency-identification
- https://en.wikipedia.org/wiki/Access_control
- https://en.wikipedia.org/wiki/Radio-frequency_identification
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
|
A valid alternative to Silab´s development board: http://www.while1.eu/arduone/arduone.html
Overall, I thoroughly enjoyed your article and found it highly informative, thanks for sharing.
Thanks for the feedback….