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)
}
asked Dec 27, 2021 at 9:27
\$\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.

answered Dec 27, 2021 at 9:40
\$\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\$ 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\$ 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.

answered Dec 27, 2021 at 12:07
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the help. I could solve the problem and I posted it. \$\endgroup\$ 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.

answered Dec 27, 2021 at 12:52
\$\endgroup\$
2
  • \$\begingroup\$ Any body knows why we have to divide the result by 4? \$\endgroup\$ 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\$ Commented Dec 27, 2021 at 16:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.