socket通信——多角度控制LED灯亮灭

今天以物联网网关(网关链接)以服务器,在多个客户端就做一个非常简单的功能:点亮或熄灭网关上的LED灯。目前想到了三种方式,分别是:TCP&UDP测试工具、自编Java客户端和Mono
Android客户端。相信这会很有意思的。

1、服务器端

在使用或编写客户端之前,首先来看看服务器端代码,其专门通过串口烧进网关内部

OutputPort led = new OutputPort((Cpu.Pin)GPIO_NAMES.PF8, false);

Socket sc;
Socket ss = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建tcp套接字
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.13.200"), 8888);//网关IP已静态配置,端口自选
try
{
	ss.Bind(iep);
	ss.Listen(3);
	Debug.Print("create server ok");
}
catch
{
	Debug.Print("connection failed");
}           

然后等待客户端的数据并在终端打印,根据所收信息来判断灯亮灭,最后向客户端发反馈

while (true)
{
	if ((sc = ss.Accept()) != null)
	{
		Debug.Print("someone connected:" + sc.RemoteEndPoint.ToString());
		while (true)
		{
			Array.Clear(data, 0, data.Length);//一定要清
			sc.Receive(data, 16, 0);//从java客户端收到的包括\r\n
			string str = new string(System.Text.Encoding.UTF8.GetChars(data));
			Debug.Print(str);
			Debug.Print(str.Length.ToString());
			if (str.IndexOf("ON") >= 0) // = 号不要忽略了
			{
				led.Write(true);
			}
			else if (str.IndexOf("OFF") >= 0)
			{
				led.Write(false);
			}

			Debug.Print("recv ok,about to send ");
			sc.Send(System.Text.Encoding.UTF8.GetBytes(str.IndexOf("ON") >= 0 ? "ON\r\n" : "OFF\r\n"));//为方便java中的readline,添加了行结束符
		}
	}
 }

注释的地方基本上是我犯错的地方

2、客户端

2.1、TCP&UDP测试工具

测试效果如下:

2.2、Java客户端

代码如下:

public class LightLED {

	private Socket client;
	private String host = "192.168.13.200";
	private int port = 8888;

	private String on = "ON";
	private String off = "OFF";

	public static void main(String[] args) throws InterruptedException,IOException {
		// TODO Auto-generated method stub
		new LightLED().doLED();
	}

	public LightLED() throws IOException{
		client = new Socket(host,port);
		System.out.println("connected...");
	}

	public void doLED() throws IOException,InterruptedException {
		try {
			BufferedReader br = getReader(client);
			PrintWriter pw = getWriter(client);
			while (true){
				pw.println(on); //不能用print,为什么?而且发过去的包括\r\n
				System.out.println("LED: " + br.readLine());
				Thread.sleep(1000);

				pw.println(off);
				System.out.println("LED: " + br.readLine());
				Thread.sleep(1000);
			}
		} catch (IOException e) {
			// TODO: handle exception
		}
	}

	private PrintWriter getWriter(Socket s) throws IOException{
		OutputStream ous = s.getOutputStream();
		return new PrintWriter(ous,true);
	}

	private BufferedReader getReader(Socket s) throws IOException {
		InputStream ins = s.getInputStream();
		return new BufferedReader(new InputStreamReader(ins));
	}
}

VS调试窗口:

Java调试窗口:

2.3、Mono Android客户端

其实用C#也可以写android程序的,并且还可跨平台,也轻松移植到IOS上。它使用的框架是Mono,开发环境是Xamarin,以前叫Mono Develop。网上有很多教程,我在这里就不细说了。我本人的相关软件放在了这里

之前我也没用过mono写过android程序,所以今天是个很好的尝试。事实证明算这一客户端最有趣了,待我细细道来。。

