[Из песочницы] Копирование ключей dallas. Запись на на rw1990(rw1990.1)

Здравствуйте! Сегодня хочу рассказать о том, как сделать устройство, которое позволяет копировать Touch Memory фирмы Dallas. Статья предназначена для тех, кто имеет опыт в программирование на языках C/C++. Рассказывать, как устроен протокол OneWire я не собираюсь, т.к. в интернете куча информации на эту тему.

Итак, что нам понадобится для изготовления данного устройства:

1) Atmega8
2) FTDI RL232, преобразующий USB в USART
3) Драйвер для FTDI RL232
4) Программатор (Я использовал USBasp)
5) Visual Studio
6) Atmel Studio
7) Макетная плата
С таким набором можно двигаться дальше. Для начала приготовьте плату, на которой будете размещать компоненты.
Я это сделал так:

image

image

image

image

Теперь давайте определимся с параметрами USART на atmega8. У меня они такие:
1) Стоповый бит — 1
2) 9600boud
3) Бит четности — нет

Я буду использовать внутренний генератор на 4Mhz, так что регистр UBRR я буду настраивать под эту частоту. Вот кусок кода, где идет настройка USART:

 DDRD|=(1<<1);
        DDRD&=~(1<<0);
        UBRRH=0;
        UBRRL=25;
        UCSRB|=(1<


Пришло время разобрать протокол записи на болванки rw1990. Команда считывания 8-байтного кода у них идентична с ключами dallas.

Запись на rw1990 происходит так:
1) Посылаем импульс reset, и ожидаем presence импульс;
2) Отправляем команду 0xD1, тем самым разрешаем запись;
3) Тайм-слот, посылаем логический »0» (смотреть рис. 1);
4) Посылаем импульс reset и ожидаем presence импульс;
5) Отправляем команду записи, 0xD5;
6) Посылаем 8-байтный код (все биты инвертированы), передача отличается от протокола oneWire (смотреть рис. 1);
7) Посылаем импульс reset и ожидаем presence импульс;
8) Отправляем команду 0xD1, тем самым запрещаем запись;
9) Тайм-слот, посылаем логический »1» (смотреть рис. 1).

Рис. 1:

image

Кусок кода, где происходит запись:

bool onewire_init(){
        onewire_low();
        _delay_us(480);
        onewire_high();
        _delay_us(2);
        for(uint8_t i= 60;i;i++){
                if(!onewire_level()){
                        while(!onewire_level());
                        return true;
                }
                _delay_us(1);
        }
        return false;
}

void time_slot(uint8_t data){
        onewire_low();
        if(data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(10);
}

void rw1990_write_bit(uint8_t data){
        onewire_low();
        if (data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(2);
}

void rw1990_write(uint8_t data){
        for(uint8_t i=0;i<8;i++){
                rw1990_write_bit(data & 0x01);
                data>>=1;
        }
}

bool rw1990_newcode(uint8_t* buf){
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(0);
        }else return false;
        if(onewire_init()){
                onewire_send(0xD5);
                for(uint8_t i=0;i<8;i++){
                        rw1990_write(~buf[i]);
                }
        }else return false;
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(1);
        }else return false;
        return true;
}


Надеюсь, понятно. Нам требуется еще написать приложение, которое будет общаться с микроконтроллером. То есть мы будем посылать запросы на чтение и на запись ключа микроконтроллеру с компьютера. Все исходники я выложу под топиком. Приложение довольно простое.

Впрочем, на видео все показано.

Исходный код для atmega8
#define F_CPU 4000000 

#include 
#include 
#include 

#define ONEWIRE_PORT      PORTB
#define ONEWIRE_DDR       DDRB
#define ONEWIRE_PIN       PINB
#define ONEWIRE_PIN_NUM   0


void     usart_init();
void     onewire_high();
void     onewire_low();
uint8_t  onewire_level();
bool     onewire_init();
void     onewire_write_bit(uint8_t);
void     onewire_send(uint8_t);
uint8_t  onewire_read_bit();
uint8_t  onewire_read();
bool     onewire_readrom(uint8_t*);
void     time_slot(uint8_t);
void     rw1990_write_bit(uint8_t);
void     rw1990_write(uint8_t);
bool     rw1990_newcode(uint8_t*);
uint8_t  usart_read();


uint8_t rom[8];
uint8_t new_rom[8];
uint8_t t=0;


ISR (USART_UDRE_vect){
        UDR=t;
        UCSRB &=~(1<>= 1;
        }
}

