Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

The first use of water to generate electricity was in 1882 on the Fox river, in the USA, which produced enough power to light two paper mills and a house.
 

Help us stay online:

small donate

ibuttonAs previously explained iButton - electronic key is widely used for electronic identification purposes in home as well as in professional high security systems. In this article we will give you entire project written in AVR C compiler Codevision that reads iButton code, checks CRC and writes it to serial port.

A microprocessor can easily generate 1-Wire timing signals if a dedicated bus master is not present. This application note provides an example, written in 'C', of the basic standard speed 1-Wire master communication routines that are used for iButton readout. Overdrive communication speed is also mentioned. There are several system requirements for proper operation of the code examples:

1. The communication port must be bidirectional, its output is open-drain, and there is a weak pull-up on the line. This is a requirement of any 1-Wire bus.

2. The system must be capable of generating an accurate and repeatable 1µs delay for standard speed and 0.25µs delay for overdrive speed.

3. The communication operations must not be interrupted while being generated.

Any modern microcontroller is capable of fulfilling these conditions. All you have to do is to place pullup resistor on digital pin thet will be used for interface with iButton.

The four basic operations of a 1-Wire bus are Reset, Write 1 bit, Write 0 bit, and Read bit. The time it takes to perform one bit of communication is called a time slot in the device datasheets. Byte functions can then be derived from multiple calls to the bit operations. See Table 1 below for a brief description of each operation and a list of the steps necessary to generate it. Figure 1 illustrates the waveforms graphically. Table 2 shows the recommended timings for the 1-Wire master to communicate with 1-Wire devices over the most common line conditions. Alternate values can be used when restricting the 1-Wire master to a particular set of devices and line conditions.

Table 1. 1-Wire Operations

 

Table 1. 1-Wire Operations

Operation Description Implementation
Write 1 bit Send a '1' bit to the 1-Wire slaves (Write 1 time slot) Drive bus low, delay A
Release bus, delay B
Write 0 bit send a '0' bit to the 1-Wire slaves (Write 0 time slot) Drive bus low, delay C
Release bus, delay D
Read bit Read a bit from the 1-Wire slaves (Read time slot) Drive bus low, delay A
Release bus, delay E
Sample bus to read bit from slave
Delay F
Reset Reset the 1-Wire bus slave devices and ready them for a command Delay G
Drive bus low, delay H
Release bus, delay I
Sample bus, 0 = device(s) present, 1 = no device present
Delay J

 

basic-operations-diagram-1-wire-iButoon

 

Figure 1. 1-Wire waveforms.

Table 2. 1-Wire Master Timing

Table 2. 1-Wire Master Timing

Parameter Speed Recommended (µs)
A Standard 6
Overdrive 1.0
B Standard 64
Overdrive 7.5
C Standard 60
Overdrive 7.5
D Standard 10
Overdrive 2.5
E Standard 9
Overdrive 1.0
F Standard 55
Overdrive 7
G Standard 0
Overdrive 2.5
H Standard 480
Overdrive 70
I Standard 70
Overdrive 8.5
J Standard 410
Overdrive 40

