View previous topic :: View next topic |
Author |
Message |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
There's any way to handle One protocol without delay? |
Posted: Wed Mar 06, 2024 11:51 am |
|
|
I have a routine that handles 2 one wire devices by a separate pins.
The first one can read temperature devices and iButton IDs. The second one only read temperature devices.
The problem is that the One Wire protocol has some change in the data line that must be wait it until some change or timeout occur.
The whole reset signal took around 736mS.
I'm checking sensor number 1 every 1 second and sensor number 2 every 1 minute.
I'm disabling interrupts during those delays but I don't like that approach.
A delay_us(500) is a lot of time for a microcontroller that is handling USB, and 2 UARTs at 115.2Kbps
What can I do to let the interrupt keep running and don't loose One Wire data? _________________ Electric Blue |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9236 Location: Greensville,Ontario
|
|
Posted: Wed Mar 06, 2024 1:21 pm |
|
|
When I used the DS18B20 (? been awhile...) temperature sensors I had the external RTC module send an interrupt every second ( I called it the 'heartbeat' ).
So every second main() would call 'readdstempsensor()'. That function got the LAST data from the sensor,then told sensor to read and store (or whatever the command is called ). yeah it's been almost a decade and grey cells are aging....
The reality is temperature doesn't vary fast so reading the LAST value is OK.
main() ..
do nothing
on RTC interrupt..set flag..
main() now does
read old temp sensor 1 data
read old temp sensor 2 data
read old temp sensor 3 data
read old temp sensor 4 data
do control stuff
update LCD module
send data to PC in CSV format
....
Each sensor was on it's own I/O pin, parasite mode.
While it does make for a larger program( 1 driver per pin ), it was a quick and easy way to get around 'nasty' several devices on one pin.
I eventually worked out code to 'scan for new devices' then confirm they were there,got around the oops, wire open/shorted problem. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Mar 06, 2024 1:43 pm |
|
|
You can poll interrupt flags during non-critical parts of the data stream or you can offload the one-wire timing to an I2C-to-1wire IC. |
|
|
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Wed Mar 06, 2024 2:24 pm |
|
|
In my case I must to check if the sensor still there because they are optional, so the can be connected or not and even disconnected with the device running.
I have a routine that calls the ReadTemp() routine but that routine calls another routines like ResetOneWire1(),WriteOneWire1() and ReadOneWire1() and those routines has delays inside that are critical to read the 1-Wire devices properly.
@gaugeguy
I can't add a new IC to the PCB, the device is in production state and I think that my boss will not be happy with the idea to change the design.
I can stop UART1 because use the RTS but on UART2 I have a GPS module and doesn't have any RTS line. _________________ Electric Blue |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Mar 06, 2024 2:51 pm |
|
|
You don't need interrupts blocked for 500us for the 1-wire timing. During the reset pulse 480us pulse is the minimum, so extra delays in this are OK. The critical time during the reset pulse is only about 70us.
When sending or reading data, the critical time is during the bit transfer, so again only about 80us. A delay between bits is OK. If you look at the timing diagram the delay between bits is 1us minimum and infinity maximum.
Having interrupts disabled for 80us will not result in any lost data at 115k. |
|
|
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Wed Mar 06, 2024 3:31 pm |
|
|
I changed a the a code a bit. Would you check if there's some flaw?
The code for the second sensor is pretty the same but with another pin.
Code: | unsigned int8 crc8(unsigned int8 *addr,unsigned int8 len)
{
unsigned int8 crc=0;
for(unsigned int8 i=0;i<len;i++)
{
unsigned int8 inbyte = addr[i];
for(unsigned int8 j=0;j<8;j++)
{
unsigned int8 mix=(crc^inbyte)&0x01;
crc>>=1;
if(mix)
{
crc^=0x8C;
}
inbyte >>=1;
}
}
return crc;
}
short ResetOneWire1() //Resetea y detecta si hay sensor presente
{
unsigned int8 Time=0;
short P=FALSE;
short RTS_Bkp;
//La salida pasa a traves de un trasistor asi que se debe trabajar con los niveles logicos invertidos.
output_high(WDO1);
delay_us(500);
disable_interrupts(GLOBAL);
RTS_Bkp=input(RTS);
output_high(RTS); //Paro el puerto del modem.
output_low(WDO1);
delay_us(15);
//A partir de aqui deberia haber un pulso de presencia los proximos 60 a 240uS
while(Time<24) //Espera hasta 240uS
{
delay_us(10);
if(input(WDI1))//El sensor bajo la linea?
{
P=TRUE; //Si- Esperar de 60 a 240 uS
break;
}
Time++;
}
if(RTS_Bkp)
{
output_high(RTS); //Si estaba en 1 queda en 1
}
else
{
output_low(RTS);//Si estaba en 0 queda en 0.
}
enable_interrupts(GLOBAL);//Se asume que las interrupciones estan activas siempre
while(Time<24) //Espera hasta 300uS - Deberia tardar entre 60 y 240uS
{
delay_us(10);
if(!input(WDI1))//Espero que la linea vuelva a subir
{
break;
}
Time++;
}
return P; //No se detecto pulso de presencia;
}
void WriteOneWire1(unsigned int8 Data)
{
unsigned int8 x;
short RTS_Bkp;
disable_interrupts(GLOBAL);
RTS_Bkp=input(RTS);
output_high(RTS); //Paro el puerto del modem.
for(x=0;x<8;x++)
{
disable_interrupts(GLOBAL);
output_high(WDO1);
if((Data&0x01)==0)
{
delay_us(60);
output_low(WDO1);
}
else
{
delay_us(5);
output_low(WDO1);
delay_us(55);
}
enable_interrupts(GLOBAL);
delay_us(5);
Data/=2;
}
if(RTS_Bkp)
{
output_high(RTS); //Si estaba en 1 queda en 1
}
else
{
output_low(RTS);//Si estaba en 0 queda en 0.
}
}
unsigned int8 1
{
unsigned int8 x;
unsigned int8 Data=0;
short RTS_Bkp;
disable_interrupts(GLOBAL);
RTS_Bkp=input(RTS);
output_high(RTS); //Paro el puerto del modem.
for(x=0;x<8;x++)
{
disable_interrupts(GLOBAL);
output_high(WDO1);
delay_us(3);
output_low(WDO1);
delay_us(14);
Data/=2;
if(!input(WDI1))
{
bit_set(Data,7);
}
else
{
bit_clear(Data,7);
}
enable_interrupts(GLOBAL);
delay_us(60);
}
if(RTS_Bkp)
{
output_high(RTS); //Si estaba en 1 queda en 1
}
else
{
output_low(RTS);//Si estaba en 0 queda en 0.
}
return Data;
} |
_________________ Electric Blue |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Mar 06, 2024 3:57 pm |
|
|
I don't think you are understanding the reset pulse diagram.
The bus must be kept low a minimum of 480us (with no maximum)
Once the bus goes high, the slave will respond with a presence pulse starting somewhere from 15us to 60us. The presence pulse from the slave can last from 60us - 240us.
If you wait 70us after the reset pulse is released you can just test the line then.
If a device is present the line will be low. If no device is present the line will be high. There is no need to keep looping and looking for the moment it changes. |
|
|
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Wed Mar 06, 2024 10:28 pm |
|
|
Ok. Thanks, I will make some changes to my code. _________________ Electric Blue |
|
|
|