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 CCS Technical Support

rs232 problem w/ pic16F877A

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hwilson
Guest







rs232 problem w/ pic16F877A
PostPosted: Tue Oct 19, 2004 9:57 am     Reply with quote

Ok, Here is the problem. this code works if I connect it to a PC and send the correct responses. But when I connect it to the device it is go to drive it don't. I have also drivin the device with the PC and it work as well.There is supose to be a built in 3 char buffer but I can't find any docs on howto use it. This is not the complete code just the driver.c that is included in the main program.

Thanks Harold

Code:

#include <stdio.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, stream=PUMP)

//char VOL;
//char VOL_LEFT;
//char LTR;
//char PERCENTAGE;
//char DISPEN;
//char CHECK;
//char STEPS;


void busy(void)
{
   char in;
   delay_ms(100); // pump command delay
   fputs("/1?",PUMP); // query pump status
   printf(Lputc,"busy1"); // for debug, this displays
   while (in != 0x40);{   // in = "@" the pump is ready for next command
      in = fgetc(PUMP);
      printf(Lputc,"%c",in); // for debug , this dosn't display
      }
      return;
}

void initpump(void)
{
   printf(Lputc,"System");
   Lsetpos(0xC0);
   printf(Lputc,"initializing...");
   fputs("/1W4R",PUMP); //send reset to pump
   printf(Lputc,"1"); //for debug, this displays
   busy();
   fputs("/1W4R",PUMP); //repeat per mfg
   printf(Lputc,"2"); //for debug
   busy();
   fputs("/V1000R",PUMP); // set pump speed
   busy();
   return;
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Oct 19, 2004 11:56 am     Reply with quote

Your UART receiver may be losing characters.

Look at the CCS example file, EX_SISR.C, which is in this folder:
c:\Program Files\Picc\Examples
It shows how to make an interrupt-driven RS-232 receive fifo.
If you implement that in your design, then you probably won't
lose any characters.

Also, you should add the ERRORS parameter to the end of your
#use rs232 statement. This will tell the compiler to put in code
to reset the UART receiver if a overrun error occurs. Without
that code, if such an error occurs then the USART receiver will
lock up. Example:
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS, stream=PUMP)

-----------
Also, I might as well add a couple other notes.

You don't need to put a "return" statement at the end of
a function that is declared as returning "void".

This section of code is written in a messy manner:
Code:
   while (in != 0x40);{   // in = "@" the pump is ready for next command
      in = fgetc(PUMP);
      printf(Lputc,"%c",in); // for debug , this dosn't display
      }


The while() statement does not pertain to the code in braces,
because it has a semi-colon after it. You don't need the braces.
The code actually looks like this, and should be written like this,
for clarity:

Code:
while (in != 0x40);

in = fgetc(PUMP);

printf(Lputc,"%c",in);
hwilson
Guest







PostPosted: Thu Oct 21, 2004 8:41 am     Reply with quote

For starters thank you for pointing out my mistakes, I changed the code to fix these. I took you advice and setup the interrupt driven RS232. Here is the new code. This code still don't work. There is nothing wrong with the pic or the pump, as the orginal PIC Basic code works fine. I would stick with the basic code but I need to do alot of floating point math for volume caluations. This will drive a Kloehn 50300 syringe pump with a 50 mil syringe.


Code:


#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, PARITY=N, BITS=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#include <stdio.h>
#include <string.h>
#include <kbd.c>
#include "lcd.h"

#define BUFFER_SIZE 9
BYTE buffer[BUFFER_SIZE];


#int_rda
void isr() {
   int in;
   
   in = 0;
   while(buffer[in]!=0xFF){  // 0xFF is the terminator from the pump controller
      buffer[in]=getc();
      in++;
      if(in==BUFFER_SIZE)  //don't over fill the buffer
         break;
     }
}

void busy(void)
{
   for(;;)  {   
      puts("/1?");  // query pump status
      delay_ms(50);   //wait for interrupt
      Lsetpos(0xD4);
      printf(Lputc,"%9Cx",buffer); //for debug, this don't display
      if(buffer[2] == 0x60) break;   // buffer = "@" the pump is ready for next command
      if(buffer[2] == 0x40) break;   // buffer = "`" the pump is ready for next command
   }
}

void initpump(void){

   printf(Lputc,"System");
   Lsetpos(0xC0);
   printf(Lputc,"initializing...");
   puts("/1W4R");
   printf(Lputc,"1"); //for debug, this displays
   busy();
   puts("/1W4R");
   printf(Lputc,"2"); //for debug, this don't display
   busy();
   puts("/1V1000R");
   busy();
   puts("/1A0R");
   busy();
   Lsetpos(0xD4);
   printf(Lputc," DONE!!!");
   delay_ms(3000);
}

void main(void) {
   char k;

   port_b_pullups(TRUE);
   enable_interrupts(global);
    enable_interrupts(int_rda);
   lcdinit();
   lcdinit(); // remove for production model
   kbd_init();
   initpump();
   printf(Lputc,"Ready...");
    while (TRUE) {
      k=kbd_getc();
      if(k!=0)
          Lputc(k);
   }
}
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Thu Oct 21, 2004 9:05 am     Reply with quote

"I would stick with the basic code but I need to do alot of floating point math for volume caluations. This will drive a Kloehn 50300 syringe pump with a 50 mil syringe. "

Think again if you really need floating point. Could you do your calculations in long integer microliters? It would save a lot of overhead, and might let you stick with BASIC (yeah I know, sacrilege on a C forum).
_________________
The search for better is endless. Instead simply find very good and get the job done.
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Oct 21, 2004 9:15 am     Reply with quote