You will notice we increased duration of delay H from 480 to 510 us. This was done with the reason. We had problems with some series of DS1990R when using recommended delay. Rest of the code provided follows Maxim guidelines. Complete code with key lines highlighted is provided below. Complete Codevision project can be downloaded from link at the bottom of this page.

 

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 2/16/2012
Author :
Company :
Comments:
Chip type : ATmega8535
Program type : Application
Clock frequency : 8.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
//example iButton code. Complete project and detailed explanation
and tutorial can be found at www.Electronics-Base.com
*****************************************************/
#include
#include
#include
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<
#define PARITY_ERROR (1<
#define DATA_OVERRUN (1<
#define DATA_REGISTER_EMPTY (1<
#define RX_COMPLETE (1<
//////////////////////////////////////////////////////////iButton part start
#define iButton_SDA PORTD.5
#define iButton_SDA_DIR DDRD.5
#define iButton_SDAPIN PIND.5
#define delay_A 1
#define delay_B 64
#define delay_C 60
#define delay_D 10
#define delay_E 9
#define delay_F 55
#define delay_G 2
#define delay_H 510 //480
#define delay_I 70
#define delay_J 410
#define IN 1
#define OUT 0
#define INPUT 0
#define OUTPUT 1
unsigned char iButtonData[8] = { 0x00, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00};
const unsigned char crcTable[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};
void initiButton()
{
iButton_SDA =0;
iButton_SDA_DIR=INPUT;
}
static int outPort(char databyte)
{
if (databyte==0)
{
iButton_SDA=0;
iButton_SDA_DIR=OUTPUT;
}
else
{
iButton_SDA_DIR=INPUT;
}
return 1;
}
static int inPort(void)
{
return iButton_SDAPIN;
}
static void OWWriteBit(unsigned char value)
{
if (value)
{
outPort(0);
delay_us(delay_A);
outPort(1);
delay_us(delay_B);
}
else
{
outPort(0);
delay_us(delay_C);
outPort(1);
delay_us(delay_D);
}
}
static int OWReadBit(void)
{
int result;
outPort(0);
delay_us(delay_A);
outPort(1);
delay_us(delay_E);
result = inPort();
delay_us(delay_F);
return result;
}
static void OWWriteByte(int data)
{
int loop;
for (loop=0;loop<8;loop++)
{
OWWriteBit(data & 0x01);
data >>= 1;
}
}
static int OWReadByte(void)
{
int loop, result=0;
for (loop=0;loop<8;loop++)
{
result >>= 1;
if (OWReadBit())
result |= 0x80;
}
return result;
}
static int OWTouchReset(void)
{
int result;
delay_us(delay_G);
outPort(0);
delay_us(delay_H);
outPort(1);
delay_us(delay_I);
result = inPort() ;
delay_us(delay_J);
return result;
}
int iButton_read()
{
unsigned char i,cond;
OWTouchReset();
OWWriteByte(0x33);
for(i=0;i<8;i++)
{
iButtonData[i] = OWReadByte();
}
cond=0;
for(i=0;i<8;i++)
{
if(iButtonData[i]!=0xFF)
cond=1;
}
if(!cond)
return(0);
cond=0;
for(i=0;i<8;i++)
{
if(iButtonData[i]!=0x00)
cond=1;
}
if(!cond)
return(0);
return(1);
}
int iButtonCRC()
{
unsigned char i,crc,tmp;
for(i=0,crc=0;i<7;i++)
{
tmp = crc ^ iButtonData[i];
crc = crcTable[tmp];
}
/*if(crc==iButtonData[7])
return(1);
return(0); */ //this can be used to accept only valid codes read
return(crc);
}
//////////////////////////////////////////////////////////iButton part end
unsigned char i;
unsigned char buff[10];
// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer[rx_wr_index]=data;
if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
if (++rx_counter == RX_BUFFER_SIZE)
{
rx_counter=0;
rx_buffer_overflow=1;
};
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
// Standard Input/Output functions
#include
// Declare your global variables here
//function that writed values in hexa decimal format to serial port this
// is format in which code is written on casing so it is usefull to read it that way
void print_hex(unsigned char nr)
{
unsigned char temp1;
temp1=nr/16;
if (temp1<10)
putchar(temp1+'0');
else
putchar(temp1-10+'A');
nr=nr-16*temp1;
temp1=nr;
if (temp1<10)
putchar(temp1+'0');
else
putchar(temp1-10+'A');
}
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=1 State4=T State3=T State2=T State1=T State0=T
PORTD=0x20;
DDRD=0x20;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
//#asm("sei") //we will not enable interrupts to have exacty timong on delay functions.
initiButton();
while (1)
{
// Place your code here
if(OWTouchReset()==0)
{
iButton_read();
//return value of the function iButton_read(); can be used to eliminate fault values on the buss
//here it is written to uart to see how often error data is received.
putchar(13);
putsf(" iButton DECIMAL format: ");
for (i=0;i<8;i++)
{
itoa(iButtonData[i],buff);
puts(buff);
putchar(',');
}
putsf(" CRC: ");
itoa(iButtonCRC(),buff);
puts(buff);
putsf(" iButton HEXADECIMAL format: ");
for (i=0;i<8;i++)
{
print_hex(iButtonData[i]);
putchar(',');
}
putsf(" CRC: ");
print_hex(iButtonCRC());
}
delay_ms(200);//this means OWTouchReset()will be called 5 times a second and that is frequency of iButton readout
};
}

 

Complete project with source code can be downloaded from this link.

Few words about this code. AVR reads code from iButton. Lid contact of iButton is connected to Port D pin 5 and ground contact is connected to microcontroller ground. You must have pullup resistor on PortD pin 5 for iButton to work properly. Resistor value is not critical, any value from 1k to 10k will work fine. Read comments inside code, I think they will explain code functionality. iButton identification code is read 5 times a second and if iButton is detected, its code is sent to UART using 9600 baud rate. To compare, if readout is correct you can read each iButton code on casing in hexadecimal format. That is the reason why code is writen to UART in hexadecimal format beside usual decimal format. CRC that is written to UART after text " CRC: " is actually CRC calculated from bytes read from iButton. This number should be equal to last byte read from iButton. This is CRC function, to make sure data is read correctly.

Photo of code written on iButton casing is shown below

ibutton code

Our example writes code to UART in next order for iButton on the picture:

14 CA CD CF 02 00 00 7D  with CRC 7D

 

 

 

 

 

 

 

On video below you can see iButton code in action: