0
\$\begingroup\$

enter image description hereI'm trying to read data from MAX6675 with PIC16f1937. The bottom is my code

#define _XTAL_FREQ  4000000
#include <xc.h>
#include "MAX6675_header.h"
#include <stdbool.h>
#include <string.h>

volatile bool spi_rx_data_ready = false;

void __interrupt() interrupt_isr(){
    INTCONbits.GIE = 0;                         //Disable interrupt
    if(PIR2bits.BCLIF == 1){                    //Checking to see if MSSP Bus Collision interrupt is triggered
        
        PIR2bits.BCLIF = 0;                     //Reseting flag
    }
    else if(PIR1bits.SSPIF){                    //Checking to see if MSSP Interrupt is triggered
        spi_rx_data_ready = true;               //A flag to indicate the data is received
        PIR1bits.SSPIF = 0;                     //Reseting flag
    }
    INTCONbits.GIE = 1;                         //Enable interrupt
}

void PORT_configuration(){
    TRISB = 0x00;
    LATB = 0;
    TRISCbits.TRISC3 = 0;                       //SCK as output
    TRISCbits.TRISC4 = 1;                       //SDI as input
    TRISCbits.TRISC5 = 0;                       //SDO as output
    TRISCbits.TRISC6 = 0;                       //SS as output
    LATCbits.LATC6 = 1;                         //SS is set to high to deselect slave
}

void SPI_Configuration(){
    SSPCON1bits.SSPEN = 0;                      //Disabling serial port
    ANSELA = 0x00;                              //Setting different PORTS as digital I/O
    ANSELB = 0x00;
    ANSELD = 0x00;
    ANSELE = 0x00;
    SSPSTATbits.SMP = 1;                        //Input data sampled at end of data output time                        
    SSPSTATbits.CKE = 1;                        //Transmit occurs on transition from Idle to active clock state
    SSPCON1bits.CKP = 0;                        //Idle state for clock is a high level
    SSPCON1bits.SSPM = 0x00;                    //SPI Master mode, clock = FOSC/4
    SSPCON1bits.SSPEN = 1;                      //Enabling serial port
    PIE1bits.SSPIE = 1;                         //MSSP Interrupt Enable bit
    PIE2bits.BCLIE = 1;                         //MSSP Bus Collision Interrupt Enable bit
}

void SPI_read(){
    unsigned char Temp1=0,Temp2=0;
    LATCbits.LATC6 = 0;
    __delay_us(0.1);                            //Wait for 100 nano seconds
    SSPBUF = 0x00;                              //Send dummy data to start communication
    while(spi_rx_data_ready == false);          //Wait for the data to be completely received
    spi_rx_data_ready = false;                  //Reset the flag
    Temp1 = SSPBUF;
    LATCbits.LATC6 = 1;
    __delay_ms(1000);                           //For better observation in PROTEUS (Remove for real_time application)
}

void main(void) {
    //Select 8MHz internal oscillator
    OSCCONbits.SCS = 0x03;              //Internal oscillator block
    OSCCONbits.IRCF = 0x0d;             //FOSC = 4MHz
    
    INTCONbits.GIE = 1;                 //To enable global interrupts
    INTCONbits.PEIE = 1;                //To enable peripheral interrupts
    
    //Calling for configuration functions
    PORT_configuration();
    SPI_Configuration();
    
    while(1){
        SPI_read();
    }
}

But the problem is that the output data of the MAX6675 is 16 bits and the microcontroller's SPI buffer is 8 bit (MAX6675 uses SPI protocol). How can I receive the second 8 bits?

EDITED SPI_READ()

void SPI_read(){
    unsigned char Temp1=0,Temp2=0;
    LATCbits.LATC6 = 0;
    __delay_us(0.1);                            //Wait for 100 nano seconds
    SSPBUF = 0x00;                              //Send dummy data to start communication
    while(spi_rx_data_ready == false);          //Wait for the data to be completely received
    spi_rx_data_ready = false;                  //Reset the flag
    LATD = SSPBUF;
    SSPBUF = 0x00;                              //Send dummy data to start communication
    while(spi_rx_data_ready == false);          //Wait for the data to be completely received
    spi_rx_data_ready = false;                  //Reset the flag
    LATB = SSPBUF;
//    LATD = Temp1;
//    LATB = Temp2;
    LATCbits.LATC6 = 1;
    __delay_ms(1000);                           //For better observation in PROTEUS (Remove for real_time application)
}
\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

You just send dummy data twice, and receive twice, without toggling the /CS line.

The delay between the two 8 bit values is not an issue.

\$\endgroup\$
3
  • \$\begingroup\$ I edited the SPI_READ() and included it in my main question with a picture of my PROTEUS. I did as you said but in PROTEUS I'm getting wrong numbers I think. \$\endgroup\$
    – Momo
    Commented Dec 27, 2021 at 9:59
  • \$\begingroup\$ That's a little more detail than I want to get into, but I don't think the delay_us macro accepts floating point numbers. \$\endgroup\$ Commented Dec 27, 2021 at 10:04
  • \$\begingroup\$ I deleted that delay. But I'm not getting any good result. \$\endgroup\$
    – Momo
    Commented Dec 27, 2021 at 10:08
0
\$\begingroup\$

In theory, Spehro is right but your timing is wrong.

enter image description here

This is the data that you will get from MAX6675.

enter image description here

As you can see from the datasheet, 100ns refers only to tCH, tCL, tCSS.

