0
votes

Following this tutorial, I wanted to send and receive data from PIC18f4520 to my computer. Sending data to the computer using serial port is working fine for me. I'm now trying to receive data from my computer using the serial port. I'm sending data from a C# app which has been created by my teacher (it's working fine for other students) so this can't be the problem.

To receive data, I need to do it using interrupts. I changed USART_RX_INT_OFF to USART_RX_INT_ON and enabled the peripheral interrupt.

Using the debugging tool, I noticed that my program was never entering is the interrupt (I must use the high-priority one).

What my program does basically (this is working fine) :

  • I'm gathering analog data from pin RA5 using ADC
  • Sending HIGH or LOW to pin RE2 to light a bulb or to turn it off
  • Using pin RA1 to control a servo motor
  • Using an LCD screen to print information on it

Init_Interruptions() is supposed to init the interrupts ADC_Init() is supposed to init ADC

Here is my code, I tried to add as much comments as possible in order to be clear. Let me know if you can help me, this would be really appreciated.

#include <stdio.h>
#include <stdlib.h>

#include "p18f4520.h"

#include <stdio.h>
#include <stdlib.h>
#include <plib/adc.h>
#include <plib/usart.h>
#include <plib/portb.h>
#include <plib/delays.h>
#include <plib/timers.h>
#include <plib/pwm.h>
#include <string.h>
#include <xc.h>
#include <stdlib.h>
#include "config.h"
#include "hd44780/hd44780.h"

#define delay1S  for(uint8_t i = 0 ; i < 20 ; i++) __delay_ms(50)

int counter;
unsigned char textTx[10];
unsigned char JourMSG[]= "jour";
unsigned char NuitMSG[]= "nuit";
        /*char chaine[10]= "";
        char buffer[10];
        char * s1, * s2;
        unsigned int i, j;*/

//Servo motor signal sending functions
void turn_middle() { //0°
        PORTAbits.RA1 = 1; 
        __delay_us(1500);
        PORTAbits.RA1 = 0; 
        __delay_us(18500);
}

void turn_left() { //-90°
        PORTAbits.RA1 = 1;
        __delay_us(1000);
        PORTAbits.RA1 = 0; 
        __delay_us(19000);
}

void turn_right() { //90°
        PORTAbits.RA1 = 1; 
        __delay_us(2000);
        PORTAbits.RA1 = 0; 
        __delay_us(18000);
}
//////////////////////////////////////

//Delay functions
void DelayxmSecond(unsigned int tempo_ms)
{
    for(int i=0;i<tempo_ms;i++)
        __delay_ms(1);
}


void   DelayxSecond(unsigned int tempo_s)
{

    for(int j=0;j<tempo_s;j++)
        DelayxmSecond(1000);


}
////////////////////////////////////////


void Init_Timer1(void)
{
   OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_EXT & T1_PS_1_1 & T1_OSC1EN_ON & T1_SYNC_EXT_ON);
   IPR1bits.TMR1IP=0;
   WriteTimer1(32768);
}

void Init_Interruptions(void)
{
        PIR1bits.RCIF = 0; //reset RX pin flag
        IPR1bits.RCIP = 1; //high priority
        PIE1bits.RCIE = 1; //Enable RX interrupt
        INTCONbits.PEIE = 1; //Enable pheripheral interrupt (serial port is a pheripheral)

        RCONbits.IPEN = 1;
        INTCONbits.GIEH = 1;
        INTCONbits.GIEL = 1;
}

void interrupt high_priority Int_haute()
{
    //check if the interrupt is caused by RX pin
    if(PIR1bits.RCIF == 1)
    {
        INTCONbits.GIEH = 0;

        getsUSART(textTx,10);
        PIR1bits.RCIF = 0; // clear rx flag

        INTCONbits.GIEH = 1;
    }
}

void interrupt low_priority Int_basse() //Not doing anything here
{
   INTCONbits.GIEL = 0;

   INTCONbits.GIEL = 1;
}

void ADC_Init() //ADC init
{
  ADCON1bits.VCFG1 = 0; //-Vref VSS
  ADCON1bits.VCFG0 = 0; //+Vref VDD
  ADCON1bits.PCFG3 = 1110;
  ADCON1bits.PCFG2 = 1110;
  ADCON1bits.PCFG1 = 1110;
  ADCON1bits.PCFG0 = 1110;

  ADCON0bits.CHS3 = 0000;
  ADCON0bits.CHS2 = 0000;
  ADCON0bits.CHS1 = 0000;
  ADCON0bits.CHS0 = 0000;
  ADCON0bits.GODONE = 0;
  ADCON0bits.ADON = 1;

  ADCON2bits.ADFM = 0;
  ADCON2bits.ACQT2 = 101;
  ADCON2bits.ACQT1 = 101;
  ADCON2bits.ACQT0 = 101;
  ADCON2bits.ADCS2 = 010;
  ADCON2bits.ADCS2 = 010;
  ADCON2bits.ADCS2 = 010;

  ADCON0bits.ADON = 1; //TURN ON AD MODULE

  ADCON1 = 0xC0; //All pins as Analog Input
                 //With reference voltages VDD and VSS
}

