![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
nizar445
Joined: 09 Jun 2009 Posts: 23
|
I2C Help needed |
Posted: Sat May 19, 2012 3:15 am |
|
|
Hi all,
I need some help to understand and control this chip (HV881); it uses I2C protocol to turn ON/OFF EL lamps.
So far I have wired the chip correctly and I have started to write a program to control it using 12F629 PIC. I did read through the forum and cannot find something similar to help me to understand a way to send the data and the acknowledgement to the chip.
The data sheet link attached below (i2c page 5). So please have a look at it and any help would be really appreciated.
http://www.supertex.com/pdf/datasheets/HV881.pdf
BTW: I have poor programming skills and I haven’t done anything with I2C before so please make it simple
My initial code is (assuming with right data and acknowledgement the chip will output something ):-
Code: | #include <12F629.h>
#fuses NOWDT, NOPROTECT,INTRC_IO, NOPUT,NOBROWNOUT, NOCPD
#use delay(clock=4000000)
#use i2c(Master,sda=PIN_A3,scl=PIN_A2)
void main()
{
char z;
while(1)
{
i2c_start();
i2c_write(0x06); //send address
i2c_write(0x00); //data (problem here what shall I send to turn ON for example the 1st and 16th lamps?)
i2c_stop();
delay_ms(100);
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19384
|
|
Posted: Sat May 19, 2012 4:23 am |
|
|
Taking things one by one:
First the device address. This is a _seven bit_ value 0b0000110, sent as the _top_ seven bits of the byte you write to the device. The low bit is the 'bus direction' control (R/W), which is always '0' for this device (you can only write to it). So the byte you have to send for the address is 0b00001100 = 0x0C, or 12 in decimal. This is a real 'annoyance' with I2C, with some devices telling you about this, saying to use bytes of 12/13 (for write/read if the device supported this), while others just give the 7bit value and assume you know how to translate it.
Second have you got the pull up resistors on the bus?. Often forgotten, and the cause of a lot of grief....
Now, if you at there example 'packet', you are meant to send the device address followed by eight bytes to control the sixteen tamp outputs (one nibble for each). Each byte is acknowledged by the slave device. When you perform an I2C_WRITE function, this _returns_ the ACK bit.
So make your function generic:
Code: |
#include <12F629.h>
#fuses NOWDT, NOPROTECT,INTRC_IO, NOPUT,NOBROWNOUT, NOCPD
#use delay(clock=4000000)
#use i2c(Master,sda=PIN_A3,scl=PIN_A2)
int1 set_levels(int8 levels[]) {
//Structure the 'levels' array as sixteen values for the 16 lamps
int8 ictr;
int8 bytetosend;
int1 ack;
I2C_START();
ack = I2C_WRITE(0xC); //address the device
if (ack==1) {
I2c_STOP(); //device did not ACK
return FALSE;
}
for (ictr=0;ictr<16;ictr++) {
if (bit_test(ictr,0)==0) { //first byte of pair
bytetosend=levels[ictr];
}
else {
bytetosend+=(levels[ictr]<<4); //second byte of pair
ack=I2C_WRITE(bytetosend);
if (ack==1) {
I2c_STOP(); //device did not ACK
return FALSE;
}
}
}
//Get here all eight bytes have sent and been ack'd
I2C_STOP();
return TRUE;
}
void main(void) {
int8 lamps[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//ensure all levels start as 0.
do {
lamps[0]=15; //First lamp to 'full on'
lamps[15]=8; //Sixteenth lamp 'half on'
if (set_levels(lamps)==FALSE) {
//Here something has gone wrong - flash an LED or something....
}
delay_ms(10000); //wait ten seconds
lamps[0]=0; //first lamp 'off'
lamps[15]=15; sixteenth lamp full on
if (set_levels(lamps)==FALSE) {
//Here something has gone wrong - flash an LED or something....
}
delay_ms(10000); wait another ten seconds
}
}
|
Lamp 'levels' are 0 to 15 for off to full power.
Probably full of errors, just 'typed in', on the screen, but it should give you a starting point.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
nizar445
Joined: 09 Jun 2009 Posts: 23
|
Wow Wow Wow |
Posted: Sat May 19, 2012 9:41 am |
|
|
@Ttelmah
First: Thanks a lot for your generous explanation and help. Thank god I do understand the address and the R/W bits now all because of your clear explanations.
Second: Yes, you are right, I have missed the pull up resistors.
From what I found on the net that they are used to determine the speed of the communication etc.. I will use 4.7k for them do you think that’s reasonable enough to just get me going?
Third: about the code you have written can you please explain it into more details as I am very interested in understanding it more than copying it
Especially the following parts (excuse my poor programming skills and understanding):-
What are you doing here and what do you mean by that?
Code: | int1 set_levels(int8 levels[]) {
//Structure the 'levels' array as sixteen values for the 16 lamps |
Does the acknowledgement need to be zero? Does it say that on the data sheet or it’s something common?
Code: | if (ack==1) {
I2c_STOP(); //device did not ACK
return FALSE; |
bit_test where did you define that?
Code: | if (bit_test(ictr,0)==0) { //first byte of pair |
How is that related to the code above the void main(void) !!?
Code: | int8 lamps[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//ensure all levels start as 0.
do {
lamps[0]=15; //First lamp to 'full on'
|
Sorry again for my poor understanding. I think you trying to control the brightness in one section and then control the ON/OFF in the main program am I right?
BTW: I have tried to compile your code and it keeps pointing towards the place under the void main(void) and says expecting a WHILE shall I just stick a while(1) loop there?
Sorry again about the inconvenience and thanks alot for help.
Best regards
Nizar |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1329
|
|
Posted: Sat May 19, 2012 1:04 pm |
|
|
You need to spend some time looking at the compiler manual. It answers a lot of your questions, such as bit_test() and the ack question |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9178 Location: Greensville,Ontario
|
|
Posted: Sat May 19, 2012 2:45 pm |
|
|
hint..
When you have your project open, press F11 to get the manual to magically open up !!
Keep it open to get instant access to all the stuff you need to know !! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 19, 2012 3:12 pm |
|
|
Quote: |
BTW: I have tried to compile your code and it keeps pointing towards the
place under the void main(void) and says expecting a WHILE shall I just
stick a while(1) loop there?
|
The code looks like this:
Look in a C language manual and see what keyword is supposed to
come after the closing brace. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19384
|
|
Posted: Sun May 20, 2012 3:52 am |
|
|
As I said, just typed in....
Manual will answer most questions (including what I have forgotten to put in on the penultimate line....).
Some comments though:
First thing. Visualise you are asked to do the accounts for a company with 10000 employees. I doubt if anybody would start with a single large 'ledger', and try to do the accounts in one 'lump'. Instead, they would do the accounts for (say) the front office, in one book, make sure these check and work out, do the same for a dozen other 'parts' of the company, and then take the results from these, and combine them to give the final result. Keeping the sections small enough, is a vital tool in a lot of things, and applies to software as much as this example. You should 'segment' your job. Thinking 'code to set the power levels on the lamps'. 'code to scan keyboard/serial', 'code to display results', etc. etc.. Each section can then be checked _on it's own_, with just a small 'test' program calling it. This is where subroutines and functions come in in coding.
Basically you need to look at a basic C book. Routines can either be declared 'in front' of where they are used, _or_ you can declare a 'prototype' (which tells the compiler what they are 'going' to contain), and then the physical routine can be declared later. I elected to use the former approach here.
The chip _does not_ have a command for 'on/off'. It controls 16 lamps, and allows you to set the level for each from '0' to '15'. Each of these numbers is coded as 4 bits in a byte, so it expects to receive 8 bytes to control the 16 lamps. A value of '0', turns a lamp 'off', while a value of '15', turns a lamp full 'on'. Values between give you different levels between this. So turning 'on/off', is done by setting the level to 0, or 15.
I wrote the function to accept 16 'lamp level numbers', each between 0, and 15 (inclusive), which it then converts into the eight bytes, and sends to the chip. Since the 16 values need to encode to eight bytes, the 'even', and 'odd' value have to be treated differently. The 'bit_test', is one way of telling if a number is even or odd.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
nizar445
Joined: 09 Jun 2009 Posts: 23
|
|
Posted: Sun May 20, 2012 5:46 am |
|
|
@jeremiah and temtronic
Thanks a lot for referring me to the C compiler manual, I haven’t seen it before.
@ PCM programmer
Found it thank you for the hint . |
|
![](templates/subSilver/images/spacer.gif) |
nizar445
Joined: 09 Jun 2009 Posts: 23
|
Thanks |
Posted: Sun May 20, 2012 5:47 am |
|
|
@Ttelmah
Thanks again for your help and clear explanations.
I do understand the main objective of the code you have written but the part that I don’t understand is that how is the function you have written “int1 set_levels(int8 levels[]) “ is called in the main program “void main(void) “.
Please be patient with me as programming is not my area.
Thanks again and again. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19384
|
|
Posted: Sun May 20, 2012 1:20 pm |
|
|
This really is basic 'C', and some reading should explain it.
In 'C', there are two ways of addressing 'lists' of things. An 'array', and a 'pointer'. The name of an array, is the pointer _to_ the array.
I declare a 16 number array (for the 16 lamps), and fill it with zeros (just so the unused lamps are turned 'off'). Then change the two values for the lamps we want to control (lamps[0], and lamps[15]), then hand the _pointer_ to the array to the subroutine. The subroutine is written so it 'knows' the pointer it receives, is to an array of integers, so uses these to build the bytes to send. It really is basic 'C 101' stuff, and you need to be able to understand this before you have any hope of writing meaningful code. Get a C primer.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|