Wiznet makers

nk_maker

Published August 20, 2023 © Creative Commons Attribution CC BY version 4.0 or later (CC BY 4+)

0 UCC

0 VAR

2 Contests

0 Followers

0 Following

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

W5300 Home Automation using STM32 BLUEPILL (STM32F103) developed using ARDUINO IDE

COMPONENTS Hardware components

WIZnet - W5300-TOE-Shield

x 1

W5300


STMicroelectronics - STM32F103RCT6

x 1

STM32F103 BLUEPILL BOARD

Software Apps and online services

Arduino - Arduino IDE

x 1

Arduino IDE


mqtt - MQTT

x 1

MQTT Client Arduino


PROJECT DESCRIPTION

W5300 TOE SHIELD + STM32F103 Based STM32 Bluepill Board + Arduino IDE

Based IoT Home Automation System

Working Video :

Components :

  1. W5300 TOE Shield
  2. 0.96 inch I2C OLED
  3. 4 - relay Module
  4. STM32F103 Bluepill Board
  5. DS18B20 Temperature Sensor

Software :

  1. Arduino IDE with STM32 Board package
  2. W5300 Arduino Library - I edited this to use it with STM32F103 Bluepill and provided in this project document
  3. MQTT Arduino Client library
  4. Android MQTT Dash app 

Hardware Development : Hardware with STM32F103 Bluepill , OLED Display , Relay interface and DS18B20 Temperature Sensor Interface developed by me. W5300 TOE Shield with useful IO expansion is received from my professor.

   

Circuit Diagram :

STM32F103 BLUE PILL and W5300 Connection :

Android MQTT Dash App:

Arduino Ethernet Library for STM32F103+W5300 :Here is edited W5300 Ethernet library to use with STM32F103 Bluepill - edited library is in document for download

1-w5300_anymcu.h

// Edited By NK MAKER to use STM32 BLUEPILL
#ifndef	_W5300_ANYMCU_H_
#define	_W5300_ANYMCU_H_
#include <Arduino.h>
// D7...D0 -> PA7...PA0
#define DATA_DIR  GPIOA->CRL
#define DATA_OUT  GPIOA->ODR
#define DATA_IN   GPIOA->IDR
#define DATA_OUT_SET 0x33333333
#define DATA_IN_SET  0x88888888

//PA10 -> ADDR2, PA09 -> ADDR1, PA08 -> ADDR0 
#define ADDR_DIR  GPIOA->CRH
#define ADDR_OUT  GPIOA->ODR
#define ADDR_OUT_MASK 0xFFFFF000
#define ADDR_OUT_SET  0x00000333

//PC15 -> CS, PC14 -> WR, PC13 -> RD 
#define CTRL_DIR  GPIOC->CRH
#define CTRL_OUT  GPIOC->ODR
#define CTRL_OUT_MASK 0x000FFFFF
#define CTRL_OUT_SET  0x33300000

#define DATA_MASK ~(0x00FF<<0)
#define ADDR_MASK ~(0x0007<<8)
#define CTRL_MASK ~(0x0007<<13)

#define ADDR_0  0x0000<<8  //bit seq A2 A1 A0
#define ADDR_1  0x0001<<8
#define ADDR_2  0x0002<<8
#define ADDR_3  0x0003<<8
#define ADDR_4  0x0004<<8
#define ADDR_5  0x0005<<8
#define ADDR_6  0x0006<<8
#define ADDR_7  0x0007<<8

#define CTRL_IDLE 0x0007<<13  //b111  //bit seq CS WR RD
#define CTRL_RDST 0x0006<<13  //b110
#define CTRL_RDEX 0x0002<<13  //b010
#define CTRL_WRST 0x0005<<13  //b101
#define CTRL_WREX 0x0001<<13  //b001

uint16_t w5300_read_indirect(uint16_t addr);
void w5300_write_indirect(uint16_t addr, uint16_t data1);
void w5300_setup_indirect_MR(void);
void w5300_init(void);
void w5300_reset(void);

#endif   

2-w5300_anymcu.cpp

// Edited By NK MAKER to use STM32 BLUEPILL
#include "w5300_anymcu.h"
#include <Arduino.h>

