0

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 ***************************************************************/
5
  • What?? You read the port: 'array[index] = PORTDbits.RD0;', and them immediately overwrite the value you read: 'array[index] = array[index+1];'. You say that this code actually works, a bit? Commented May 18, 2016 at 8:35
  • Also, 'unsigned char array[SIZE];' is an 8 BYTE array, not 8 bits. Can you be clearer re. your actual intent? Commented May 18, 2016 at 8:38
  • Hi, Yes I know it's absolutely stupid and illogical. But I've tried the other way : array[index+1] = array[index] and it wasn't better... EDIT : I looked up for the help on the bit shifting and that's what I have found to do it manually Commented May 18, 2016 at 8:39
  • The application of the code would be audio monitoring. I just want to create frames from the audio signal given in input. They will be sent to the slave to compare if the audio in output is the same Commented May 18, 2016 at 8:42
  • Ok, I have tried like this and it seems to work. 'array[index] = PORTDbits.RD0;' // Read RD0 and save in array 'printf("%s", array);' '++index; ' // Getting index ready for next bit Commented May 18, 2016 at 9:28

1 Answer 1

1
  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
         }
     }
    
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks ! Before I could read you answer, I had re-written the code for filling the data into the array to one very close to the one you are suggesting (just the name of the variables were different). Regarding the global flag, I'm sorry but in don't really understand its purpose. When configuring my timer, I have set the registers, prescaler to get my 100ms delay. Won't it do a redundancy if I use the flag ?
The flag is required to have a delay in between two reads of PORTDbits.RD0. In your original code, after completing one iteration of the data acquisition while(1) loop, it reads the data again immediately. The while loop will take in the order of microseconds to execute. The next data is read after few microseconds rather than 100ms as desired.
OK. Thanks a lot for your help.
Quick additional question : would it work if I use a delay function between two acquisition instead of the flag ?
Yes, But you have gone to all the trouble of setting up the timer. So you can use the better solution of the timer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.