CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Multiple fprintf statements with different streams problem
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

Multiple fprintf statements with different streams problem
PostPosted: Mon Feb 07, 2011 11:12 pm     Reply with quote

Hey all,

I have yet another snag that I have hit that I cannot for the life of me figure out.

I have multiple streams going on a chip and they control communication to other chips. I was wondering how this all works because the behavior of the device is very strange to say the least.

Here is the scenario:
Code:

#use rs232(stream=pc, baud=9600, xmit=PIN_A1, rcv=PIN_A0)
#use rs232(stream=chipA, baud=9600, xmit=PIN_B0, rcv=PIN_B1)
#use rs232(stream=chipB, baud=9600, xmit=PIN_B2, rcv=PIN_B3)
#use rs232(stream=chipC, baud=9600, xmit=PIN_B4, rcv=PIN_B5)
#use rs232(stream=chipD, baud=9600, xmit=PIN_B6, rcv=PIN_B7)
#use rs232(stream=chipE, baud=9600, xmit=PIN_C6, rcv=PIN_C7)

if (input(PIN_C3)){
   fprintf(chipA,"3");
   fprintf(chipB,"3");
   fprintf(chipC,"3");
   fprintf(chipD,"3");
   fprintf(chipE,"3");
}

And all set_tris commands are set up properly.

I want to send a number three to all five devices. This is what happens: only "chipA" gets the number three sent to it and all the other chips do not get the number sent to it. However, later on in the code there are some "if then" areas that depending on information given to the system from the user it will send subsequent data out to these five chips.

The strange part:

This subsequent data goes across to each chip, when the user sends a command to that specific chip, and all is good.

Thus, the only thing I can see that may be causing a problem is that calling the fprintf statements back to back just does not work. I have also tried putting 1ms delays in between the fprintf statements and that has no effect.

If anyone has had this problem and has a fix for it I would love to hear what you have to say.

Thanks so much and I will eagerly be watching for a reply.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Feb 09, 2011 4:06 pm     Reply with quote

Expand those code fragments into a small test program. Add the #include
for the PIC, #fuses, #use delay(), other #use statements, and main().
Show any setup code that you have in main(). The program should be
compilable if its copied and pasted into an MPLAB project.

Post your compiler version.
Tell us if you're testing this with Proteus or a real hardware board.

If possible, get rid of the if() test for the fprintf() statements. Just have
those 5 statements in main(). Put a while(1); statement at the end of
main(). Test and verify that it fails. Tell us the exact details of the
failure mode and how you know it fails. The more simple you make the
test program, the easier it will be for us to help you find the problem.
Make sure you post your compiler version.
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Wed Feb 09, 2011 8:22 pm     Reply with quote

Thank you so much for your reply.

I took your suggestions and made a smaller program that you can cut and paste into mplab ide. This is what I use is MPLAB IDE.

I am testing this on an actual hardware board.

My compiler version is 4.119.


Here is the main chip's test code:
Code:

#include <16f886.h>
#include <string.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use fast_io(B)
#use fast_io(C)
#use rs232(stream=pc, baud=9600, xmit=PIN_A1, rcv=PIN_A0)
#use rs232(stream=chipA, baud=9600, xmit=PIN_B0, rcv=PIN_B1)
#use rs232(stream=chipB, baud=9600, xmit=PIN_B2, rcv=PIN_B3)
#use rs232(stream=chipC, baud=9600, xmit=PIN_B4, rcv=PIN_B5)
#use rs232(stream=chipD, baud=9600, xmit=PIN_B6, rcv=PIN_B7)
#use rs232(stream=chipE, baud=9600, xmit=PIN_C6, rcv=PIN_C7)

void main(){
   char c;
   int delay_num=0;
   set_tris_c(0b10111111);
   //get which switch is flipped
   if (input(PIN_C5))
      delay_num=1;
   else if (input(PIN_C4))
      delay_num=2;
   else if (input(PIN_C3))
      delay_num=3;
   else if (input(PIN_C2))
      delay_num=4;
   else if (input(PIN_C1))
      delay_num=5;
   else if (input(PIN_C0))
      delay_num=6;
   delay_ms(10);
   //print number to all five chips
   fprintf(chipA,"%d",delay_num);
   fprintf(chipB,"%d",delay_num);
   fprintf(chipC,"%d",delay_num);
   fprintf(chipD,"%d",delay_num);
   fprintf(chipE,"%d",delay_num);
   fprintf(pc,"hello world%d\n",delay_num);
   
   c=getch();// get the letter that was sent to other chip back
   fprintf(pc,"%c",c); //print the letter received from sub chip to screen
   delay_ms(100);
}

