|
|
View previous topic :: View next topic |
Author |
Message |
sorenson
Joined: 13 Jan 2004 Posts: 1
|
kbhit() and two serial ports on PIC16F873 |
Posted: Fri Nov 19, 2004 3:08 pm |
|
|
I am having problems getting a PIC16F873 to work with two serial ports,
one hardware and the other software. The code and comments are below.
Thank you for your time and assistance.
Code: |
[size=7]/*
** posting.c -- Code posted on the CCS C user forum to request assistance.
**
** The purpose of this code is to enable a local computer to communicate with a remote computer
** using an RF modem operating at 9600 bits per second (b/s). Because of the nature of our
** experiment, a 49 MHz modem must be used; higher-frequency modems will not work. Most of the
** computers are inside underwater vehicles and water is quite opaque to higher frequencies.
**
** The local computer exchanges half-duplex serial data with this PIC's code via an RS-485
** interface using its hardware UART at 115,200 b/s. When it wants to send data to the remote
** computer, it places it on the RS-485 bus (Busy and ready flags are used to mediate the bus,
** but this part isn't fully implemented yet.). This PIC buffers it until the ENTER_CHAR is
** received, enables the transmitter on the RF modem, sends this buffer to it, via a TTL
** interface, and then disables the transmitter. (Delays are necessary for proper operation of
** the RF modem as well as the RS-485 bus.) The remote RF modem detects this data and sends it
** to its PIC which places the data in its buffer (This is the part that does not seem to work).
** When the ENTER_CHAR is received, the remote PIC sends the data to its local host. Note: The
** link between each computer and its RF modem PIC uses a dedicated RS-485 port so no other
** devices can cause data collisions.
**
** Problem: These #use rs232 functions are known to work properly: bus_kbhit(), bus_getc(),
** bus_putc() and rf_putc(). The function rf_kbhit() always returns TRUE and no character is
** returned by rf_getc(). A TTL bit sequence does appear on PIN_C4, the pin assigned to the RF
** modem receiver output, but it appears that the rf_kbhit() function does not detect a start
** bit, or any other activity. This may be why rf_getc() does not return anything. Note: The
** baud rates in the two serial ports are different in this code. I tried an experiment and
** made them both the same (9600 baud), thinking that maybe there was only one baud-rate
** generator and they had to be the same, but the results were exactly the same: it didn't
** work.
**
** I tried using two streams, with the appropriate symbol passed to the functions, with even
** less success. Nothing worked. I can supply that code if anyone is interested in helping me
** from that perspective.
*/
#include <16F873.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP, PUT
#use delay(clock = 14745600)
#define EXIT_CHAR 0x03 // Ctrl-C, used to terminate the program.
#define ENTER_CHAR 0x0d // Ctrl-M, used to indicate completion of the data stream.
#define NULL 0
#use rs232(baud = 115200, xmit = PIN_C6, rcv = PIN_C7, enable = PIN_C2, PARITY = N, BITS = 8, ERRORS)
char bus_kbhit()
{
return kbhit();
}
char bus_getc()
{
return getc();
}
void bus_putc(char c)
{
putc(c);
}
#use rs232(baud = 9600, xmit = PIN_C5, rcv = PIN_C4, PARITY = N, BITS = 8, ERRORS)
char rf_kbhit()
{
return kbhit();
}
char rf_getc()
{
return getc();
}
void rf_putc(char c)
{
putc(c);
}
#define C1_DELAY_MS 1 // mS after toggling pin C1 for transmit.
#define SLEEP_PIN PIN_A3 // High is operate; low is sleep
#define TX_ENABLE PIN_A5 // Aliased to make the code more readable.
#define TX_DELAY_US 150 // Time to wait after pulling XMIT_ENABLE pin high.
#define RX_DELAY_US 150 // Time to wait after pulling XMIT_ENABLE pin low.
void rf_send_buffer(char *buffer)
{
int idx;
output_high(TX_ENABLE);
delay_us(TX_DELAY_US);
for (idx = 0; NULL != buffer[idx]; idx++) {
rf_putc(buffer[idx]);
}
output_low(TX_ENABLE);
delay_us(RX_DELAY_US);
}
void bus_send_buffer(char *buffer)
{
int idx;
output_high(PIN_C1); // Prevent sent data from appearing on PIC's input pin.
delay_ms(C1_DELAY_MS);
for (idx = 0; NULL != buffer[idx]; idx++) {
bus_putc(buffer[idx]);
}
output_low(PIN_C1); // Resume listening to RS-485 bus.
}
#define MAX_MESSAGE 18
#define MAX_BUFFER 64
void main()
{
char bus_ch, rf_ch;
short bus_busy = FALSE, bus_data_ready = FALSE;
short rf_busy = FALSE, rf_data_ready = FALSE;
char message[MAX_MESSAGE + 1], bus_buffer[MAX_BUFFER + 2], rf_buffer[MAX_BUFFER + 2];
int i_bus, i_rf;
set_tris_a(0x13); // Define the unused I/O pins of the A register as inputs.
set_tris_b(0xff); // Define all of the I/O pins of the B register as inputs.
set_tris_c(0x9f); // Originally 0x96. Some pins may be set by the #use rs232 directives.
output_high(SLEEP_PIN); // Ensure the RF modem is "awake."
output_low(TX_ENABLE); // Ensure the "TX Enable" on the modem is in the idle state.
strcpy(message, "Started...\r");
bus_send_buffer(message);
i_bus = i_rf = 0;
while(TRUE) {
if (TRUE == bus_kbhit()) { // Character from local computer in buffer.
bus_ch = bus_getc();
bus_busy = TRUE;
if (EXIT_CHAR == bus_ch) {
break;
} else {
if (TRUE != bus_data_ready) { // Add characters only to an unfinished message.
if (ENTER_CHAR == bus_ch) {
bus_buffer[i_bus++] = ENTER_CHAR;
bus_buffer[i_bus] = NULL;
bus_data_ready = TRUE;
bus_busy = FALSE;
i_bus = 0;
} else { // Append incoming character to bus buffer; do not overflow.
if (MAX_BUFFER > i_bus) {
bus_buffer[i_bus++] = bus_ch;
bus_buffer[i_bus] = NULL;
}
}
}
}
}
if (TRUE == rf_kbhit()) { // Character from RF modem in buffer.
// rf_kbhit() seems to always return TRUE so this block always executes. There
// does not seem to be a character in the buffer either.
rf_ch = rf_getc();
rf_busy = TRUE;
if (EXIT_CHAR == rf_ch) {
//break;
} else {
if (TRUE != rf_data_ready) { // Add characters only to an unfinished message.
if (ENTER_CHAR == rf_ch) {
rf_buffer[i_rf++] = ENTER_CHAR;
rf_buffer[i_rf] = NULL;
// Check if this message is for this module here.
rf_data_ready = TRUE;
rf_busy = FALSE;
i_rf = 0;
} else { // Append incoming character to RF buffer; do not overflow.
if (MAX_BUFFER > i_rf) {
rf_buffer[i_rf++] = rf_ch;
rf_buffer[i_rf] = NULL;
}
}
}
}
}
if (TRUE == bus_data_ready) {
//if (FALSE == rf_busy) {
rf_send_buffer(bus_buffer);
bus_send_buffer(rf_buffer);
bus_data_ready = FALSE;
//}
}
if (TRUE == rf_data_ready) {
if (FALSE == bus_busy) {
bus_send_buffer(rf_buffer);
rf_data_ready = FALSE;
}
}
}
strcpy(message, "\rFinished.\r");
bus_send_buffer(message);
while(TRUE); // Keep PIC from entering SLEEP mode.
}
[/size] |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Nov 19, 2004 7:51 pm |
|
|
Just a wild guess about your hardware, but I assume your RF-unit is directly connected to your PIC? And the RF-unit doesn't have the 12V voltage levels of RS232, so you left out the MAX232 chip? Besides voltage level conversion the MAX232 also is an inverter, so without the MAX232 your signal is inverted. This explains why kbhit() is immediately returning, it always detects a logic low, corresponding to the start character.
Add the INVERT option to your software UART.
Something else:
Code: | if (TRUE == rf_kbhit()) { // Character from RF modem in buffer. |
The software UART has no buffer!
Also make sure to meet the following condition stated in the manual: Quote: | Note that in
the case of software RS232 this function should be
called at least 10 times the bit rate to ensure incoming
data is not lost. |
Using a software UART in parallel with other processes is a bit tricky because you don't want to disturb your incomming data. Do you have some way of flow control? If not, you might consider writing your own interrupt driven software UART. Examples of this are given in the book Serial Communications [Formerly Serial PIC'n], available here. |
|
|
|
|
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
|