PDA

View Full Version : 16F690 and i2c Com



ross246
- 24th May 2010, 03:38
Hi again everyone, I've been trying to interface my PIC16F690 with a DS1621 Digital Thermometer. I haven't been able to find many resources and the code I have found within the forum I could not get to work. The code which I have tried to adapt now is for a DS1624 and the commands seem identical to me but yet it returns "0.00". my serial communication is working 100% and I have gone over my wiring a lot. Open to any suggestions/changes. I have got A0, A1, A2 all grounded which gives the device an address of %10010000. Aswell as 4.7k pick ups on the sda scl lines. I thought it possibly could be because I am using Port A.0 and A.1? Not sure.



DEFINE OSC 4
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_SPBRG 25
DEFINE HSER_CLROERR 1

SDA VAR PORTA.0
SCL VAR PORTA.1

i2c_read CON 1 'R/W configuration bit (1 = read)
i2c_write CON 0 'R/W configuration bit (0 = write)
i2c_out VAR BYTE 'data to sent over I2C bus
i2c_in VAR BYTE[2] 'data received over I2C bus
i2c_ack VAR BIT 'acknowledgement bit
temp VAR WORD

Hserout ["Starting"]
GOSUB Config_Register 'Set Configuration
GOSUB Start_Convert 'Start continuous conversion

TOP:
PAUSE 2000
GOSUB Read_Temp 'Read the current temperature
i2c_in[2] = i2c_in[1] >> 3 'Shift 5 decimal bits to LS position
temp = (i2c_in[1]*1000) 'PIC Doesn’t like decimals, but there is a way to work around this
HSEROUT [DEC i2c_in[0],".",DEC2 (temp ** 2048)/100,13,10]'Outputs temperature to termina
GOTO top 'Loops forever

Config_Register: 'Set continuous conversion
GOSUB I2C_START 'Start Condition
i2c_out = %10010000 'Send Address, (device= %1001, A0= 0, A1= 0, A2= 0, R/W= 0)
GOSUB I2C_TX 'Send data in “i2c_out”
i2c_out = $AC 'Send “Access Configuration” command
GOSUB I2C_TX 'Send data in “i2c_out”
i2c_out = $00 'Send “Continuous Conversion” command
GOSUB I2C_TX 'Send data in “i2c_out”
GOSUB I2C_STOP 'Stop Condition
RETURN

Start_Convert: 'Start Conversion
GOSUB I2C_START
i2c_out = %10010000 'Send Address, (device= %1001, A0= 0, A1= 0, A2= 0, R/W= 0)
GOSUB I2C_TX
i2c_out = $EE 'Send “Start to Convert” command
GOSUB I2C_TX
GOSUB I2C_STOP
RETURN

Read_Temp: 'Read temperature
GOSUB I2C_START
i2c_out = %10010000 'You must “write” the command to read the temperature before
GOSUB I2C_TX 'reading it, therefore R/W still is 0
i2c_out = $AA 'Send “Read Temperature” command
GOSUB I2C_TX
GOSUB I2C_START '* Reissue Start Condition *
i2c_out = %10010001 'Send Address, (device= %1001, A0= 0, A1= 0, A2= 0, R/W= *1*)
GOSUB I2C_TX 'Transmit address with R/W bit as 1 (“read”)
GOSUB I2C_RX 'Start getting data coming in
GOSUB I2C_STOP 'Issue stop condition
RETURN

I2C_START: 'I2C start (start communication on I2C bus)
HIGH SDA
HIGH SCL
LOW SDA
LOW SCL
RETURN

I2C_STOP: 'I2C stop (terminate communication on I2C bus)
LOW SDA
HIGH SCL
HIGH SDA
PAUSE 1
RETURN

I2C_RX: 'I2C receive -> receive data from slave
SHIFTIN SDA,SCL,0,[i2c_in[0]] 'Shift in first byte MSBpre
SHIFTOUT SDA,SCL,1,[%0\1] 'Send acknowledge (ACK) = 0
SHIFTIN SDA,SCL,0,[i2c_in[1]] 'Shift in second byte MSBpre
SHIFTOUT SDA,SCL,1,[%1\1] 'Send not acknowledge (NACK) = 1
RETURN

