Using SPI with arduino MEGA 2560 to communicate with ENC28J60 and MAX6675

Hi, I am building a smart system for garden care, and I need to measure the temperature with a thermocouple for my temp control system, the problem is that I also need to connect my system to internet, reason why I am using the ENC28J60 module. When I am using those individually, everything works fine but when I try to use both at the same time, the Ethernet module works fine but the MAX6675 says me that the temperature is 0 (IN OTHER WORDS IT DOESNT WORK). Any idea of how to resolve my problem. The other small problem that I have, is that while my module is waiting for the DHCP to assign it an IP, my LCD is not showing any information.

Thank you,

I leave my code here.

//LCD config (i2c LCD screen, you need to install the LiquidCrystal_I2C if you don't have it )
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

//LCD config (i2c LCD screen, you need to install the LiquidCrystal_I2C if you don't have it )
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

#include <max6675.h>
#include <SPI.h>
//We define the SPI pìns
#define SO_PIN 50
#define CK_PIN 52
#define CS_PIN_A 25

MAX6675 thermocouple(CK_PIN, CS_PIN_A, SO_PIN); // Creacion del objeto MAX6675 para lectura de termocupla

//BLYNK
#define BLYNK_PRINT Serial
#include <UIPEthernet.h>
#include <BlynkSimpleUIPEthernet.h>
char auth[] = "c9d17da1a5ac40bd962d76366322e149";
BlynkTimer timer; // Create a Timer object called "timer"!

//Pins
int PINRELAY = 3;
int PINBOTONMAS = 4;
int PINBOTONMENOS = 9;
int PINSENHUMEDAD = A0;
int PINRELAYLUZ = 5;
int PININTERRUPTOR = 6;
int PINRELAYBOMBA = 7;
int PINSENSORDENIVEL = 8;

//Variables
float temperature_read = 0.0;
int set_temperature = 20;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
int PID_value = 0;
int Valuetouse = 0;
int BotonMenos;
int BotonMas;
int ValeurSensorHumedad = 0;
int pourcentageHumedad = 0;
int Interruptorluz;
int Nivel;
int Interruptorcalefaccion;

//PID constants
int kp = 9.1; int ki = 0.3; int kd = 1.8;
int PID_p = 0; int PID_i = 0; int PID_d = 0;

//BLYNK
BLYNK_WRITE(V0)//Permite leer el valor del virtual PIN 1 en BLYNK
{
Interruptorluz = param.asInt(); // Asigna los valores que lee del Virtual PIN 1 a una variable
}
BLYNK_WRITE(V1)//Permite leer el valor del virtual PIN 1 en BLYNK
{
Interruptorcalefaccion = param.asInt(); // Asigna los valores que lee del Virtual PIN 1 a una variable
}
BLYNK_WRITE(V2)//Permite leer el valor del virtual PIN 2 en BLYNK
{
set_temperature = param.asInt(); // Asigna los valores que lee del Virtual PIN 2 a una variable
}

BLYNK_READ(V3) // Widget in the app READs Virtal Pin V3 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V3
Blynk.virtualWrite(3, set_temperature);
}

BLYNK_READ(V4) // Widget in the app READs Virtal Pin V4 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V4
Blynk.virtualWrite(4, pourcentageHumedad);
}

BLYNK_READ(V9) // Widget in the app READs Virtal Pin V4 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V4
Blynk.virtualWrite(9, temperature_read);
}

WidgetLED led1(V5); //register to virtual pin 5
WidgetLED led2(V6); //register to virtual pin 6

void lednivelaguablynk(){
if (Nivel==1){
led1.off();
}
else{
led1.on();
}
}

void ledpumpstateblynk(){
if (pourcentageHumedad <= 60 or Nivel !=1) {
led2.on();
}
else {
led2.off();
}
}

void setup() {
pinMode(PINRELAY,OUTPUT);
pinMode(PINBOTONMAS,INPUT);
pinMode(PINBOTONMENOS,INPUT);
pinMode(PININTERRUPTOR,INPUT);
pinMode(PINRELAYLUZ,OUTPUT);
pinMode(PINRELAYBOMBA,OUTPUT);
pinMode(PINSENSORDENIVEL,INPUT);
Time = millis();
lcd.setBacklightPin(3,POSITIVE);
lcd.setBacklight(HIGH);
lcd.begin(16, 2);

//Blynk
Serial.begin(9600);
Blynk.begin(auth);
Blynk.begin(auth, "blynk-cloud.com", 80);
timer.setInterval(1000L, lednivelaguablynk);
timer.setInterval(1000L, ledpumpstateblynk);
}

