PDA

View Full Version : I2C write - value too big



ruijc
- 5th April 2008, 15:40
Hi all,

i have found a bug in my temperature logger (16F88 + 24LC512+LM35).
I works pretty well until it reaches temp values of 124ºC, for values above it are displayed as 0ºC or 0,5ºC.

I've looked at my code and i think a know what the problem is: I need to separate the variable into lowbyte and highbyte.

The problem is that i'm not being able to get this working that way. Here's why :


This way does not work:


I2CWRITE SDA,SCL,CTW,ADDR,[tempe.highbyte]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR,[tempe.lowbyte]


This way does not work:


I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe.highbyte]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe.LOWBYTE]


Only this way one works:


I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]


Long story short:
I can make it work with the eeprom BUT only with Address high and low. If i try to separate the variable tempe into high and low it doesnt work :(

Any ideas ?
Thanks
.

JD123
- 5th April 2008, 16:05
Use a word size variable. PBP will read the two bytes. Check PBP manual for the loading order. You may have to flip .highbyte and .lowbyte outside the I2CREAD statement.

ruijc
- 5th April 2008, 16:15
Thanks for the help JD123,

The variable is already a word sized.



You may have to flip .highbyte and .lowbyte outside the I2CREAD statement


Outside ? How is this done ?

.

ruijc
- 5th April 2008, 16:31
checked the PBP manual and did some changes to the code but did not worked ( not sure this is what you mean ):

what i did:

Added alias


tempe var word

temp1 var tempe.highbyte
temp2 var tempe.lowbyte


saving data to eeprom


I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[temp1]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[temp2]


.

JD123
- 5th April 2008, 16:36
Just the use of a word size variable, invokes PBP to read two bytes. It places the first byte in the var.highbyte and the second in the var.lowbyte. EDIT: Sorry, I didn't see that you were not writing, not reading - this is for reading)

If this is not the order you want, you'll have to exchange the two bytes outside the I2C instruction. I'm not sure of all the techniques (like using PBP SWAP) will work, but it's a standard process that can be done using a temporary 'working' word size variable.

temp.highbyte = var.lowbyte
temp.lowbyte = var.highbyte
var = temp

JD123
- 5th April 2008, 16:40
checked the PBP manual and did some changes to the code but did not worked ( not sure this is what you mean ):

what i did:

Added alias


tempe var word

temp1 var tempe.highbyte
temp2 var tempe.lowbyte


saving data to eeprom


I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[temp1]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[temp2]


.

Just use:

I2CWRITE SDA,SCL,CTW,ADDR,[TEMP]

In both ADDR and TEMP they are word size and PBP will send each byte out for the word - no need to bust them up and send them individually.

ruijc
- 5th April 2008, 18:24
Just use:
I2CWRITE SDA,SCL,CTW,ADDR,[TEMP]


This was my first option, but for some reason the eeprom does not store the data this way.

Actually, with the 12F675 chip this eeprom works well with :


I2CWRITE SDA,SCL,CTW,ADDR,[temp.highbyte]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR,[temp.lowbyte]



But not with the 16F88.

I got it working with :


I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]
pause 10
ADDR=ADDR+1
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]


The problem now is for the lenght of the tempe value when over 125ºC

.

mister_e
- 5th April 2008, 18:28
something don't make sense... could you post your whole code for the 16F88?

ruijc
- 5th April 2008, 18:40
Here's the code:



OSCCON = $7e 'Internal RC w/ I/Os
CMCON = 7 'comparators off
CVRCON = 0 'Vref Off
CCP1CON=0
T1CON = 0

OSCTUNE=0

'************************************************* ****************************
'DEFINEs
'************************************************* ****************************

@ DEVICE INTRC_OSC
@ DEVICE MCLR_OFF
@ DEVICE PROTECT_OFF

DEFINE OSC 8

@ DEVICE CPD_OFF
@ DEVICE LVP_OFF
@ DEVICE BOD_OFF
@ DEVICE PWRT_OFF
@ DEVICE WDT_OFF

'************************************************* ****************************
'ADC

DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 3
DEFINE ADC_SAMPLEUS 50

'************************************************* ****************************
'ADC parameters

ADCON1 =%10000000 'right justify
ANSEL =%00000110
ADCON0 =%11000001

'************************************************* ****************************