// Initlize W5300 in use 8 bit Indirect addressing mode
void w5300_init(void)
{  
	// init all w5300 connection pins as output and set all pins high
	DATA_DIR = DATA_OUT_SET;
	ADDR_DIR = (ADDR_DIR & ADDR_OUT_MASK) | ADDR_OUT_SET ;
	CTRL_DIR = (CTRL_DIR & CTRL_OUT_MASK) | CTRL_OUT_SET ;
	DATA_OUT |= ~DATA_MASK; 
	ADDR_OUT |= ~ADDR_MASK;     
	CTRL_OUT |= ~CTRL_MASK; 
	delay(1000);
	Serial.println("\r\n--> Modified W5300 Arduino ethernet library for any mcu with Indirect Addressing  (need 14 GPIO Only) \r\n--> Developed by - M.Vaghasia (rcele_85@yahoo.com) \r\n--> edited by NK MAKER to use STM32 BLUEPILL \r\n--> Current MCU Selected - STM32 BLUEPILL");
	Serial.println("--> Soft Reset W5300");
	w5300_reset();
	delay(1000);
	// configure W5300 to work in indirect addressing mode
	w5300_setup_indirect_MR();
	//Serial.println(w5300_read_indirect(0),HEX);
	delay(1000);
	if(w5300_read_indirect(0) == 0x3801)	  Serial.println("--> w5300 indirect addressing Init - Success ;)");
	else 
	  {
		while(1)
		 {
			Serial.println("--> w5300 indirect addressing Init - Fail :(\r\n--> Check w5300 hardware connections and reset mcu");
			delay(5000);
		  }
	  }
	delay(1000);
}

// Setup W5300 to use 8 bit Indirect addressing mode
void w5300_setup_indirect_MR(void)
{
	DATA_DIR = DATA_OUT_SET; // Set Databus as output
	// Write 0x01 to MR_LOW (Addr - 0x01) for configure w5300 indirect addressing
	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | 0x0001;
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_1;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);
}

// Soft Reset W5300
void w5300_reset(void)
{
	DATA_DIR = DATA_OUT_SET; // Set Databus as output
	// Write 0x80 to MR_LOW (Addr - 0x01) for soft reset w5300
	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | 0x0080;
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_1;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);
}

// Write 16 Bit register of W5300 using 8 bit indirect addressing
void w5300_write_indirect(uint16_t addr, uint16_t data1)
{
	uint16_t data = data1;
	DATA_DIR = DATA_OUT_SET; // Set Databus as output
	// set desired addr in indirect address reg 0x02, 0x03 address
	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | ((addr>>8) & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_2;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);

	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | (addr & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_3;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);
	  
	// set desired data in indirect data reg 0x04, 0x05 address
	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | ((data1>>8) & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_4;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);

	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | (data1 & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_5;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);
}

// Read 16 Bit register of W5300 using 8 bit indirect addressing
uint16_t w5300_read_indirect(uint16_t addr)
{
	uint16_t data =0;
	uint32_t data1 = 0;
	uint32_t data2 = 0;
	DATA_DIR = DATA_OUT_SET; // Set Databus as output
	  
	// set desired addr in indirect address reg 0x02, 0x03 address
	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | ((addr>>8) & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_2;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);

	DATA_OUT |= ~DATA_MASK; DATA_OUT &= DATA_MASK | (addr & 0xFF);
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_3;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WRST;  
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_WREX; 
	delayMicroseconds(1);
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE;  
	delayMicroseconds(1);
	   
	DATA_DIR = DATA_IN_SET; // Set Data Bus input
	  
	// read data from indirect data register
	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_4;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_RDEX; 
	delayMicroseconds(2);
	data1 = DATA_IN & 0xFF;
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE; 
	delayMicroseconds(1);

	ADDR_OUT |= ~ADDR_MASK; ADDR_OUT &= ADDR_MASK | ADDR_5;     
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_RDEX;  
	delayMicroseconds(2);
	data2 = DATA_IN & 0xFF;
	data = (data1<<8)|data2;
	CTRL_OUT |= ~CTRL_MASK; CTRL_OUT &= CTRL_MASK | CTRL_IDLE; 
	delayMicroseconds(1);
	return data;
}



Arduino Code for this project application of IoT Home automation: Full code in documentation for download

// W5300 AND STM32F103 Based IoT Home automation
// Developed By - NK MAKER 
#include <Ethernet.h> // This library should be replaced with library available in project
#include <PubSubClient.h>
#include <Wire.h> 

// OLED libs
#include "SSD1306.h" 

#define LED    	PC13 // for STM32F103 onboard LED
#define RELAY1 	PB7
#define RELAY2 	PB6
#define RELAY3 	PB5
#define RELAY4 	PB3

#define DSPIN	PB4
// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 137, 5);

//IPAddress server(52,57,167,165);
char* server= "broker.hivemq.com";

uint32_t premillis = 0;
uint32_t premillis1 = 0;

uint8_t oled_flag1 = 10;
uint8_t oled_flag2 = 20;
uint8_t oled_flag3 = 30;
uint8_t oled_flag4 = 40;