void loop() {
Blynk.run();
timer.run();
// First we read the real value of temperature
temperature_read = thermocouple.readCelsius();
//Next we calculate the error between the setpoint and the real value
PID_error = set_temperature - temperature_read;
//Calculate the P value
PID_p = kp * PID_error;
//Calculate the I value in a range on +-3
if(-3 < PID_error <3)
{
PID_i = PID_i + (ki * PID_error);
}

//For derivative we need real time to calculate speed change rate
timePrev = Time; // the previous time is stored before the actual time read
Time = millis(); // actual time read
elapsedTime = (Time - timePrev) / 1000;
//Now we can calculate the D calue
PID_d = kd*((PID_error - previous_error)/elapsedTime);
//Final total PID value is the sum of P + I + D
PID_value = PID_p + PID_i + PID_d;

//We define PWM range between 0 and 255
if(PID_value < 0)
{ PID_value = 0; }
if(PID_value > 100)
{ PID_value = 100; }

Valuetouse=(100-PID_value);

if (Interruptorluz==0){
digitalWrite(PINRELAYLUZ,LOW);
}

else{
digitalWrite(PINRELAYLUZ,HIGH);
}

if (Interruptorcalefaccion==0){
//HIGH ES APAGADO - LOW ES PRENDIDO
if (temperature_read > set_temperature*(1-(Valuetouse/100))){
digitalWrite(PINRELAY,HIGH);
}
else{
digitalWrite(PINRELAY,LOW);
}
}
else{
digitalWrite(PINRELAY,HIGH);
}

previous_error = PID_error; //Remember to store the previous error for next loop.

Nivel = digitalRead(PINSENSORDENIVEL);
ValeurSensorHumedad = readhumidity();
pourcentageHumedad = ConvertEnPorcentaje(ValeurSensorHumedad);

if (pourcentageHumedad > 100){
pourcentageHumedad = 100;
}
if (pourcentageHumedad < 0){
pourcentageHumedad = 0;
}

if (pourcentageHumedad <= 60 or Nivel !=1) {
digitalWrite(PINRELAYBOMBA,LOW);
}
else {
digitalWrite(PINRELAYBOMBA,HIGH);
}

BotonMenos = digitalRead(PINBOTONMENOS);
BotonMas= digitalRead(PINBOTONMAS);

if (BotonMenos != 1){
set_temperature--;
}
if (BotonMas != 1){
set_temperature++;
}

delay(500);
lcd.clear();

lcd.setCursor(0,0);
lcd.print("H:");
lcd.setCursor(2,0);
lcd.print(pourcentageHumedad);
lcd.setCursor(5,0);
lcd.print("%");
lcd.setCursor(0,1);
lcd.print("S:");
lcd.setCursor(2,1);
lcd.print(set_temperature,1);
lcd.setCursor(9,1);
lcd.print("R:");
lcd.setCursor(11,1);
lcd.print(temperature_read,1);
}

int ConvertEnPorcentaje(int value){
int ValeurPorcentage = 0;
ValeurPorcentage = map(value, 1023, 350, 0, 100);
return ValeurPorcentage;
}

int readhumidity(){
int valorhumedad = 0;
valorhumedad = analogRead(PINSENHUMEDAD);
return valorhumedad;
}

/* Max6675 Module ==> Arduino

  • CS ==> D25
  • SO ==> D50
  • SCK ==> D52
  • Vcc ==> Vcc (5v)
  • Gnd ==> Gnd */

/* Temp ==> Arduino

  • RelayIN1 ==> D3

/* Botones ==> Arduino

  • Boton+Temp ==> D4
  • Boton-Temp ==> D9 */

/* i2c LCD Module ==> Arduino

  • SCL ==> D21
  • SDA ==> D20
  • Vcc ==> Vcc (5v)
  • Gnd ==> Gnd */

/* YL-69 ==> Arduino

  • A0 ==> A0
  • D0 ==> --
  • Gnd ==> Gnd
  • Vcc ==> Vcc (5v)
    */

/* Foco (interruptor+relay) ==> Arduino

  • Interruport (iz) ==> D6
  • Interruptor (cen) ==> Vcc (5v)
  • Interruptor (iz2) ==> GND
  • RelayIN2 ==> D5
    */

/* Bomba de agua ==> Arduino

  • RelayIN3 ==> D7
    */

/* Sensor de nivel ==> Arduino

  • Sensor ==> D8
    */

/* Modulo Ethernet ENC28J60 ==> Arduino

  • CS ==> D53
  • SI ==> D51
  • SCK ==> D52
  • SO ==> D50
  • INT ==> D19
  • Gnd ==> GND
  • Vcc ==> Vcc (5v)
    */

Why do you suppose that you need to define pins for the MAX6675 instance? Do you suppose that that is because it does NOT do hardware SPI? You are trying to do software SPI on the hardware SPI pins while also doing hardware SPI is just not a good idea.

Hi Paul, thank you to answer. In reality we have to define the pins for two reason, the first one is that depending of your Arduino models, the SCK and SO are placed in different pins and the other reason is that you are suppose to be able to choose any digital pin for the CS because it is the one that will declare that one of the module want to communicate.

@jonathanprieto, MAX6675-library doesn't use hardware SPI so it is in conflict with the SPI library on SPI pins. use other pins.

byte MAX6675::spiread(void) { 
  int i;
  byte d = 0;

  for (i=7; i>=0; i--)
  {
    digitalWrite(sclk, LOW);
    _delay_ms(1);
    if (digitalRead(miso)) {
      //set the bit to 0 no matter what
      d |= (1 << i);
    }

    digitalWrite(sclk, HIGH);
    _delay_ms(1);
  }

  return d;
}

@Juraj thank you very much for you answer, I am really trying to use a small amount of pins because my project is always growing a bit more. Do you know how could I do to read MAX6675 module with a real Hardware SPI?

jonathanprieto:
Do you know how could I do to read MAX6675 module with a real Hardware SPI?

From the datasheet this is the description of the bits you would receive:

So using the uC hardware SPI maybe try something like this to see if you get anything:

#include "SPI.h"

//Define SPI pins
#define MOSI 11
#define MISO 12
#define SCK 13
#define CS 10

void setup() {
  Serial.begin(115200);

  //Define SPI IOs
  //pinMode(MOSI, OUTPUT); //no real need to declare
  //pinMode(MISO, INPUT);
  //pinMode(SCK, OUTPUT);
  pinMode(CS, OUTPUT);


  //Initialise SPI interface
  //SPI clock speed:4MHz, Data Shift:MSB First, Data Clock Idle: SPI_MODE0
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));

}

void loop() {
  uint16_t Tdeg = 0;
  float Tdeg_f;
  byte temp;

  //select MAX6675 device
  digitalWrite(CS, LOW);

  //get temperature reading
  //receive bits 15-8
  temp = SPI.transfer(0x00);
  //Put in Tdeg upper nibble
  Tdeg |= temp;
  Tdeg <<= 8;

  //receive bits 7-0
  temp = SPI.transfer(0x00);
  //Put in Tdeg lower nibble
  Tdeg |= temp;

  //deselect device
  digitalWrite(CS, HIGH);

  Serial.print("STATE: ");
  Serial.println(bitRead(Tdeg, 0), DEC);
  Serial.print("DEVICE ID: ");
  Serial.println(bitRead(Tdeg, 1), DEC);
  Serial.print("Thermocouple Input: ");
  Serial.println(bitRead(Tdeg, 2), DEC);
  Serial.print("Tempurature(degC): ");
  Tdeg_f = ((Tdeg >> 3) & 0x0FFF)*0.25; //get rid bits 2-0 in Tdeg (&0x0FFF is a nice to have). multiply by 0.25 for conversion
  Serial.println(Tdeg, 2);

  //poll device every second
  delay(1000);
}

Hope that helps.

Hi sherzaad, is it a problem if I don't have the MOSI conector in the MAX6675 module?
I changed my code with a pure SPI communication but again it works great alone but when I use it with the Ethernet module, I simply get 0.

//LCD config (i2c LCD screen, you need to install the LiquidCrystal_I2C if you don't have it )
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

#include <SPI.h>
//We define the SPI pins
#define MAX6675_CS 25
#define MAX6675_SO 50
#define MAX6675_SCK 52

//BLYNK
#define BLYNK_PRINT Serial
#include <UIPEthernet.h>
#include <BlynkSimpleUIPEthernet.h>
char auth[] = "c9d17da1a5ac40bd962d76366322e149";
BlynkTimer timer; // Create a Timer object called "timer"!

//Pins
int PINRELAY = 3;
int PINBOTONMAS = 4;
int PINBOTONMENOS = 9;
int PINSENHUMEDAD = A0;
int PINRELAYLUZ = 5;
int PININTERRUPTOR = 6;
int PINRELAYBOMBA = 7;
int PINSENSORDENIVEL = 8;

