51 single chip microcomputer + ESP8266 to realize Internet remote control lamp

1. Preparations

1.1 software

  • keil 4
  • Serial debugging tool

1.2 hardware

  • Stc89c516 (the chip that has been stopped production, the first time to buy learning board, the business is really black, just use it)
  • Some jumpers
  • ESP8266

The general Chinese 51-single-core-A4 learning board I use here has basically been connected. What's more, it provides an interface from ttl to usb, which can be used to configure ESP8266, and also provides 3.3V & 5V external power supply (Note: do not use external power supply when burning the program, or the program will not burn in) It's still very considerate. Taobao costs more than 60 yuan. It's enough for a programmer like me who is engaged in the development of Internet pure software to test 51 single chip microcomputer.

2. Hardware connection

In fact, the hardware connection is very simple. Businesses will provide the circuit schematic diagram of the single-chip microcomputer learning board, and the development board has an external interface reserved for the single-chip microcomputer I/O. as long as you find out the RXD/TXD I/O port according to the circuit diagram, the RXD and TXD of the general 51 single-core-A4 single-chip microcomputer are P31 and P30 ports, as long as the ESP8266 is connected to the 3.3V power supply, the RX and TX of the wifi module are connected It's OK to connect with the corresponding interface of single chip microcomputer. The actual connection is as follows:

From top to bottom, the left wiring of the single chip microcomputer is 3.3V and GND respectively, and from top to bottom, the right wiring is P31(TXD) and P30(RXD) port. Please check the pin diagram of the single chip microcomputer in your hand.

To configure ESP8266, I refer to MCU + wifi remote control switch lamp , very detailed, please refer to the operation.

3. C language program

#include <stdio.h>
#include <reg52.h>
#include <ctype.h>
#include <string.h>
#include <math.h>

#define uchar unsigned char
#define uint unsigned int

sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
sbit LED5 = P2^4;
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;

// Serial port interrupt reception related
uint scount = 0, maxLen = 25, tscount = 0;
uchar srdatas[25];
// Timer 0, which represents how many 50ms(0 ~ 65535)
uint time0Count = 0;
// Serial port received data processed flag
bit sflag = 0;
// Check connection sending flag (1-indicates to send)
bit tsflag = 0;

void Delay2(unsigned long cnt);

void Tranfer(uchar *s);
void SysInit();
void SetWifi();
void dealReceiveData();
void dealReceiveLine(uchar* line, uint length);
void dealWifiConnectInfo();
// Decimal = > binary
//uchar* decimal2binary(uint val);
// String to number
// uint parseInt(uchar* str, uint len);

void Delay2(unsigned long cnt) {
	long i;
 	for(i=0;i<cnt*10;i++);
}

/*
uchar* decimal2binary(uint val) {
	uchar chs[8];
    uint i = 0, tmp = val;
	for(i = 0; i < 8; i++) {
		if(tmp == 0) {
			chs[i] = 0;
			continue;
		}
		chs[i] = (tmp % 2) + 48;
		tmp = tmp / 2;
	}
	
	for(i = 0; i < 4; i++) {
		tmp = chs[i];
		chs[i] = chs[8-i-1];
		chs[8-i-1] = tmp;	
	}

	return chs;
}
*/

/*
uint parseInt(uchar* str, uint len) {
	uint i = 0, resVal = 0;
	for(i = 0; i < len; i++) {
		resVal = resVal + ((str[i] - 0x30) * pow(10, len - i - 1)); 	
	}
	return resVal;
}
*/

// Receive string occurrence / r/n, treat as new line flag
void dealReceiveData() {
	uint t = 0;

	if(sflag == 1 || scount <= 0) {
		return;
	}

	// After the delay, there is still no data. It is concluded that the serial port has received data
	tscount = scount;
	// There is a problem using Delay2
	// Delay2(100);
	t = time0Count;

	// Demo 50 ms
	while(abs(time0Count - t) <= 0);

	if(scount != tscount) {
	   return;
	}
   	
	// Pause serial interrupt enable during data processing
	ES = 0;
	// Array does not overflow
	if(scount < maxLen) {
	  // After receiving the second data, judge whether there is an end character
	  if(scount > 2) {
	  	// A new line character appears to process the data of the received line
	  	if(srdatas[scount - 2] == '\r' && srdatas[scount - 1] == '\n') {
		   dealReceiveLine(srdatas, scount - 2);
		   scount = 0;	
		}	
	  }
	}

	// After execution, the data received by the serial port has been processed
	sflag = 1;
	ES = 1;
}

void dealWifiConnectInfo() {
	// Start sending attempt to reconnect
	 if(tsflag == 1) {
	 	ET0 = 0;
		printf("AT+CIPCLOSE=2\r\n");
		Delay2(5);
		printf("AT+CIPSTART=2,\"TCP\",\"115.29.109.104\",6520\r\n");
		Delay2(10);
		tsflag = 0;
		ET0 = 1;
	 }
}