INCLUDE "modedefs.bas"
DEFINE debug_reg PORTA
DEFINE debug_bit 1
DEFINE debug_baud 9600
DEFINE debug_mode 1

'************************************************* ****************************
' variables

va var word
tempe var word
mem var word
state var byte
st var word
ed var word
ADDR var word
m1 var word
m2 var word
m3 var word
m4 var word
slot var byte
w var byte
RA var word
x var word
ps1 var word
ps2 var word
ps3 var word
ps4 var word
temp1 var tempe.highbyte
temp2 var tempe.lowbyte

rm con 8
ps1=1
ps2=4
ps3=7
ps4=10

p1a con $10
p1b con $e20
p2a con $e2a
p2b con $1c3a
p3a con $1c44
p3b con $2a54
p4a con $2a5e
p4b con $386e

'CLEAR

ctw CON $A0

'************************************************* ****************************

PORTA=0
PORTB=0
TRISA=%00100101
TRISB=%00001111

'************************************************* ****************************
'PINS

temp var PORTA.0
out var PORTA.1
volt var PORTA.2
a3 var PORTA.3
jumper var PORTA.4
but1 var PORTA.5 'read
led2 var PORTA.6
led1 var PORTA.7
but2 var PORTB.0 ' record
p1 var PORTB.1
SCL var PORTB.2 ' eeprom
SDA var PORTB.3 ' eeprom
green var PORTB.4 ' bicolor led (green)
red var PORTB.5 ' bicolor led (red)
led4 var PORTB.6
led3 var PORTB.7

'************************************************* ****************************
startmenu:
st=p1a
ed=p1b

if but1=1
While but1=1
Wend ' Wait here for Button to be released
gosub readmenu
endif
if but2=1
While but2=1
Wend ' Wait here for Button to be released
gosub recordmenu
endif
goto startmenu

'************************************************* ****************************

readmem:
led2=1
led3=0
'debug "Reading Memory",13,10
'debug "Address: ",dec mem," start at ",dec st, " and finish at ",dec ed,13,10
'debug " Memory # ",dec mem,13,10
FOR ADDR =st TO ed
toggle led2
toggle led3

I2CREAD SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]
PAUSE 10
toggle green
debug dec3 tempe/10,",",dec1 tempe//10,13,10
ADDR=ADDR+1
NEXT
green=1
return

'*************************************************

FOR ADDR=st TO ed

adcin temp,va

tempe=(va*/5000 )>>2

toggle red
toggle green
pause 418 ' calibration to get 1200 readings ( 2 per second ) in 10 minutes -
debug " Valor Gravado: ", dec tempe," Na posição ", dec ADDR, 13,10
I2CWRITE SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]
pause 10
ADDR=ADDR+1
I2Cread SDA,SCL,CTW,mem.highbyte,mem.lowbyte,[x]
pause 10
'debug "Address: ",dec mem," started at ",dec st, "finish value ",dec x,13,10
debug " ",13,10
if but1=1 then 'stop recording
pause 600
goto timing
goto startmenu
endif
NEXT
red=1
return
*************************************************

sayzer
- 6th April 2008, 09:53
Ruijc,

I did not check the code in detail but at first look there is something that should not be done.



....
goto timing
goto startmenu
endif
NEXT
red=1
return




1. You have two "goto" s one after the other. When the first one runs, the second one will not run!

2. When the first one runs, then you will have a return address on stack; Thus, the next time you hit a return, where ever it is, it will ruin your logic flow. You must organize a logic flow that will clear the return address of the subroutine you are in. Example: set a flag and then exit the subroutine with "return".

mister_e
- 6th April 2008, 10:11
i'm a bit surprised you don't have any compilation errors...
a) 2 mistyped IF statements,
b) it miss Readmenu, recordmenu, timing section,
c) and as Sayzer point-out.. those goto are a bit weird... and in case you remove Goto timing... it will branch to the startMenu indeed... but you will always add 1 on the Stack.. shortly it will overflow...


OSCTUNE=0
why? You don't need to do it unless you want to calibrate the internal OSC, just remove it. Almost sure your Serial comm wasn't working really well huh? (DEFINES aren't in caps either.. but it can be a paste error)


I2CREAD SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]
Why do you split addr in 2 ?

I2CREAD SDA,SCL,CTW,ADDR,[tempe]
This have to be changed in ALL I2CREAD AND I2CWRITE lines

This must be written the right way.. unless YOU will have problem indeed.