//Variables
float temperature_read = 0.0;
int set_temperature = 20;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
int PID_value = 0;
int Valuetouse = 0;
int BotonMenos;
int BotonMas;
int ValeurSensorHumedad = 0;
int pourcentageHumedad = 0;
int Interruptorluz;
int Nivel;
int Interruptorcalefaccion;

//PID constants
int kp = 9.1; int ki = 0.3; int kd = 1.8;
int PID_p = 0; int PID_i = 0; int PID_d = 0;

//BLYNK
BLYNK_WRITE(V0)//Permite leer el valor del virtual PIN 1 en BLYNK
{
Interruptorluz = param.asInt(); // Asigna los valores que lee del Virtual PIN 1 a una variable
}
BLYNK_WRITE(V1)//Permite leer el valor del virtual PIN 1 en BLYNK
{
Interruptorcalefaccion = param.asInt(); // Asigna los valores que lee del Virtual PIN 1 a una variable
}
BLYNK_WRITE(V2)//Permite leer el valor del virtual PIN 2 en BLYNK
{
set_temperature = param.asInt(); // Asigna los valores que lee del Virtual PIN 2 a una variable
}

BLYNK_READ(V3) // Widget in the app READs Virtal Pin V3 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V3
Blynk.virtualWrite(3, set_temperature);
}

BLYNK_READ(V4) // Widget in the app READs Virtal Pin V4 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V4
Blynk.virtualWrite(4, pourcentageHumedad);
}

BLYNK_READ(V9) // Widget in the app READs Virtal Pin V4 with the certain frequency
{
// This command writes Arduino's uptime in seconds to Virtual Pin V4
Blynk.virtualWrite(9, temperature_read);
}

WidgetLED led1(V5); //register to virtual pin 5
WidgetLED led2(V6); //register to virtual pin 6

void lednivelaguablynk(){
if (Nivel==1){
led1.off();
}
else{
led1.on();
}
}

void ledpumpstateblynk(){
if (pourcentageHumedad <= 60 or Nivel !=1) {
led2.on();
}
else {
led2.off();
}
}

void setup() {
pinMode(PINRELAY,OUTPUT);
pinMode(PINBOTONMAS,INPUT);
pinMode(PINBOTONMENOS,INPUT);
pinMode(PININTERRUPTOR,INPUT);
pinMode(PINRELAYLUZ,OUTPUT);
pinMode(PINRELAYBOMBA,OUTPUT);
pinMode(PINSENSORDENIVEL,INPUT);
Time = millis();
lcd.setBacklightPin(3,POSITIVE);
lcd.setBacklight(HIGH);
lcd.begin(16, 2);

//Blynk
Serial.begin(9600);
Blynk.begin(auth);
Blynk.begin(auth, "blynk-cloud.com", 80);
timer.setInterval(1000L, lednivelaguablynk);
timer.setInterval(1000L, ledpumpstateblynk);

}

void loop() {
Blynk.run();
timer.run();
// First we read the real value of temperature
temperature_read = readThermocouple();
//Next we calculate the error between the setpoint and the real value
PID_error = set_temperature - temperature_read;
//Calculate the P value
PID_p = kp * PID_error;
//Calculate the I value in a range on +-3
if(-3 < PID_error <3)
{
PID_i = PID_i + (ki * PID_error);
}

//For derivative we need real time to calculate speed change rate
timePrev = Time; // the previous time is stored before the actual time read
Time = millis(); // actual time read
elapsedTime = (Time - timePrev) / 1000;
//Now we can calculate the D calue
PID_d = kd*((PID_error - previous_error)/elapsedTime);
//Final total PID value is the sum of P + I + D
PID_value = PID_p + PID_i + PID_d;

//We define PWM range between 0 and 255
if(PID_value < 0)
{ PID_value = 0; }
if(PID_value > 100)
{ PID_value = 100; }

Valuetouse=(100-PID_value);

if (Interruptorluz==0){
digitalWrite(PINRELAYLUZ,LOW);
}

else{
digitalWrite(PINRELAYLUZ,HIGH);
}

if (Interruptorcalefaccion==0){
//HIGH ES APAGADO - LOW ES PRENDIDO
if (temperature_read > set_temperature*(1-(Valuetouse/100))){
digitalWrite(PINRELAY,HIGH);
}
else{
digitalWrite(PINRELAY,LOW);
}
}
else{
digitalWrite(PINRELAY,HIGH);
}

previous_error = PID_error; //Remember to store the previous error for next loop.

Nivel = digitalRead(PINSENSORDENIVEL);
ValeurSensorHumedad = readhumidity();
pourcentageHumedad = ConvertEnPorcentaje(ValeurSensorHumedad);

if (pourcentageHumedad > 100){
pourcentageHumedad = 100;
}
if (pourcentageHumedad < 0){
pourcentageHumedad = 0;
}

if (pourcentageHumedad <= 60 or Nivel !=1) {
digitalWrite(PINRELAYBOMBA,LOW);
}
else {
digitalWrite(PINRELAYBOMBA,HIGH);
}

BotonMenos = digitalRead(PINBOTONMENOS);
BotonMas= digitalRead(PINBOTONMAS);

if (BotonMenos != 1){
set_temperature--;
}
if (BotonMas != 1){
set_temperature++;
}

delay(500);
lcd.clear();

lcd.setCursor(0,0);
lcd.print("H:");
lcd.setCursor(2,0);
lcd.print(pourcentageHumedad);
lcd.setCursor(5,0);
lcd.print("%");
lcd.setCursor(0,1);
lcd.print("S:");
lcd.setCursor(2,1);
lcd.print(set_temperature,1);
lcd.setCursor(9,1);
lcd.print("R:");
lcd.setCursor(11,1);
lcd.print(temperature_read,1);
}