void dealReceiveLine(uchar* line, uint length) {
	// bit hasCommand = 0;
	uint i = 0, t = 0;
	uchar command;
	uchar newLine[25];

	// Remove line breaks
	if(length > 3) {
		for(i = 0; i < length; i++) {
			if(line[i] != '\r' && line[i] != '\n') {
			   newLine[t] = line[i];
			   t++; 
			}
			if(t >= 25) {
				length = t;
				break;
			}
		}	
	}
	
	if(length > 3) {
		// Process switch control command
	 	if(
			newLine[0] == '+'
			&& newLine[1] == 'I'
			&& newLine[2] == 'P'
			&& newLine[3] == 'D'	
		) {
			i = 0;
			while(i < length && newLine[i] != ':') {
				i++;
			}
			// There are valid locations
			if(i < length) {
			   t = 0;
			   for(i = i + 1; i < length; i++) {
			   		t++;
                    if(newLine[i] == '/') {
						continue;
					}
			   		command = newLine[i] - 0x30;
			   		switch(t) {
						case 1:
							LED1 = !command;
							break;
						case 2:
							LED2 = !command;
							break;
					    case 3:
							LED3 = !command;
							break;
						case 4:
							LED4 = !command;
							break;
						case 5:
							LED5 = !command;
							break;
						case 6:
							LED6 = !command;
							break;
						case 7:
							LED7 = !command;
							break;
						case 8:
							LED8 = !command;
							break;
					}
					
					if(t >= 8) {
						break;
					}	
			   }
			}	
		}

		/*
		LED6 = ~LED6;

		 // Processing remote connection status response data for scheduled polling
		 if(tsflag == 1) {
		   LED7 = ~LED7;
		   if(
			 	newLine[0] == 'A'
				&& newLine[1] == 'L'
				&& newLine[2] == 'R'
				&& newLine[3] == 'E'
				&& newLine[4] == 'A'
				&& newLine[5] == 'D'
				&& newLine[6] == 'Y'
			) {
			 	LED8 = 0;
			} else {
				LED8 = 1;
			}
			tsflag = 0;
		 }
		 */
	 }
}

void SysInit() {
  	// Initialize timer 1 and configure baud rate generator
	TH1 = 0xFD;	 //Crystal oscillator 11.0592mhz baud rate set to 9600
	TL1 = TH1;
	TMOD |= 0x20;	 //Timer 1 mode 2
	SCON = 0x50;	 //Serial reception enable
	ES = 1;			 //Serial port interrupt enable
	TR1 = 1;		 //Timer 1 enable
	TI = 1;			 //Send interrupt flag bit, must be set

	// Initialize timer 0, do system timing task (11.0592MHz, timing 50ms)
	/* */
	TH0 = 0x4C;
	TL0 = 0x00;
	TMOD |= 0x01; // Working in mode 2
	TR0 = 1; // Timer 0 enable
	ET0 = 1;
	
	
	//REN = 0; / / serial port is forbidden to receive data
	printf("begin init wifi...\r\n");
	SetWifi();
	printf("wifi inited...\r\n");
	//REN = 1;
	EA=1;
}


void SetWifi() {
   Delay2(1000);		
   printf("AT+CIPMUX=1\r\n");
   
   Delay2(1000);		
   printf("AT+CIPSERVER=1\r\n");

   Delay2(1000);
   printf("AT+CIPCLOSE=2\r\n");

   Delay2(2000);
   printf("AT+CIPSTART=2,\"TCP\",\"115.29.109.104\",6520\r\n");

   Delay2(2000);
}

/**/
void Timer0() interrupt 1 {
	uint t = 0;
	ET0 = 0;
	// Continue the next round of timing
	TH0 = 0x4C;
	TL0 = 0x00;
	time0Count = (time0Count + 1) % 1200;
	// About 30s, judge whether the connection is disconnected. After disconnection, reconnect it
	if(time0Count % 600 == 0) {
		tsflag = 1;
	}
	ET0 = 1;
}


void Usart() interrupt 4 {
    if(RI == 1)
    {
		RI = 0;
		srdatas[scount] = SBUF;
		scount += 1;
		if(scount >= maxLen) {
			scount = 0;	
		}
		sflag = 0;
	}
}

void main() {
	SysInit();
	while(1) {
		dealReceiveData();
		dealWifiConnectInfo();	
	}
}

