|
|
View previous topic :: View next topic |
Author |
Message |
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
sprintf/fprintf behaviour |
Posted: Wed Jun 29, 2016 6:04 am |
|
|
Hi,
Yet another problem going from v3 to v5 compiler (5.056d)! It worked fine before!
18LF2620 at 10MHz
In this test program, you will see from the comments that the output to the LCD117 display is correct if I use fprintf on its own, but wrong if I assemble the data first, using sprintf and then fprintf it! I am at a loss to see why.
Code: |
#include <TestLCD.h>
#include <DS3232.c>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void main()
{
char temp[14];
float value;
char LCDline0[21];
char const dayOfWeek[8][4] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};//days of week, 0 = Sun
byte year, month, day, dow, hour, minute, second;
//LBV on AN0, LBI on AN1, Aquaroll on AN2, O/B tank on AN3
setup_adc_ports(AN0_TO_AN3|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL|ADC_TAD_MUL_8);
setup_spi(false);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(false);
setup_low_volt_detect(false);
DS3232init();
//setup serial LCD
fputs("?S0", lcd); //no display screen on boot
fputs("?f", lcd); //clear lcd
fputs("?G420", lcd); //4x20 LCD
fputs("?c0", lcd); //no cursor
fputs("?BFF", lcd); //display at full brightness
delay_ms(100);
//define Euro symbol for LCD
fputs("?D003041E081E040300", lcd);
//define Pound symbol for LCD
fputs("?D10609081E08081F00", lcd);
//define ßeta symbol for LCD
fputs("?D20C12121412111116", lcd);
fputs("?f", lcd); //clear lcd
delay_ms(200);
fputs("Caravan monitoring?nunit, version 5.00?n(c) 2016 B.L. Lonnon", lcd);
delay_ms(2700);
fputs("?f", lcd); //clear lcd
delay_ms(200);
for(;;)
{
//read the RTC
DS3232getDate(dow, day, month, year);
DS3232getTime(hour, minute, second);
//using sprintf and then writing to the LCD misses out the day (eg. Wed),
//replacing it with a single space!
sprintf(LCDline0, "%s %02u/%02u/%02u %02u:%02u ", dayOfWeek[dow], day, month, year, hour, minute);
fputs("?f", lcd); //clear lcd
delay_ms(200);
fprintf(lcd, "?y0?x00%s", LCDline0);
//using this instead works as it should - WHY the difference?
//fprintf(lcd, "?y0?x00%s %02u/%02u/%02u %02u:%02u ",
//dayOfWeek[dow], day, month, year, hour, minute);
delay_ms(500);
}
}
|
Brian |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Wed Jun 29, 2016 8:45 am |
|
|
When it works using just fprintf, what does an example output on the LCD look like (exactly...counting chars here)? |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
sprintf etc |
Posted: Wed Jun 29, 2016 10:21 am |
|
|
Hi, Thanks for the reply.
The top and currently only line is:
Wed 29/06/16 17:20
When using sprintf and fprintf, it becomes
29/06/16 17:20
Where I have shown spaces, these are as on the display.
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2016 12:24 pm |
|
|
Trouble-shoot it. Experiment. Print the buffer to a serial terminal
such as TeraTerm, instead of your LCD. Is the day-of-week still missing ?
For example, using this stripped down test program in MPLAB vs. 8.92
simulator, with PCH vs. 5.059 (will test with 5.056 later), it works fine.
I get this in the MPLAB output window:
Quote: | ?y0?x00 Wed 29/06/16 05:41
?y0?x00 Wed 29/06/16 05:41 |
Note that this is a true test program. It has the #include for the PIC,
#fuses, #use delay, #use rs232, all variable declarations, and can be
dropped into MPLAB and will compile.
Code: | #include <18F2620.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS, stream=lcd)
//=====================================
void main()
{
char LCDline0[21];
char const dayOfWeek[8][4] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};//days of week, 0 = Sun
int8 year, month, day, dow, hour, minute, second;
dow = 3;
day = 29;
month = 6;
year = 16;
hour = 05;
minute = 41;
second = 10;
//using sprintf and then writing to the LCD misses out the day (eg. Wed),
//replacing it with a single space!
sprintf(LCDline0, "%s %02u/%02u/%02u %02u:%02u ", dayOfWeek[dow], day, month, year, hour, minute);
fprintf(lcd, "?y0?x00 %s", LCDline0);
fprintf(lcd, "\n\r");
//using this instead works as it should - WHY the difference?
fprintf(lcd, "?y0?x00 %s %02u/%02u/%02u %02u:%02u ", dayOfWeek[dow], day, month, year, hour, minute);
} |
Also, the day-of-week array doesn't have to be [8][4]. It can be [7][4].
It has only 7 rows of data, not 8. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
sprintf etc |
Posted: Wed Jun 29, 2016 3:06 pm |
|
|
Hi, Thanks for the reply.
I have, this evening, fed the display data to putty and the output of the first line is now OK. I then added code for the second line, which displays voltage, current and power from a CS5490 electricity meter chip.
It should read, for example:
229V @ 11.3A = 2.6kW
Both the LCD and putty show:
22911.32.6kW
so the figures are right, but V and A are missing, but the W is there!
The line sending these values is:
Code: |
fprintf(lcd, "?y1?x00%luV @ %2.1fA = %1.1fkW", VAC, IAC, PAC);
|
(VAC, IAC & PAC are floats)
Fine on the array - that's how it was - changed in desperation!
I have been on this all day and am now befuddled! Tomorrow's another day!
Thanks
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2016 11:03 pm |
|
|
I tested it with PCH vs. 5.056 (not the 'd' version) with TeraTerm and
at first I was getting garbage characters in the first part of the line.
So I did the following:
1. I removed your serial LCD commands from the printf - no effect.
2. I added a 100 ms delay at the start of main() - no effect.
3. I checked TeraTerm setup and Device manager for Com ports in
Windows, thinking that Flow Control was possibly left enabled. But it was not.
4. I noticed in Device Manager that Fifo Buffers were turned off. I thought
what the heck, let's enable them. Then it worked. It displays the
following with no garbage characters in front. This is with Windows XP.
Quote: | 123V @ 4.5A = 7.8kW |
Test program:
Code: |
#include <18F2620.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS, stream=lcd)
//=====================================
void main()
{
float IAC, PAC;
int16 VAC;
delay_ms(100);
VAC = 123;
IAC = 4.56;
PAC = 7.89;
fprintf(lcd, "%luV @ %2.1fA = %1.1fkW", VAC, IAC, PAC);
fprintf(lcd, "\r");
while(1);
}
|
If it still doesn't work for you, post your test program. Not code snippets.
A test program has the #include for the PIC, #fuses, #use delay(), all
variable declarations and #define statements, and a short main().
It must compile with no errors.
Also post your version of Windows. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Thu Jun 30, 2016 1:27 am |
|
|
That type of display problem was common on early PC's, which didn't have the FIFO. Though a PC is 'fast', is unfortunately very cumbersome at handling things like serial interrupts. This was 'why' the bigger buffers were introduced....
I can understand TeraTerm disabling them though. For some types of operation (like boot-loading), with software serial flow control, the buffers can cause problems.
However the 'terminal' display on a lot of systems is very slow to write to. I must admit 'surprised' to see this at 9600bps, but this sort of problem is why having something like a little serial line monitor is so useful. Would have shown that the data is being sent correctly, but that the display could not keep up!...
What is happening, is that if the data is assembled in advance, the PIC is outputting it 'non stop'. The compiler has got more efficient at this, and the bytes will be being loaded as soon as the transmit buffer goes empty, so the serial stream will be 'flat out'. So twenty characters in probably about 21mSec You'll probably find that printed 'live', there are a few uSec pause between each character. Just enough time to allow the PC to handle the data. ... |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
fprintf etc |
Posted: Thu Jun 30, 2016 4:52 am |
|
|
Thanks for your reply. Whereas I appreciate what you say, I am reading data perfectly at 9600 from the PIC to my PC and Raspberry Pi.
The display worked perfectly on the v3 compiler. It is only since trying to move to this v5 compiler that things have stopped working properly!
I will post my test program although I will have to include all the code for the CS5490 for it to be a fair test.
I wonder if increasing the clock speed might help as well?
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 30, 2016 5:00 am |
|
|
You most recently say it works fine on the PC:
Quote: |
Whereas I appreciate what you say, I am reading data perfectly at 9600
from the PIC to my PC and Raspberry Pi. |
But in a earlier post, you said it doesn't work:
Quote: | I have, this evening, fed the display data to putty and the output of the first line is now OK. I then added code for the second line, which displays voltage, current and power from a CS5490 electricity meter chip.
It should read, for example:
229V @ 11.3A = 2.6kW
Both the LCD and putty show:
22911.32.6kW
so the figures are right, but V and A are missing, but the W is there! |
So what is the truth ? I assume feeding data to Putty means Putty is
running on your PC. So is it working or is it failing ?
I am up a little early today and have to leave, but I wanted to get in this
question. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
sprintf etc |
Posted: Thu Jun 30, 2016 6:01 am |
|
|
Yes, putty is on the PC. As I said, it was wrong on BOTH the LCD and putty.
However, this morning, having touched nothing, both lines 0 and 1 are reading correctly on the LCD! I know not why!
I shall now continue to add functionality from the main program to the test program, a step at a time and see if I get further problems.
Thanks to all who have replied with help - I much appreciate it.
Brian |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Thu Jun 30, 2016 6:26 am |
|
|
and, as I said: "The compiler has got more efficient at this". A string printf, will now not have even a one bit gap between the bytes. On older compilers, there were slightly more delays....
So it could be that you have a borderline timing issue. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
fprintf etc |
Posted: Thu Jun 30, 2016 9:55 am |
|
|
Hi, If I have a borderline timing issue, how the heck do I sort it?
Matters have now got worse as I have added the first isr. This has completely cocked up the LCD! I am at my wits end. Even if the isr is empty, things go awry. What can I try to get this to work? Otherwise, v5 goes in the bin and it's back to 3.248 where at least I had a fully functioning program!
TestLCD.h:
Code: |
#include <18LF2620.h>
#device *=16 ADC=10 HIGH_INTS=TRUE
#FUSES EBTRB //memory protected from table reads
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4MHz)
#FUSES PROTECT //Code protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //Data EEPROM Code not protected
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES WRT //Program memory write protected
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOPBADEN //PORTB pins are not configured as analog input channels on RESET
#FUSES NOWRTC //configuration registers are not write protected
#FUSES WRTB //Boot block write protected
#FUSES CPB //Boot Block code protection
#FUSES MCLR //Master Clear pin enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(crystal=10MHz)
//LCD117 (SMT version runs at 19K2)
#use rs232(baud=19200,xmit=PIN_C6,stream=lcd)
//CS5490
#use rs232(baud=9600,xmit=PIN_C0,rcv=PIN_C1,ERRORS,stream=cs5490fast)
#use rs232(baud=600,xmit=PIN_C0,rcv=PIN_C1,ERRORS,stream=cs5490slow)
|
TestLCD.c
Code: |
#include <TestLCD.h>
#include <DS3232.c>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <internal_eeprom.c>
#define SLOW 0
#define FAST 1
#define Send_to_5490(x) if(baud == SLOW) fputc(x, cs5490slow);\
else fputc(x, cs5490fast)
void CS5490Init();
void write_register(int32 value, int8 page, int8 regnum);
int32 read_register(int8 page, int8 regnum);
int8 from_chip();
float round(float);
char VAW[18]; //holds V, I & W, ready for sending
int8 pulse = 0;
//used today in Wh
int16 used_today;
int1 baud = SLOW;
float value;
//if this function is remmed out, the LCD is fine but with it,
//even if it is empty, it completely ruins the LCD!
//reads meter pulses (each pulse is 1 Watt-hour)
#int_ext HIGH //RB0 interrupt
void ext_isr()
{
pulse++;
}
//---------------------------------------------------------------------------
void main()
{
char const dayOfWeek[8][4] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};//days of week, 0 = Sun
//used for quot & remd of used_today;
ldiv_t lidiv;
byte year, month, day, dow, hour, minute, second;
int32 VAC = 0, value = 0;
float IAC = 0, PAC = 0;
pulse = 0;
setup_spi(false);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(false);
setup_low_volt_detect(false);
//pulse edge for EPG (RB0) (pulses from CS5490)
ext_int_edge(H_TO_L);
//if restarted during the day, load Wh used so far
//used_today = (1000 * read_int16_eeprom(0)) + (10 * read_int16_eeprom(2));
//line above temporarily replaced as after programming, don't know what eeprom
//"data" will be present!
write_int16_eeprom(0, 0L);
write_int16_eeprom(2, 0L);
DS3232init();
delay_ms(300);
//setup serial LCD
fputs("?S0", lcd); //no display screen on boot
fputs("?f", lcd); //clear lcd
fputs("?G420", lcd); //4x20 LCD
fputs("?c0", lcd); //no cursor
fputs("?BFF", lcd); //display at full brightness
delay_ms(300);
//define Euro symbol for LCD
fputs("?D003041E081E040300", lcd);
//define Pound symbol for LCD
fputs("?D10609081E08081F00", lcd);
//define ßeta symbol for LCD
fputs("?D20C12121412111116", lcd);
fputs("?f", lcd); //clear lcd
delay_ms(300);
fputs("?y0?x00Caravan monitoring", lcd);
fputs("?y1?x00unit, version 5.00", lcd);
fputs("?y2?x00(c) 2016 B.L. Lonnon", lcd);
delay_ms(2700);
fputs("?f", lcd); //clear lcd
delay_ms(300);
CS5490Init();
for(;;)
{
//update here so very little is done in isr
//pulses have been received since last processing if pulse > 0
if(pulse > 0)
{
//add to today's total
used_today += pulse;
//integral part stored in eeprom(0) in kWh
//fractional part stored in eeprom(2)
//eg. 2.99kWh stored as 2 (eeprom(0)) and 99 (eeprom(2))
used_today = used_today + (1000 * read_int16_eeprom(0))
+ 10 * read_int16_eeprom(3);
lidiv = ldiv(used_today, 1000);
//integral number of kWh
write_int16_eeprom(0, lidiv.quot);
//fractional part of kWh
write_int16_eeprom(2, lidiv.rem);
delay_ms(10);
//now reset as processed
pulse = 0;
}//end if(pulse..
//read the RTC
DS3232getDate(dow, day, month, year);
DS3232getTime(hour, minute, second);
//disable interrupts while writing to LCD
disable_interrupts(int_ext);
disable_interrupts(global);
delay_ms(10);
fputs("?f", lcd); //clear lcd
delay_ms(300);
fprintf(lcd, "?y0?x00%s %02u/%02u/%02u %02u:%02u ",
dayOfWeek[dow], day, month, year, hour, minute);
//get readings from CS5490 for line 2 of LCD
//read Vrms, page 16, address 7
VAC = read_register(16, 7) / 47246;
//read Irms, page 16, address 6
value = read_register(16, 6);
IAC = (float)value / 554905;
//read Power, page 16, address 20
value = read_register(16, 20);
PAC = (float)value / 781;
if(IAC == 0)
PAC = 0;
delay_ms(10);
if(PAC < 1000)
{
fprintf(lcd, "?y1?x00%luV @ %2.1fA = %3.0fW", VAC, IAC, PAC);
//assemble values in case PIC is asked to send them
//done here because of W/kW units
sprintf(VAW, "%lu,%2.1f,%3.0f,", VAC, IAC, PAC);
}
else
{
PAC /= 1000; //to kW
PAC = round(PAC);
fprintf(lcd, "?y1?x00%luV @ %2.1fA = %1.1fkW", VAC, IAC, PAC);
}//end else
//line 2 of LCD, used today and daily avg (not yet included)
fprintf(lcd, "?y2?x00Today:%lu.%lu", read_int16_eeprom(0), read_int16_eeprom(2));
enable_interrupts(int_ext);
enable_interrupts(global);
delay_ms(2000);
}//end for(;;)
}//end main
//-----------------------------------------------------------------------------
void CS5490Init()
{
//reset CS5490
output_low(PIN_B4);
delay_ms(100);
output_high(PIN_B4);
delay_ms(80);
delay_ms(100);
output_high(PIN_B4);
delay_ms(80);
//Cirrus recommended to prevent Vref problems
write_register(0x000016, 0, 28);
write_register(0x0C0008, 0, 30);
write_register(0x000000, 0, 28);
//switch to 9600Bd
write_register(0x0204CD, 0, 7);
delay_ms(200);
baud = FAST;
//enable HPFs
write_register(0x10060A, 16, 0);
//set EPG
//256us pulse width, step 1, p20
write_register(0x80000, 0, 8);
write_register(0x3121EB, 18, 28);
//step 3
write_register(0, 0, 9);
//step 4
write_register(0x11EEEE, 0, 1);
//step 5 (> 0.1s)
delay_ms(150);
//step 6
write_register(0x11EEE0, 0, 1);
//continuous conversions, step 7
send_to_5490(0xD5);
delay_ms(100);
}
//---------------------------------------------------------------------------
void write_register(int32 value, int8 page, int8 regnum)
{
send_to_5490(page | 0x80); //select page
send_to_5490(regnum | 0x40); //select register write
send_to_5490(make8(value, 0));
send_to_5490(make8(value, 1));
send_to_5490(make8(value, 2)); //send 24bits
}
//---------------------------------------------------------------------------
int32 read_register(int8 page, int8 regnum)
{
int8 lo, mid, hi;
send_to_5490(page | 0x80); //select page
send_to_5490(regnum); //select register read
lo = from_chip(); //LSB
mid = from_chip();
hi = from_chip(); //MSB
return(make32(hi, mid, lo));
}
//---------------------------------------------------------------------------
int8 from_chip()
{
if(baud == SLOW)
return fgetc(cs5490slow);
return fgetc(cs5490fast);
}
//---------------------------------------------------------------------------
float round(float val)
{
val *= 10;
val += 0.5;
floor(val);
return val/10;
}
//---------------------------------------------------------------------------
|
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 30, 2016 10:08 am |
|
|
Code: | //LCD117 (SMT version runs at 19K2)
#use rs232(baud=19200,xmit=PIN_C6,stream=lcd)
//CS5490
#use rs232(baud=9600,xmit=PIN_C0,rcv=PIN_C1,ERRORS,stream=cs5490fast)
#use rs232(baud=600,xmit=PIN_C0,rcv=PIN_C1,ERRORS,stream=cs5490slow)
#int_ext HIGH //RB0 interrupt
void ext_isr()
{
pulse++;
}
//
|
Finally you post the truth. Every one of your UARTs is a soft UART.
And you are using interrupts. This is what I suspected. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
fprintf etc |
Posted: Thu Jun 30, 2016 11:36 am |
|
|
Hi, Thanks for your cryptic reply! I am using RS232 as I have always done. Obviously, I am missing something, although I don't know what!
Brian |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Thu Jun 30, 2016 12:17 pm |
|
|
You may not realize it, but he is not being cryptic. What PCM posted is most likely the issue.
I'm not trying to be mean here. I just want you to think critically about this:
Hardware UART is on C6 and C7 of your chip, so you are telling the compiler to use a software UART. Now in the absence of hardware to properly time the bits, the compiler has to precisely do that in code. If it takes a specific amount of time (no more, no less) between bits, what do you think will happen when an interrupt occurs in the middle of a transmission?
My guess is the version 3 compiler (incorrectly) sets interrupts to disabled and the version 5 does not. Normally you are supposed to supply a parameter to do this as an option, not the default (it's in the manual under #use rs232). You will want to set this option for the version 5 compiler and see if the problem still persists.
Again, not meaning to be obtuse, but want you to take a step back and look at it differently is all.
As a side note, while a software UART is passable for transmit purposes, receiving can be much more difficult to do properly as you must know the exact time and amount of data coming in and/or disable interrupts for very long (relatively) periods of time. Software receive needs to be done with care. I know you are just transmitting in this example, but wanted to toss that out there. |
|
|
|
|
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
|