Here is a piece of code for a sub chip:
Code:

#include <16f886.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_A1, rcv=PIN_A0)


void main(){
char c2;

set_tris_a(0b00111101);
set_tris_b(0b11100000);
set_tris_c(0b00111111);

c2=getch();  //get the number from main chip
delay_ms(10);
printf("%c",c2); //send the number received back to main chip
}

There are five chips connected over 10 pins on the main 16f886 chip for 5 rs232 connections. All these chips get the same command. These chips are connected to the main chip through a plug/header connection. Therefor, I can move the sub chip from one rs232 connection to the next to test if all connections are receiving the data sent to them correctly.

This is how I know that the data is not going across correctly is that the above program should print to a PC the number that the sub board received. This is where I have been using a serial port monitoring software and I always receive the 0x00/NULL back from the port when I sent out, for example, the number "2".

If I need to send a picture of what I have, because I know how confusing typing out the problem can be, I will gladly affix one.

Thanks again for your reply.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Feb 09, 2011 10:57 pm     Reply with quote

Quote:

c=getch();

If you're using streams, you shouldn't be using getch(). You should be
using fgetc(), with the desired stream as the parameter.
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Thu Feb 10, 2011 11:18 pm     Reply with quote

Oh yeah. I forgot this. I changed it to "c=fgetc(chipB);"

I then connected the secondary chip to the apropriate rx & tx pins on the first chip and the same thing happens. I receive NULL back from the secondary chip.
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Thu Feb 10, 2011 11:23 pm     Reply with quote

Oh and here is something funny I found. When I use the following code I get the number back on chipA but not on chipB through chipE.
Code:

   fprintf(chipA,"%d",delay_num);
   delay_ms(1);
   fprintf(chipB,"%d",delay_num);
   delay_ms(1);
   fprintf(chipC,"%d",delay_num);
   delay_ms(1);
   fprintf(chipD,"%d",delay_num);
   delay_ms(1);
   fprintf(chipE,"%d",delay_num);
   fprintf(pc,"hello world%d\n",delay_num);
   
   c=fgetc(chipA);// get the letter that was sent to other chip back
   fprintf(pc,"%c",c); //print the letter recieved from sub chip to screen
   delay_ms(100);

Is it something to do with hardware UART and software UART?
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Fri Feb 11, 2011 3:33 am     Reply with quote

I'd say 'floating'.....

Now, your receive devices are all using software UARTs. When you do a 'getc' from these, they look at the RX pin, and when/if it goes low, they start sampling. If the line is then low, you will get a '0'.
Now, on a PIC, pins 'wake up' as inputs, and only switch to being outputs when used.
So depending on how the lines float, you will get garbage.
Either stop using fast_io, or get the tris right. You show no TRIS for portB, so how is this every going too send anything?. You need B0,2,4 & 6, set as outputs. Remember the default TRIS, is everything as inputs....

Then, right at the start of the main in the 'master', set each of the serial output lines high. So:
Code:

output_high(PIN_B0);
output_high(PIN_B2);
output_high(PIN_B4);
output_high(PIN_B6);
output_high(PIN_C6);

Then in the slaves, wait at the start of the code, till the line is seen to be high. Only when it is high, call the getc. Currently, if the line is not driven as the master boots up, the receive getc, will start immediately.

Best Wishes
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Fri Feb 11, 2011 8:41 pm     Reply with quote

Thank you so much for pointing that out. When I was copying the original program I did not get the tris copied like I wanted. I apologize. I have done what you have suggested with the output_high and such but I still cannot get the number back from the slave.

Here are my codes I am using:

Master:
Code:

