[Из песочницы] Копирование ключей 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) Макетная плата
С таким набором можно двигаться дальше. Для начала приготовьте плату, на которой будете размещать компоненты.
Я это сделал так:
Теперь давайте определимся с параметрами 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:
Кусок кода, где происходит запись:
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;
}
Надеюсь, понятно. Нам требуется еще написать приложение, которое будет общаться с микроконтроллером. То есть мы будем посылать запросы на чтение и на запись ключа микроконтроллеру с компьютера. Все исходники я выложу под топиком. Приложение довольно простое.
Впрочем, на видео все показано.
#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;
}
Конечно, можно было сделать все в ООП стиле, но почему-то я решил так.
#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!"<
#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
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);
};
Код, конечно, не самый лучший, т.к. я пытался быстрее написать, но все же он прекрасно работает.
Вот что получилось у меня в конце:
А вот видео: