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 communication (PIC16F877)

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



Joined: 10 Jun 2007
Posts: 2

View user's profile Send private message

RS232 communication (PIC16F877)
PostPosted: Sun Jun 10, 2007 11:47 am     Reply with quote

Hello,

For a school project we were asked to make a small boat that can be controlled via Bluetooth.

On our boat we use a PIC16F877 microcontroller to receive the steering information that's sent via Bluetooth (with the use of Java and a joystick).

Because our Bluetooth module responds in the form of <CR><LF>response<CR><LF> we filter the carriage returns and linefeeds, and interpret the data between it.

We actually look at the first letter of "response" to establish what to do. The Bluetooth steering data consists of a letter (L (left), R (right), B (backwards), F (forward)) and a number specifying the 'intensity'. With that number we send something to some ports, which causes the motor's speed to change, or the 'boat-steer-thingy' to rotate.

But we have been having a problem for 1.5 week or so with the RS232 communication.

As it seems now, there are much garbage characters being both received and sent by the microcontroller. But occasionally good data will be passed.

In the (small) school example code INT_RDA is used for receiving data. But because the port of that is used by something else we use port B7 for receive and port B6 for transmitting, so we use INT_RB for receiving data.

There are also two RS232 ports. One for debugging purposes, and the other one for the Bluetooth module.

Does anyone see something wrong with this code? Is it wrong to use INT_RB? Or do we have to do something extra when using INT_RB? Should we configure things differently?

I don't have the MPLAB IDE and CCS we have at school at hand. So I don't know which compiler version we have exactly. But it's definitely not a new version.

I'm not a really electronically technical person, by the way. It's a multidisciplinary project. I'm one of the two Software Engineers.

Any help's very much appreciated!

Code:

/* IDP Project: groep 11 */
#device PIC16F877 adc=8
#include "16f877.h"
#include <STDLIB.H>
#define HIGH_START 114
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=4000000)                                   // 4 MHz clock
#use rs232(baud=9600, xmit=PIN_b6, rcv=PIN_b7, stream=bt)   // Seriele communicatie bt module
#use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7, stream=cpu)  // Seriele communicatie mc
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

// PROTOCOL VOOR ONTVANGEN BERICHTEN
const char CONNECT = 'C';
const char OK = 'O';
const char ERROR = 'E';
const char LEFT = 'L' ;
const char RIGHT = 'R';
const char FORWARD = 'F';
const char BACKWARD = 'B';
const char WEAPON = 'W';
const char POWER = 'P';
const char STATUS = 'S';

// Globale constanten.
const int8 bufsize=50;            // Maximale grootte van de strbuf[] array.
const tijd = 3;               // ingestelde tijd hoe lang de poorten hoog zijn
                           // voor aansturing van het wapen.

// Globale variabelen.
int8 i;                  // Pointer strbuf[] array.
char strbuf[bufsize];            // Data karakters op rs232 poort bufferen.
long t_high, t_low, ms;            // kompas tijd: begin en eind.
float dir                  // kompas resultaat, richting.
int1 polarity;               // polariteit van de motor voor de vaarrichting
                      // true = forward, false = backward.

int1 connected;               // geeft aan of er al connectie gemaakt is via bt.
int1 compas_verzonden;            // geeft aan of er al een richting is verzonden
                      // naar de Wal.

int8 stuur;                  // stuur
int8 vlag;                  // stuur: vlag
int1 do_wapen;               // wapen

#INT_TIMER0
void servo() {
/*
 * Omschrijving: Frequentie voor de servo regelen.
 * Argumenten: -
 * Return: -
 * Commentaar: De frequentie van de servo is 50 Hertz. De richting van de servo,
 *             het roer, wordt bepaald aan de hand van hoe lang er een hoog
 *             signaal wordt gegeven.
*/
    if (vlag <= stuur)
      output_HIGH(PIN_e1);
   if (vlag >= stuur)
      output_LOW(PIN_e1);
   if (vlag > 40)
      vlag=0;

   vlag++;
   set_timer0(1500);
}

   
void switch_polarity() {
/*
 * Omschrijving: Polariteit omzetten.
 * Argumenten: -
 * Return: -
 * Commentaar: De polariteit bepaald de vaarrichting van de boot.
*/
   polarity = !polarity;
   if (polarity)
      OUTPUT_low(PIN_e2);   
   else
      output_high(PIN_e2);
}

void do_left(byte b) {
/*
 * Omschrijving: Stuurt roer naar links.
 * Argumenten: richting in bytes.
 * Return: -
 * Commentaar: De hoeveelheid de er wordt gestuurd wordt bepaald aan de hand van
 *             de groote van de byte b. Er wordt in zes stappen gemeten, waarbij
 *             stuur is dertien rechtdoor is.
 *             Tevens wordt er nadat er roer is gegeven het compas vlaggetje
 *             weer op nul gezet, waardoor er een nieuw bericht wordt verzonden
 *             naar de wal met de laatste richting, dir.
*/
   //printf("Do left: %x\n", b);
   if (b < 20)
      stuur = 13;
   else if (b < 40)
      stuur = 12;
   else if (b < 60)
      stuur = 11;
   else if (b < 80)
      stuur = 10;
   else if (b < 100)
      stuur = 9;
   else
      stuur = 8;

   compas_verzonden = 0;         // 0 is opnieuw verzenden van compas
}

void do_right(byte b) {
/*
 * Omschrijving: Stuurt roer naar rechts.
 * Argumenten: richting in bytes.
 * Return: -
 * Commentaar: De hoeveelheid de er wordt gestuurd wordt bepaald aan de hand van
 *             de groote van de byte b. Er wordt in zes stappen gemeten, waarbij
 *             stuur is dertien rechtdoor is.
 *             Tevens wordt er nadat er roer is gegeven het compas vlaggetje
 *             weer op nul gezet, waardoor er een nieuw bericht wordt verzonden
 *             naar de wal met de laatste richting, dir.
*/
     //printf("Do right: %x\n", b);
   if (b < 20)
      stuur = 13;
   else if (b < 40)
      stuur = 14;
   else if (b < 60)
      stuur = 15;
   else if (b < 80)
      stuur = 16;
   else if (b < 100)
      stuur = 17;
   else
      stuur = 18;

   compas_verzonden = 0;         // 0 is opnieuw verzenden van compas
}

void do_forward(byte b) {
/*
 * Omschrijving: Zet vaarrichting en snelheid.
 * Argumenten: snelheid in bytes.
 * Return: -
 * Commentaar: Eerst wordt er getest of de polariteit zo nodig moet worden omge-
 *             zet. Vervolgens wordt de duty van de pwm gezet met byte b. Dit is
 *             de snelheid van de motor.
*/
   if (!polarity) {         // als de polariteit op achteruit staat:
      switch_polarity();
   }

   set_pwm1_duty(b);
}

void do_backward(byte b) {
/*
 * Omschrijving: Zet vaarrichting en snelheid.
 * Argumenten: snelheid in bytes.
 * Return: -
 * Commentaar: Eerst wordt er getest of de polariteit zo nodig moet worden omge-
 *             zet. Vervolgens wordt de duty van de pwm gezet met byte b. Dit is
 *             de snelheid van de motor.
*/
   if (polarity) {         // als de polariteit op vooruit staat:
      switch_polarity();
   }

   set_pwm1_duty(b);
}

void do_weapon(boolean b) {
/*
 * Omschrijving: Zet wapen vlaggetje.
 * Argumenten: vlaggetje byte b. Had eerst de bedoeling om het wapen aan en uit
 *             de doen, maar is later veranderd naar alleen een vlaggetje
 *             zetten.
 * Return: -
 * Commentaar: Zet wapen vlaggetje waardoor het wapen wordt uitgevoerd in de
 *             main.
*/
   do_wapen = 1;
}

void do_power(boolean b) {
/*
 * Omschrijving: Zet power vlaggetje.
 * Argumenten: vlaggetje byte b. Had eerst de bedoeling om de power aan en uit
 *             de doen, maar is later veranderd naar alleen een vlaggetje
 *             zetten.
 * Return: -
 * Commentaar: Zet wapen vlaggetje waardoor het wapen wordt uitgevoerd in de
 *             main.
*/
   //pin ff hoog voor uitschakelen spanning, 200ms?
   set_pwm1_duty(0);
}

void get_direction() {
/*
 * Omschrijving: Berekend de vaarrichting van de boot.
 * Argumenten: -
 * Return: -
 * Commentaar:   Er wordt gewacht zolang de input van het kompas hoog is,
 *               vervolgens zolang het laag is en dan wordt de timer op nul
 *               gezet, dus bij het begin van een periode.
 *               Vervolgens wordt er weer gewacht zolang het inputsignaal van
 *               het kompas hoog is en wordt er vervolgens de tijd van hoelang
 *               het signaal hoog was opgeslagen.
 *               Vervolgens wordt op dezelfde manier gemeten hoelang het lage
 *               signaal is.
*/
   //printf("Compass CMPS03\n");

   while (input(PIN_c1));
   while (!input(PIN_c1));
   set_timer1(0);

   while (input(PIN_c1));
   t_high = get_timer1();

   set_timer1(0);
   while (!input(PIN_c1));
   t_low = get_timer1();

   ms = (float) t_low/65;      // laag pulse is altijd  65ms
                  // => ms is aantal timer pulsen per ms
   dir = (float) t_high/ms-1;   // hoog pulse breedte in ms min 1
                  // is 1/10 van de hoek
                  // in graden.

   dir = 2.22;
   //printf("Direction: %f\n", dir);
}

void protocol(char cmd[]) {
/*
 * Omschrijving: Afhandelen van de ontvangen commando's bluetooth IC of walsysteem.
 * Argumenten: commando string.
 * Return: -
 * Commentaar: -
*/
   switch(cmd[0]) {
   case CONNECT:
      printf("Connected\n");
      break;
   case OK:
      printf("OK\n");
      break;
   case ERROR:
      printf("Error\n");
      break;
   case LEFT:
      do_left(cmd[1]);
      //output_d(0x02);         // led 2 aan
      break;
   case RIGHT:
      do_right(cmd[1]);
      //output_d(0x04);         // led 3 aan
      break;
   case FORWARD:
      do_forward(cmd[1]);
      //output_d(0x08);         // led 4 aan
      break;
   case BACKWARD:
      do_backward(cmd[1]);
      //output_d(0x10);         // led 5 aan
      break;
   case WEAPON:
      do_weapon(cmd[1]);
      //output_d(0x20);         // led 6 aan
      break;
   case POWER:
      do_power(cmd[1]);
      //output_d(0x40);         // led 7 aan
      break;
   case STATUS:
      //output_d(0x80);         // led 7 aan
      break;
   default:
      //printf("unknown cmd: %S\n", cmd[0]);
   }
}

#INT_Rb
void rs232(void) {
/*
 * Omschrijving: Inlezen van data karakters op de rs232 bufferpoort
 * Argumenten: -
 * Return: -
 * Commentaar: De data strings worden gescheiden door <cr> en <lf>.
 *             Deze karakters worden uit de data gefilterd. De data string
 *             die overblijft wordt als parameter meegegeven aan de procedure
 *             protocol.
*/
   char chr;               // Uitgelezen karakter (letter).

   disable_INTERRUPTS(GLOBAL);

   while (kbhit()) {
      // Filter de <cr> en <lf> uit de data.
      if (((chr=getc())!='\n')&&(chr!='\r')&&(i<(bufsize-1)))
         strbuf[i++]=chr;
      else {
         if ((chr=='\r')) {
            strbuf[i]='\0';
            // Controlleer of er wel data in de strbuf staat
            // ivm commando's Bluetooth IC,
            // deze beginnen namelijk met <cr><lf> en
            // eindigen ook met <cr><lf>.
               if(i > 0)
               protocol(strbuf);
            i = 0;
         }
         // Voorkom bufsize overflow van array.
         if (i >= bufsize-1)
            i = 0;
      }
   }

   ENABLE_INTERRUPTS(GLOBAL);
}

void bluetoothinitialisatie(void) {
/*
 * Omschrijving: Instellen van bluetooth IC.
 * Argumenten: -
 * Return: -
 * Commentaar: Resetten van bluetooth IC en AT commando's sturen naar IC.
 *             Door een key en een bluetooth adres in te stellen is het onmogelijk om
 *             het bootsysteem door een ander systeem over te nemen.
*/
   output_d(0x10);
   output_b(0x00);      // Resetten van bluetooth IC. Gebruik reset pin bluetooth IC.
   delay_ms(2000);      // Minimaal 1 seconden resetten, hier gebeurt het 2 seconden.
   output_b(0x20);
}

void bluetoothcommunicatie(void) {
/*
 * Omschrijving: communicatie opzetten.
 * Argumenten: -
 * Return: -
 * Commentaar: verbinding maken met de bluetooth adres.
*/
   disable_interrupts(GLOBAL);
   
   fprintf(BT, "\n\rat+btname=plankjegas\n\r");   // naam vastellen bt module
   fprintf(BT, "\n\ratd00A0961d2FF4\n\r");      //connecten met walsysteem
   delay_ms(100);   
   
   enable_interrupts(INT_Rb);
   enable_interrupts(GLOBAL);   
}