I2C_TX: 'I2C transmit -> send data to the slave
SHIFTOUT SDA,SCL,1,[i2c_out] 'Shift out “i2c_out” MSBfirst
SHIFTIN SDA,SCL,0,[i2c_ack\1] 'Receive ACK bit
RETURN


END

Jumper
- 24th May 2010, 05:54
Read this..http://www.picbasic.co.uk/forum/showthread.php?t=561&p=88252#post88252

Read the datasheet

Pull some hair from the head... read some more datasheet...

Port A could have some extra features... also a search for "all digital" might give a few answers as well

ross246
- 24th May 2010, 11:02
OK the hair is pulled :p

From all my reading I *think* what I need to do is add


ANSEL=%00000000
ADCON1=%00000111

Will be giving it a try when I get home, I appreciate the type of reply it is way better to be steered in the right direction compared to being given the answer. I struggle to make sense of the datasheets sometimes and I cant figure out why, it may be my lack of electronic knowledge or maybe it just takes time and practice.

I understand what the registers do but I don't understand where the value "7" comes in, why not another value.

vaporized
- 24th May 2010, 11:49
Hello.
Decimal 7 is same as binary 00000111, that's why mr. Jumper provided the link above. In order to disable analog functions of the portA you have to set first three bits (i.e. bit0, bit1, bit2) of the register, which is described in a datasheet.

ross246
- 24th May 2010, 17:36
It worked perfectly :) thank you for explaining. I wanted to ask another question I thought I would just keep it in this thread since its small.

I am thinking of ways to hook up a 3 digit seven segment display to my pic, it has a common cathode. I was wondering if it would work to hook up each anode to lets say portc.0 through to portc.7 (the dot) and connect the cathode for each digit to a different port say portb.4 through to say portb.6. That way when I want to write something to the first digit I set portb.4 low and set portb.5 and portb.6 to high. When I tried to connect it up this way, the numbers appeared very dim. I think I have the right idea because I can decrease the pause between switching to each digit and to the human eye it would appear like they are all on at the same time? I am new to both electronics and microcontrollers so i apologise if it's a stupid question :) I will post the code I was fiddling with:


define OSC 4

LEDTOP var PORTC.0
LEDTOPLEFT var PORTC.1
LEDTOPRIGHT VAR PORTC.2

LEDMIDDLE VAR PORTC.3

LEDBOTTOMRIGHT VAR PORTC.4
LEDBOTTOM VAR PORTC.5
LEDBOTTOMLEFT VAR PORTC.6

SEG1 VAR PORTB.4
SEG2 VAR PORTB.5
SEG3 VAR PORTB.6

TRISC = %00000000
TRISB = %00000000

ADCON1=%00000111
ANSELH=0
ANSEL=0
CM1CON0=0
CM2CON0=0



loop:
gosub Selseg1
gosub DisNo5
pause 500

goto Selseg2
goto DisNo5
pause 500

goto Selseg3
goto DisNo5
pause 500

goto loop

Selseg1:
seg1 = 0
seg2 = 1
seg3 = 1
RETURN

Selseg2:
seg1 = 1
seg2 = 0
seg3 = 1
Return

Selseg3:
seg1 = 1
seg2 = 1
seg3 = 0
RETURN

DisNo1:
LEDTOP = 0
LEDTOPLEFT = 0
LEDTOPRIGHT = 1
LEDMIDDLE = 0
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 0
LEDBOTTOMLEFT = 0
return


DisNo2:
LEDTOP = 1
LEDTOPLEFT = 0
LEDTOPRIGHT = 1
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 0
LEDBOTTOM = 1
LEDBOTTOMLEFT = 1
return

DisNo3:
LEDTOP = 1
LEDTOPLEFT = 0
LEDTOPRIGHT = 1
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 1
LEDBOTTOMLEFT = 0
return

