Try Googling "implement 1-wire slave" (without the quotes). There's been plenty of discussion.
It should not be too difficult, provided that you can guarantee a fairly low interrupt latency - that is, your interrupt handler needs to get control within a few microseconds of the 1-wire master driving the bus low. If it doesn't, it won't be able to hold the bus low when the master releases it, to transmit a 0-bit. So all the other code running on the device must not lock out interrupts for more than a few microseconds, maximum.
A timer running at 1 MHz or higher with an available free-running count register could help with the timing, or you can just use instruction cycle counting if the micro behaves consistently in this respect.
There's a fair amount of work required to implement the full protocol, but if you understand the master end, implementing a slave end shouldn't be too hard.
I've never done it though. There might be a stumbling block somewhere.
Have a look at the other people who have tried it. If you have any specific questions, ask them here and I may be able to help.
Edit: A small amount of external hardware would probably greatly decrease the load and requirements on the firmware. You can get micros with a PLD or FPGA block built in; these would be ideal.
[...] the problem is that I'm not able to measure the low bus time from master, so i can't read the command by master.
As I said, I'm not familiar with the STM8S architecture, but I do know the AVR architecture. Actually I think I've written a 1-wire bus driver for AVR, but not a slave. But please go ahead and post the code here and I'll see if I can help.If you are interested, i could post arduino codes, and my stm8s code.
#include <inttypes.h>
#include "pins_arduino.h"
extern "C" {
//#include "WConstants.h"
#include "Arduino.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
}
// you can exclude onewire_search by defining that to 0
#ifndef ONEWIRE_SEARCH
#define ONEWIRE_SEARCH 1
#endif
// You can exclude CRC checks altogether by defining this to 0
#ifndef ONEWIRE_CRC
#define ONEWIRE_CRC 1
#endif
// Select the table-lookup method of computing the 8-bit CRC
// by setting this to 1. The lookup table no longer consumes
// limited RAM, but enlarges total code size by about 250 bytes
#ifndef ONEWIRE_CRC8_TABLE
#define ONEWIRE_CRC8_TABLE 0
#endif
// You can allow 16-bit CRC checks by defining this to 1
// (Note that ONEWIRE_CRC must also be 1.)
#ifndef ONEWIRE_CRC16
#define ONEWIRE_CRC16 0
#endif
#define FALSE 0
#define TRUE 1
class OneWire
{
private:
uint8_t bitmask;
volatile uint8_t *baseReg;
#if ONEWIRE_SEARCH
// global search state
unsigned char ROM_NO[8];
uint8_t LastDiscrepancy;
uint8_t LastFamilyDiscrepancy;
uint8_t LastDeviceFlag;
#endif
public:
OneWire( uint8_t pin);
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
// with a presence pulse. Returns 0 if there is no device or the
// bus is shorted or otherwise held low for more than 250uS
uint8_t reset(void);
// Issue a 1-Wire rom select command, you do the reset first.
void select( uint8_t rom[8]);
// Issue a 1-Wire rom skip command, to address all on bus.
void skip(void);
// Write a byte. If 'power' is one then the wire is held high at
// the end for parasitically powered devices. You are responsible
// for eventually depowering it by calling depower() or doing
// another read or write.
void write(uint8_t v, uint8_t power = 0);
// Read a byte.
uint8_t read(void);
// Write a bit. The bus is always left powered at the end, see
// note in write() about that.
void write_bit(uint8_t v);
// Read a bit.
uint8_t read_bit(void);
// Stop forcing power onto the bus. You only need to do this if
// you used the 'power' flag to write() or used a write_bit() call
// and aren't about to do another read or write. You would rather
// not leave this powered if you don't have to, just in case
// someone shorts your bus.
void depower(void);
#if ONEWIRE_SEARCH
// Clear the search state so that if will start from the beginning again.
void reset_search();
// Look for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are
// no devices, or you have already retrieved all of them. It
// might be a good idea to check the CRC to make sure you didn't
// get garbage. The order is deterministic. You will always get
// the same devices in the same order.
uint8_t search(uint8_t *newAddr);
#endif
#if ONEWIRE_CRC
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
// ROM and scratchpad registers.
static uint8_t crc8( uint8_t *addr, uint8_t len);
#if ONEWIRE_CRC16
// Compute a Dallas Semiconductor 16 bit CRC. Maybe. I don't have
// any devices that use this so this might be wrong. I just copied
// it from their sample code.
static unsigned short crc16(unsigned short *data, unsigned short len);
#endif
#endif
};
OneWire::OneWire(uint8_t pin)
{
bitmask = digitalPinToBitMask(pin);
baseReg = portInputRegister(digitalPinToPort(pin));
#if ONEWIRE_SEARCH
reset_search();
#endif
}
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask))
// Perform the onewire reset function. We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return a 0;
//
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
//
uint8_t OneWire::reset(void)
{
uint8_t mask=bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
uint8_t r;
uint8_t retries = 125;
cli();
DIRECT_MODE_INPUT(reg, mask);
sei();
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0;
delayMicroseconds(2);
} while ( !DIRECT_READ(reg, mask));
cli();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
sei();
delayMicroseconds(500); // send reset signal
cli();
DIRECT_MODE_INPUT(reg, mask); // allow it to float
delayMicroseconds(80);
r = !DIRECT_READ(reg, mask);
sei();
delayMicroseconds(420);
/*
if(r)
Serial.println("Presence received");
else
Serial.println("Presence not received");
*/
return r;
}
//
// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
void OneWire::write_bit(uint8_t v)
{
uint8_t mask=bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
if (v & 1) {
cli();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
delayMicroseconds(10);
DIRECT_WRITE_HIGH(reg, mask); // drive output high
sei();
delayMicroseconds(55);
} else {
cli();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
delayMicroseconds(65);
DIRECT_WRITE_HIGH(reg, mask); // drive output high
sei();
delayMicroseconds(5);
}
}
//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
uint8_t OneWire::read_bit(void)
{
uint8_t mask=bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
uint8_t r;
cli();
DIRECT_MODE_OUTPUT(reg, mask);
DIRECT_WRITE_LOW(reg, mask);
delayMicroseconds(3);
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
delayMicroseconds(9);
r = DIRECT_READ(reg, mask);
sei();
delayMicroseconds(53);
return r;
}
//
// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
//
void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
OneWire::write_bit( (bitMask & v)?1:0);
}
if ( !power) {
cli();
DIRECT_MODE_INPUT(baseReg, bitmask);
DIRECT_WRITE_LOW(baseReg, bitmask);
sei();
}
}
//
// Read a byte
//
uint8_t OneWire::read() {
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if ( OneWire::read_bit()) r |= bitMask;
}
return r;
}
//
// Do a ROM select
//
void OneWire::select( uint8_t rom[8])
{
int i;
write(0x55); // Choose ROM
for( i = 0; i < 8; i++) write(rom[i]);
}
//
// Do a ROM skip
//
void OneWire::skip()
{
write(0xCC); // Skip ROM
}
void OneWire::depower()
{
cli();
DIRECT_MODE_INPUT(baseReg, bitmask);
sei();
}
#if ONEWIRE_SEARCH
//
// You need to use this function to start a search again from the beginning.
// You do not need to do it for the first search, though you could.
//
void OneWire::reset_search()
{
// reset the search state
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
for(int i = 7; ; i--)
{
ROM_NO[i] = 0;
if ( i == 0) break;
}
}
//
// Perform a search. If this function returns a '1' then it has
// enumerated the next device and you may retrieve the ROM from the
// OneWire::address variable. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then a 0 is returned. If a new device is found then
// its address is copied to newAddr. Use OneWire::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : device not found, end of search
//
uint8_t OneWire::search(uint8_t *newAddr)
{
uint8_t id_bit_number;
uint8_t last_zero, rom_byte_number, search_result;
uint8_t id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!LastDeviceFlag)
{
// 1-Wire reset
if (!reset())
{
// reset the search
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
return FALSE;
}
// issue the search command
write(0xF0);
// loop to do the search
do
{
// read a bit and its complement
id_bit = read_bit();
cmp_id_bit = read_bit();
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy)
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy);
// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
write_bit(search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy = last_zero;
// check for last device
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;
search_result = TRUE;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0])
{
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
search_result = FALSE;
}
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
return search_result;
}
#endif
#if ONEWIRE_CRC
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#if ONEWIRE_CRC8_TABLE
// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (C) 2000 Dallas Semiconductor Corporation
static const uint8_t PROGMEM dscrc_table[] = {
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};
//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls. But I got
// confused, so I use this table from the examples.)
//
uint8_t OneWire::crc8( uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
}
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
//
uint8_t OneWire::crc8( uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
#endif
#if ONEWIRE_CRC16
static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
//
// Compute a Dallas Semiconductor 16 bit CRC. I have never seen one of
// these, but here it is.
//
unsigned short OneWire::crc16(unsigned short *data, unsigned short len)
{
unsigned short i;
unsigned short crc = 0;
for ( i = 0; i < len; i++) {
unsigned short cdata = data[len];
cdata = (cdata ^ (crc & 0xff)) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]) crc ^= 0xc001;
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
}
#endif
#endif
OneWire ds(12);
//LiquidCrystal lcd(7,6,5,4,3,2);
byte addr[8];
String keyStatus="";
void setup(void) {
Serial.begin(115200);
//lcd.begin(16,2);
}
void loop(void) {
//getKeyCode();
if ( !ds.search(addr)) {
ds.reset_search();
return;
}
Serial.println("=================================");
for(int i=0;i<8;i++)
{
Serial.print(addr[i],HEX);
Serial.print(" ");
}
Serial.println("\n=================================");
keyStatus="ok";
ds.reset();
}
#include <inttypes.h>
#include "pins_arduino.h"
extern "C" {
#include "Arduino.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
}
// You can exclude CRC checks altogether by defining this to 0
#ifndef ONEWIRESLAVE_CRC
#define ONEWIRESLAVE_CRC 1
#endif
// Select the table-lookup method of computing the 8-bit CRC
// by setting this to 1. The lookup table no longer consumes
// limited RAM, but enlarges total code size by about 250 bytes
#ifndef ONEWIRESLAVE_CRC8_TABLE
#define ONEWIRESLAVE_CRC8_TABLE 0
#endif
#define FALSE 0
#define TRUE 1
#define ONEWIRE_NO_ERROR 0
#define ONEWIRE_READ_TIMESLOT_TIMEOUT 1
#define ONEWIRE_WRITE_TIMESLOT_TIMEOUT 2
#define ONEWIRE_WAIT_RESET_TIMEOUT 3
#define ONEWIRE_VERY_LONG_RESET 4
#define ONEWIRE_VERY_SHORT_RESET 5
#define ONEWIRE_PRESENCE_LOW_ON_LINE 6
class OneWireSlave {
private:
bool recvAndProcessCmd();
bool waitTimeSlot();
uint8_t pin_bitmask;
volatile uint8_t *baseReg;
char rom[8];
public:
OneWireSlave(uint8_t pin);
void setRom(char rom[8]);
bool waitForRequest(bool ignore_errors);
bool waitReset(uint16_t timeout_ms);
bool waitReset();
bool presence(uint8_t delta);
bool presence();
bool search();
uint8_t sendData(char buf[], uint8_t data_len);
uint8_t recvData(char buf[], uint8_t data_len);
void send(uint8_t v);
uint8_t recv(void);
void sendBit(uint8_t v);
uint8_t recvBit(void);
#if ONEWIRESLAVE_CRC
static uint8_t crc8(char addr[], uint8_t len);
#endif
uint8_t errno;
};
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask))
/* тайм слот ожидается 120 микросекунд (стандартная длина тайм-слота 60-120 micrs)
* при компиляции с флагом -Os в цикле ожидания присутствуют следующие команды:
* ld, ldi, and, and, or, breq, subi, sbci
* общая продолжительность цикла составляет 10 тактов.
* Таблицу соответствия между командами микроконтроллера и количеством тактов
* можно найти в даташите на микроконтроллер, см. раздел
* Instruction Set Summary в конце даташита. */
#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(120) / 10L
OneWireSlave::OneWireSlave(uint8_t pin) {
pin_bitmask = digitalPinToBitMask(pin);
baseReg = portInputRegister(digitalPinToPort(pin));
}
void OneWireSlave::setRom(char rom[8]) {
#if ONEWIRESLAVE_CRC
for (int i=0; i<7; i++)
this->rom[i] = rom[i];
this->rom[7] = crc8(this->rom, 7);
#else
for (int i=0; i<8; i++)
this->rom[i] = rom[i];
#endif
}
bool OneWireSlave::waitForRequest(bool ignore_errors) {
errno = ONEWIRE_NO_ERROR;
for (;;) {
if (!waitReset(0) )
continue;
if (!presence() )
continue;
if (recvAndProcessCmd() )
return TRUE;
else if ((errno == ONEWIRE_NO_ERROR) || ignore_errors)
continue;
else
return FALSE;
}
}
bool OneWireSlave::recvAndProcessCmd() {
char addr[8];
for (;;) {
switch (recv() ) {
case 0xF0: // SEARCH ROM
search();
return FALSE;
case 0x33: // READ ROM
sendData(rom, 8);
if (errno != ONEWIRE_NO_ERROR)
return FALSE;
break;
case 0x55: // MATCH ROM
recvData(addr, 8);
if (errno != ONEWIRE_NO_ERROR)
return FALSE;
for (int i=0; i<8; i++)
if (rom[i] != addr[i])
return FALSE;
return TRUE;
case 0xCC: // SKIP ROM
return TRUE;
default: // Unknow command
if (errno == ONEWIRE_NO_ERROR)
break; // skip if no error
else
return FALSE;
}
}
}
bool OneWireSlave::search() {
uint8_t bitmask;
uint8_t bit_send, bit_recv;
for (int i=0; i<8; i++) {
for (bitmask = 0x01; bitmask; bitmask <<= 1) {
bit_send = (bitmask & rom[i])?1:0;
sendBit(bit_send);
sendBit(!bit_send);
bit_recv = recvBit();
if (errno != ONEWIRE_NO_ERROR)
return FALSE;
if (bit_recv != bit_send)
return FALSE;
}
}
return TRUE;
}
bool OneWireSlave::waitReset(uint16_t timeout_ms) {
uint8_t mask = pin_bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
unsigned long time_stamp;
errno = ONEWIRE_NO_ERROR;
cli();
DIRECT_MODE_INPUT(reg, mask);
sei();
if (timeout_ms != 0) {
time_stamp = micros() + timeout_ms*1000;
while (DIRECT_READ(reg, mask)) {
if (micros() > time_stamp) {
errno = ONEWIRE_WAIT_RESET_TIMEOUT;
return FALSE;
}
}
} else
while (DIRECT_READ(reg, mask)) {};
time_stamp = micros() + 540;
while (DIRECT_READ(reg, mask) == 0) {
if (micros() > time_stamp) {
errno = ONEWIRE_VERY_LONG_RESET;
return FALSE;
}
}
if ((time_stamp - micros()) > 70) {
errno = ONEWIRE_VERY_SHORT_RESET;
return FALSE;
}
delayMicroseconds(30);
return TRUE;
}
bool OneWireSlave::waitReset() {
return waitReset(1000);
}
bool OneWireSlave::presence(uint8_t delta) {
uint8_t mask = pin_bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
errno = ONEWIRE_NO_ERROR;
cli();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
sei();
delayMicroseconds(120);
cli();
DIRECT_MODE_INPUT(reg, mask); // allow it to float
sei();
delayMicroseconds(300 - delta);
if ( !DIRECT_READ(reg, mask)) {
errno = ONEWIRE_PRESENCE_LOW_ON_LINE;
return FALSE;
} else
{
return TRUE;
}
}
bool OneWireSlave::presence() {
return presence(25);
}
uint8_t OneWireSlave::sendData(char buf[], uint8_t len) {
uint8_t bytes_sended = 0;
for (int i=0; i<len; i++) {
send(buf[i]);
if (errno != ONEWIRE_NO_ERROR)
break;
bytes_sended++;
}
return bytes_sended;
}
uint8_t OneWireSlave::recvData(char buf[], uint8_t len) {
uint8_t bytes_received = 0;
for (int i=0; i<len; i++) {
buf[i] = recv();
if (errno != ONEWIRE_NO_ERROR)
break;
bytes_received++;
}
return bytes_received;
}
void OneWireSlave::send(uint8_t v) {
errno = ONEWIRE_NO_ERROR;
for (uint8_t bitmask = 0x01; bitmask && (errno == ONEWIRE_NO_ERROR); bitmask <<= 1)
sendBit((bitmask & v)?1:0);
}
uint8_t OneWireSlave::recv() {
uint8_t r = 0;
errno = ONEWIRE_NO_ERROR;
for (uint8_t bitmask = 0x01; bitmask && (errno == ONEWIRE_NO_ERROR); bitmask <<= 1)
if (recvBit())
r |= bitmask;
return r;
}
void OneWireSlave::sendBit(uint8_t v) {
uint8_t mask = pin_bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
cli();
DIRECT_MODE_INPUT(reg, mask);
if (!waitTimeSlot() ) {
errno = ONEWIRE_WRITE_TIMESLOT_TIMEOUT;
sei();
return;
}
if (v & 1)
delayMicroseconds(30);
else {
cli();
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask);
delayMicroseconds(30);
DIRECT_WRITE_HIGH(reg, mask);
sei();
}
sei();
return;
}
uint8_t OneWireSlave::recvBit(void) {
uint8_t mask = pin_bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
uint8_t r;
cli();
DIRECT_MODE_INPUT(reg, mask);
if (!waitTimeSlot() ) {
errno = ONEWIRE_READ_TIMESLOT_TIMEOUT;
sei();
return 0;
}
delayMicroseconds(30);
r = DIRECT_READ(reg, mask);
sei();
return r;
}
bool OneWireSlave::waitTimeSlot() {
uint8_t mask = pin_bitmask;
volatile uint8_t *reg asm("r30") = baseReg;
uint16_t retries;
retries = TIMESLOT_WAIT_RETRY_COUNT;
while ( !DIRECT_READ(reg, mask))
if (--retries == 0)
return FALSE;
retries = TIMESLOT_WAIT_RETRY_COUNT;
while ( DIRECT_READ(reg, mask))
if (--retries == 0)
return FALSE;
return TRUE;
}
#if ONEWIRESLAVE_CRC
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#if ONEWIRESLAVE_CRC8_TABLE
// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (C) 2000 Dallas Semiconductor Corporation
static const uint8_t PROGMEM dscrc_table[] = {
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};
//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls. But I got
// confused, so I use this table from the examples.)
//
uint8_t OneWireSlave::crc8(char addr[], uint8_t len)
{
uint8_t crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
}
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
//
uint8_t OneWireSlave::crc8(char addr[], uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
#endif
#endif
char romadd[8] = {0x01, 0xAD, 0xDA, 0xCE, 0x0F, 0x00, 0x00, 0x00};
OneWireSlave ds(8);
void setup()
{ ds.setRom(romadd);
Serial.begin(115200);
}
void loop()
{ ds.waitForRequest(false); }
#include"stm8s.h"
#include <iostm8S105c6.h>
#include <intrinsics.h>
//
// Setup Timer 2 to generate an interrupt every 480 clock ticks (30 uS).
//
char A[64] = "1010101010101010101010101010101010101010101010101010101010101010"; // serial number to send to one wire
//int i ;
void SetupTimer2(char a) //40 us
{
TIM2_PSCR = 0x00; // Prescaler = 1.
if(a == 'r') //
{
TIM2_ARRH = 0x04; // Wait for 480.
TIM2_ARRL = 0x38;
}
else if(a == 'p')
{
TIM2_ARRH = 0x01; // High byte of 120.
TIM2_ARRL = 0x18;
}
else if(a == 'b')
{
TIM2_ARRH = 0x00; // wait for 30us.
TIM2_ARRL = 0x3c;
}
else if(a == 'c')
{
TIM2_ARRH = 0x00; // wait for 10us.
TIM2_ARRL = 0x14;
}
// TIM2_IER_UIE = 1; // Turn on the interrupts.
TIM2_CR1_CEN = 1; // Finally enable the timer.
}
//
// Timer 2 Overflow handler.
//
#pragma vector = TIM2_OVR_UIF_vector
__interrupt void TIM2_UPD_OVF_IRQHandler(void)
{
TIM2_SR1_UIF = 0; // Reset the interrupt otherwise it will fire again straight away.
TIM1_IER_UIE = 0;
}
int i_count;
char proc_isr;
#pragma vector = 6
__interrupt void EXTI_PORTB_IRQHandler(void) // B interrupt
{
PB_CR2 = 0x00; // disable EXTI_PORTB
if(i_count<1)
{
SetupTimer2('r'); // delay_us(510);
__enable_interrupt();
__wait_for_interrupt();
//__disable_interrupt();
PB_ODR_ODR4 = 0;//low -> presence
PB_DDR = 0xff;
SetupTimer2('p');//delay_us(140);
__enable_interrupt();
__wait_for_interrupt();
}
else
if(i_count<9) // receive command from master -> 0xF0 search();
{}
else
if(i_count<73) // send data bits
{
if(A[i_count-8] == 0)
{
//send 0 bit
PB_ODR_ODR4 = 0;//low -> bit
PB_DDR = 0xff;
SetupTimer2('b');//delay us = 60 us
__enable_interrupt();
__wait_for_interrupt();
// send 1 bit
PB_ODR_ODR4 = 1;
PB_DDR = 0x00;
SetupTimer2('b');//delay us = 60 us
__enable_interrupt();
__wait_for_interrupt();
}
else
{
// send 1 bit
PB_DDR = 0x00;
SetupTimer2('b');//delay us = 60 us
__enable_interrupt();
__wait_for_interrupt();
// send 0 bit
PB_DDR = 0xff;
SetupTimer2('b');//delay us = 60 us
__enable_interrupt();
__wait_for_interrupt();
}
PB_DDR = 0x00;
SetupTimer2('b');//delay 30us for recv signal, do nothing.
__enable_interrupt();
__wait_for_interrupt();
}
i_count++;
if(i_count>73)
i_count = 0;
//rim();
PB_CR2 = 0x00;
}
//
// Main program loop.
//
void main()
{
i_count = 0;
PB_ODR_ODR4 = 1;
PB_DDR = 0x00; // porta D pin 4 input
PB_CR1 = 0xff; // PB4 is pull-up input.
PB_CR2 = 0xff; // PB4 is with interrupt
EXTI_CR1_PBIS = 2; // Interrupt on falling edge.
EXTI_CR2_TLIS = 0; // Falling edge only.
__enable_interrupt();
i_count = 0;
while (1)
{
__wait_for_interrupt();
PB_DDR = 0x00; // porta D pin 4 input
PB_CR1 = 0xff; // PB4 is pull-up input.
PB_CR2 = 0xff;
EXTI_CR1_PBIS = 2; // Interrupt on falling edge.
EXTI_CR2_TLIS = 0; // Falling edge only.
}
}
Thanks for the expanation.
I've had a look at your code, the data sheet for the MCU, and the other information you've provided. In my opinion you are a long way from being ready to write this code.
You do not have a specification of what you want to do with the 1-wire interface - you haven't even described your requirements in any detail. You aren't familiar with the MCU architecture. You don't have a schematic. You are way out of your depth.
I don't say these things to be insulting or to put you down; I'm trying to help. If you want to get this project going, you need to hire someone with embedded systems design and programming experience. There is little point in me trying to help because I can't give you the type or level of help you need.