Acetronics2
- 6th April 2008, 10:15
Hi,

I wonder the '675 was running @ 4Mhz , the '88 is running @ 8Mhz ... which is the limit for using " I2C SLOW" ...

Did you try that DEFINE ???

Just an idea ...
Alain

mister_e
- 6th April 2008, 10:25
Not a problem for the 24LC512 unless the pull-up resistor are way to high... it can run up to 400KHz, 1MHz for FC version.

But there's few mistakes in the code.... sure i missed a few ;)

ruijc
- 6th April 2008, 10:48
Hello sayzer, Mister-e and Acetronics



1. You have two "goto" s one after the other. When the first one runs, the second one will not run!


this is true. I sampled this section from the hole code to test your help ;) but there are some " ' " missing there.

However, removing the missing links and compiling errors the final result is the same.




Code:

I2CREAD SDA,SCL,CTW,ADDR.highbyte,addr.lowbyte,[tempe]

Why do you split addr in 2 ?
Code:

I2CREAD SDA,SCL,CTW,ADDR,[tempe]

This have to be changed in ALL I2CREAD AND I2CWRITE lines


This is my biggest problem. What you suggested was my first written code and it didnt worked.

This was my problem in the past and resolved with the help of Skimask.
(see post...)
http://www.picbasic.co.uk/forum/showthread.php?t=8153

Frankly,i didnt understood then as i still dont now, but it worked.

The problem now is that it's not returning good values after the 127 mark and i believe that it's related with 1111111 going to 10000000 since that i read nothing but 000.x from there.

( see attached pic )

.

ruijc
- 6th April 2008, 12:35
Well, i think i just fixed one problem and found a new one :(

I have sucessfuly use the code " I2CREAD SDA,SCL,CTW,ADDR,[tempe] ".

After several changes i tryed Mister-e's suggestion and removed the OSCTUNE=0 line.

It doesnt make sense to me ( or does it ? ), but it's working this way now.

The new problem that i found is that while debugging i found out that the problem related with getting low values passed the 120'ich mark IS NOT related with the eeprom/low-highbytes.

I got a variable resistor to simulate the LM35 and was changing the value while recording, and i could see that the value captured dropped after the conversion and before recording to the eeprom.

this is the capture while increasing the variable resistor


111,3
111,3
111,8
112,3
112,3
112,7
112,7
113,2
113,7
114,2
114,7
115,2
115,7
116,2
117,6
118,1
118,6
118,6
118,6
118,6
119,1
121
121,5
122
122,5
122,5
122,5
122,5
0,4
0,9
0,4
0,9
0,4
0,9
0,4
0,9
0,4
0,9


now i'm lost :(

.

Acetronics2
- 6th April 2008, 12:41
Hi, Ruicj

Can you tell us how you get those values :

( 122.5 is NOT a PbP value ...)

- Input value range ( volts ? ) / ref voltage
- Math used ( in PbP )
- Values you want to to output

It's "not so clear" ...

Alain

PS : ANSEL doesn't match the ADCIN PORT !!! Check it !!!

ruijc
- 6th April 2008, 12:52
Hello Acetronics,

these values i get from:



FOR ADDR=st TO ed

adcin temp,va

tempe=(va*/5000 )>>2

toggle red
toggle green
pause 418 ' calibration to get 1200 readings ( 2 per second ) in 10 minutes -
debug " recorded value: ", dec tempe," position ", dec ADDR, 13,10


the debug line gave these values after the adcin conversion.
I'm colecting the voltage directly from the variable resistor which is simulating the voltage from a LM35 ( 0,2v - 1,5V )
I'm not using any reference value, just VDD and VSS( i know...it's lame...but i'm not looking for the best resolution for now ;) )

.

Acetronics2
- 6th April 2008, 12:56
seen it ???

: ANSEL doesn't match the ADCIN PORT !!! Check it !!!

ANSEL select A1 and A2
ADCIN select A0 ...

Alain

ruijc
- 6th April 2008, 13:04
Acetronics,

You are right !!! Thank you ( and the rest of the guys for the help :) )

This was set when i was playing with several sensors :(

But how can it be ?? If i have the ANSEL with a different channel, how can i get values on channel A0 ??

This is why i didnt see it :(

Acetronics2
- 6th April 2008, 13:20
Capacitive coupling ... pins are side-by-side !!!