|
|
View previous topic :: View next topic |
Author |
Message |
hwilson Guest
|
rs232 problem w/ pic16F877A |
Posted: Tue Oct 19, 2004 9:57 am |
|
|
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
|
|
Posted: Tue Oct 19, 2004 11:56 am |
|
|
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
|
|
Posted: Thu Oct 21, 2004 8:41 am |
|
|
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
|
|
Posted: Thu Oct 21, 2004 9:05 am |
|
|
"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
|
|
Posted: Thu Oct 21, 2004 9:15 am |
|
|
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
|
|
Posted: Thu Oct 21, 2004 9:22 am |
|
|
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
|
|
Posted: Thu Oct 21, 2004 9:27 am |
|
|
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. |
|
|
Guest
|
|
Posted: Mon Oct 25, 2004 9:50 am |
|
|
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);
}
}
|
|
|
|
|
|
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
|