W5300 Home Automation using STM32 BLUEPILL (STM32F103)
W5300 Home Automation using STM32 BLUEPILL (STM32F103) developed using ARDUINO IDE
Software Apps and online services
W5300 TOE SHIELD + STM32F103 Based STM32 Bluepill Board + Arduino IDE
Based IoT Home Automation System
Working Video :
Components :
- W5300 TOE Shield
- 0.96 inch I2C OLED
- 4 - relay Module
- STM32F103 Bluepill Board
- DS18B20 Temperature Sensor
Software :
- Arduino IDE with STM32 Board package
- W5300 Arduino Library - I edited this to use it with STM32F103 Bluepill and provided in this project document
- MQTT Arduino Client library
- 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;
}
-
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