View previous topic :: View next topic |
Author |
Message |
Ringo42
Joined: 07 May 2004 Posts: 263
|
Code weirdness |
Posted: Sun Apr 26, 2009 1:26 pm |
|
|
I'm using a 16F876A and ccs 3.249 (tried it with 4.007 also)
I'm reading an I2C temp sensor and displaying the value on some 7-segment leds. If I read the sensor and display it directly then it is fine. IF I convert the reading from C to F then I get a wrong reading, even if I Display the original variable.
So If I use the first DisplayNumber below it is ok, but If I comment that line out and use one of the other ones below I always get a 30. It is not the match because displaying Tempnumber there still gives a 30. What am I missing here.
Code: |
tempnumber=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
// DisplayNumber(tempnumber);//this works perfectly, I get a 22 or 23C reading
TC=tempnumber;
tempnumber2=tempnumber;
TF=(tempnumber * 1.8) +32;
DisplayNumber(tempnumber); //This always outputs a 30.
// DisplayNumber(TF);//This always outputs a 30.
// DisplayNumber(tempnumber2);//This always outputs a 30.
// DisplayNumber(TC);//This always outputs a 30.
|
Complete code
Code: | //#include "18f2221.h"
#include "16f876a.h"
#fuses hs,nowdt,noprotect,put,nolvp
#device *=16
#device adc=10
#use delay(clock=20000000)
//#priority ext
#include "stdlib.h"
#use I2C(master, sda=PIN_c4, scl=PIN_c3,slow)
//#define BAUD_RATE 115200 //19200
//#define BAUD_RATE 19200
#define thermoC PIN_A0
#define local_temp PIN_A1
#define SW1 PIN_B4//high limit left
#define SW2 PIN_B5//high limit right
#define SW3 PIN_B6//low limit left
#define SW4 PIN_B7//low limit right
#define DIG0 PIN_C1
#define DIG1 PIN_C5
#define DIG2 PIN_C6
#define DIG3 PIN_C7
#define DIG4 PIN_B0
#define RELAY PIN_C5
//#define LED2_PIN PIN_C6
//#define LED1_PIN PIN_C7
#define A PIN_B5
#define B PIN_B4
#define C PIN_B3
#define D PIN_B2
#define E PIN_B1
#define F PIN_B6
#define G PIN_B7
#define Relay_off output_low(RELAY)
#define Relay_on output_High(RELAY)
//#define one 0x18 //0x18 is sent to port B to turn on correct segments to show a "one"
#define one 0xE7 //0x18 is sent to port B to turn on correct segments to show a "one"
#define two 0x49 //0xB6 //0xB6 is sent to port B to turn on correct segments to show a "two"
#define three 0x43//0xBC
#define four 0x27//0xD8
#define five 0x13//0xEC
#define six 0x31//0xCE
#define seven 0xc7//0x38
#define eight 0x01//0xFE
#define nine 0x07//0xF8
#define zero 0x81//0x7E
#define CEE 0x79//0x86 //0x86 is sent to port B to turn on correct segments to show a "C" for celcius
#define EFF 0x1d//0xE2 //0xE2 is sent to port B to turn on correct segments to show a "f" for Fahrenheit
#define H 0x25
#define L 0xB9
int digits[10]={zero,one,two,three,four,five,six,seven,eight,nine};
#byte port_b = 0xF81
int HighLimit, LowLimit;
int _HighLimit, _LowLimit;
int function=0; //0 = F, 1=C, 2=H, 3=L
//long int heartbeat_counter=0;
void itos(char s[],signed int n);
void BlinkLeds (void);
void toggle_led();
void init_PIC();
void heartbeat();
int ReadTempI2C(int ADDRESS);
void DisplayNumber(int Num);
void CheckPots();
/*****************************************************
void main() --
*****************************************************/
void main()
{
int i;
// int timeon=3;
//long int j;
// int testnum=0;
int Mynumber;
int Tc;
int Tf;
int tempnumber;
int tempnumber2;
init_PIC();
Relay_off;
set_tris_b(0); // all outputs
port_B=0xff;// all high
output_b(0xff);
//turn off all segments
output_high(dig1);
output_high(dig2);
output_high(dig3);
output_high(dig0);
while (1)
{
// set_adc_channel( 1 );
// delay_ms(1);
// HighLimit = Read_ADC();
// set_adc_channel( 2 );
// delay_ms(1);
// LowLimit = Read_ADC();
// CheckPots();
// get reading frm I2C bus
// number=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
// DisplayNumber(number);
tempnumber=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
// DisplayNumber(tempnumber);
TC=tempnumber;
tempnumber2=tempnumber;
TF=(tempnumber * 1.8) +32;
DisplayNumber(tempnumber);
// DisplayNumber(TF);
// DisplayNumber(tempnumber2);
// DisplayNumber(TC);
// for(i=0;i<20;i++)
// {
// function=1; //display C
// mynumber=TC;//celcius
// if(i<10)
// {
// function=1; //Display F
// mynumber=TC;//farenheight
// }
// DisplayNumber(mynumber);
// }
// if(TF >= HighLimit)
// Relay_on;
// if(TF <= LowLimit)
// Relay_off;
}//end while
}//end main
void DisplayNumber(int Num)
{
int number,ones,tens,hundreds;
long int j;
int timeon=3;
hundreds=number/100;
tens=(number-(hundreds*100))/10;
ones=(number-(hundreds*100)-(tens*10));
for(j=0;j<50;j++)
{
output_b(digits[ones]|0);
output_low(dig2);//turn on segment 1
delay_ms(timeon);
output_high(dig2);//turn off segment 1
output_low(dig3);//turn on segment 2
output_b(digits[tens]|0);
delay_ms(timeon);
output_high(dig3);//turn off segment 1
if(hundreds >0)
{
output_b(digits[hundreds]|0);
output_low(dig4);//turn on segment 1
delay_ms(timeon);
output_high(dig4);//turn off segment 1
}
output_low(dig1);//turn on segment 2
if(function==0)
output_b(eff);
if(function==1)
output_b(CEE);
if(function==2)
output_b(H);
if(function==3)
output_b(L);
delay_ms(timeon);
output_high(dig1);//turn off segment 1
// if(hundreds >0)
// port_b=port_b | digits[hundreds];/
// else
// port_b=port_b | 0;
// output_low(dig0);//turn on segment 1
// port_b=port_b & 0x1; // set all off but digit
// port_b=port_b | eff;
// delay_ms(1);
// output_high(dig0);//turn off segment 1
}
}
void CheckPots()
{
set_adc_channel( 1 );
delay_ms(1);
HighLimit = Read_ADC(); //0-1024
HighLimit /= 5; //0-204 F
set_adc_channel( 2 );
delay_ms(1);
LowLimit = Read_ADC();
LowLimit /= 5; //0-204 F
if (HighLimit != _HighLimit)
{
function=2;
DisplayNumber(HighLimit);
}
if (LowLimit != _LowLimit)
{
function=3;
DisplayNumber(LowLimit);
}
_HighLimit = HighLimit;
_LowLimit = LowLimit;
}
int ReadTempI2C(int ADDRESS)
{
int ValueH=0;
int ValueL=0;
i2c_start(); // restart condition
i2c_write(ADDRESS + 1);
valueH = i2c_read(1);
valueL = i2c_read(0);
i2c_stop();
return(ValueH);
}
/***************************************************
void init_PIC() -- Initializes variables
***************************************************/
void init_PIC()
{
// int i;
//short int dummy_variable;
setup_adc_ports(All_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
setup_spi(FALSE);
//setup_psp(PSP_DISABLED);
//enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
//output_low(PIN_A0);
//output_low(PIN_A1);
output_low(PIN_A2);
output_low(PIN_A3);
output_high(PIN_A4);
output_low(PIN_A5);
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B5);
output_low(PIN_B6);
output_low(PIN_B7);
output_low(PIN_C0);
//output_low(PIN_C1);
//output_low(PIN_C2);
output_low(PIN_C3);
output_low(PIN_C4);
output_low(PIN_C5);
output_low(PIN_C6);
//output_low(PIN_C7);RX
}
/************************************************
void BlinkLeds (void)
*************************************************/
void BlinkLeds (void)
{
// int i;
// for(i=0;i<10;i++)
// {
// LED1_ON;
// LED2_Off;
// delay_ms(150);
// LED1_OFF;
// LED2_On;
// delay_ms(150);
// }
}
/************************************************
void heartbeat()
************************************************/
void heartbeat()
{
// heartbeat_counter++;
// if (heartbeat_counter >= 100)
// {
// heartbeat_counter=0;
// toggle_led();
// }
}
/************************************************
toggle_led()
***********************************************/
void toggle_led()
{
// static short Toggle=0;
// Toggle=1-Toggle;
// if ( Toggle==1)
// {
// LED1_on;
// }
// else LED1_OFF;
// return;
}
|
_________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Sun Apr 26, 2009 1:28 pm |
|
|
Quote: | It is not the match |
Should be
It is not a math thing _________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Sun Apr 26, 2009 1:40 pm |
|
|
The Line
TF=(tempnumber * 1.8) +32;
is definitey the problem. Without this line then I can display TempNumber, or Tc without a problem. Adding that line somehow screws up the other variables. I also tried
TF=((tempnumber * 1.8) +32);
just in case but extra () did not help.
I'm using 9% of Rom and RAM so that is not an issue.
Anybody have any ideas here?
Thanks
Ringo _________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Apr 26, 2009 1:47 pm |
|
|
Make two test programs.
1. Make a test program to check your display routine. Count up from
00 to 99 (or whatever the max limit of your display is) with a for() loop.
Put a half second delay after you display each number, so it's long
enough for you to see it. Verify that your display routine works.
2. Make a test program to check your C to F conversion routine.
Make a for() loop and have it count through the expected range of C
values, and display the F results in a terminal window on your PC.
(Not with the 7-segment display). Verify that the F values are correct.
If both of these tests work OK, then the problem is likely in the interface
between the two routines. In other words, it's in the passing of the
variables between the two routines.
Don't use PCH vs. 4.007. It can't possibly be reliable. |
|
![](templates/subSilver/images/spacer.gif) |
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Sun Apr 26, 2009 2:08 pm |
|
|
I've got a routine to test the display and it works fine.
I can reduce the problem down to this
This works fine
tempnumber=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
TC=tempnumber;
// TF=(tempnumber * 1.8) +32;
DisplayNumber(TC);
This does not
tempnumber=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
TC=tempnumber;
TF=(tempnumber * 1.8) +32;
DisplayNumber(TC);
Notice I'm not even using TF, just doing the conversion screws up TC.
How can I figure this out?
If I warm up the sensor, without the conversion it goes 22,23,24,etc.
With the conversion in place it goes 30,37,44,52 (difference of 7,7,9)
This is still without even using TF. TC gets these new weird values.
Ringo _________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Apr 26, 2009 2:12 pm |
|
|
Use a printf statement to a terminal window to trouble-shoot the
conversion. I don't have any suggestions beyond that. |
|
![](templates/subSilver/images/spacer.gif) |
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Sun Apr 26, 2009 3:28 pm |
|
|
1 more thing, Now it acts like it is not getting re-programmed.
I changed the code to always to display the same number like this
tempnumber=ReadTempI2C(144);// address of MCP9801 ranges from 144 to 160
TC=tempnumber;
TC=99;
DisplayNumber(TC);
But it is still displaying to temp in C, Touching the sensor raises the temp a degree or 2 so it really is working, and ignoring the 99 thing. It programs and verifies which is the weird part. So either the compiler is ignoring the 99 line, or the pic is not really getting programmed. has anybody ever seen anything like this?
Ringo _________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Apr 26, 2009 3:54 pm |
|
|
Code: | void DisplayNumber(int Num) | The variable Num is never used in DisplayNumber. So whatever value you pass to DisplayNumber, it doesn't matter... ![Cool](images/smiles/icon_cool.gif) |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Apr 26, 2009 3:57 pm |
|
|
One of the points no clear from your post is, if you also tried the C/F conversion in a minimal application, without the sensor control and the display routine? If the problem still persists, then it's proven related to the said conversion.
I just saw, that the conversion expression works well - standalone and compiled with a recent PCM version.
P.S.: Quote: | The variable Num is never used in DisplayNumber | Something similar could be expected. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Apr 26, 2009 4:00 pm |
|
|
Quote: |
The variable Num is never used in DisplayNumber. So whatever value
you pass to DisplayNumber, it doesn't matter... |
That means that this statement was in error:
Quote: | I've got a routine to test the display and it works fine. |
This means I am proven right.
My "strict regime" of testing would have found this problem (if followed). |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Apr 26, 2009 4:10 pm |
|
|
Quote: | That means that this statement was in error | Could be determined, if we see the test. There is a certain chance to produce a false positive result by accidentally getting the source variable overlaid with the unconnected subroutine variable. But systematic test is the right way though. |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Apr 26, 2009 4:17 pm |
|
|
Just a few other notes on the code:
- Next time post a small as possible program demonstrating your problem, it will get you more, quicker and better responses. The program as posted has 81 lines with code commented out...
- Don't start variable names with an '_' character. Somewhere in the C standards it is described that these variable names are reserved for compiler internal usage only.
- port_b for a PIC16 is not located at 0xF81.
- The CCS compiler by default handles the TRIS register settings for you, unless you set the #use fast_io directive. You don't have this directive set so you might corrupt the compiler's TRIS management and at least are generating extra code. I suggest you remove all TRIS related code.
- The function toggle_led can be replaced by the more efficient CCS function output_toggle. |
|
![](templates/subSilver/images/spacer.gif) |
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Mon Apr 27, 2009 10:55 am |
|
|
I found the problem.
In DisplayNumber I'm passing in Num but using Number in the calculations. Number was never initialized to anything.
The weird part is I put a test at the top of the code, just a for loop to count from 1 to 255 and it works.
The other code worked unless I did the C to F conversion, so I'm assuming what was happening was the number in the for loop, or the C value was either in the Working register, or on the stack or something and the un-initialized "number" picked up that value. However doing the conversion screwed that up. I would have thought "number" would always be a random value, but in this case it almost worked. Of course the day after I called the project done it probably would have started being random :-)
Thanks
Ringo _________________ Ringo Davis |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Apr 27, 2009 4:43 pm |
|
|
Ringo42 wrote: | I found the problem.
In DisplayNumber I'm passing in Num but using Number in the calculations. Number was never initialized to anything. |
Eh, yes. That's what I said too.
Ringo42 wrote: | The weird part is I put a test at the top of the code, just a for loop to count from 1 to 255 and it works.
The other code worked unless I did the C to F conversion, so I'm assuming what was happening was the number in the for loop, or the C value was either in the Working register, or on the stack or something and the un-initialized "number" picked up that value. | The same conclusion as FvM.
Glad to hear your problem is solved. |
|
![](templates/subSilver/images/spacer.gif) |
|