carraysmicrocontrollerpicmicrochip

Storing PORTD value in array on PIC18F452 (C)


I'm a looking for some advice as I'm working on a PIC18F452 on Proteus.

My objective is to acquire the value of PORTDbits.RD0 (set as input) every 100 ms (set through timer1) and store it in an 8-bit array. This frame would be later sent through SPI to the slave.

For the moment, I have only implemented what I consider to be the filling of the array and the bit shifting. Sadly, when I start the simulation, only on bit of the array contains at some point the value of PORTDbits.RD0.

What should I do?

Here's my code:

/* CONFIG *******************************************************************/
#pragma config PWRT  = ON    // Power-up timer
#pragma config OSC   = HS    // High-speed oscillator
#pragma config LVP   = OFF   // Low-voltage in-circuit serial Programming
#pragma config DEBUG = ON    //

/* INCLUDES *****************************************************************/
#include "project_config.h"  // All headers inclusion

/* MACROS *******************************************************************/
#define nop() {_asm nop _endasm}

/* DEFINES ******************************************************************/
#define SIZE 8

/* FUNCTIONS PROTOTYPES *****************************************************/
void main(void);

void isr_config(void);
void io_config(void);

void timer1_config(void);
void timer1_isr(void);

/* PROTOTYPES ***************************************************************/

/* VARIABLES DEFINITION *****************************************************/
unsigned int filling_cnt = 0;

/* MAIN *********************************************************************/
void main(void) {
    unsigned char array[SIZE];
    unsigned int index = 0;
    int j;

    /// Initialization
    io_config();
    timer1_config();
    isr_config();

    /// Interruption
    timer1_isr();

    /// Data acquisiton
    while(1) {
        array[index] = PORTDbits.RD0;           // Read RD0 and save in array
        for(index = 0; index < SIZE; index++) { // Fill array
            array[index] = array[index+1];      // Shifting n_value to insert n+1_value
            //printf("%s\n", array);
        } // rof

        filling_cnt++;              // Array counter for filling control

        if(filling_cnt > SIZE) {     // Reached the end of array ?
            index = 0;               // Reset counter
            printf("%s\n", array);   // Send data to terminal
            for (j=0; j<SIZE; j++) {
                array[j] = '\0';     // Empty array
            } //rof
        } // fi
    }
}

/* FUNCTIONS ****************************************************************/
/// Configurations
void timer1_config(void) {
    T1CONbits.RD16 = 1;    // Timer/Counter 8-bits/16-bits Control bit: 0=8-bits / 1=16-bits
    T1CONbits.T1CKPS1 = 1; // Prescaler
    T1CONbits.T1CKPS0 = 1; //   1 = 0b00
                           //   2 = 0b01
                           //   4 = 0b10
                           //   8 = 0b11
    T1CONbits.T1OSCEN = 1; // Timer1 Oscillator shut off
    T1CONbits.TMR1CS = 0;  // Timer1 Clock Source Select bit
                           //   0 = Internal Clock (Fosc/4)
                           //   1 = Transition on T1CKI pin
    T1CONbits.TMR1ON = 1;  // Timer1 On/Off Control bit
                           //   1 = Enables Timer1
                           //   0 = Stops Timer1
    TMR1H = 0x0B;          // Preset timer1 value for MSB register
    TMR1L = 0xDB;          // Preset timer1 value for LSB register
                           // to get a 100 ms delay
}

void isr_config(void) {
    PIE1bits.TMR1IE = 1;   // Enable Timer1 interrupts
    PIR1bits.TMR1IF = 0;   // Clear Timer1 interrupt flag
    IPR1bits.TMR1IP = 1;   // Non high priority interrupt

    RCONbits.IPEN   = 1;   // Interrupt High level

    INTCONbits.PEIE = 1;   // All peripherals interrupts verified
    INTCONbits.GIE  = 1;   // All interrupts verified
}

void io_config(void) {
    TRISB = 0x00;          // PORTB as output
    TRISDbits.TRISD0 = 1;  // COMP_OUT as input
    TRISDbits.TRISD1 = 0;  // DATA as output
}

/// Interrupts
#pragma code highVector = 0x08 //lowVector = 0x18
void InterruptHigh (void) {
    _asm
    goto timer1_isr
    _endasm
}
#pragma code

#pragma interrupt timer1_isr
void timer1_isr(void) {
    if (PIR1bits.TMR1IF == 1) {  // Check that timer1 overflow is reason for ISR.
                                 // even though there is only one Interrupt source
                                 // trigger enabled, it is good programming practice to
                                 // test why we have arrived at the ISR.
        PIR1bits.TMR1IF = 0; // Timer1 interrupt flag clear

        TMR1H = 0x0B;  // Preset timer1 value for MSB register
        TMR1L = 0xDC;  // Preset timer1 value for LSB register
                       // with a 20 MHz quartz crystal, Timer1 prescaler set to /8
                       // decimal 3036 (0x0B 0xDC) is the counter start point
                       // which will result in Timer1 overflow 1 per 100 ms
                       // 65536 - 3036 = 62500 cycles
                       // 10 interrupts per second

        LATBbits.LATB4 = !LATBbits.LATB4; // Invert the condition of LED to show program
                                          // has entered the Interrupt routine
        PORTDbits.RD1 = !PORTDbits.RD1;   // Invert the condition of DATA to show program
                                          // has entered the Interrupt routine
    } //fi
}

/* EOF main.c ***************************************************************/

Solution

    1. In the main function, you have an infinite loop, which runs without any delay between two acquisitions. You need to have a delay of 100 ms between the two times that you read PORTD.

      You can introduce a global flag. This is set in the timer subroutine, and is cleared in main.

    2. The code for filling the data into the array is not correct. The code below fills the array, starting from location arrray[0], array[1] to maximum in order.

      The timer should be modified like this:

       void timer1_isr(void) {
           if (PIR1bits.TMR1IF == 1) {
               blTimeOverFlag = 1;
               // Other code here
           }
       }
      

      The main function loop is below:

       while(1) {
           if (blTimeOverFlag == 1)
           {
               blTimeOverFlag = 0;
               array[filling_cnt] = PORTDbits.RD0;  // Read RD0 and save in array
               filling_cnt++;                       // Array counter for filling control
      
               if(filling_cnt >= SIZE) {            // Reached the end of array?
                   filling_cnt = 0;
                   printf("%s\n", array);           // Send data to terminal
                   for (j=0; j<SIZE; j++) {
                       array[j] = '\0';             // Empty array
                   } // rof
               } // fi
           }
       }