Skip to content

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

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

nk_maker

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

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

Components

Hardware components
Software Apps and online services

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.

W5300 Home Automation using STM32 BLUEPILL (STM32F103)    W5300 Home Automation using STM32 BLUEPILL (STM32F103)

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

Circuit Diagram :

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

STM32F103 BLUE PILL and W5300 Connection :

W5300 Home Automation using STM32 BLUEPILL (STM32F103)
W5300 Home Automation using STM32 BLUEPILL (STM32F103)

Android MQTT Dash App:

W5300 Home Automation using STM32 BLUEPILL (STM32F103)

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

Comments