void main(){

    TRISCbits.TRISC7 = 1;
    TRISCbits.TRISC6 = 0;
    OpenUSART( USART_TX_INT_OFF &USART_RX_INT_ON &USART_ASYNCH_MODE &USART_EIGHT_BIT &USART_BRGH_HIGH,12 );

    Init_Interruptions();

    //Set LCD pins to output
    TRISD=0x00;

    //PIC2DEMPLUS related stuffs. Not needed on board without LCD power control and with R/W wired to ground
    LATDbits.LD7 = 1;           // LCD power on
    __delay_ms(50);             // LCD power up delay
    LATDbits.LD5 = 0;           // R/W set to W

    //LCD init
    LCDinit(LCD_INIT_CURSOR_DISABLED);
    __delay_ms(2);

    ADC_Init();

    TRISAbits.TRISA5 = 1; // configure RA5 as analog input

    ADCON0           = 0b01100000;  // Set channel select to AN5
    ADCON1           = 0b00001011;  // Configure RA5/AN5 as analogue
    ADCON2           = 0b10101010;  // Right justified result
    // configure voltage reference
    //ADCON1bits.VCFG1 = 0;      // -ve ref = Vss
    //ADCON1bits.VCFG0 = 1;   // +ve ref = Vdd
    // select ADC input channel
    ADCON0bits.CHS = 100;   // input = AN5
    ADCON2bits.ACQT = 100;   // input = AN5
    ADCON2bits.ADCS = 100;   // input = AN5
    ADCON2bits.ADFM = 1;
    ADCON0bits.ADON = 1; // turn on ADC module

    TRISAbits.TRISA1 = 0; //RA1 output -> SERVOMOTOR
    TRISEbits.TRISE2 = 0; //RB1 output -> BULB
    PORTBbits.RB1 = 1;
    int compteur=0;
    int modejour=1; //Starting with day mode
    unsigned int N;
    while(1)
    {
        ADCON0bits.GO_DONE = 1; //LAUNCH CONVERSION
        while(ADCON0bits.GO_DONE != 0);
        LCDpos(0,3);
        N=(ADRESH<<8)+ADRESL;
        putsUSART(textTx);
        if(N>800 && modejour==0)
        {
            LCDpos(0,3);
            LCDprintConst("PLEIN JOUR");
            putsUSART(JourMSG);
            PORTEbits.RE2 = 0;
            modejour=1;
            compteur=0;
            while(compteur<20) 
            {
                turn_right();
                compteur++;
            }
        }
        if(N<800 && modejour==1)
        {
            LCDpos(0,3);
            LCDprintConst("MODE NUIT ");
            putsUSART(NuitMSG);
            PORTEbits.RE2 = 1;
            modejour=0;
            compteur=0;
            while(compteur<20) 
            {
                turn_left();
                compteur++;
            }
        }
    }
}
2
numbers like this: ADCON2bits.ADCS2 = 010; are octal values, it that what you actually want?user3629249
the posted code is not initializing the clock peripheral, I would think that step is necessary to get accurate baud rates, delay timings, etc.user3629249
the referenced tutorial includes the appropriate code to use the PIC81 as an echo device. Amongst other things, the ADC peripheral needs to be disabled to be able to use the appropriate I/O pin for 'rx' data bits. I do not see that step being performed in the code.user3629249
in the Int_haute() function, calling getsUSART() with a second parameter of 10 will cause the code to stay in that interrupt for a minimum of 10 'char' times. That is a VERY long time to be sitting in an interrupt. getsUSART() performs polling rather than interrupt driven I/O. Suggest removing the interrupt code, then calling: char DataRdyUSART( void ); on a regular basis. keep a status of how many bytes are currently in the input buffer. And when that buffer is full, invoking the code to process the buffer.user3629249
the char DataRdyUSART( void ); can be invoked from within the main() while() loop and if returns true, then call getsUSART() to get one(1) char which the code appends to the input buffer. When the input buffer is full, then process the data and indicate buffer is again empty.user3629249

2 Answers

2
votes

Seems like you did not enable global interrupts.

From the tutorial you posted:

ei();       //remember the master switch for interrupt?

This call is missing in your code.

0
votes

After adding "ei();" to my program, it didn't work as expected. I was using "SparkFun FTDI Basic Breakout - 5V" to connect through serial port. I changed my way to connect the PC and the PIC using an RS-232 cable and it worked ! – nico1717 9 mins ago

So I don't really know why but I think that the FTDI board was not sending data from computer to the pic properly (even if the Rx led blinked everytime I sent an info). All is OK now I both transmit and receive info (I still call ei(); in my programm).