我突然想改变一下前面的想法,由于网关上有3个LED灯,于是这次想让客户端同时操作这3个灯。当我发一个数值时,相应的灯亮或灭。具体细则是这样规定的:我所发送的数值范围是0-7,共8个数,化成二进制恰好可以代表3个灯的状态,1为亮,0为灭,就这样简单定义。而且,为了使得多个android客户端可同时登陆服务器,利用多线程方式来实现。主线程只负责接收客户端连接,每个客户端对应一个单独线程来与服务器通信。

既然这样,服务器端代码就得变了,见下:

首先还是服务器的初使化:

Socket sc = null;
Socket ss = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建tcp套接字
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.13.200"), 8888);//网关IP已静态配置,端口自选
try
{
	ss.Bind(iep);
	ss.Listen(5);
	Debug.Print("create server ok");
}
catch
{
	Debug.Print("connection failed");
}           

然后无限循环接收客户连接:

while (true)
{
	byte[] recedata = new byte[1];
	if ((sc = ss.Accept()) != null)
	{
		Debug.Print("someone connected:" + sc.RemoteEndPoint.ToString());
		ClientThread ch = new ClientThread(sc);//创建客户线程类
		Thread t = new Thread(new ThreadStart(ch.service));
		t.Start();
	}
}

相信已发现上面用到了一个类ClientThread,这是我自定义的:

internal class ClientThread
{
	enum GPIO_NAMES
	{
		PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
		PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,
		PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,
		PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15,
		PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15,
		PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15,
		PG0, PG1, PG2, PG3, PG4, PG5, PG6, PG7, PG8, PG9, PG10, PG11, PG12, PG13, PG14, PG15
	};

	private Socket sc;
	OutputPort led1 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF8, false);//第一个LED
	OutputPort led2 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF7, false);//第二个LED
	OutputPort led3 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF6, false);//第三个LED

	public ClientThread(Socket s)
	{
		sc = s;
		//sc.ReceiveTimeout = 60000; // 1分钟内若未收到数据,则关闭连接。由于在虚拟设备中反应很慢,所以就注释掉了
	}

	public void service()
	{
		byte[] recedata = new byte[1];//目前只接收0-7的某个数
		try
		{
			while (sc.Receive(recedata) != 0)
			{
				Debug.Print(recedata[0].ToString());
				doLED(recedata);//根据数值点亮或熄灭灯
				Array.Clear(recedata,0,1);
			}
		}
		catch (System.Exception ex)
		{
			sc.Close();
			Debug.Print("rece timeout" + ex.Message);
		}

	}
	private void doLED(byte[] recedata)
	{
		//感觉下面写得不太简洁
		byte L1 = (byte)(recedata[0] >> 2);
		byte L2 = (byte)((recedata[0] & 3) >> 1);
		byte L3 = (byte)(recedata[0] & 1);
		if (L1 == 1)
		{
			led1.Write(true);
		}
		else
		{
			led1.Write(false);
		}
		if (L2 == 1)
		{
			led2.Write(true);
		}
		else
		{
			led2.Write(false);
		}
		if (L3 == 1)
		{
			led3.Write(true);
		}
		else
		{
			led3.Write(false);
		}
	}
}

好,以上就是修改过的服务器端。下面是用c#写的android客户端。安装好相关软件,打开Xamarin,创建android工程:

相关细节就不详述了,具体可参考官方文档,写得很详细,其实还是用到了android开发的相关概念比如Activity

IDE已经为你生成了相关框架代码,生成了类MainActivity,继承自Activity,重点修改其OnCreate方法,它在界面出现时被调用。

首先创建一些私有量:

private Socket sc = null;
private string host = "192.168.13.200";//服务器端IP和端口
private int port = 8888;

修改OnCreate方法如下:

protected override void OnCreate (Bundle bundle)
{
	base.OnCreate (bundle);
	var layout = new LinearLayout (this);
	layout.Orientation = Orientation.Vertical;

	var lbl = new TextView (this);
	lbl.Text = "hello,xmarin.android";

	sc= new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	try
	{
		sc.Connect(IPAddress.Parse(host),port);//连接服务器
		lbl.Text = "connected with gateway server";
	}
	catch {
		lbl.Text = "conn failed";
	}

	EditText et = new EditText (this);
	var btn = new Button (this);
	btn.Text = "click and send";
	btn.Click += (sender, e) => {	//添加事件处理
		doLED(et.Text);
	};

	layout.AddView (lbl);
	layout.AddView (et);
	layout.AddView (btn);
	SetContentView (layout);
}

一旦button被点击,执行发送:

public void doLED(string leddata)
{
	byte num = Convert.ToByte (leddata);//获取EditText的数值
	byte[] senddata = new byte[1] {num};
	sc.Send (senddata);
}

最后来一张界面截图:

Yoxi.. 客户端代码就是这样,接下来配置好android模拟器,先在模拟器中跑一跑。在服务器端设一个断点,首先开启服务器,然后再开启Xamarin中的程序。一段时间的等待后(android模拟器启动忒慢),部署程序到模拟器,自动启动了客户端。于是首先在文本框中输入7,使3个灯全亮,见下图:

果然,三灯全亮。再输入4,使第1灯亮,其余二个灯全灭:

最后输入0,不用说,全灭。如果没有反应,可尝试给网关重新上电。

好,最后一招,将客户端部署到android手机。注意,要提前破解Mono for Android,而且不要简简单单地把bin目录中的apk安装到手机中,我试过,不能启动。正确做法是将手机连接PC,安装好驱动后,在IDE中可看到设备:

我在第一次部署到手机时,碰到了这个问题:FastDev directory creation failed。经查询这里有了答案:

https://bugzilla.xamarin.com/show_bug.cgi?id=14474

所以我首先采用release模式部署,再改成debug模式,最后部署成功。

启动android客户端,连上路由器使手机与网关在同一个局域网内。先后输入7,4,0,三灯反应正常:

VS调试窗口如下:

OK,到目前为止,我的目标总算是实现了,能在android跑还是挺欢喜的。逻辑上没问题,至于界面的美化嘛,慢慢修改呗。

其实,又有了个新想法,可创建一个html5 移动web应用,放在手机上运行,应该也可以。那个前端东西我不是很熟悉就不做了,感觉应该也不难。或者这样也可以,以网关为服务器,以Netduino为客户端,通过红外操作netduino,从而控制网关,这样也不错。今天暂搁笔于此,以后有想法再补充。

socket通信——多角度控制LED灯亮灭

时间: 2024-10-24 07:29:08

socket通信——多角度控制LED灯亮灭的相关文章

四、按键控制LED灯亮灭

材料: 1.SAGOO UNO 1块: 2.按键模块 1块: 3.杜邦线若干. 步骤: 1.按照下图连接按键模块和UNO: SAGOO UNO引脚                                      按键模块引脚 3V3  <------------------------------------>    V(电源) GND <------------------------------------>    G(电源) Pin2  <----------

CC2530学习路线-基础实验-GPIO 按键控制LED灯亮灭(2)

目录 1.前期预备知识 1.1 新大陆Zigbee模块按键电路图 1.2 CC2530相关寄存器 1.3 CC2530中断走向图 1.4 使用C语言为51单片机编写中断程序 1.5 *函数指针 2. 程序代码 THE END 1.前期预备知识 1.1 新大陆Zigbee模块按键电路图 由上图可知,Zigbee模块的SW1按钮连接在P1.2端口上,当SW1导通,P1.2电平从3.3V被拉低接地.所以P1.2输入模式为下拉输入. 1.2 CC2530相关寄存器 寄存器名称 寄存器作用 寄存器描述 P

stm32控制LED的亮灭