int ConvertEnPorcentaje(int value){
int ValeurPorcentage = 0;
ValeurPorcentage = map(value, 1023, 350, 0, 100);
return ValeurPorcentage;
}

int readhumidity(){
int valorhumedad = 0;
valorhumedad = analogRead(PINSENHUMEDAD);
return valorhumedad;
}

double readThermocouple() {

uint16_t v;
pinMode(MAX6675_CS, OUTPUT);
pinMode(MAX6675_SO, INPUT);
pinMode(MAX6675_SCK, OUTPUT);

digitalWrite(MAX6675_CS, LOW);
delay(1);

// Read in 16 bits,
// 15 = 0 always
// 14..2 = 0.25 degree counts MSB First
// 2 = 1 if thermocouple is open circuit
// 1..0 = uninteresting status

v = shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
v <<= 8;
v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);

digitalWrite(MAX6675_CS, HIGH);
if (v & 0x4)
{
// Bit 2 indicates if the thermocouple is disconnected
return NAN;
}

// The lower three bits (0,1,2) are discarded status bits
v >>= 3;

// The remaining bits are the number of 0.25 degree (C) counts
return v*0.25;
}

/* Max6675 Module ==> Arduino

  • CS ==> D25
  • SO ==> D50
  • SCK ==> D52
  • Vcc ==> Vcc (5v)
  • Gnd ==> Gnd */

/* Temp ==> Arduino

  • RelayIN1 ==> D3

/* Botones ==> Arduino

  • Boton+Temp ==> D4
  • Boton-Temp ==> D9 */

/* i2c LCD Module ==> Arduino

  • SCL ==> D21
  • SDA ==> D20
  • Vcc ==> Vcc (5v)
  • Gnd ==> Gnd */

/* YL-69 ==> Arduino

  • A0 ==> A0
  • D0 ==> --
  • Gnd ==> Gnd
  • Vcc ==> Vcc (5v)
    */

/* Foco (interruptor+relay) ==> Arduino

  • Interruport (iz) ==> D6
  • Interruptor (cen) ==> Vcc (5v)
  • Interruptor (iz2) ==> GND
  • RelayIN2 ==> D5
    */

/* Bomba de agua ==> Arduino

  • RelayIN3 ==> D7
    */

/* Sensor de nivel ==> Arduino

  • Sensor ==> D8
    */

/* Modulo Ethernet ENC28J60 ==> Arduino

  • CS ==> D53
  • SI ==> D51
  • SCK ==> D52
  • SO ==> D50
  • INT ==> D19
  • Gnd ==> GND
  • Vcc ==> Vcc (5v)
    */

did you test the rewrite without the rest of the sketch?

jonathanprieto:
Hi sherzaad, is it a problem if I don't have the MOSI conector in the MAX6675 module?
I changed my code with a pure SPI communication but again it works great alone but when I use it with the Ethernet module, I simply get 0.

You seem to fail to grasp how SPI works... please try to understand that for starters.

secondly as @Juraj suggested, try the piece of code I provided WITHOUT the rest of your code. Note that for hardware SPI, the pins are pre-assigned and CANNOT be changed.
SCK, MOSI and MISO will be the same for all connected devices, and there will be ONE dedicated CS pin per device.

I dont have the MOSI conector in the MAX6675 module? --- does not matter. Just leave the MOSI pin unterminated in that case (assuming that was the only device you were connecting to). Same would apply if device had a MOSI but no MISO.