#include <16f886.h>
#include <string.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
//#use fast_io(B)
//#use fast_io(C)
#use rs232(stream=pc, baud=9600, xmit=PIN_A1, rcv=PIN_A0)
#use rs232(stream=chipA, baud=9600, xmit=PIN_B0, rcv=PIN_B1)
#use rs232(stream=chipB, baud=9600, xmit=PIN_B2, rcv=PIN_B3)
#use rs232(stream=chipC, baud=9600, xmit=PIN_B4, rcv=PIN_B5)
#use rs232(stream=chipD, baud=9600, xmit=PIN_B6, rcv=PIN_B7)
#use rs232(stream=chipE, baud=9600, xmit=PIN_C6, rcv=PIN_C7)

void main(){
   char c;
   int delay_num=0;
   set_tris_a(0b00000001);
   set_tris_b(0b10101010);
   set_tris_c(0b10111111);
   
   //get which switch is flipped
   if (input(PIN_C5))
      delay_num=1;
   else if (input(PIN_C4))
      delay_num=2;
   else if (input(PIN_C3))
      delay_num=3;
   else if (input(PIN_C2))
      delay_num=4;
   else if (input(PIN_C1))
      delay_num=5;
   else if (input(PIN_C0))
      delay_num=6;
   delay_ms(10);
   output_high(PIN_B0);
   //print number to all five chips
   fprintf(chipA,"%d",delay_num);
   delay_ms(1);
   output_high(PIN_B2);
   fprintf(chipB,"%d",delay_num);
   delay_ms(1);
   output_high(PIN_B4);
   fprintf(chipC,"%d",delay_num);
   delay_ms(1);
   output_high(PIN_B6);
   fprintf(chipD,"%d",delay_num);
   delay_ms(1);
   output_high(PIN_C6);
   fprintf(chipE,"%d",delay_num);
   fprintf(pc,"hello world%d\n",delay_num);
   for (;;){
      if (input(PIN_B1)){
         c=fgetc(chipA);// get the letter that was sent to other chip back
         break;
      }
   }      
   fprintf(pc,"%c",c); //print the letter recieved from sub chip to screen
   delay_ms(100);
}

Slave code:
Code:

#include <16f886.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_A1, rcv=PIN_A0)

void main(){
char c2;

set_tris_a(0b00111101);
set_tris_b(0b11100000);
set_tris_c(0b00111111);

for (;;){
   if (input(PIN_A0)){
      c2=getch();  //get the number from main chip
      break;
   }
}      
delay_ms(10);
output_high(PIN_A1);
printf("%c",c2); //send the number recieved back to main chip
}

Thanks again for the great Help!
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Sat Feb 12, 2011 2:52 am     Reply with quote

No, you are not doing what I said. The output_high instructions want to be _right at the top_ of the main. before your delay.
You want the line to be sitting high _before_ anything else happens. Currently the line is still 'undriven', till your print statements start. Sitting floating for 10mSec.....

Best Wishes
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Sat Feb 12, 2011 2:57 pm     Reply with quote

Hey there,

I had tried that but it didn't work so that is where I came up with the code I had posted above.

However, here is the code I now am using, based on your suggestion, and I am not getting the number back with it.

If I am just completely missing the mark here, which I some time do (he he), could I bother you for a code snip it showing me where it should be placed?

Thank you so much for all your help on this perplexing situation.

Code:

#include <16f886.h>
#include <string.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
//#use fast_io(B)
//#use fast_io(C)
#use rs232(stream=pc, baud=9600, xmit=PIN_A1, rcv=PIN_A0)
#use rs232(stream=chipA, baud=9600, xmit=PIN_B0, rcv=PIN_B1)
#use rs232(stream=chipB, baud=9600, xmit=PIN_B2, rcv=PIN_B3)
#use rs232(stream=chipC, baud=9600, xmit=PIN_B4, rcv=PIN_B5)
#use rs232(stream=chipD, baud=9600, xmit=PIN_B6, rcv=PIN_B7)
#use rs232(stream=chipE, baud=9600, xmit=PIN_C6, rcv=PIN_C7)