Code:
#int_rda
void isr() {
   int in;
   
   in = 0;
   while(buffer[in]!=0xFF){  // 0xFF is the terminator from the pump controller
      buffer[in]=getc();
      in++;
      if(in==BUFFER_SIZE)  //don't over fill the buffer
         break;
     }
}


There are a couple of problems here. What if buffer[0] happened to contain an 0xFF? Your code would never execute.

You could try something like this...



Code:

#define BUFFER_SIZE 9
BYTE buffer[BUFFER_SIZE];
short found_it = false;
int8 rx_head = 0;
int8 rx_tail = 0;


#int_rda
void isr() {
      buffer[rx_head]=getc();
      if (Buffer[rx_head] == 0xFF)
           found_it = true;
      rx_head = (rx_head + 1) % BUFFER_SIZE;
     }

   
.....
     while (TRUE)
           {
           // .. we know if rx_tail != rx_head then there is something in the buffer
           if (found_it)
                  {
                  //.. here we know we have found a 0xFF in the buffer
                   //.. rx_tail points to the first unread position in the buffer
                   //.. rx_head points to the next free position in the buffer
                   //.. if necessary we could copy this to a linear buffer
                   .. your code here   
                   while ((rx_tail != rx_head) && found_it)
                          {
                           Lputc(Buffer[rx_tail]);
                           if (Buffer[rx_tail] == 0xFF)
                                  found_it = false;
                           rx_tail = (rx_tail + 1) % BUFFER_SIZE;
                           }
                    }
}


In the above code you only enter the processing loop if you have found the 0xFF in the interrupt handler. However you do not need to use the flag. You could let you mainline process anything in the buffer and keep waiting until it extracts the 0xFF from the buffer.


Last edited by asmallri on Thu Oct 21, 2004 9:32 am; edited 2 times in total
hwilson
Guest







PostPosted: Thu Oct 21, 2004 9:22 am     Reply with quote

I already tried to do this in Basic. The math is to far off for the application. To do the math in Basic you need to move the decimal point by multiplying the number by a 10,000. Do the calculations the divided the answer by 10,000. You lose to much in the conversion. The solution was to port it over to C to get the 32 bit floating point math routines.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Oct 21, 2004 9:27 am     Reply with quote

Code:
#int_rda
void isr() {
   int in;
   
   in = 0;
   while(buffer[in]!=0xFF){  // 0xFF is the terminator from the pump controller
      buffer[in]=getc();
      in++;
      if(in==BUFFER_SIZE)  //don't over fill the buffer
         break;
     }
}


A bug in above code is that after reading a character you increase the value of 'in' and then in
Code:
   while(buffer[in]!=0xFF){  // 0xFF is the terminator from the pump controller
you check the wrong memory location here.

A general remark on interrupts:
Every character received over RS232 will generate an interrupt, so you don't need to call getc() in a while loop. More basic: Normally you don't want to block your program flow until the whole message is received, that's not what interrupts are there for.

I agree with SherpaDoug that a quicker solution might be to change your original BASIC program. Often you can look different at your problem and you will see a solution not requiring floats, for example, 0.1ml is a float but 100 microliters is an integer. You say that you tried but dividing the value by 10.000 would loose too much in the conversion. The big trick here is .... not to divide by 10.000!!!
Seeing your knowledge of C, I think it is saver for your patients to stick to BASIC. Wink
Guest








PostPosted: Mon Oct 25, 2004 9:50 am     Reply with quote

Ok, This code works perfectly. My C is very rusty as it is only a hobby, that I haven't done anything with in a couple years. My boss wants me to learn it as a tool to program PIC's. I'm an electronics guy not a programmer. I think it maybe time to dig out that copy of “ANSI C made Easy” that I learned with and brush up on it. Once again Thank you “ALL” for your help.

Harold


Code:

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, PARITY=N, BITS=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#include <stdio.h>
#include <string.h>
#include <kbd.c>
#include "lcd.h"


#define BUFFER_SIZE   9

BYTE buffer[BUFFER_SIZE];
short found_it = FALSE;
int8 rx_head = 0;
int8 rx_tail = 0;


#int_rda
void isr() {
      buffer[rx_head]=getc();
      if(buffer[rx_head] == 0xFF)
           found_it = TRUE;
      rx_head = (rx_head + 1) % BUFFER_SIZE;
     
}

void clear_buffer(void)
{
   int i;
   found_it = FALSE;
   rx_head = 0;
   rx_tail = 0;

   for(i=0;i<=8;++i)
      buffer[i]= 0x20;
}

void busy(void)
{
   for(;;) {               // wait for pump to send ready response
      clear_buffer();         //clear out current command response as the pump sends a response to everything
      puts("/1?");         //query pump
      delay_ms(100);         //give pump time to respond
      if (buffer[2] == 0x60)   // if the third char is the ready char b reak the loop
         break;
   }
}

void initpump(void){

   printf(Lputc,"System");
   Lsetpos(0xC0);
   printf(Lputc,"initializing...");
   puts("/1W4R");
   printf(Lputc,"1"); //for debug
   busy();
   puts("/1W4R");
   printf(Lputc,"2"); //for debug
   busy();
   puts("/1V1000R");
   busy();
   puts("/1A0R");
   printf(Lputc,"3"); //for debug
   busy();
   Lsetpos(0xD4);
   printf(Lputc," DONE!!!");
   delay_ms(3000);
}

void main(void) {
   char k;

   port_b_pullups(TRUE);
   enable_interrupts(global);
    enable_interrupts(int_rda);
   lcdinit();
   lcdinit(); // remove for production model
   kbd_init();
   initpump();
   printf(Lputc,"Ready...");
    while (TRUE) {
      k=kbd_getc();
      if(k!=0)
          Lputc(k);
   }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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