200ns is 1 Period and every bit comes at the rising edge of the period. In theory, you should get 8 bit in 1600ns. After 1600ns, you should be ready to get the second part of the data.

Try 1600ns delay, I might miscalculate but just give it a try.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the help. I could solve the problem and I posted it. \$\endgroup\$
    – Momo
    Commented Dec 27, 2021 at 12:56
0
\$\begingroup\$

Alright, the problem is solved. The right code is as follows:

#define _XTAL_FREQ  4000000
#include <xc.h>
#include "MAX6675_header.h"
#include <stdbool.h>
#include <string.h>

#define RS LATBbits.LATB2
#define EN LATBbits.LATB3
#define D4 LATBbits.LATB4
#define D5 LATBbits.LATB5
#define D6 LATBbits.LATB6
#define D7 LATBbits.LATB7
#include "lcd.h"
#include "stdio.h"
#include "stdlib.h"

volatile bool spi_rx_data_ready = false;

void __interrupt() interrupt_isr(){
    INTCONbits.GIE = 0;                         //Disable interrupt
    if(PIR2bits.BCLIF == 1){                    //Checking to see if MSSP Bus Collision interrupt is triggered
        
        PIR2bits.BCLIF = 0;                     //Reseting flag
    }
    else if(PIR1bits.SSPIF){                    //Checking to see if MSSP Interrupt is triggered
        spi_rx_data_ready = true;               //A flag to indicate the data is received
        PIR1bits.SSPIF = 0;                     //Reseting flag
    }
    INTCONbits.GIE = 1;                         //Enable interrupt
}

void PORT_configuration(){
    TRISB = 0x00;
    LATB = 0;
    TRISD = 0x00;
    LATD = 0;
    TRISCbits.TRISC3 = 0;                       //SCK as output
    TRISCbits.TRISC4 = 1;                       //SDI as input
    TRISCbits.TRISC5 = 0;                       //SDO as output
    TRISCbits.TRISC6 = 0;                       //SS as output
    LATCbits.LATC6 = 1;                         //SS is set to high to deselect slave
}

void SPI_Configuration(){
    SSPCON1bits.SSPEN = 0;                      //Disabling serial port
    ANSELA = 0x00;                              //Setting different PORTS as digital I/O
    ANSELB = 0x00;
    ANSELD = 0x00;
    ANSELE = 0x00;
    SSPSTATbits.SMP = 1;                        //Input data sampled at end of data output time                        
    SSPSTATbits.CKE = 1;                        //Transmit occurs on transition from Idle to active clock state
    SSPCON1bits.CKP = 0;                        //Idle state for clock is a high level
    SSPCON1bits.SSPM = 0x00;                    //SPI Master mode, clock = FOSC/4
    SSPCON1bits.SSPEN = 1;                      //Enabling serial port
    PIE1bits.SSPIE = 1;                         //MSSP Interrupt Enable bit
    PIE2bits.BCLIE = 1;                         //MSSP Bus Collision Interrupt Enable bit
}

void SPI_read(){
    int raw_value=0;
    char d[16];
    float temp=0.0;
    unsigned char Temp1=0,Temp2=0;
    LATCbits.LATC6 = 0;
    SSPBUF = 0x00;                              //Send dummy data to start communication
    while(spi_rx_data_ready == false);          //Wait for the data to be completely received
    spi_rx_data_ready = false;                  //Reset the flag
    Temp1 = SSPBUF;
    SSPBUF = 0x00;                              //Send dummy data to start communication
    while(spi_rx_data_ready == false);          //Wait for the data to be completely received
    spi_rx_data_ready = false;                  //Reset the flag
    Temp2 = SSPBUF;
    raw_value = (Temp1 << 5) | (Temp2 >> 3) ;
    temp = (float)raw_value / 4;
    LATCbits.LATC6 = 1;
    sprintf(d,"%f",temp);
    Lcd_Clear();
    Lcd_Set_Cursor(1,1);
    Lcd_Write_String(d);
}

void main(void) {
    //Select 8MHz internal oscillator
    OSCCONbits.SCS = 0x03;              //Internal oscillator block
    OSCCONbits.IRCF = 0x0d;             //FOSC = 4MHz
    
    INTCONbits.GIE = 1;                 //To enable global interrupts
    INTCONbits.PEIE = 1;                //To enable peripheral interrupts
    
    //Calling for configuration functions
    PORT_configuration();
    SPI_Configuration();
    Lcd_Init();    
    
    while(1){
        SPI_read();
    }
}

So basically, I read it twice as @SpehroPefhany said. And remove the extra bits and put it into another variable and then divide it by 4 which is supposed to give you the temperature in centigrade.

\$\endgroup\$
2
  • \$\begingroup\$ Any body knows why we have to divide the result by 4? \$\endgroup\$
    – Momo
    Commented Dec 27, 2021 at 12:58
  • 1
    \$\begingroup\$ You should the datasheet of the part MA6675 very carefully. On top of first page: General Description The MAX6675 performs cold-junction compensation and digitizes the signal from a type-K thermocouple. The data is output in a 12-bit resolution, SPI-compatible, read-only format. This converter resolves temperatures to 0.25°C, allows readings as high as +1024°C, and exhibits thermocouple accuracy of 8 LSBs for temperatures ranging from 0°C to +700°C. Result is given as a multiple of 0.25 °C, after a divison by 4 you get a multiple of 1 °C with a fractional part of two bits. \$\endgroup\$
    – Uwe
    Commented Dec 27, 2021 at 16:17

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.