项目需求
我们平时开发物联网相关的项目时,无线控制是我们必须具备的一个功能。我们可以通过编写的电脑客户端,实时控制我们开发板进行相应的操作。比如控制智能家居的灯光、风扇和加湿器等一系列操作。
开发环境
- VS Code
- HUAWEI DevEco Device Tool(HarmonyOS面向智能设备开发者提供的一站式集成开发环境)
- HiBurn(用于烧录)
- VMware
- Ubuntu(Linux系统)
- VS
使用的技术
UDP
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。 Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情。 UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但即使在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。 方法 说明 Close 关闭 UDP 连接 Connect 建立与远程主机的连接 DropMulticastGroup 退出多路广播组 JoinMulticastGroup 将 UdpClient 添加到多路广播组 Receive 返回已由远程主机发送的 UDP 数据文报 Send 将 UDP 数据文报发送到远程主机
方法 | 说明 |
---|---|
Close | 关闭 UDP 连接 |
Connect | 建立与远程主机的连接 |
DropMulticastGroup | 退出多路广播组 |
JoinMulticastGroup | 将 UdpClient 添加到多路广播组 |
Receive | 返回已由远程主机发送的 UDP 数据文报 |
Send | 将 UDP 数据文报发送到远程主机 |
创建监听举例:
代码语言:javascript复制UdpClient udpserver;
private void udpListen()
{
udpserver = new UdpClient(8888);//参数为要进行UDP监听的端口
}
接收数据举例:
代码语言:javascript复制private void getMsg()//开启一个异步线程去执行该方法
{
//定义一个IPEndPoint对象用来装载数据来源的IP和端口信息
IPEndPoint remoteIpAndPort = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
//等待消息,注意,使用该方法在等待消息时会阻塞线程
byte[] msgBytes = udpserver.Receive(ref remoteIpAndPort)
string receivedStr = System.Text.Encoding.UTF8.GetString(msgBytes);
}
}
发送数据举例:
代码语言:javascript复制 private void buttonSend_Click(object sender, EventArgs e)
{
//将要发送的数据转化成byte数组
byte[] b = System.Text.Encoding.UTF8.GetBytes("Hello");
//创建目标IP端口信息
IPEndPoint sendTo = new IPEndPoint(IPAddress.Parse("192.168.1.233"),1234);
//发送数据
this.udpserver.Send(b, b.Length, sendTo);
}
JSON
JSON介绍
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
JSON 语法规则
JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名。 JSON是一个序列化的对象或数组。
- 六个构造字符: begin-array = ws %x5B ws ; [ 左方括号 begin-object = ws %x7B ws ; { 左大括号 end-array = ws %x5D ws ; ] 右方括号 end-object = ws %x7D ws ; } 右大括号 name-separator = ws %x3A ws ; : 冒号 value-separator = ws %x2C ws ; , 逗号
- 在这六个构造字符的前或后允许存在无意义的空白符(ws): ws = *(%x20 /; 空间 %x09 /; 水平标签 %x0A /; 换行或换行 %x0D); 回程
- JSON的值 JSON的构成: ws 值 ws [1] 值可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个。值中的字面值中的英文必须使用小写。 对象由花括号括起来的逗号分割的成员构成,成员是字符串键和上文所述的值由逗号分割的键值对组成,如: 1
{“name”: “John Doe”, “age”: 18, “address”: {“country” : “china”, “zip-code”: “10000”}}
数组是由方括号括起来的一组值构成,如:
代码语言:javascript复制[3, 1, 4, 1, 5, 9, 2, 6]
字符串与C或者Java的字符串非常相似。字符串是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。 数字也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。 一些合法的JSON的实例:
代码语言:javascript复制{"a": 1, "b": [1, 2, 3]}
代码语言:javascript复制[1, 2, "3", {"a": 4}]
代码语言:javascript复制3.14
代码语言:javascript复制"wulianwangzhishi"
具体设计
功能介绍
当按下电脑端的按钮,通过UDP下发命令,开发板通过WiFi模块连接,之后对电脑端发送的命令进行解析,之后对相应命令执行相应操作。
电脑客户端
页面设计
程序代码
代码语言:javascript复制namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
UdpClient ctrludpcRecv = null; //控制指令
IPEndPoint ctrllocalIpep = null;
public Form1()
{
InitializeComponent();
ctrllocalIpep = new IPEndPoint(IPAddress.Any, 50001); // 本机IP和监听端口号
ctrludpcRecv = new UdpClient(ctrllocalIpep);
ctrludpcRecv.Client.ReceiveBufferSize = 64 * 4096 * 4096;
ctrludpcRecv.EnableBroadcast = true;
}
private void button1_Click(object sender, EventArgs e)
{
IPAddress Adrr;
if (string.IsNullOrEmpty(textBox1.Text))
{
Adrr = IPAddress.Parse("255.255.255.255");
}
else
{
Adrr = IPAddress.Parse(textBox1.Text);
}
IPEndPoint remoteIpep = new IPEndPoint(Adrr, 50001); ;
JavaScriptSerializer ser = new JavaScriptSerializer();
CtrlJson rcj = new CtrlJson() { cmd = "RED" };
string outputJson = ser.Serialize(rcj);
byte[] sendByte = System.Text.Encoding.Default.GetBytes(outputJson);
//发送
ctrludpcRecv.Send(sendByte, sendByte.Length, remoteIpep);
}
private void button2_Click(object sender, EventArgs e)
{
IPAddress Adrr;
if (string.IsNullOrEmpty(textBox1.Text))
{
Adrr = IPAddress.Parse("255.255.255.255");
}
else
{
Adrr = IPAddress.Parse(textBox1.Text);
}
IPEndPoint remoteIpep = new IPEndPoint(Adrr, 50001); ;
JavaScriptSerializer ser = new JavaScriptSerializer();
CtrlJson rcj = new CtrlJson() { cmd = "YELLOW" };
string outputJson = ser.Serialize(rcj);
byte[] sendByte = System.Text.Encoding.Default.GetBytes(outputJson);
//发送
ctrludpcRecv.Send(sendByte, sendByte.Length, remoteIpep);
}
private void button4_Click(object sender, EventArgs e)
{
IPAddress Adrr;
if (string.IsNullOrEmpty(textBox1.Text))
{
Adrr = IPAddress.Parse("255.255.255.255");
}
else
{
Adrr = IPAddress.Parse(textBox1.Text);
}
IPEndPoint remoteIpep = new IPEndPoint(Adrr, 50001); ;
JavaScriptSerializer ser = new JavaScriptSerializer();
CtrlJson rcj = new CtrlJson() { cmd = "GREEN" };
string outputJson = ser.Serialize(rcj);
byte[] sendByte = System.Text.Encoding.Default.GetBytes(outputJson);
//发送
ctrludpcRecv.Send(sendByte, sendByte.Length, remoteIpep);
}
private void button3_Click(object sender, EventArgs e)
{
IPAddress Adrr;
if (string.IsNullOrEmpty(textBox1.Text))
{
Adrr = IPAddress.Parse("255.255.255.255");
}
else
{
Adrr = IPAddress.Parse(textBox1.Text);
}
IPEndPoint remoteIpep = new IPEndPoint(Adrr, 50001); ;
JavaScriptSerializer ser = new JavaScriptSerializer();
CtrlJson rcj = new CtrlJson() { cmd = "CLOSE" };
string outputJson = ser.Serialize(rcj);
byte[] sendByte = System.Text.Encoding.Default.GetBytes(outputJson);
//发送
ctrludpcRecv.Send(sendByte, sendByte.Length, remoteIpep);
}
}
}
MCU端
搭建的模块
- WiFi模块
- OLED显示屏
- 红绿黄三色交通灯
主要代码
代码语言:javascript复制char recvline[1024];
void udp_thread(void *pdata)
{
int ret;
struct sockaddr_in servaddr;
cJSON *recvjson;
pdata = pdata;
int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
//服务器 ip port
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(50001);
printf("udp_thread rn");
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while(1)
{
struct sockaddr_in addrClient;
int sizeClientAddr = sizeof(struct sockaddr_in);
memset(recvline, sizeof(recvline), 0);
ret = recvfrom(sockfd, recvline, 1024, 0, (struct sockaddr*)&addrClient,(socklen_t*)&sizeClientAddr);
if(ret>0)
{
char *pClientIP =inet_ntoa(addrClient.sin_addr);
printf("%s-%d(%d) says:%sn",pClientIP,ntohs(addrClient.sin_port),addrClient.sin_port, recvline);
//进行json解析
recvjson = cJSON_Parse(recvline);
if(recvjson != NULL)
{
if(cJSON_GetObjectItem(recvjson, "cmd")->valuestring != NULL)
{
printf("cmd : %srn", cJSON_GetObjectItem(recvjson, "cmd")->valuestring);
if(strcmp("RED", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
{
set_LED_status(LED_STATUS_RED);
printf("REDrn");
}
if(strcmp("YELLOW", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
{
set_LED_status(LED_STATUS_YELLOW);
printf("YELLOWrn");
}
if(strcmp("GREEN", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
{
set_LED_status(LED_STATUS_GREEN);
printf("GREENrn");
}
if(strcmp("CLOSE", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
{
set_LED_status(LED_STATUS_CLOSE);
printf("CLOSErn");
}
}
cJSON_Delete(recvjson);
}
}
}
}
void start_udp_thread(void)
{
osThreadAttr_t attr;
attr.name = "wifi_config_thread";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 2048;
attr.priority = 36;
if (osThreadNew((osThreadFunc_t)udp_thread, NULL, &attr) == NULL) {
printf("[LedExample] Falied to create LedTask!n");
}
}