The above program has been tested in practice, and there is no problem. The details are as follows:

  • void Uart() interrupt 4 {...}
    • This method is a serial port receiving data method. When receiving, the receiving is a byte receiving, and when receiving, the sending end is sending continuously, not until the RI = 0 (receiving completion flag) or ES = 1 (serial port interrupt enable) of the receiving end The next byte will be sent, but a series of data will be sent to us. For example, the string abc will be sent to us now, the baud rate is 9600, 9600/8=1.2KB in a second, and about 0.83ms will send a letter. If we are in Uart Too much processing logic is added to it, which may lead to incomplete data transmission (this problem has been puzzling me for a long time, the common problem of pure software, interface data transmission is to call API written by others, who cares about these details)! So my processing logic here is to define a length of 25 uchar array to receive the data received by the serial port. After the data exceeds the limit, the data bit icon is set to 0, and sflag is set to 0, indicating that there is new data in the receiving cache, which is not processed.
  • void Time0() interrupt 1 {...}
    • This is the interrupt function of timer 0, which is used for other timing tasks in the system. The interval is about 50ms.
  • void SetWifi() {...}
    • The wifi module has configured the connected AP information in advance, so it needs to delay at the beginning to ensure the success of wifi connection.
    • At + cipmux = 1 = > allow multiple connections
    • At + cipserver = 1 = > enable server mode
    • At + cipclose = 2 = > close the TCP connection first. It is useful when resetting
    • At + cipstart = 2, "TCP", "115.29.109.104", 6520 = > reconnect TCP, 115.29.109.104:6520 is an open TCP Server, similar to the function of A chat room, for example, if A, B, C are all connected to the TCP Server, then the data sent by A can be received by B, C, and so on. Here, it's no time to write one by yourself. Interested friends can write it by themselves
  • void SysInit() { ... }
    • Initialize timer 1 as baud rate generator, baud rate is 9600
    • Open serial port
    • Open interrupt
    • Initialize timer 0 to do other timing tasks
    • Initialize wifi. Note that interrupt enable should be enabled after initialization
  • void dealReceiveData() { ... }
    • To judge whether the serial port has received a line of commands, the logic is to judge whether the length of the currently received data has changed every 50ms. If it changes, and the last two characters of the currently received data are '/ r', '/ n' (hexadecimal is 0x0D, 0x0A). If so, it is handed over to the dealReceiveLine function for processing.
  • void¬†dealReceiveLine(...) { ... }
    • The processing logic is as follows
      1. Remove line breaks before and after received lines.
      2. Judge whether the processed result starts with + IPD.
      3. Find: the next 8 characters, successively control the LED1 ~ LED8 switch status, 1 is on, 0 is off.
    • Example of switch string
      1. +IPD, 2,2:111 = > LED1: on, LED2: on, LED3: on (if there is no data later, the small lamp after control will be skipped, so to control the small lamp after control, you need to add the front small lamp control instruction, of course, if the corresponding position switch instruction is' / ', the switch instruction will be skipped)
  • void dealWifiConnectInfo( ... ) { ... }
    • Reconnect the TCP Server every 30s or so (because the test TCP Server does not receive or send data after a few minutes, it will be discarded by the server).

In the dealReceiveData method, the delay uses a timer instead of Delay2(), because if an interrupt occurs during the delay, Delay2() There will be a dead cycle. The specific reason is unknown. I would like to leave a message for you to explain. Thank you very much. Other things need to be noted are that when processing the data received by the serial port, the serial port needs to be closed and opened after processing. Why? Because the data buffer received by the serial port is mutually exclusive, the data can not be changed during the processing of the read data. In fact, it is a variable additive lock. When reading the receive cache, it is not allowed to change the data of the receive cache.

4. Testing

Write a java program, send 0 ~ 255 binary data to TCP Server every 1S to control the lamp. The program is written in Java, as follows:

pulbic class LEDTests {
    
    @Test
    public void ledControlTest() throws InterruptedException {
        try {
            //Create Socket object
            Socket socket = new Socket("115.29.109.104", 6520);
            //Get an output stream and send information to the server
            OutputStream outputStream = socket.getOutputStream();
            //Wrap the output stream as a print stream
            PrintWriter printWriter = new PrintWriter(outputStream);

            //Connect to the server according to the input / output stream
            for(int i = 0; i < 10000; i++) {
                String binaryStr = Integer.toBinaryString((i + 1) % 256);
                 char chs[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
                char[] tchs = binaryStr.toCharArray();
                int t  = 0;
                for(int j = 0; j < 8; j++) {
                    if(j < (8 - tchs.length)) {
                        chs[j] = '0';
                    } else {
                        chs[j] = tchs[t++];
                    }
                }
                StringBuffer sb = new StringBuffer();
                for (char ch : chs) {
                    sb.append(String.valueOf(ch));
                }
                binaryStr = sb.toString();
                // Need to add line break after sending data
                printWriter.print(binaryStr + "\r\n");
                Thread.sleep(1000);
                printWriter.flush();
                System.out.println("=> " + binaryStr);
            }

            //Close output stream
            socket.shutdownOutput();
            printWriter.close();
            outputStream.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }    

}

The actual effect is as follows:

5. Summary

Originally, I wanted to expand many functions, such as using infrared remote control to configure hot spot connection information, timeout reconnection time, upload temperature and humidity to the server, transmit information encryption, MCU sends heartbeat packets to the server at intervals, point-to-point control and other functions, but STC8251 only has 128 bytes RAM, expansion seems to be very troublesome, the hand is also lack of hardware, think or forget it!!! It's said that the RAM of arduino and STM32 is much larger. Let's learn from these single-chip computers later and do these functions. We don't want to toss over so many functions for this kind of microcontroller.

If feel this article is helpful to you, don't forget to praise!!!

 

Tags: socket Java C

Posted on Tue, 09 Jun 2020 02:06:52 -0400 by piyush23424