CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

ds18b20 one code on multiple pins

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Danni



Joined: 05 Mar 2016
Posts: 10

View user's profile Send private message

ds18b20 one code on multiple pins
PostPosted: Tue Jul 12, 2016 12:29 pm     Reply with quote

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: 9161
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jul 12, 2016 1:58 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jul 12, 2016 2:35 pm     Reply with quote

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: 19326

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 12:41 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 11:36 am     Reply with quote

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: 19326

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 12:45 pm     Reply with quote

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: 19326

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 12:55 pm     Reply with quote

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: 9161
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 2:04 pm     Reply with quote

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: 291

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 2:28 pm     Reply with quote

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: 9161
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jul 13, 2016 6:11 pm     Reply with quote

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: 19326

View user's profile Send private message

PostPosted: Thu Jul 14, 2016 1:45 am     Reply with quote

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: 291

View user's profile Send private message

PostPosted: Thu Jul 14, 2016 6:42 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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