其实这个小实验就是学会运用GPIO这个外设. GPIO是一个片上高速外设,它是由几个寄存器来控制的,每个寄存器占据0x04: GPIOx_BSSR: 端口位设置/清除寄存器,这个寄存器的BSy位是0-15位(BS0-BS15),BRy位是16-31位(BR0-BR15):通过这两个位可以控制16个引脚:BSy只写,写0对ODRy无作用,写1置ODRy位1:BSy只写,写0对ODRy无作用,写1清除ODRy为0:如若两个位同时设置,BSy位起作用. GPIOx_CRL/CRH: 端口配置低/高寄存

LED灯亮灭模拟小星星第一句

著名歌曲小星星第一句是 1 1 5 5 6 6 5 ,4 4 3 3 2 2 1 然后我们用D1这个发光二级管代替1 依次类推. #include "reg52.h" typedef unsigned char u8; typedef unsigned int u16; sbit ledD1=P2^0; //P20 sbit ledD2=P2^1; sbit ledD3=P2^2; sbit ledD4=P2^3; sbit ledD5=P2^4; sbit ledD6=P2^5; s

嵌入式Linux学习入门:控制LED灯

记录自己linux学习过程,让自己能够一直坚持下去 1.原理图分析: nLED_1, nLED_2, nLED_4, 给低电平则对应LED灯亮,高电平则对应LED灯灭, S3C2440芯片GPF4-GPF6对应nLED_1, nLED_2, nLED_4, 所以代码里面操作GPF4-GPF6就可以控制LED灯亮灭. 2.写代码前了解事项 第一步:将GPF0-GPF4配置为输出功能 第二步:控制GPF0-GPF4输出低电平 3.编写代码 1 .text 2 .global _start 3 _st

通过linux命令来控制板上GP_LED灯亮灭

通过linux命令来控制板上GP_LED灯亮灭 下图是在某网站找到的,这里我们可以看到GP_LED 是跟GPIO3相连.至于GPIO13,在此图上看,跟GP_LED没有啥关系,但为什么在blink草案中,却能控制GP_LED,这个留在下一帖.这里主要是通过对GPIO3的控制来实现GP_LED的亮灭. 下图是从开机到控制GP_LED亮灭的过程. 1.进入gpio的目录 2.通过ls指令可以看到在gpio目录下各个gpio口,这里找到gpio3 3.进入gpio3的目录 4.cat directio

arduino入门学习实现语音控制LED灯

需要的准备的硬件arduino+PC+麦克风实现语音命令控制LED灯的亮灭. 首先需要将写好的arduino程序烧录到arduino uno主板中,下面是代码如下: int val;//定义变量val int ledpin=10;//定义数字接口13 void setup() { Serial.begin(9600);//设置波特率为9600,这里要跟软件设置相一致.当接入特定设备(如:蓝牙)时,我们也要跟其他设备的波特率达到一致. pinMode(ledpin,OUTPUT);//设置数字10

单片机IO口标准双向,推挽,高阻,开漏模式 ,LED感应亮灭实验【原创!】

单片机IO口标准双向,推挽,高阻,开漏模式 ,LED感应亮灭实验  十一长假在家快烂了,没事儿做,DIY技术搞起来!  [关于12C增强型单片机I/O口的工作类型实验研究] 文中动画视频效果下载: STC单片机头文件[51CTO-->单片机-->LED感应亮灭实验] 下载链接 链接:http://pan.baidu.com/s/1pJKK4w7   密码:a0re  1.用强推模式,点亮一个LED  /* 工程创建MCU选取,Atmel 89C55 单片机:STC12C4052AD 晶振:无要

arduino 红外遥控器控制LED灯

/* 日期:2016.9.1 功能:红外遥控器控制LED灯 开,关,闪烁 元件: 跳线公公头 * 5 led, 220欧电阻 红外接收管,红外遥控 接线: 红外灯面向自己从左到右分别接 IO3, GND, 5V LED 负极接GND 正极串联电阻接 IO5 红外1-9口编码: FF30CF 1 FF18E7 2 FF7A85 3 FF10EF 4 FF38C7 5 FF5AA5 6 FF42BD 7 FF4AB5 8 FF52AD 9 参考:http://www.arduino.cn/threa