char tempc[20] = {' '} ;
EthernetClient ethClient;
PubSubClient client(ethClient);

// Oled Display Instance
SSD1306  display(0x3C, PB9, PB8);


void setup()
{
  Serial.begin(115200);
  pinMode(LED,OUTPUT);
  pinMode(RELAY1,OUTPUT);
  pinMode(RELAY2,OUTPUT);
  pinMode(RELAY3,OUTPUT);
  pinMode(RELAY4,OUTPUT);
  digitalWrite(RELAY1,HIGH);
  digitalWrite(RELAY2,HIGH);
  digitalWrite(RELAY3,HIGH);
  digitalWrite(RELAY4,HIGH);

  // Init OLED Sisplay
  display.init();
  display.flipScreenVertically();
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.setFont(ArialMT_Plain_16);
  display.drawString(64, 16, "W5300 IOT Hub");
  display.drawString(64, 32, "STM32F103");
  display.drawString(64, 48, "By NK Maker");
  display.display();
  delay(4000);

  client.setServer(server, 1883);
  client.setCallback(callback);

  Serial.println("** W5300 + STM32F103 BLUEPILL IOT HUB By - NK Maker **");
  Ethernet.begin(mac, ip);
  // Allow the hardware to sort itself out
  delay(1500);
}

void loop()
{
  if(millis() - premillis1 > 500)
  {
    premillis1 = millis();
    display.clear();
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_10);
    if(oled_flag1 == 10)display.drawString(0, 0,  "S1 OFF");
    if(oled_flag2 == 20)display.drawString(0, 16, "S2 OFF");
    if(oled_flag3 == 30)display.drawString(0, 32, "S3 OFF");
    if(oled_flag4 == 40)display.drawString(0, 48, "S4 OFF");
    if(oled_flag1 == 11)display.drawString(0, 0,  "S1 ON");
    if(oled_flag2 == 21)display.drawString(0, 16, "S2 ON");
    if(oled_flag3 == 31)display.drawString(0, 32, "S3 ON");
    if(oled_flag4 == 41)display.drawString(0, 48, "S4 ON");
    display.drawString(64, 0, "NW - YES");
    
    display.setFont(ArialMT_Plain_16);
    display.drawString(64, 24, " TEMP");
    display.drawString(64, 44, tempc);
    display.display();  
  }
  
  if (!client.connected()) {
    reconnect();
  }
  if(millis() - premillis > 4000)
  {
    premillis = millis();
    // put your main code here, to run repeatedly:
    double temp = TempRead();
    temp  = temp * 0.0625; // conversion accuracy is 0.0625 / LSB
    Serial.print("Temperature: ");
    Serial.print(temp);
    Serial.println(" °C");
    int val_int = (int)temp;   // compute the integer part of the float
    float val_float = (abs(temp) - abs(val_int)) * 100;
    int val_fra = (int)val_float;
    sprintf (tempc, "%d.%d", val_int, val_fra); 
    //Serial.println (tempc) ;
    client.publish("W5300_IOT_PUBT",tempc);
  }
  delay(10);
  client.loop();
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    if(payload[0] == 'a') {digitalWrite(RELAY1, LOW);Serial.println("RELAY1 turned ON");client.publish("W5300_IOT_PUB","a");oled_flag1 = 11;}
    else if(payload[0] == 'b') {digitalWrite(RELAY2, LOW);Serial.println("RELAY2 turned ON");client.publish("W5300_IOT_PUB","b");oled_flag2 = 21;}
    else if(payload[0] == 'c') {digitalWrite(RELAY3, LOW);Serial.println("RELAY3 turned ON");client.publish("W5300_IOT_PUB","c");oled_flag3 = 31;}
    else if(payload[0] == 'd') {digitalWrite(RELAY4, LOW);Serial.println("RELAY4 turned ON");client.publish("W5300_IOT_PUB","d");oled_flag4 = 41;}
    else if(payload[0] == 'A') {digitalWrite(RELAY1, HIGH);Serial.println("RELAY1 turned OFF");client.publish("W5300_IOT_PUB","A");oled_flag1 = 10;}
    else if(payload[0] == 'B') {digitalWrite(RELAY2, HIGH);Serial.println("RELAY2 turned OFF");client.publish("W5300_IOT_PUB","B");oled_flag2 = 20;}
    else if(payload[0] == 'C') {digitalWrite(RELAY3, HIGH);Serial.println("RELAY3 turned OFF");client.publish("W5300_IOT_PUB","C");oled_flag3 = 30;}
    else if(payload[0] == 'D') {digitalWrite(RELAY4, HIGH);Serial.println("RELAY4 turned OFF");client.publish("W5300_IOT_PUB","D");oled_flag4 = 40;}
    else if(payload[0] == 'x') {digitalWrite(RELAY1, LOW);digitalWrite(RELAY2, LOW);digitalWrite(RELAY3, LOW);digitalWrite(RELAY4, LOW);Serial.println("ALL RELAY turned ON");client.publish("W5300_IOT_PUB","x");client.publish("W5300_IOT_PUB","a");client.publish("W5300_IOT_PUB","b");client.publish("W5300_IOT_PUB","c");client.publish("W5300_IOT_PUB","d");oled_flag1 = 11;oled_flag2 = 21;oled_flag3 = 31;oled_flag4 = 41;}
    else if(payload[0] == 'X') {digitalWrite(RELAY1, HIGH);digitalWrite(RELAY2, HIGH);digitalWrite(RELAY3, HIGH);digitalWrite(RELAY4, HIGH);Serial.println("ALL RELAY turned OFF");client.publish("W5300_IOT_PUB","X");client.publish("W5300_IOT_PUB","A");client.publish("W5300_IOT_PUB","B");client.publish("W5300_IOT_PUB","C");client.publish("W5300_IOT_PUB","D");oled_flag1 = 10;oled_flag2 = 20;oled_flag3 = 30;oled_flag4 = 40;}
    
    }
}


