View previous topic :: View next topic |
Author |
Message |
JPH
Joined: 02 Feb 2005 Posts: 9 Location: Finland
|
Strange problem with printf() |
Posted: Tue Feb 28, 2006 2:40 pm |
|
|
Hey
I have PCH 3.242 compiler and PIC18F6722@32MHz.I have strange problem with printf() when I read data from the Sensirion SHT15 sensor. It works's right when I have uncommented one of the printf() lines in the end of the CASE 3. But when all printf() lines are commented and I try to read temp and humi inside the program, values are off the scale. When I put the program to print out temp or humi, then the function works like it should be I can read right values to other function.
So question is where should I start to look the problem?
Code: |
////////////////////////////////////////////////////////////////////////////////
execute(int8 number)
{
switch(number)
{
case 0:
{
sht1x_connection_reset();
sht1x_command_mode(MEASURE_TEMP);
set_timer0(58660); //220ms
state++;
}
break;
case 1:
{
lValue_temp = sht1x_read_data();
fTemp_true = (D1+(D2*lValue_temp));
set_timer0(65224); //10ms
state++;
}
break;
case 2:
{
sht1x_connection_reset();
sht1x_command_mode(MEASURE_HUMI);
set_timer0(63503); //65ms
state++;
}
break;
case 3:
{
clear_interrupt(int_timer0);
disable_interrupts(int_timer0);
lValue_rh = sht1x_read_data();
fRh_lin = (C1+(C2*lValue_rh)+(C3*lValue_rh*lValue_rh));
fRh_true = (((fTemp_true-25)*(T1+(T2*lValue_rh)))+fRh_lin);
fDew_point = sht1x_calc_dewpoint(fRh_true,fTemp_true);
//printf("\nRelative Humidity: %3.4f%%",fRh_true);
//printf("\nDew Point: %3.4fC",fDew_point);
printf("\nTemperature: %3.4fC",fTemp_true);
}
break;
default:
{
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void read_temp_humi(void)
{
set_timer0(65000);
state=0;
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#INT_TIMER0
int_timer0_isr()
{
execute(state);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
main()
{
SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_256);
while(1)
{
if(!input(PIN_F1))
{
read_temp_humi();
}
}
}
////////////////////////////////////////////////////////////////////////////////
|
Cheers
Jussi |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 28, 2006 3:21 pm |
|
|
It takes time to send characters with the UART. It also takes time
for the floating point printf routines to execute. At 9600 baud, it takes
about 1 ms to transmit a character.
So I would guess that just one of your printf statements is at least
the equivalent of this statement:
That may give you a clue regarding the source of the problem. |
|
|
JPH
Joined: 02 Feb 2005 Posts: 9 Location: Finland
|
|
Posted: Wed Mar 01, 2006 2:02 pm |
|
|
Thanks for the fast reply. I debugged and tested function with different interrupt times and I still didn't get it work without using at least one printf(). How should I fix the problem?
Code: |
execute(int8 number)
{
switch(number)
{
case 0:
{
sht1x_connection_reset();
sht1x_command_mode(MEASURE_TEMP);
set_timer0(58660); //220ms
state++;
}
break;
case 1:
{
lValue_temp = sht1x_read_data();
fTemp_true = (D1+(D2*lValue_temp));
set_timer0(65224); //10ms
state++;
}
break;
case 2:
{
sht1x_connection_reset();
sht1x_command_mode(MEASURE_HUMI);
set_timer0(20000); //1.4s
state++;
}
break;
case 3:
{
lValue_rh = sht1x_read_data();
fRh_lin = (C1+(C2*lValue_rh)+(C3*lValue_rh*lValue_rh));
fRh_true = (((fTemp_true-25)*(T1+(T2*lValue_rh)))+fRh_lin);
fDew_point = sht1x_calc_dewpoint(fRh_true,fTemp_true);
set_timer0(20000); //1.4s
state++;
//printf("\nRelative Humidity: %3.4f%%",fRh_true);
//printf("\nDew Point: %3.4fC",fDew_point);
//printf("\nTemperature: %3.4fC",fTemp_true);
}
break;
case 4:
{
clear_interrupt(int_timer0);
disable_interrupts(int_timer0);
}
break;
default:
{
}
break;
}
}
|
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed Mar 01, 2006 3:31 pm |
|
|
Your problem might not be with the printf() command. I've worked with this sensor quite a bit and you need to allow the sensor to do it's thing once you give it a read() command. The sensor is not quite I2C compatible so you need to bit_bang communications to it.
Once you have sent a read() command to the sensor it will hold the SDA line High until it's finished it's measurement. Monitoring this line will allow you to know when to clock the result out of it. You can put a specified delay time if you want but, to reduce down time, simply monitor when the SDA line goes low to clock the data out.
Here's a small section of code that I have used that works quite well. The SDA line is assigned to the variable XSDA. Send_sense() and read_sense() are simply bit_bang routines. Calc_rh() and calc_temp() are routines to convert the values that are read to displayable values.
Code: |
if(sensor)// time to read the sensor
{
switch(status)
{
CASE 1:
if(send_sense(0x03))// send command to read the Temperature and test if it ACK'd
{
status = 0;// if this is entered, the sensor did NOT ACK and we stop trying to
sensor = 0;// talk to the sensor until the next time we want to read it
}
else
{
status = 2;// if the sensor ACK'd, increment the status var
}
break;
CASE 2:
if(!input(XSDA))// we need to wait until the sensor is finished
{ // making it's measurement before we try to get
stemp = read_sense(); // the data from it
status = 3;
}
break;
CASE 3:
if(!send_sense(0x05))// this is the read command for the RH
{
status = 4;
}
break;
CASE 4:
if(!input(XSDA))// we need to wait for the same thing as the temp
{
shumid = read_sense();
status = 5;
}
break;
CASE 5:
if((!stemp && !shumid) || (stemp > 0x3FFF || shumid > 0xFFF))
{ // if the sensor has
if(pwr++ > 10) // wigged out, cycle the power to it
{
puked = 1;
}
cycle_power();
}
else
{
TEMP = calc_temp(stemp);
HUMI = calc_rh(shumid);
pwr = 0;
}
status = 6;
break;
CASE 6:
if(!send_sense(0x07));// this sends the command to address the Sesor's
{ // Status Register
status = 7;
}
break;
CASE 7:
if(!input(XSDA))// we need to wait until the sensor is ready to
{ // send the data
r_stat = read_status();
if((r_stat & 0x40) == 0x40)// mask out unwanted bits
{
if(eol_status++ > 9)// test the End of Life bit from the sensor and
{ // if it is set for 9 straight tests...
eol_done = 1; // set the End of Life status bit
}
}
else
{
eol_status = 0;
eol_done = 0;
}
status = 0;// reset these flags for the next use
sensor = 0;
}
break;
default:
break;
}// end of switch()
}// end of if(sensor)
|
This code is placed inside of main() and a timer sets a flag 'sensor' whenever a measurement needs to be made. Since it's inside of main() each Case is tested every scan and there is very little down time waiting for any delay.
Clear as mud?
Ronald |
|
|
|