void usart_init(){
        DDRD|=(1<<1);
        DDRD&=~(1<<0);
        UBRRH=0;
        UBRRL=25;
        UCSRB|=(1<>= 1;
         if (onewire_read_bit())
                  r |= 0x80;
          }
          return r;
}

void time_slot(uint8_t data){
        onewire_low();
        if(data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(10);
}

void rw1990_write_bit(uint8_t data){
        onewire_low();
        if (data)
                _delay_us(6);
        else
                _delay_us(60);
        onewire_high();
        _delay_ms(2);
}

void rw1990_write(uint8_t data){
        for(uint8_t i=0;i<8;i++){
                rw1990_write_bit(data & 0x01);
                data>>=1;
        }
}

bool rw1990_newcode(uint8_t* buf){
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(0);
        }else return false;
        if(onewire_init()){
                onewire_send(0xD5);
                for(uint8_t i=0;i<8;i++){
                        rw1990_write(~buf[i]);
                }
        }else return false;
        if (onewire_init()){
                onewire_send(0xD1);
                time_slot(1);
        }else return false;
        return true;
}

bool onewire_readrom(uint8_t* buf){
                if (onewire_init()){
                        onewire_send(0x33);
                        for(uint8_t i=0;i<8;i++){
                                buf[i]=onewire_read();
                        }
                }else return false;
                return true;
}

uint8_t  usart_read(){
while(!(UCSRA & (1 << RXC)));
        return UDR;
}



Конечно, можно было сделать все в ООП стиле, но почему-то я решил так.

Исходник так называемого мной терминала iButton
main.cpp
#include 
#include 
#include "ComPort.h"


using namespace std;

int main(){
        char buf_file[10];
        wchar_t file[10];
        char name[20];
        char command[10];
        unsigned char rom[8];

        cout<<"Enter COM port: ";
        cin>>buf_file;

        cout<<"Enter your name: ";
        cin>>name;

        mbstowcs(file,buf_file,10);
        ComPort port((LPCWSTR)file,CBR_9600);

        cout<<"Welcome "< ";
                cin>>command;
                if(!strcmp(command,"write_rom")){
                        scanf("%x %x %x %x %x %x %x %x",&rom[0],&rom[1],&rom[2],&rom[3],&rom[4],&rom[5],&rom[6],&rom[7]);
                        for(int i=0;i<50;i++){
                                port.ComWrite(0x40);
                                port.ComWrite((char*)rom,sizeof(rom));
                                char recv=port.ComRead();
                                if(recv==0x45){ 
                                        cout<<"Device> write successfull!"< write fail!"< read successfull!    ";
                                        printf("%02X %02X %02X %02X %02X %02X %02X %0X\n",rom[0],rom[1],rom[2],rom[3],rom[4],rom[5],rom[6],rom[7]);
                                        break;
                                }else if(recv==0x36){ 
                                        cout<<"Device> read fail!"<


ComPort.cpp
#include 
#include "ComPort.h"

ComPort::ComPort(LPCWSTR str,DWORD baud)
{
        hSerial=CreateFile(str,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        ComPort::baud=baud;
        SerialParams.DCBlength=sizeof(SerialParams);
        if(!GetCommState(hSerial,&SerialParams))
                MessageBox(NULL,L"Getting state error!",L"Error!",MB_OK|MB_ICONERROR);
        SerialParams.BaudRate=baud;
        SerialParams.ByteSize=8;
        SerialParams.StopBits=ONESTOPBIT;
        SerialParams.Parity=NOPARITY;
        if(!SetCommState(hSerial,&SerialParams))
                MessageBox(NULL,L"Error setting serial port state!",L"Error!",MB_OK|MB_ICONERROR);

}

void ComPort::ComWrite(unsigned char buf)
{
        DWORD send;
        WriteFile(hSerial,&buf,1,&send,NULL);
}

void ComPort::ComWrite(char* buf,int size)
{
        DWORD send;
        WriteFile(hSerial,buf,size,&send,NULL);
}

bool ComPort::ComRead(char* buf,int size)
{
        DWORD recv;
        char recvchar;
        ZeroMemory(buf,size);
        for(int i=0;i


ComPort.h
class ComPort
{
private:
        HANDLE hSerial;
        DCB SerialParams;
        LPCWSTR sPort;
        int baud;
public:
        ComPort(LPCWSTR,DWORD);
        void ComWrite(unsigned char);
        void ComWrite(char*,int);
        bool ComRead(char*,int);
        char ComRead();
        ~ComPort(void);
};





Код, конечно, не самый лучший, т.к. я пытался быстрее написать, но все же он прекрасно работает.

Вот что получилось у меня в конце:

image

image

image

image

А вот видео:

© Habrahabr.ru