void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("arduinoclient")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("W5300_IOT_PUB","X");
      client.publish("W5300_IOT_PUB","A");
      client.publish("W5300_IOT_PUB","B");
      client.publish("W5300_IOT_PUB","C");
      client.publish("W5300_IOT_PUB","D");
      // ... and resubscribe
      client.subscribe("W5300_IOT_SUB");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

boolean DS18B20_Init()
{
  pinMode(DSPIN, OUTPUT);
  digitalWrite(DSPIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(DSPIN, LOW);
  delayMicroseconds(750);//480-960
  digitalWrite(DSPIN, HIGH);
  pinMode(DSPIN, INPUT);
  int t = 0;
  while (digitalRead(DSPIN))
  {
    t++;
    if (t > 60) return false;
    delayMicroseconds(1);
  }
  t = 480 - t;
  pinMode(DSPIN, OUTPUT);
  delayMicroseconds(t);
  digitalWrite(DSPIN, HIGH);
  return true;
}
 
void DS18B20_Write(byte data)
{
  pinMode(DSPIN, OUTPUT);
  for (int i = 0; i < 8; i++)
  {
    digitalWrite(DSPIN, LOW);
    delayMicroseconds(10);
    if (data & 1) digitalWrite(DSPIN, HIGH);
    else digitalWrite(DSPIN, LOW);
    data >>= 1;
    delayMicroseconds(50);
    digitalWrite(DSPIN, HIGH);
  }
}
 
byte DS18B20_Read()
{
  pinMode(DSPIN, OUTPUT);
  digitalWrite(DSPIN, HIGH);
  delayMicroseconds(2);
  byte data = 0;
  for (int i = 0; i < 8; i++)
  {
    digitalWrite(DSPIN, LOW);
    delayMicroseconds(1);
    digitalWrite(DSPIN, HIGH);
    pinMode(DSPIN, INPUT);
    delayMicroseconds(5);
    data >>= 1;
    if (digitalRead(DSPIN)) data |= 0x80;
    delayMicroseconds(55);
    pinMode(DSPIN, OUTPUT);
    digitalWrite(DSPIN, HIGH);
  }
  return data;
}
 
int TempRead()
{
  if (!DS18B20_Init()) return 0;
  DS18B20_Write (0xCC); // Send skip ROM command
  DS18B20_Write (0x44); // Send reading start conversion command
  if (!DS18B20_Init()) return 0;
  DS18B20_Write (0xCC); // Send skip ROM command
  DS18B20_Write (0xBE); // Read the register, a total of nine bytes, the first two bytes are the conversion value
  int temp = DS18B20_Read (); // Low byte
  temp |= DS18B20_Read () << 8; // High byte
  return temp;
}

 

Documents
  • Arduino W5300 STM32F103 Bluepill Ethernet Library

    Arduino W5300 STM32F103 Bluepill Ethernet Library edited version

  • W5300 STM32F103 IOT HOME CIRCUIT DIAGRAM

    W5300 STM32F103 IOT HOME CIRCUIT DIAGRAM

  • Arduino code for IoT Home Automation Project

    Arduino code for IoT Home Automation Project for W5300 + STM32F103 BLUEPILL

Comments Write