单片机——小型物联网系统

Posted by 周宝航 on May 3, 2018

老师布置的单片机大作业是自选命题,随便怎么写都行。我就随便做个有三层架构的小系统玩玩,毕竟大创就是做一套物联网系统。(等结题答辩后再写吧) 基友打算做一个六面LED贪吃蛇,而且是随重力感应改变方向。结果可想而知。。。。。。时间紧,板子画出来,再到调试。。。。反正最后鸽了。。。。。。

系统原理图

Alt text

系统功能

  1. 将STC89C52单片机作为温度采集下位机,通过串口与上位机通信。将下位机采集得到的温度信息通过串口,发送至上位机。上位机发送协议指令,控制LED灯光。
  2. 上位机存在一个服务器程序,作为网关,处理来自手机APP的网络请求。包括:获取温度信息、打开LED灯、关闭LED灯等请求操作。
  3. 实现的基本功能包括:手机APP连接局域网WIFI、配置好IP地址后,实时获取环境温度信息,使用折线图动态实时呈现;按下APP中的按钮可以实现打开LED灯、关闭LED灯的操作。

系统工作原理

  1. 下位机部分使用的是基于STC89C52的单片机来开发。温度采集部分使用的是DS18B20温度传感器,获取的温度数值较为精确。在与上位机进行通信时,采用的是串口通信,接受与发送数据均采用这一方式。
  2. 上位机部分串口通信程序与服务器程序均使用Go语言来开发。由于Go语言是新兴语言,开发多线程程序十分快速,而且写出来的程序十分健壮,程序运行效率高。同时,该语言有良好的服务器库,开发服务器程序也是十分便捷。因此使用这一语言便成为首选。
  3. 移动端开发自然采用Android框架,使用okhttp网络请求框架、HelloChart图表框架,开发起来同样十分便捷。尤其在动态显示温度曲线时,使用多线程来实现这一效果,使得程序的运行效率较高,界面流畅。

移动端

  • 网络通信采用的okhttp框架。协议嘛,就是简单的GET请求。具体的全在代码里。
  • 图表部分使用的是HelloChart框架,动态图表十分方便。
  • 为了实现实时温度展示,当然要使用多线程啦。使用的Timer类定时任务,每秒采集一次温度数据来更新。

界面

  • 网络配置界面 Alt text

  • 主界面 ALt text

上位机

  • 使用Go语言来设计该部分程序。原因就是那时候正在学这个新语言,毕竟原生的goroutine十分方便。
  • 主要涉及的是串口通信与服务器编程。
  • 串口通信使用的是“github.com/tarm/serial”这个库,我将其封装为CommPort类。在实例化该类后,调用Listen方法开始接收串口发送的信息。
package CommPort

import
(
	"github.com/tarm/serial"
	"log"
	"fmt"
)

// Commport : the comm struct for connecting
type Commport struct {
	port *serial.Port
	SPort string
	IBaud int
	CBReceive chan string
	CBSend chan string
	CBQuit chan bool
}

func (comm * Commport) openport() {
	c := &serial.Config{Name:comm.SPort, Baud:comm.IBaud}
	commio, err := serial.OpenPort(c);
	if err != nil {
		log.Fatal("open port error ")
		log.Fatal(err)
	}
	comm.port = commio
}

func (comm * Commport) receive() {
	buf := make([]byte, 128)
	n, err := comm.port.Read(buf)
	if err != nil {
		log.Fatal("receive error ")
		log.Fatal(err)
	}
	if n > 1 {
		//log.Printf(">>>> reveice data size:%d %q", n, buf[:n])
		data := fmt.Sprintf("%d%d.%d%d", buf[0], buf[1], buf[2], buf[3])
		comm.CBReceive <- data
	} else {
		comm.CBReceive <- ""
	}
}

func (comm * Commport) send(data string) {
	_, err := comm.port.Write([]byte(data))
	if err != nil {
		log.Fatal(err)
	}
}

// Listen the comm port and receive the data
func (comm * Commport) Listen() {
	comm.openport()
	if comm.port != nil {
		for {
			select {
			case flag := <- comm.CBQuit:
				if flag {
					break
				} else {
					go comm.receive()
				}
			case data := <- comm.CBSend:
				go comm.send(data)
			}
		}
	}
}

下位机

  • 使用DS18B20温度传感器来获取环境温度。
  • 实际工程中的下位机都是被动的,受上位机的指令控制。不过,这里为了方便,我做成自动向上位机发送数据。

系统效果

  • 温度采集显示 Alt text

  • 开启LED灯 Alt text

  • 关闭LED灯 Alt text

总结

  1. 移动端手机APP通过局域网WIFI实现控制下位机时,实际是要向上位机的服务器程序发送请求,由服务器程序通过串口向下位机发送指令。在本系统中,我将不同的控制指令映射成不同的链接,在访问不同的链接时就实现了控制下位机的操作。
  2. 在服务器端,我将串口采集程序与服务器程序合并在了一起,使用Go语言完成。其中,Go语言本身的多线程以及通道特性,对于我的程序有很大的帮助。串口采集、服务器程序属于同时进行的两项服务,分别处于不同的线程来运行。而两个线程间的信息传递则靠channel(通道)来完成。如此一来,程序的运行效率提高,应对大量请求的能力随之提升。

Android、Go、Keil工程