void main(){
   char c;
   int delay_num=0;
   set_tris_a(0b00000001);
   set_tris_b(0b10101010);
   set_tris_c(0b10111111);
   output_high(PIN_B0);
   output_high(PIN_B2);
   output_high(PIN_B4);
   output_high(PIN_B6);
   output_high(PIN_C6);
   
   //get which switch is flipped
   if (input(PIN_C5))
      delay_num=1;
   else if (input(PIN_C4))
      delay_num=2;
   else if (input(PIN_C3))
      delay_num=3;
   else if (input(PIN_C2))
      delay_num=4;
   else if (input(PIN_C1))
      delay_num=5;
   else if (input(PIN_C0))
      delay_num=6;
   delay_ms(10);
   //print number to all five chips
   fprintf(chipA,"%d",delay_num);
   delay_ms(1);
   fprintf(chipB,"%d",delay_num);
   delay_ms(1);
   fprintf(chipC,"%d",delay_num);
   delay_ms(1);
   fprintf(chipD,"%d",delay_num);
   delay_ms(1);
   fprintf(chipE,"%d",delay_num);
   fprintf(pc,"hello world%d\n",delay_num);
   for (;;){
      if (input(PIN_B1)){
         c=fgetc(chipA);// get the letter that was sent to other chip back
         break;
      }
   }      
   fprintf(pc,"%c",c); //print the letter recieved from sub chip to screen
   delay_ms(100);
}


Slave controller:
Code:

#include <16f886.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_A1, rcv=PIN_A0)


void main(){
char c2;

set_tris_a(0b00111101);
set_tris_b(0b11100000);
set_tris_c(0b00111111);
output_high(PIN_A1);
for (;;){
   if (input(PIN_A0)){
      c2=getch();  //get the number from main chip
      break;
   }
}      
delay_ms(10);
printf("%c",c2); //send the number received back to main chip
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Sun Feb 13, 2011 3:22 am     Reply with quote

OK, lets start at the beginning.
With a _software_ UART, _you_ need to be sitting 'waiting' for the character to arrive. If a character arrives, and you are not waiting for it, it is lost. Now you send out potentially five characters, then try to read the return. Either, if the remote chips have not yet responded (10mSec delay), you will get the first character, and miss the rest, or if they have already started to respond, you will get whichever one arrives at this point. Your whole basic sequencing is wrong:
Code:

#include <string.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
//#use fast_io(B)
//#use fast_io(C)
#use rs232(stream=pc, baud=9600, xmit=PIN_A1, rcv=PIN_A0)
#use rs232(stream=chipA, baud=9600, xmit=PIN_B0, rcv=PIN_B1)
#use rs232(stream=chipB, baud=9600, xmit=PIN_B2, rcv=PIN_B3)
#use rs232(stream=chipC, baud=9600, xmit=PIN_B4, rcv=PIN_B5)
#use rs232(stream=chipD, baud=9600, xmit=PIN_B6, rcv=PIN_B7)
#use rs232(stream=chipE, baud=9600, xmit=PIN_C6, rcv=PIN_C7)

void scan_chip(int16 stream, int8 delay) {
      int8 c;
      fprintf(stream,"%d",delay);
      //You must now handle the response for _this_ chip
      c=fgetc(stream);// get the letter that was sent to other chip back
      fprintf(pc,"%c",c); //print the letter received from sub chip to screen
}

void main(){
   int delay_num=0;
   set_tris_a(0b00000001);
   set_tris_b(0b10101010);
   set_tris_c(0b10111111);
   output_high(PIN_B0);
   output_high(PIN_B2);
   output_high(PIN_B4);
   output_high(PIN_B6);
   output_high(PIN_C6);
   //Assuming the remote chips are switched on, they will now start
   
   for (;;) { 
      //get which switch is flipped
      if (input(PIN_C5))
         delay_num=1;
      else if (input(PIN_C4))
         delay_num=2;
      else if (input(PIN_C3))
         delay_num=3;
      else if (input(PIN_C2))
         delay_num=4;
      else if (input(PIN_C1))
         delay_num=5;
      else if (input(PIN_C0))
         delay_num=6;
      delay_ms(10);
      //print number to all five chips _in turn_
      scan_chip(ChipA,delay_num);
      scan_chip(ChipB,delay_num);
      scan_chip(ChipC,delay_num);
      scan_chip(ChipD,delay_num);
      scan_chip(ChipE,delay_num);
      fprintf(pc,"/n/r");
      //Add a LF/CR, do you can see that one sequence is complete

      delay_ms(500);
   } //And loop to repeat     
}

//And for the slaves

#include <16f886.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_A1, rcv=PIN_A0)

void main(){
   char c2;

   set_tris_a(0b00111101);
   set_tris_b(0b11100000);
   set_tris_c(0b00111111);
   output_high(PIN_A1);
   while (INPUT(PIN_A0)==0) ; //Wait till you see the serial line go high
   //Master is now 'awake'
   for (;;){
      c2=getch();  //get the number from main chip
      //Why delay?.
      putc(c2); //send the number received back to main chip
   } //and loop to wait for the next character
}

The point is the same one as the startup one already mentioned. With a software serial, there is no 'in advance' reception, and buffering. You need to be _waiting_ for the character, and as soon as the line drops, getc, _will_ start sampling. So just as on wakeup, where you need to ensure that the line is high, so that the slave does not start to sample 'early', on receive, you need to be there and reading the data from _each chip in turn_, if it is not going to be missed.
If you want the system to be reliable, and not get hung if a unit _does not_ respond, then you need to consider something like:
Code:

//when waiting for the remote to respond
set_timer0(0);

while (!kbhit(ChipA)) {
   if (get_timer0)>LIM) break;
   delay_us(10);
}