DisNo4:
LEDTOP = 0
LEDTOPLEFT = 1
LEDTOPRIGHT = 1
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 0
LEDBOTTOMLEFT = 0
return

DisNo5:
LEDTOP = 1
LEDTOPLEFT = 1
LEDTOPRIGHT = 0
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 1
LEDBOTTOMLEFT = 0
return

DisNo6:
LEDTOP = 0
LEDTOPLEFT = 1
LEDTOPRIGHT = 0
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 1
LEDBOTTOMLEFT = 1
return

DisNo7:
LEDTOP = 1
LEDTOPLEFT = 0
LEDTOPRIGHT = 1
LEDMIDDLE = 0
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 0
LEDBOTTOMLEFT = 0
return

DisNo8:
LEDTOP = 1
LEDTOPLEFT = 1
LEDTOPRIGHT = 1
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 1
LEDBOTTOMLEFT = 1
return

DisNo9:
LEDTOP = 1
LEDTOPLEFT = 1
LEDTOPRIGHT = 1
LEDMIDDLE = 1
LEDBOTTOMRIGHT = 1
LEDBOTTOM = 0
LEDBOTTOMLEFT = 0
return
End

HenrikOlsson
- 24th May 2010, 19:03
Hi,
I haven't looked at your code but remember that the pins can source and sink 25mA. This is probably enough for direct driving the segments but if you have 10mA thru each segment and all seven segments lit up the poor pin on PortB that is trying to sink 70mA is going to have a hard time.

Otherwise your aproach is correct, called multiplexing. Since each digit is only "on" 1/3 of the time (or less) it's quite common to drive the segments harder than their continous rating to get more light out of them. That way the average current thru the segments is still kept below their rating.

/Henrik.

ross246
- 24th May 2010, 19:11
So I have the theory correct :) the strange thing is when i set B.4 and B.5 to high and B.6 to low, it displays on the 3rd segment with correct brightness. But when I try set B.4 or B.5 low and the others high, those 2 segments (1st and 2nd) appear dim. Can only think it's my code I will keep reading and trying. Thanks for the response

HenrikOlsson
- 24th May 2010, 19:37
Hi,
Yes, the theory is correct but 500ms per digit seems a bit slow, it'll definitely be flickering... ;-)

I don't mean to step on any toes or anything but you DO have resistors in series with LED segments don't you? Don't connect them directly to the PIC. If you don't have any resistors you may have toasted some of the segments due to too much current.... And don't forget the driver/buffer for the common cathodes, don't try to sink all that current thru the PICs I/O's.

/Henrik.

ross246
- 24th May 2010, 19:48
Yea I had it at 500ms just to see if I could get each digit to display in sequence (which doesn't work). I have resistors in series with each segment but I will be honest I dont know what you mean by driver/buffer? I thought if it was a common ANODE you could use a transistor but as I said earlier my electronics is touch and go and I'm not sure how I would go about hooking that up :)

ross246
- 24th May 2010, 20:37
I neatened up my code and it solved the problem :) why exactly it solved the problem I am not sure, but im glad it did ;)


TRISC = %00000000
TRISB = %00000000

ADCON1=%00000111
ANSELH=0
ANSEL=0
CM1CON0=0
CM2CON0=0



loop:
GOSUB selseg1
gosub disno1
pause 5
GOSUB selseg2
gosub disno2
pause 5
GOSUB selseg3
gosub disno3
pause 5
goto loop

Selseg1:
portb = %01111111
RETURN

Selseg2:
portb = %11011111
Return

Selseg3:
portb = %10111111
RETURN

DisNo1:
PORTC = %01000010
Return

DisNo2:
PORTC = %01101101
return

DisNo3:
PORTC= %00111101
return

DisNo4:
PORTC = %00011110
return

DisNo5:
PORTC = %00111011
return

DisNo6:
PORTC = %01111010
return

DisNo7:
PORTC = %00010101
return

DisNo8:
PORTC = %01111111
return

DisNo9:
PORTC = %00111111
return
End