|
|
View previous topic :: View next topic |
Author |
Message |
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
I2C problem? |
Posted: Sun Dec 15, 2013 10:26 pm |
|
|
Hi,
I'm using PIC18LF2520, CCS 4.114
My program goes more than 1500 lines. Thats the reason i cannot post the file.
i2c reads wrong value.
in my program,
timer0 interrupt
incrementing a variable for every 1ms
timer1 interrupt
displaying seven segment display using timer1 for every 250us
main loop,
using mcp3421, reading the adc value and formula used to display the value from 0 to 9999.
When i use 2Mhz oscillator, everything works good.
But when i change the oscillator to 4Mhz, display values are wrong. I have set the timer values for 4Mhz.
Why is it so? timer1 executes very fast. will it creates the problem?
I have already test a sample program in reading only adc value using mcp3421. It was working good with 4Mhz during that time.
Why it is creating problem now? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Dec 16, 2013 2:08 am |
|
|
You need to learn to debug.
Start by getting the I2C working without the 1500 lines of other code.
Once it is working add back the other stuff 'section by section'. After each section is added test if the I2C goes wrong. When it does, you have identified the part where the problem appears. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Dec 16, 2013 6:30 am |
|
|
hmm.... displaying seven segment display using timer1 for every 250us
comment: are you using 4, seven segment displays to show your data and you're 'mulitplexing' them using the PIC as the controller?
if so, as Mr. T say, cut simpler code. Just the 'display' section,that you said worked at 2MHz and edit to run at 4MHz.
a description of the hardware would be very helpful but if you're using LED 7SDs, I suspect a 'timing' issue between muxing and updating the displays.
hth
jay |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Mon Dec 16, 2013 9:10 pm |
|
|
Thanks Ttelmah & temtronic,
I debug the code using pickit3.
I comment 250us interrupt routine, & read the adc value. Values are perfect.
then, i uncomment the 250us interrupt routine, now the adc value varies. sometimes, it reads 0, some other value, sometimes correct value. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Dec 17, 2013 2:56 am |
|
|
OK.
I'd be looking at an update problem. Something reading/writing a variable that is updated in the interrupt, or used in the interrupt. Remember that any variable that is more than 8bits, could be half updated when the interrupt occurs, which then would give screwy results.....
Best Wishes |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sun Dec 22, 2013 9:38 pm |
|
|
thanks Ttelmah.
Interrupt occurs separately and displaying the value.
In the while loop only, i'm reading the adc value.
Then how to read 16 bit adc value without getting screwy results?
below is the function used to read adc value,
Code: | int16 get_adc()
{
int16 upper, lower, config, ans;
i2c_start ();
i2c_write (0xD0); // 1101 0000 -address byte write (SELECT ADDRESS A0 AND SET IN WRITE MODE) FOR MCP3421A0
i2c_write (0x88); // ADC Gain 1
i2c_stop();
i2c_start ();
i2c_write (0xD1); // 1101 0001 - CHANGE TO READ MODE (ADDRESS A0) FOR MCP3421A0
upper = i2c_read (1); // read slave data
lower = i2c_read (1); // read slave data
config = i2c_read (0); // read slave data
i2c_stop ();
ans =( upper * 256) + lower;
if(ans>32767 )
{
ans=0;
}
return ans;
} |
|
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Mon Dec 23, 2013 12:11 am |
|
|
You will have to supply more data.
1) How are your chip setup, Continious conversion, no of bits?
2) How long do you spend in your interrupt routine? Possibly post code for the int.
Regards |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Dec 23, 2013 2:11 am |
|
|
Yes.
'Occurs separately'. No it doesn't. If it is 'displaying the value', this has to come from somewhere.
Best Wishes |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Tue Dec 24, 2013 11:09 pm |
|
|
ADC value keeps on changing? below is the sample compiled code
Code: | #include "18F2520.h"
#fuses INTRC_IO
#use delay(clock = 4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#use fixed_io(b_outputs= PIN_B3,PIN_B4,PIN_B5)
#define Digit1 PIN_B3
#define Digit2 PIN_B4
#define Digit3 PIN_B5
#define Digit4 PIN_C0
const unsigned char CA_LED[37][8] = {
// 0 - indicates ON, 1 - indicates OFF
// a, b , c, d, e, f, g, dp
{0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xFF, 0x7F}, // 0
{0xFF, 0xFD, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // 1
{0xFE, 0xFD, 0xFF, 0xF7, 0xEF, 0xFF, 0xBF, 0x7F}, // 2
{0xFE, 0xFD, 0xFB, 0xF7, 0xFF, 0xFF, 0xBF, 0x7F}, // 3
{0xFF, 0xFD, 0xFB, 0xFF, 0xFF, 0xDF, 0xBF, 0x7F}, // 4
{0xFE, 0xFF, 0xFB, 0xF7, 0xFF, 0xDF, 0xBF, 0x7F}, // 5
{0xFE, 0xFF, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, // 6
{0xFE, 0xFD, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // 7
{0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, // 8
{0xFE, 0xFD, 0xFB, 0xFF, 0xFF, 0xDF, 0xBF, 0x7F}, // 9
{0xFE, 0xFD, 0xFB, 0xFF, 0xEF, 0xDF, 0xBF, 0x7F}, // A
{0xFF, 0xFF, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, // b
{0xFF, 0xFF, 0xFF, 0xF7, 0xEF, 0xFF, 0xBF, 0x7F}, // c
{0xFF, 0xFD, 0xFB, 0xF7, 0xEF, 0xFF, 0xBF, 0x7F}, // d
{0xFE, 0xFF, 0xFF, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, // E
{0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xBF, 0x7F}, // F
{0xFE, 0xFD, 0xFB, 0xF7, 0xFF, 0xDF, 0xBF, 0x7F}, // g
{0xFF, 0xFD, 0xFB, 0xFF, 0xEF, 0xDF, 0xBF, 0x7F}, // H
{0xFF, 0xFD, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // l
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // J wrong value
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // K wrong value
{0xFF, 0xFF, 0xFF, 0xF7, 0xEF, 0xDF, 0xFF, 0x7F}, // L
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // M wrong value
{0xFF, 0xFF, 0xFB, 0xFF, 0xEF, 0xFF, 0xBF, 0x7F}, // n
{0xFF, 0xFF, 0xFB, 0xF7, 0xEF, 0xFF, 0xBF, 0x7F}, // o
{0xFE, 0xFD, 0xFF, 0xFF, 0xEF, 0xDF, 0xBF, 0x7F}, // P
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // Q wrong value
{0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xBF, 0x7F}, // r
{0xFE, 0xFF, 0xFB, 0xF7, 0xFF, 0xDF, 0xBF, 0x7F}, // S
{0xFF, 0xFF, 0xFF, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, // t
{0xFF, 0xFF, 0xFB, 0xF7, 0xEF, 0xFF, 0xFF, 0x7F}, // u
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // v wrong value
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // w wrong value
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // x wrong value
{0xFF, 0xFD, 0xFB, 0xF7, 0xFF, 0xDF, 0xBF, 0x7F}, // y
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, // z wrong value
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F} // No character
};
unsigned int16 digits[4];
unsigned int current_digit = 0;
unsigned int SEGMENT = 0;
int16 adc_value;
unsigned int Decimal_point_value = 0;
int1 decimal_point;
void value_with_decimal();
int16 variable;
#INT_TIMER1
void timer1_isr()
{
if(interrupt_active(INT_TIMER1))
{
output_low(Digit4);
output_b(0x00);
output_a(0x00);
variable++;
switch(SEGMENT)
{
case 0: output_a(CA_LED[digits[current_digit]][0]);
break;
case 1: output_a(CA_LED[digits[current_digit]][1]);
break;
case 2: output_a(CA_LED[digits[current_digit]][2]);
break;
case 3: output_a(CA_LED[digits[current_digit]][3]);
break;
case 4: output_a(CA_LED[digits[current_digit]][4]);
break;
case 5: output_a(CA_LED[digits[current_digit]][5]);
break;
case 6: output_a(CA_LED[digits[current_digit]][6]);
break;
case 7:
if(decimal_point == 0)
{
output_a((CA_LED[digits[current_digit]][7]) | 0b11111111); // for no decimal point selection
break;
}
else if(decimal_point == 1) // For decimal point selection
{
output_a(CA_LED[digits[current_digit]][7]);
break;
}
};
if(SEGMENT++ == 8)
{
SEGMENT = 0;
current_digit++;
}
value_with_decimal();
if(current_digit > 3)
{
current_digit = 0;
}
set_timer1(0xFF05); // 250us
clear_interrupt(INT_TIMER1);
}
}
void timer1_init()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); // setup interrupts
set_timer1(0xFF05);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}
int16 get_adc()
{
int16 upper, lower, config, ans;
i2c_start ();
i2c_write (0xD0); // 1101 0000 -address byte write (SELECT ADDRESS A0 AND SET IN WRITE MODE) FOR MCP3421A0
i2c_write (0x88); // ADC Gain 1
i2c_stop();
i2c_start ();
i2c_write (0xD1); // 1101 0001 - CHANGE TO READ MODE (ADDRESS A0) FOR MCP3421A0
upper = i2c_read (1); // read slave data
lower = i2c_read (1); // read slave data
config = i2c_read (0); // read slave data
i2c_stop ();
ans =( upper * 256) + lower;
if(ans>32767 )
{
ans=0;
}
return ans;
}
void main()
{
set_Tris_a(0b00000000);
set_Tris_b(0b00000111);
output_low(Digit4);
output_b(0x00);
output_a(0x00);
setup_comparator (NC_NC_NC_NC);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
timer1_init(); // Timer1 Initialization
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
decimal_point_value = 0;
adc_value = get_adc();
while(1)
{
adc_value = get_adc();
digits[0] = (adc_value/1000)%10;
digits[1] = (adc_value/100)%10;
digits[2] = (adc_value/10)%10;
digits[3] = (adc_value%10);
variable = 0;
while(variable == 300);
}
}
void value_with_decimal()
{
if(decimal_point_value == 0) // No Decimal Point
{
if(current_digit == 0)
{
output_high(DIGIT1); output_low(DIGIT2);output_low(DIGIT3);output_low(DIGIT4);
decimal_point = 0;
}
if(current_digit == 1) // for digit 2
{
output_low(DIGIT1); output_high(DIGIT2);output_low(DIGIT3);output_low(DIGIT4);
decimal_point = 0;
}
if(current_digit == 2) // for digit 3
{
output_low(DIGIT1); output_low(DIGIT2);output_high(DIGIT3);output_low(DIGIT4);
decimal_point = 0;
}
if(current_digit == 3) // for digit 4
{
output_low(DIGIT1); output_low(DIGIT2);output_low(DIGIT3);output_high(DIGIT4);
decimal_point = 0;
}
}
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Dec 25, 2013 7:16 am |
|
|
comment: One thing I noticed is that you create a 16 bit adc value from the actual ADC chip (ans= 0 to 65536) but if >32767 you 0 it, so 32766 would be 'legal', yet your LED display can only display 0 to 9999. You're trying to display a 5 digit result on a 4 digit display.
For debugging purposes you should take the ADC result and send it to a PC using a serial link. That will show whether the 'bad reading' is actually an analog problem (noise, wiring, etc.) or digital (logic or code).
hth
jay |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Dec 25, 2013 11:03 am |
|
|
comment: I've downloaded the MCP3421 datasheet and it appears you've got it configured for 16bit mode so data should be -32767 to 32767.
Still 32767 won't fit into 9999 unless I'm misreading something here.
Also 1 bit is 62uV ! Put a scope on the analog line and see how much NOISE you have, as well as the power supply lines. It is CRITICAL that proper anaolg PCB layouts are done, shielding, etc.
Again, dump the raw ADC data to a PC in terminal mode to see what the data is. Either you've got 'bad data' or 'bad conversion' of good data to the display.
hth
jay |
|
|
|
|
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
|