void main(void) {
   set_tris_a(0xCF); //1100 1111
   set_tris_b(0x8f); //1000 1111 (b0 input)
   set_tris_c(0x93); //1000 0011 (alle lijnen input)
   set_tris_d(0x00); //0000 0000 (alle lijnen output)
   set_tris_e(0xE8); //1110 1000 (b4=0: No PSPMODE!)
   
   // declareren
   int x;                // wapen: teller
   
   // initialiseren
   x = 0;
   connected = 0;
   vlag = 0;   
   compas_verzonden = 1;
   do_wapen = 0;
   i = 0;


   // MOTER van de voortstuwing instellen. (frequentie)
   setup_ccp1(CCP_PWM);            // Pwm voor aandrijving
   setup_timer_2(T2_DIV_BY_4, 127, 16);   // frequentie voor pwm signaal +/- 500Hz
   setup_timer_0 (RTCC_DIV_2|RTCC_INTERNAL);   // set timer voor servo mtr
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);   // TIMER voor compas


   enable_interrupts(INT_TIMER0);      // Timer voor servo v/h sturen
   enable_interrupts(GLOBAL);


   while(true) {
      if (connected == 0) {
         bluetoothcommunicatie();
         delay_ms(100);
      }

      if (compas_verzonden == 0) {
         get_direction();
         disable_interrupts(INT_Rb);
         fprintf(BT, "\rD%f\r", dir);   // Verzend richting via BT.
         enable_interrupts(INT_Rb);
         compas_verzonden = 1;      // Kompas vlaggetje op true zetten.
      }   

      if (do_wapen == 1) {
         for(x = 0; x < 13; x++) {
            output_d(0x01);      // uitgang d1 hoog
            delay_ms(tijd);
            output_d(0x02);      // uitgang d2 hoog
            delay_ms(tijd);
            output_d(0x04);      // uitgang d3 hoog
            delay_ms(tijd);
            output_d(0x08);      // uitgang d4 hoog
            delay_ms(tijd);
         }
         do_wapen = 0;         // Wapen vlaggetje op true false zetten.
      }   
   }
}
[/code]
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 10, 2007 12:51 pm     Reply with quote

Quote:

#include "16f877.h"
#include <STDLIB.H>
#define HIGH_START 114
#fuses HS,NOWDT,NOPROTECT, NOLVP

Add NOLVP to your #fuses statement as shown in bold.


Quote:

#INT_Rb
void rs232(void) {
char chr;

disable_INTERRUPTS(GLOBAL);



ENABLE_INTERRUPTS(GLOBAL); }
}

You don't have to enable/disable global interrupts in any interrupt routine.
The PIC automatically does this for you in hardware. In fact, it's
dangerous to re-enable Global interrupts inside an interrupt routine.
Nested interrupts are not supported for the 16F series PICs.
Delete those two lines.


Quote:

Is it wrong to use INT_RB?

The standard method is to use INT_EXT (on pin B0) for the Rx pin
of a software UART.
Wieger



Joined: 10 Jun 2007
Posts: 2

View user's profile Send private message

PostPosted: Sun Jun 10, 2007 1:25 pm     Reply with quote

Thanks, I hope this will help. Smile

But what exactly is the effect of the NOLVP (no low-voltage programming) option (or the missing of it)?

And why is using INT_EXT the standard method?
arunb



Joined: 08 Sep 2003
Posts: 492
Location: India

View user's profile Send private message Send e-mail

RE:
PostPosted: Sun Jun 10, 2007 2:38 pm     Reply with quote

Hi,

Technically it is possible to use INT_EXT or INT_RB for detecting USART characters, I have also used them in my applications, but I I have found that they work well in low baud rates only, as the baud rate is increased, more and more garbage is received. Also you must put a delay_us() statement in the interrupt routine.

for eg:

int_ext
usart2()
{

delay_us(100)
cData=getc(UART2_STERAM);

}

thank
arunb
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Sun Jun 10, 2007 5:43 pm     Reply with quote

To use PB on change interrupt feature be aware that:

1) Any pin PB4...7 will fire the interrupt. Be sure that all the 3 "unused"
PortB pins should be in steady state.

2) It is the programmer responsibility to clear the interruption, it is not cleared
"automatically" like another interrupts.
To clear the interrupt, you must do a portB read operation inside the interrupt.
Add: x = portB;
inside the interrupt handler, if not you will receive only one of the expected char.


Humberto
ckielstra



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

View user's profile Send private message

PostPosted: Mon Jun 11, 2007 12:53 am     Reply with quote

Quote:
But what exactly is the effect of the NOLVP (no low-voltage programming) option (or the missing of it)?
95% of the chip programmer devices are of the high voltage type.
The low voltage programmers require the PGM (B3 on the 16F877) so this can't be used in your application for other purposes. With LVP active an (accidental) low voltage on the PGM input activates the programming mode stalling your processor. Setting the NOLVP fuse saves you these potential problems.

Your protocol() function is calling printf. Calling printf from inside an interrupt routine shouldn't be done as it takes a long time and you are going to miss received data.
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