|
|
View previous topic :: View next topic |
Author |
Message |
Danni
Joined: 05 Mar 2016 Posts: 10
|
ds18b20 one code on multiple pins |
Posted: Tue Jul 12, 2016 12:29 pm |
|
|
Hello guys.
im trying to adapt my ds18b20 code so i can change pin number and use the same code on multiple pins.
Im using case to change pin number and it works until the line with !!!!!:
Code: |
int8 DQ;
DQ = 0;
void write_byte(int8 val, int8 power_on)
{
int i;
for(i=0; i<8; i++)
{
_output_low(DQ);
delay_us( 2 );
!!!!!!!!!! output_bit(DQ, shift_right(&val,1,0)); !!!!!!!!
delay_us(60);
if((i == 7) && (power_on == 1))
{
_output_high(DQ);
}
else
{
_output_float(DQ);
delay_us( 2 );
}
}
}
|
I changed it to:
Code: |
void write_byte(int8 val, int8 power_on)
{
int i;
for(i=0; i<8; i++)
{
_output_low(DQ);
delay_us( 2 );
!!!!!!!!!!! _output_bit(DQ, val); !!!!!!!!!!!!!!!
delay_us(60);
if((i == 7) && (power_on == 1))
{
_output_high(DQ);
}
else
{
_output_float(DQ);
delay_us( 2 );
}
}
}
|
and
Code: |
#inline
void _output_bit(int8 n, int8 val)
{
switch(n)
{
case 0 : output_bit(PIN_B0, shift_right(&val,1,0)); break;
}
}
|
But i'm doing something wrong. it's the only line i fighting with and cant get it to work...
Can someone point me in the right direction??
Regards Danni |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Tue Jul 12, 2016 1:58 pm |
|
|
can't be done..
from the CCS manual.....
Syntax:
output_bit (pin, value)
Parameters:
Pins are defined in the devices .h file. The actual number is a bit address. For example, port a (byte 5 ) bit 3 would have a value of 5*8+3 or 43 . This is defined as follows: #define PIN_A3 43 . The PIN could also be a variable. The variable must have a value equal to one of the constants (like PIN_A1) to work properly. The tristate register is updated unless the FAST_IO mode is set on port A. Note that doing I/O with a variable instead of a constant will take much longer time.
Value is a 1 or a 0.
Please note 'value' MUST be a '1' or a '0' NOT a 'variable' .
As for 1 ds18b20 per pin, I simple copied the 'driver' functions twice.
ie:
Code: | // Reset one wire bus ,#1
void ow1_reset(void)
{
output_low(OW1);
delay_us(500); // Min. 480uS
output_float(OW1);
delay_us(500); // Wait for end of timeslot
}
//-------------------------------------
// Reset one wire bus, #2
void ow2_reset(void)
{
output_low(OW2);
delay_us(500); // Min. 480uS
output_float(OW2);
delay_us(500); // Wait for end of timeslot
} |
OW1 refers to the first sensor, OW2 to the second.
This was a LOT faster than your way,had lots of memory space, AND I KNEW the one sensor' code worked. If you're good at typing, it should only take 10 minutes to be 'up and running'. The really nice thing is that ANY capable pin can be used, simply just define OW2 for whatever pin you want to use.
Jay |
|
|
Danni
Joined: 05 Mar 2016 Posts: 10
|
|
Posted: Tue Jul 12, 2016 2:35 pm |
|
|
But when i need 8 or 10 sensors it's a loooong code.
i did copy the code on a pic i have with two sensors.
i have changed all the code but only need the line output_bit(DQ, shift_right(&val,1,0));
My reset code its:
Code: |
void ow_reset(void)
{
_output_low(DQ);
delay_us(500); // Min. 480uS
_output_float(DQ);
delay_us(500); // Wait for end of timeslot
}
#inline
void _output_low(int8 n)
{
switch(n)
{
case 0 : output_low(PIN_B0); break;
case 1 : output_low(PIN_B1); break;
case 2 : output_low(PIN_B2); break;
case 3 : output_low(PIN_B3); break;
case 4 : output_low(PIN_B4); break;
case 5 : output_low(PIN_B5); break;
case 6 : output_low(PIN_B6); break;
case 7 : output_low(PIN_B7); break;
}
}
#inline
void _output_float(int8 n)
{
switch(n)
{
case 0 : output_float(PIN_B0); break;
case 1 : output_float(PIN_B1); break;
case 2 : output_float(PIN_B2); break;
case 3 : output_float(PIN_B3); break;
case 4 : output_float(PIN_B4); break;
case 5 : output_float(PIN_B5); break;
case 6 : output_float(PIN_B6); break;
case 7 : output_float(PIN_B7); break;
}
}
|
It's working great then i'm just counting the DQ up after each temperature read. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 13, 2016 12:41 am |
|
|
The reason the core function only supports constants, is that it is basically coding a PIC _hardware_ function.
This does not support variables.
Going back, the original output_high, and output_low functions had the same limitation.
However CCS added 'variable' based versions for these a (long) while ago.
Your 'output_low' code will work with a variable. Your _output_low code is not needed, but the pin number needs to be an int16.
However they did not code 'output_bit' this way.
Add this:
Code: |
#inline
void output_level(int16 pin, int1 level)
{
if (level==0)
output_low(pin);
else
output_high(pin);
}
|
Variable pin numbers need to be an int16, not an int8 (for PIN16/18).
output_level(PIN_NUMBER, shift_right(&val,1,0));
will then work, using int_16 pin numbers. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 13, 2016 11:36 am |
|
|
Using variables for CCS pin numbers generates very long ASM code which
doesn't allow the correct timing intervals required for a one wire driver.
This is the code produced by the test program shown below.
Code: | 00004: MOVF ??65535,W
00006: ANDLW 07
00008: MOVWF @00
0000A: RRCF ??65535,W
0000C: MOVWF @01
0000E: RRCF @01,F
00010: RRCF @01,F
00012: MOVLW 1F
00014: ANDWF @01,F
00016: MOVF @01,W
00018: ADDWF @WRITEBITA.P2,W
0001A: MOVWF FSR0L
0001C: MOVLW 00
0001E: ADDWFC @WRITEBITA.P2+1,W
00020: MOVWF FSR0H
00022: CLRF @01
00024: INCF @01,F
00026: INCF @00,F
00028: BRA 002C
0002A: RLCF @01,F
0002C: DECFSZ @00,F
0002E: BRA 002A
00030: MOVF @WRITEBITA.P1,F
00032: BZ 003A
00034: MOVF @01,W
00036: IORWF INDF0,F
00038: BRA 0040
0003A: COMF @01,F
0003C: MOVF @01,W
0003E: ANDWF INDF0,F
00040: RETURN 0
....................
.................... #inline
.................... void output_level(int16 pin, int1 level)
.................... {
.................... if (level==0)
*
00082: MOVF level,F
00084: BNZ 00A8
.................... output_low(pin);
00086: MOVFF pin,??65535
0008A: CLRF @WRITEBITA.P1
0008C: MOVLW 0F
0008E: MOVWF @WRITEBITA.P2+1
00090: MOVLW 89
00092: MOVWF @WRITEBITA.P2
00094: RCALL 0004
00096: MOVFF pin,??65535
0009A: CLRF @WRITEBITA.P1
0009C: MOVLW 0F
0009E: MOVWF @WRITEBITA.P2+1
000A0: MOVLW 92
000A2: MOVWF @WRITEBITA.P2
000A4: RCALL 0004
000A6: BRA 00CA
.................... else
.................... output_high(pin);
000A8: MOVFF pin,??65535
000AC: MOVLW 01
000AE: MOVWF @WRITEBITA.P1
000B0: MOVLW 0F
000B2: MOVWF @WRITEBITA.P2+1
000B4: MOVLW 89
000B6: MOVWF @WRITEBITA.P2
000B8: RCALL 0004
000BA: MOVFF pin,??65535
000BE: CLRF @WRITEBITA.P1
000C0: MOVLW 0F
000C2: MOVWF @WRITEBITA.P2+1
000C4: MOVLW 92
000C6: MOVWF @WRITEBITA.P2
000C8: RCALL 0004
.................... } |
Test program:
Code: | #include <18F4620.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
#define PIN_NUMBER PIN_B5
#inline
void output_level(int16 pin, int1 level)
{
if (level==0)
output_low(pin);
else
output_high(pin);
}
//======================================
void main(void)
{
int8 val;
output_level(PIN_NUMBER, shift_right(&val,1,0));
while(TRUE);
} |
Also see:
http://www.ccsinfo.com/forum/viewtopic.php?t=36953&start=3 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 13, 2016 12:45 pm |
|
|
Very much agreed.
I actually thought I said this, but I must have left it out..... :(
It's a balancing act.
For just two or three pins, the switch solution will be smaller/faster. However for the large number of pins involved, I'd suspect both solutions will be comparable.
The key thing is that the 'simple' code, using variables, will probably actually be as large as doing the multiple solutions. And (more importantly possibly), there is the very real risk of the extra delays inside the routines, may well create timing problems.
I have to say that I'd probably code the routine as a multi-line #define macro, so that the code can be kept simple, and the timings right. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 13, 2016 12:55 pm |
|
|
Looking at it again, there is another solution that should be considered.
Since all the bits are on one port, the best way to do this, is to simply create a mask at the start of the routine for the bit required, and then do all the operations using byte wide operations. This will be nearly as fast as the standard code, and only a very few bytes larger.
Otherwise the solutions are honestly awful..... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Jul 13, 2016 2:04 pm |
|
|
Since it's almost 100*F here (40*C), I thought I'd look at this again. The ds18b20p driver I use is about 922 bytes long for 2 devices, 1 per pin. So... simple math says 460 bytes per driver per pin. 8 devices on 8 pins is 8 * 460 =+-3680 bytes.
Two things to consider. 1) TIMING ! 'one wire' is time sensitive so you have to be accurate and repeatable with your code to get proper communications.
2) cost. It should be possible to get a PIC with LOTS of program space for maybe a few pennies more, same pinout, just more memory.
Yes, my individual driver per pin is not code efficient BUT it does work. You've mentioned using 8 or 10 devices and that implies that 'main() has a lot to do, so you should be using a 'big' PIC (one with lots of memory).
Now Mr. T's 'masking' has merit but when you say 8 or 10 sensors...hmm the mask might need to be 16 bits or 2 x 8 bit, IF you can use byte wide ports. MY way doesn't care which bits on what ports...
It's one of those sounds simple but gets very complicated in working out the details... remember this is bit banged so TIMING is the most important factor.
I know cost is always a factor but you need to consider your TIME. R&D is not free, even at $50 per hour, how many DAYS have you put into this and not got a workable solution? I'm guilty of using the 18F46K22 for some 'simple' tasks but I've never run out of memory or pins and always delivered the product before the due date. Just something to consider.
Jay |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Jul 13, 2016 2:28 pm |
|
|
Another thing to consider is that the DS18B20, like most of the 1-wire product line, is designed to be multi-drop. 8-10 of these can easily be connected on a single line. There is some added communication involved but very simple hardware using just one pin. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Jul 13, 2016 6:11 pm |
|
|
One problem with the DS implementation of 'one wire' communications with multiple devices is that if there's a break in that wire, say between sensor #2 and #3, you'll lose sensors #3 thru 8 so the option of one pin, one sensor eliminates that possibilty.
There are other ways to effect 'single wire' communications that will still work even if there's a break in the wire though.
It'd be interesting to see if the driver code for 'multiple devices on one pin' IS actually smaller than a 'one device-one pin' driver.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Jul 14, 2016 1:45 am |
|
|
OK. off the cuff code here.
Code: |
//Modified driver to support 8*one wire connections on a single port
//define the port to use here
#define OUTPUT_ONE output_b
#define TRIS_ONE set_tris_b
#define INPUT_ONE input_b
//just reset one bus = just like standard driver, but requires sensor
//number 0 to 7
void onewire_reset(int8 sensor)
{
int8 mask;
if (sensor>7)
return;
mask=1<<sensor;
OUTPUT_ONE(mask ^ 0xFF); //sensor pin low
delay_us(500);
TRIS_ONE(0xFF); //float the port
delay_us(500);
}
//Write to one sensor. Requires sensor number (0 to 7), and byte to write.
//drops out if you try to write beyond sensor 7
void onewire_write(int8 sensor, int8 data)
{
int8 count;
int8 mask;
if (sensor>7)
return; //error
mask=1<<sensor;
for (count=0; count<8; ++count)
{
OUTPUT_ONE(mask ^ 0xFF);
delay_us( 2 ); // pull 1-wire low to initiate write time-slot.
if (shift_right(&data,1,0))
OUTPUT_ONE(0xFF);
else
OUTPUT_ONE(MASK^0xFF);
delay_us( 60 ); // wait for write slot
TRIS_ONE(0xFF); // Float the port
delay_us( 2 ); // for more than 1us minimum.
}
}
//Read one sensor. Requires sensor number to read
//Returns byte read.
int8 onewire_read(int8 sensor)
{
int8 count, data;
int8 mask;
if (sensor>7)
return 0; //Ignore error
for (count=0; count<8; ++count)
{
OUTPUT_ONE(mask ^ 0xFF);
delay_us( 2 ); // pull 1-wire low to trigger time-slot
TRIS_ONE(0xFF); // Float the port
delay_us( 8 ); // let device reply
shift_right(&data,1,((INPUT_ONE() & MASK)!=0)); //bit
delay_us( 120 ); // wait for read slot
}
return data;
}
|
Used exactly like the standard driver, except (for instance), you need a bus number in each transaction.
As posted 'onewire_reset(0)' will issue a reset on B0 etc..
Untested, but the idea should work. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Thu Jul 14, 2016 6:42 am |
|
|
As far as the broken wire concern, having one input at the system does not mean there cannot be 8 or 10 connections going out, one for each sensor.
That being said my first product using the 1-wire sensors did use a separate pin for each of 4 DS1820 sensors using a PIC16C58 to drive a 2x16 display.
The search ROM code to find the sensor ID's is a little long so it comes down to a trade off. There isn't one perfect solution for every situation. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|