Here is the circuit showing how a Web Server on an STM32F103C8T6 can be used to control a Relay Switch:
The Fritzing code used to create that diagram/image can be downloaded here.
An ENC28J60 ethernet module is used to connect the STM32F103C8T6 (BluePill) to a network.
Here is the source code for the sketch to load into the STM32F103C8T6 (BluePill):
/* Web Server A simple web server that shows the value of the analog input pins. blinks the built in LED, or toggles a Relay Switch (check the comments) From: earl@microcontrollerelectronics.com Also Demonstrates checking the ENC28J60 and keeping it from freezing. ENC28J60 STM32F103 SCK PA5 SO PA6 SI PA7 CS PA4 RST PA0 VCC - 5V GND - GND --ENC28J60-- CLK INT WOL SO SI SCK CS RESET VCC GND +-----------------[USB]-----------------+ [SS2|PB12] | [31] [Gnd] | [SCK2|PB13] | [30] +---+ [Gnd] | [MISO2|PB14] | [29] +-----+ |0 0| [3V3] | [MOSI2|PB15] | [28] |Reset| |x x| [Reset] | [PA8] | [27] +-----+ |1 1| [ 0] | [PB11|SDA2|RX3] [TX1|PA9] | [26] +---+ [ 1] | [PB10|SCL2|TX3] [RX1|PA10] | [25] ^ ^ [33] | [PB1] [USB-|PA11] | [24] Boot1--+ | [ 3] | [PB0|A0] [USB+|PA12] | [23] Boot0----+ [ 4] | [PA7|A1|MOSI1] [PA15] | [20] [ 5] | [PA6|A2|MISO1] [PB3] | [19] +-----------+ [ 6] | [PA5|A3|SCK1] [PB4] | [18] | STM32F103 | [ 7] | [PA4|A4|SS1] [PB5] | [17] | Blue Pill | [ 8] | [PA3|A5|RX2] [SCL1|PB6] | [16] +-----------+ [ 9] | [PA2|A6|TX2] [SDA1|PB7] | [15] [10] | [PA1|A7] [PB8] | [32] [11] | [PA0|A8] [PB9] | [PB9] [12] | [PC15] | [5V] +---------------+ [13] | [PC14] | [Gnd] | ST-Link | [14] | [PC13|LED] | [3V3] |3V3 DIO CLK GND| [Vbat]| +-------------+---+---+---+-------------+ | | | | */ #define BOARD_SPI1_NSS_PIN PA4 #define BOARD_SPI1_SCK_PIN PA5 #define BOARD_SPI1_MISO_PIN PA6 #define BOARD_SPI1_MOSI_PIN PA7 #include <libmaple/iwdg.h> #include <SPI.h> #include <UIPEthernet.h> // ..utility\Enc28J60Network.h file - //move readReg() subroutine def from private to public #define NET_ENC28J60_EIR 0x1C #define NET_ENC28J60_ESTAT 0x1D #define NET_ENC28J60_ECON1 0x1F #define NET_ENC28J60_EIR_RXERIF 0x01 #define NET_ENC28J60_ESTAT_BUFFER 0x40 #define NET_ENC28J60_ECON1_RXEN 0x04 #define NET_ENC28J60_CHECK_PERIOD 5000UL #define iwdg_init_ms(N) iwdg_init(IWDG_PRE_256,((N)/5)) #define pinLED PC13 #define pinSwitch PA15 #define ETH_RS_PIN PA0 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ipdns(192, 168, 0, 1); IPAddress ip(192, 168, 0, 150); IPAddress gateway(192, 168, 0, 1); IPAddress subnet(255, 255, 255, 0); EthernetServer server = EthernetServer(80); String cdata = ""; unsigned long timer; void setup() { disableDebugPorts(); Serial.begin(115200); pinMode(pinLED, OUTPUT); pinMode(pinSwitch, OUTPUT); digitalWrite(pinLED,LOW); digitalWrite(pinSwitch,LOW); eth_reset(); iwdg_init_ms(4000); timer = millis(); } void eth_reset() { pinMode(ETH_RS_PIN, OUTPUT); digitalWrite(ETH_RS_PIN, LOW); delay(100); digitalWrite(ETH_RS_PIN, HIGH); pinMode(ETH_RS_PIN, INPUT); Ethernet.begin(mac, ip, ipdns, gateway, subnet); server.begin(); Serial.print(F("WEB server is at ")); Serial.println(Ethernet.localIP()); Serial.print(F("DNS server is at ")); Serial.println(Ethernet.dnsServerIP()); } void loop() { iwdg_feed(); Ethernet.maintain(); if ((millis() - timer) > NET_ENC28J60_CHECK_PERIOD) { // Enc28J60 is Enc28J60Network class that is defined in Enc28J60Network.h // readReg() subroutine must be moved from private to public members area in utility\Enc28J60Network.h // ENC28J60 ignore all incoming packets if ECON1.RXEN is not set uint8_t stateEconRxen = Enc28J60.readReg((uint8_t) NET_ENC28J60_ECON1) & NET_ENC28J60_ECON1_RXEN; // ESTAT.BUFFER rised on TX or RX error // I think the test of this register is not necessary - EIR.RXERIF state checking may be enough uint8_t stateEstatBuffer = Enc28J60.readReg((uint8_t) NET_ENC28J60_ESTAT) & NET_ENC28J60_ESTAT_BUFFER; // EIR.RXERIF set on RX error uint8_t stateEirRxerif = Enc28J60.readReg((uint8_t) NET_ENC28J60_EIR) & NET_ENC28J60_EIR_RXERIF; Serial.println("---REGS---"); Serial.println(stateEconRxen,HEX); Serial.println(stateEstatBuffer,HEX); Serial.println(stateEirRxerif,HEX); if (!stateEconRxen || (stateEstatBuffer && stateEirRxerif)) { Serial.println ("ENC28J60 reinit"); // Enc28J60.init(netConfig->macAddress); eth_reset(); } timer = millis(); } EthernetClient client = server.available(); if (client) { Serial.println(F("\n--Client Connected--\n")); cdata = ""; Serial.println(cdata); while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); cdata.concat(c); if (cdata.indexOf("\r\n\r\n") > 0) { Serial.print(F("Buffer Length: ")); Serial.println(cdata.length()); client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(F("Connection: close")); if(cdata.indexOf("Analog") > 0) client.println(F("Refresh: 5")); client.println(); client.println(F("<!DOCTYPE HTML>")); client.println(F("<html>")); client.println(F("<body>")); client.println(F("<br><br><center><H1>STM32F103C8T6 WEB Server</H1></center>")); if ( (cdata.indexOf("LED") > 0) || (cdata.indexOf("led") > 0) ) { digitalWrite(pinLED,!digitalRead(pinLED)); if (digitalRead(pinLED)) client.println(F("<center><br><br><br><br><H1>LED OFF!</H1></center>")); else client.println(F("<center><br><br><br><br><H1>LED ON!</H1></center>")); client.println(F("</body>")); client.println(F("</html>")); break; } if (cdata.indexOf("switch") > 0) { digitalWrite(pinSwitch,!digitalRead(pinSwitch)); if (digitalRead(pinSwitch)) client.println(F("<center><br><br><br><br><H1>Switch ON! </H1></center>")); else client.println(F("<center><br><br><br><br><H1>Switch OFF!</H1></center>")); client.println(F("</body>")); client.println(F("</html>")); break; } if(cdata.indexOf("Analog") > 0) { client.println(F("<table border=1 cellspacing=4 cellpadding=4>")); client.println(F("<tr><th>Analog</th><th>Value</th></tr>")); for (int analogChannel = 0; analogChannel < 4; analogChannel++) { int sensorReading = analogRead(analogChannel); client.print(F("<tr><td>")); client.print(analogChannel); client.print(F("</td><td>")); client.print(sensorReading); client.println(F("</td></tr>")); } client.println(F("</table>")); client.println(F("</body>")); client.println(F("</html>")); break; } client.println(F("<center><br><br><br><br><H1>Unknown Command!</H1></center>")); client.println(F("</body>")); client.println(F("</html>")); break; } } } client.stop(); Serial.println(F("\n--Client Disconnected--")); timer = millis(); } }
This is an updated and enhanced sketch from a previous post on a WEB server using both the BluePill (STM32F103C8T6) and the ENC28J60 module. It seems the UIPEthernet library has changed since then. I had to add these lines to the code to define the correct pin settings:
#define BOARD_SPI1_NSS_PIN PA4 #define BOARD_SPI1_SCK_PIN PA5 #define BOARD_SPI1_MISO_PIN PA6 #define BOARD_SPI1_MOSI_PIN PA7
The source code has the IP address and network settings for the ENC28J60 ethernet module hard coded. Those settings may need changed for use on a different network.
The relay switch can be attached to any number of AC type low current devices and turned ON/OFF by accessing the WEB server. (The relay switch can possibly handle low current DC devices as well). I used a 2N3904 NPN transistor in my circuit to allow the STM32F103CT6 to turn the relay OFF and ON. This circuit also has a red LED to visually show when the relay is ON or OFF.
The WEB server accepts several ‘commands’:
http://192.168.0.150/led
http://192.168.0.150/analog
http://192.168.0.150/switch
‘LED’ toggles the internal LED On/Off, ‘analog’ displays the analog values of the first 4 analog pins and ‘switch’ toggles the relay On/Off. So now you know how a Web Server on an STM32F103C8T6 can be used to control a Relay Switch.
Recent Comments