Вводная
Время не стоит на месте — оно течет и изменяется. Технический прогресс диктует свои правила жизни. Одно из этих правил — наличие важнейшего инструмента повседневности — пластиковой карточки. Кредитные, расчетные, депозитные, карточки-визитки, клубные, карточки постоянных покупателей — теперь без них не обходится ни одно цивилизованное общество. Но что делать, если этих «общепризнанных инструментов жизнедеятельности человека» становится слишком много? Что если от их избытка ваш любимый кошелек начинает трещать по швам? Сегодня мы поговорим о том, как данной проблемы можно избежать. А именно, как несколько карточек превратить… в одну.
Немного теории
Как же хранится информация? Да очень просто. По сути, магнитная полоса — это последовательность маленьких участков, намагниченных в противоположных направлениях. На месте перехода между участками напряженность магнитного поля резко меняется. Именно это изменение магнитного поля фиксирует магнитная головка, которая скользит по полосе, когда вы проводите карточку. За счет резкого изменения магнитного поля в катушке головки возникает ЭДС (электродвижущая сила), проще говоря, появляется импульс напряжения, который затем усиливается и передается дальше.
Для различия нулей и единиц используется так называемое F/2F кодирование: то есть при кодировании нуля используется частота F, а для единицы — частота 2F. Например, в начале дорожки у нас идет несколько нулей, служащих для синхронизации, тогда декодирующее устройство примерно вычисляет частоту F (в частности время одного полупериода равного Т), и если же импульс возникал по истечению времени Т, то мы имеем дело с нулем, если посередине этого времени и в конце (удвоенная частота), то это логическая единица.
Этот метод построен на принципе того, что мы не сможем моментально изменить скорость провода карточкой в 1.5 раза. Благодаря тому, что у нас присутствует импульс в конце каждого бита, мы можем корректировать время Т без опасения плавного изменения скорости. В противном случае это грозит сбоем синхронизации.
На каждой карточке с магнитной полосой всегда имеется 3 трека. Другое дело, что они не всегда используются.
1й трек | формат ALPHA | 79 символов | 7 бит на символ | плотность записи 210 бит на дюйм |
2й трек | формат BCD | 40 символов | 5 бит на символ | плотность записи 75 бит на дюйм |
3й трек | формат BCD | 107 символов | 5 бит на символ | плотность записи 210 бит на дюйм |
В случае дисконтных карт чаще всего используется только вторая дорожка, по причине того, что на ней самая маленькая плотность записи, и, как следствие, самая большая устойчивость к помехам в виде прилипших субстанций, царапин или даже трещин. Обычно там записан числовой идентификатор носителя карты, он же на всякий случай продублирован на лицевой части самой карты.
В случае банковских карт используется первая и вторая дорожки. Смысл данных известен только самим банкам.
3-я дорожка в подавляющем количестве случаев не используется.
Физическая ширина информационной дорожки составляет 2.8 мм.
b1 | b2 | b3 | b4 | b5 | Character | Function | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 | (0H) | Data |
1 | 0 | 0 | 0 | 0 | 1 | (1H) | " |
0 | 1 | 0 | 0 | 0 | 2 | (2H) | " |
1 | 1 | 0 | 0 | 1 | 3 | (3H) | " |
0 | 0 | 1 | 0 | 0 | 4 | (4H) | " |
1 | 0 | 1 | 0 | 1 | 5 | (5H) | " |
0 | 1 | 1 | 0 | 1 | 6 | (6H) | " |
1 | 1 | 1 | 0 | 0 | 7 | (7H) | " |
0 | 0 | 0 | 1 | 0 | 8 | (8H) | " |
1 | 0 | 0 | 1 | 1 | 9 | (9H) | " |
0 | 1 | 0 | 1 | 1 | : | (AH) | Control |
1 | 1 | 0 | 1 | 0 | ; | (BH) | Start Sentinel |
0 | 0 | 1 | 1 | 1 | < | (CH) | Control |
1 | 0 | 1 | 1 | 0 | = | (DH) | Field Separator |
0 | 1 | 1 | 1 | 0 | > | (EH) | Control |
1 | 1 | 1 | 1 | 1 | ? | (FH) | End Sentinel |
5-й бит выступает в роли бита паритета.
В формате кодирования альфа (там, где 7 бит на символ) есть возможность хранить цифры, латинские буквы и немного спецсимволов.
b1 | b2 | b3 | b4 | b5 | b6 | b7 | Character | Function | |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 1 | space | (0H) | Special |
1 | 0 | 0 | 0 | 0 | 0 | 0 | ! | (1H) | " |
0 | 1 | 0 | 0 | 0 | 0 | 0 | " | (2H) | " |
1 | 1 | 0 | 0 | 0 | 0 | 1 | # | (3H) | " |
0 | 0 | 1 | 0 | 0 | 0 | 0 | $ | (4H) | " |
1 | 0 | 1 | 0 | 0 | 0 | 1 | % | (5H) | Start Sentinel |
0 | 1 | 1 | 0 | 0 | 0 | 1 | & | (6H) | Special |
1 | 1 | 1 | 0 | 0 | 0 | 0 | ' | (7H) | " |
0 | 0 | 0 | 1 | 0 | 0 | 0 | ( | (8H) | " |
1 | 0 | 0 | 1 | 0 | 0 | 1 | ) | (9H) | " |
0 | 1 | 0 | 1 | 0 | 0 | 1 | * | (AH) | " |
1 | 1 | 0 | 1 | 0 | 0 | 0 | + | (BH) | " |
0 | 0 | 1 | 1 | 0 | 0 | 1 | , | (CH) | " |
1 | 0 | 1 | 1 | 0 | 0 | 0 | — | (DH) | " |
0 | 1 | 1 | 1 | 0 | 0 | 0 | . | (EH) | " |
1 | 1 | 1 | 1 | 0 | 0 | 1 | / | (FH) | " |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | (10H) | Data (numeric) |
1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | (11H) | " |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 2 | (12H) | " |
1 | 1 | 0 | 0 | 1 | 0 | 0 | 3 | (13H) | " |
0 | 0 | 1 | 0 | 1 | 0 | 1 | 4 | (14H) | " |
1 | 0 | 1 | 0 | 1 | 0 | 0 | 5 | (15H) | " |
0 | 1 | 1 | 0 | 1 | 0 | 0 | 6 | (16H) | " |
1 | 1 | 1 | 0 | 1 | 0 | 1 | 7 | (17H) | " |
0 | 0 | 0 | 1 | 1 | 0 | 1 | 8 | (18H) | " |
1 | 0 | 0 | 1 | 1 | 0 | 0 | 9 | (19H) | " |
0 | 1 | 0 | 1 | 1 | 0 | 0 | : | (1AH) | Special |
1 | 1 | 0 | 1 | 1 | 0 | 1 | ; | (1BH) | " |
0 | 0 | 1 | 1 | 1 | 0 | 0 | < | (1CH) | " |
1 | 0 | 1 | 1 | 1 | 0 | 1 | = | (1DH) | " |
0 | 1 | 1 | 1 | 1 | 0 | 1 | > | (1EH) | " |
1 | 1 | 1 | 1 | 1 | 0 | 0 | ? | (1FH) | End Sentinel |
0 | 0 | 0 | 0 | 0 | 1 | 0 | @ | (20H) | Special |
1 | 0 | 0 | 0 | 0 | 1 | 1 | A | (21H) | Data (alpha) |
0 | 1 | 0 | 0 | 0 | 1 | 1 | B | (22H) | " |
1 | 1 | 0 | 0 | 0 | 1 | 0 | C | (23H) | " |
0 | 0 | 1 | 0 | 0 | 1 | 1 | D | (24H) | " |
1 | 0 | 1 | 0 | 0 | 1 | 0 | E | (25H) | " |
0 | 1 | 1 | 0 | 0 | 1 | 0 | F | (26H) | " |
1 | 1 | 1 | 0 | 0 | 1 | 1 | G | (27H) | " |
0 | 0 | 0 | 1 | 0 | 1 | 1 | H | (28H) | " |
1 | 0 | 0 | 1 | 0 | 1 | 0 | I | (29H) | " |
0 | 1 | 0 | 1 | 0 | 1 | 0 | J | (2AH) | " |
1 | 1 | 0 | 1 | 0 | 1 | 1 | K | (2BH) | " |
0 | 0 | 1 | 1 | 0 | 1 | 0 | L | (2CH) | " |
1 | 0 | 1 | 1 | 0 | 1 | 1 | M | (2DH) | " |
0 | 1 | 1 | 1 | 0 | 1 | 1 | N | (2EH) | " |
1 | 1 | 1 | 1 | 0 | 1 | 0 | O | (2FH) | " |
0 | 0 | 0 | 0 | 1 | 1 | 1 | P | (30H) | " |
1 | 0 | 0 | 0 | 1 | 1 | 0 | Q | (31H) | " |
0 | 1 | 0 | 0 | 1 | 1 | 0 | R | (32H) | " |
1 | 1 | 0 | 0 | 1 | 1 | 1 | S | (33H) | " |
0 | 0 | 1 | 0 | 1 | 1 | 0 | T | (34H) | " |
1 | 0 | 1 | 0 | 1 | 1 | 1 | U | (35H) | " |
0 | 1 | 1 | 0 | 1 | 1 | 1 | V | (36H) | " |
1 | 1 | 1 | 0 | 1 | 1 | 0 | W | (37H) | " |
0 | 0 | 0 | 1 | 1 | 1 | 0 | X | (38H) | " |
1 | 0 | 0 | 1 | 1 | 1 | 1 | Y | (39H) | " |
0 | 1 | 0 | 1 | 1 | 1 | 1 | Z | (3AH) | " |
1 | 1 | 0 | 1 | 1 | 1 | 0 | [ | (3BH) | Special |
0 | 0 | 1 | 1 | 1 | 1 | 1 | ( | 3DH) Special | |
1 | 0 | 1 | 1 | 1 | 1 | 0 | ] | (3EH) | Special |
0 | 1 | 1 | 1 | 1 | 1 | 0 | ^ | (3FH) | Field Separator |
1 | 1 | 1 | 1 | 1 | 1 | 1 | _ | (40H) | Special |
7-й бит выступает в качестве бита паритета.
Информация на 2-й или 3-й дорожке хранится в следующей последовательности:
- Некоторое количество нулевых бит, около 20;
- Символ начала данных «;»;
- число, или несколько чисел разделенных между собой символом «=»;
- признак конца данных «?»;
- LRC (Longitudinal Redundancy Check) — для проверки всего сообщения;
- Некоторое количество нулевых бит, около 20;
Первая дорожка содержит аналогичную последовательность за исключением символа начала данных «%».
К практике
Для того, чтобы имитировать магнитную полосу во время провода карточкой, необходимо генерировать изменение магнитного поля вблизи считывающей головки. Для этого подойдет простая катушка, на которую будет подаваться специально промодулированный сигнал. Для того, чтобы наш имитатор карточки можно было протягивать, необходимо катушку разместить на протяжении всей карточки. Также неплохо, чтобы направление намагниченности совпадало с направлением на карточке. Тут нам повезло: он проходит вдоль длинного края карточки и будет достаточно однослойной катушки длинной примерно с карточку. Для усиления намагниченности в качестве сердечника будем использовать магнитомягкий ферромагнетик из электрической стали (сердечника трансформатора). Форма сердечника — прямоугольная; плоской стороной прилегает к считывающей головке, что делает их взаимосвязь более сильной.
В процессе намотки нам поможет шуруповерт. Также желательно покрыть перед этим сердечник лаком, чтобы исключить возможность короткого замыкания витков через сердечник, иначе область катушки в пространствах между замкнутыми витками не эффективна.
Для удобства считывания упакуем нашу катушку в «корпус», сходный с формой стандартной пластиковой карточкой.
Обмотаем скотчем.
Теперь задумаемся о том, как будем подавать на катушку сигнал. Для этого нам понадобится драйвер. Так как выходной мощности портов GPIO контроллера нам не хватит, воспользуемся схемой типа Н-мост.
MS1 и MS2 подключаем к портам контроллера, выход Р1 — на катушку.
Конденсаторы С43 и С44 служат в качестве фильтров для снятия постоянной составляющей с катушки. Это позволяет сэкономить заряд батареи, а также управлять крутизной фронтов импульса, что в свою очередь положительно влияет на магнитное взаимодействие катушки и магнитной головки (величина ЭДС прямпропорциональна скорости изменения магнитного поля).
Установим фильтр, чтобы избавить остальную часть схемы от бросков по питанию.
Для генерации импульсов на выходе головки нам нужно на выходы катушки подавать импульсы в противофазе. Для этого одновременно меняем логические уровни на MS1 и MS2 на противоположные, благодаря чему на выходы катушки кратковременно будет приложено удвоенное значение напряжения VMS. Другой способ — использовать только одно плечо H-моста с одной стороны катушки и среднюю точку на другом.
Контроллер для управления схемой взят с запасом вычислительной мощности — STM32F405.
Итак, код на примере второй дорожки:
//инициализация порта:
#define STRIPE_2_PIN_P GPIO_Pin_13
#define STRIPE_2_PIN_N GPIO_Pin_14
#define STRIPE_2_PORT GPIOB
#define STRIPE_2_RCC_PERIPH RCC_AHB1Periph_GPIOB
void stripe_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(STRIPE_2_RCC_PERIPH, ENABLE);
GPIO_SetBits(STRIPE_2_PORT, STRIPE_2_PIN_P);
GPIO_ResetBits(STRIPE_2_PORT, STRIPE_2_PIN_N);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = STRIPE_2_PIN_P | STRIPE_2_PIN_N;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(STRIPE_2_PORT, &GPIO_InitStructure);
}
//генерация одного импульса:
void stripe_2_toggle(void) {
GPIO_ToggleBits(STRIPE_2_PORT, STRIPE_2_PIN_P | STRIPE_2_PIN_N);
}
//передача логического нуля:
void stripe_2_tx_0 (void) {
stripe_2_toggle();
vait_stripe_2_period();
}
//передача логической единицы:
void stripe_2_tx_1 (void) {
stripe_2_toggle();
vait_stripe_2_half_period();
stripe_2_toggle();
vait_stripe_2_half_period();
}
Функции для передачи битов готовы.
Более продвинутый уровень — преобразовать информацию в последовательность нулей и единиц и начинать их поочередную передачу (если же преобразовывать каждый символ в момент передачи это сулит сдвижки по времени и нарушением синхронизации приемной части). Но мы пренебрежем этим для простоты исполнения.
//отправка сообщения
void buff_2_to_magnetic(char * stripe_2_buff) {
unsigned char i, lrc = 0;
for (i = 0; i < 20; i++) {
stripe_2_tx_0();
}
while (*stripe_2_buff) {
for (i = 0; i < 5; i++) {
if (*stripe_2_buff & (1 << i)) {
stripe_2_tx_1();
} else {
stripe_2_tx_0();
}
}
lrc ^= *stripe_2_buff;
stripe_2_buff++;
}
for (i = 0; i < 5; i++) {
if (lrc & (1 << i)) {
stripe_2_tx_1();
} else {
stripe_2_tx_0();
}
}
}
В случае, если вы планируете одновременно эмулировать две или более полосы, следует учесть, что из-за разной плотности записи на дорожках между импульсами возникают различные временные промежутки, для измерения которых потребуется соответственное количество измерителей времени. Например, можно воспользоваться таймерами или «таском» в операционной системе.
Исследовательская часть
- В основном успешность затеи зависит от следующих факторов:
- Напряжение VMS;
- Количества витков катушки;
- Диаметр провода в катушке;
- Поперечное сечение сердечника;
- Емкость конденсаторов С43 и С44;
- Частота F;
- Расстояние катушки от считывающей головки;
- Магнитная проницаемость сердечника.
Стоит учесть, что некоторые параметры изменяемы в конкретных пределах, некоторые — зависимы друг от друга.
К примеру, давайте подадим различное напряжение на катушку и выясним, как будет его изменение влиять на результат при учете неизменности остальных параметров:
Напряжение В | Расстояние срабатывания мм | Расстояние воздействия мм | Неравномерность считывания % | Неравномерность воздействия % |
---|---|---|---|---|
2.3 | 0 | 0 | 10% с концов | 15% с концов |
2.6 | 0 | 1 | 30% с концов | 70% с концов |
2.8 | 0 | 2 | 70% | 30% |
2.9 | 1 | 5 | 100% | 0% |
3 | 2 | 7 | 100% | 0% |
3.3 | 4 | 11 | 100% | 0% |
Расстояние срабатывания – максимальное расстояние, при котором происходит успешное считывание (0 при непосредственном прикосновении).
Расстояние воздействия – расстояние, при котором чтение производится, но с ошибкой.
Неравномерность считывания – в связи с тем, что магнитный сердечник не замкнут, на его концах более сильное магнитное поле.
По составленной таблице видно, что лучший результат приходится на диапазон напряжения 2.8-2.9 В.
2.6 В:
2.8 В:
2.9 В:
3 В:
3.3 В:
Выводы
В процессе работы два недостатка:
- Влияние сигнала предыдущей дорожки на соседнюю;
- Неравномерная интенсивность магнитного поля вдоль катушки. Проявляется особенно сильно при протаскивании карточки в отличие от ее неподвижного состояния.
В первом случае может помочь использование дополнительных экранов, или схематическое решение в виде подачи ослабленного сигнала на соседнюю катушку в инверсном подключении. Таким образом, сигнал и помеха будут в противофазе и погасят друг друга. Также дополнительную помощь оказывает замыкание магнитного контура.
Во втором случае может помочь замкнутость магнитного контура, а также плавное изменение площади сечения сердечника ближе к концам катушки.
Видео работы устройства:
Автор: tachcard