if (kbhit(ChipA)) {
   //Now read ChipA

}

If you set the timer from a clock to suit you, and with a prescaler to suit, then set 'LIM' to some count value reflecting the chip not having responded, then you will only call the 'ChipA' code if ChipA responds.
You can do the same for each chip in turn.

Best Wishes
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Sun Feb 13, 2011 7:42 pm     Reply with quote

Thank yo sooooooo Much!!!!! I got a piece of it to work.

The thing that I noticed that I had been doing wrong is stating the multiple fprintf statements back to back.

The only thing I have a slight issue with is passing the stream identifier to the function the funciton scan_chip. The compiler does not like using the variable for the identifier and it gives me this error:

*** Error 130 "Main_5cab_firmware_v1.0.c" Line 151(15,21): Stream must be a constant in the valid range ::

I think that if we can get past this we are gold!

Thank you so much for sticking with me and explaining all that you have. This has been a great learning experience.
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Thu Feb 24, 2011 6:53 pm     Reply with quote

Hello there,

I am still having an issue with this problem. I still cannot get the information passed between the two chips.

If anyone out there has any Ideas this would be great!

Thanks again for all the help.
misperry



Joined: 03 Mar 2009
Posts: 40

View user's profile Send private message

PostPosted: Thu Feb 24, 2011 8:07 pm     Reply with quote

I have been extensively testing this problem. I have found that if you call the printf statements back to back this does not work.

i.e.

printf(chipA,"%d",delay_num);
printf(chipB,"%d",delay_num);
printf(chipC,"%d",delay_num);
printf(chipD,"%d",delay_num);
printf(chipE,"%d",delay_num);

I don't know what type of timing issue there is but I have tried everything.

I have tried making the master wait for the rcv pin to go high coming from the slave before it sends the printf statement. this has not worked. I have tried waiting for a start char from the slave before sending and this also has not worked.

I have been trying a variety of things and I still have nothing working. I only have two more weeks to work on this project so I am getting a bit antsy Smile.

If there is anyone out there that has an idea of what I could be doing wrong I am all ears.

Ttelmah has been wonderfully helpful in all of his suggestions. But I still cannot get past the fact that when you state the printf statements back to back it fails.

I have even been crazy enough to write separate functions with the printf statements in them and call these functions back to back but this still does not work.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Feb 25, 2011 12:24 am     Reply with quote

Why can't you do it this way:

1. Each slave PIC (16F886) uses the hardware UART to communicate
with the master PIC.

2. The master PIC uses separate software UARTs, and each one is
connected to a different slave chip.

3. The Master PIC does only one transaction at a time. It sends a
command to one slave. Then it immediately calls fgetc() and waits
for the slave to send back the data. There is no delay_ms() statement
in the Master PIC's code, between the command transmit line and the
fgetc() line.

4. When the complete transaction for the 1st slave is done, then the
Master PIC talks to the 2nd slave. Etc.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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