嵌入式开发疫情期间的模拟工作—UDP通信实现无线装置
嵌入式开发模拟红外测距仪
这学期学习嵌入式开发,由于没有硬件设备,因此课程主要由模拟构成
主要是通过UDP实现服务端和客户端的交互,客户端向服务端发送一个信号,服务端接收后将产生的模拟数据发送给客户端,从而实现目标功能。
以下是代码部分
服务端:
// Sensor_UDP.cpp: 定义控制台应用程序的入口点。
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib") // 使用WinSock2.2实现网络通信所需文件
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <time.h>
#include <stdio.h>
#include <math.h>
#include<time.h>
#define BUFF_SIZE 64
double generate();
char response[BUFF_SIZE];
int main()
{
//创建接收与发送缓冲区
char recvbuff[BUFF_SIZE];
char sendbuff[BUFF_SIZE];
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("dll初始化失败");
}
//创建套接字
SOCKET hServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (hServer == INVALID_SOCKET) {
printf("socket failed \n");
return 0;
}
//创建服务器端地址并绑定端口号的IP地址
sockaddr_in addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(8889);
addrServer.sin_addr.S_un.S_addr = INADDR_ANY;
int nRet = bind(hServer, (sockaddr*)&addrServer, sizeof(addrServer));
if (nRet == SOCKET_ERROR) {
printf("socket bind failed\n");
closesocket(hServer);
WSACleanup();
return 0;
}
//接收客户端请求
SOCKADDR clntAddr; //客户端地址信息
int nSize = sizeof(SOCKADDR);
//等待接收初始化命令
while (1) {
int strLen = recvfrom(hServer, recvbuff, BUFF_SIZE, 0, &clntAddr, &nSize); //接收指令,并储存数据长度
recvbuff[strLen] = '\0'; //防止出现乱码
if (recvbuff != 0)
{
sendto(hServer, "1", strlen("1"), 0, &clntAddr, nSize);
break;
}
}
memset(recvbuff, 0, BUFF_SIZE); //重置缓冲区
while (1) {
int strLen = recvfrom(hServer, recvbuff, BUFF_SIZE, 0, &clntAddr, &nSize); //接收指令,并储存数据长度
recvbuff[strLen] = '\0'; //防止出现乱码
if (strcmp(recvbuff, "read_mode") == 0)
{
//判断指令
double timing = generate(); //产生模拟数据
printf("单次距离读取指令\n");
sprintf_s(response, sizeof(response), "%.6f", timing); //double 转 字符串
sendto(hServer, response, strlen(response), 0, &clntAddr, nSize);
}
else if (strcmp(recvbuff, "close") == 0)
{
printf("断开连接指令\n");
sendto(hServer, "服务器已关闭\0", strlen("服务器已关闭\0"), 0, &clntAddr, nSize);
break;
}
else
{
printf("指令输入有误\n");
sendto(hServer, "指令输入有误\0", strlen("指令输入有误\0"), 0, &clntAddr, nSize);
printf("错误指令:%s\n", recvbuff);
}
memset(recvbuff, 0, BUFF_SIZE); //重置缓冲区
memset(sendbuff, 0, BUFF_SIZE); //重置缓冲区
}
//关闭套接字
closesocket(hServer);
WSACleanup();
return 0;
}
double generate()
{ //产生模拟数据
srand((unsigned)time(NULL));
double timing = (rand() % 1000) ;//生成时间单位为微秒
return timing;
}
客户端部分
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") // 使用WinSock2.2实现网络通信所需文件
#include<stdlib.h>
#include<windows.h>
#include<iostream>
#include<stdio.h>
#include<string>
#include <Ws2tcpip.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define BUFF_SIZE 64 // 缓冲区大小
#define STORAGE_SIZE 10 //历史记录上限
#define Cspeed 3.0e8
#define ACCURACY 3
const int BUFFER_SIZE = 1024;
char buffer[BUFFER_SIZE]; //show函数中所用
char recvbuff[BUFF_SIZE] = { 0 };
char sendbuff[BUFF_SIZE] = { 0 }; // 创建接收与发送缓冲
double timing = 0.0;
double storage[STORAGE_SIZE] = { 0,0,0,0,0,0,0,0,0,0 }; //储存历史数据
int J = -1; //指向最新数据
int K = 0; //指向回查数据
//函数声明
int sensorInit(SOCKET ConnectSocket, sockaddr_in servAddr, int accuracy); //初始化
double trans(double timing); //把时间转换成距离并存储
double read_storage(); //阅读历史数据
void read_mode(SOCKET ConnectSocket); //读取距离
void show(double storage[STORAGE_SIZE]); //把历史数据转换成曲线
sockaddr serSockAddr; //不断获取输入并发送到服务器,接收服务器数据
int addrLen = sizeof(serSockAddr);
int main()
{
// WSADATA结构体主要包含了系统所支持的winsock版本
WSADATA wsaData;
// 初始化winsock 2.2
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup 无法初始化! ");
return 0;
}
//创建连接到服务器的SOCKET对象
SOCKET sClient;
sClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (SOCKET_ERROR == sClient) {
printf("socket failed !\n");
return 0;
}
//创建服务器端地址
sockaddr_in serverAddr;
//创建服务器端地址
sockaddr_in clientAddr;
//设置服务器端地址,端口号,协议族
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8889);
serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// 传感器初始化
int init_zet = sensorInit(sClient, serverAddr, ACCURACY);
//char strC1[30] = "单次距离读取",strC2[30] = "读取历史数据",strC3[30] = "清除历史数据";
printf("提示: \n read_mode:单次距离读取\n read_storage:读取历史数据\n clear_storage:清空历史数据\nclose:关闭服务端\n");
while (1) {
if (init_zet == 1)
{
printf("Input a command:"); //输入命令
scanf_s("%s", sendbuff, BUFF_SIZE);
if (strcmp(sendbuff, "read_storage") == 0)
{
printf("历史记录: %f\n", read_storage()); //读取历史记录
}
else if (strcmp(sendbuff, "clear_storage") == 0)
{
memset(storage, 0, STORAGE_SIZE);
}
else {
sendto(sClient, sendbuff, strlen(sendbuff), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); //发送数据
}
if (strcmp(sendbuff, "read_mode") == 0)
{
read_mode(sClient);
}
if (strcmp(sendbuff, "close") == 0)
{
printf("服务端已关闭\n");
}
memset(recvbuff, 0, BUFF_SIZE);
memset(sendbuff, 0, BUFF_SIZE); //重置缓冲区
}
else
{
printf("传感器初始化失败\n");
Sleep(10000);
break;
}
}
closesocket(sClient);
WSACleanup(); // 释放资源
// 清除工作
if (WSACleanup() == SOCKET_ERROR)
printf("WSACleanup 出错! ");
printf("\n\n");
system("pause");
return 0;
}
int sensorInit(SOCKET ConnectSocket, sockaddr_in servAddr, int accuracy)
//初始化:成功返回1,不成功返回0
{
int i = 0;
sprintf_s(sendbuff, sizeof(sendbuff), "%d", accuracy);
while (strcmp(recvbuff, "1") != 0)
{
sendto(ConnectSocket, sendbuff, strlen(sendbuff), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
//发送初始化信息,并建立连接
recvfrom(ConnectSocket, recvbuff, BUFF_SIZE, 0, &serSockAddr, &addrLen); //接收初始化结果信息
Sleep(1); //延时1ms
i++;
}
if (i > 10) //等待10ms以上
{
return 0; //初始化失败
}
else return 1; //初始化成功
}
double read_storage()
{
char recvdata[BUFF_SIZE];
printf("回看记录数(范围:0-9):");
scanf_s("%s", recvdata, sizeof(recvdata));
K = (J - strtol(recvdata, NULL, 10) + STORAGE_SIZE) % STORAGE_SIZE;
//求回看数
return storage[K];
}
double trans(double timing)
{
double distance = 0;
distance = timing * Cspeed / 2;
J = (J + 1) % STORAGE_SIZE;
storage[J] = distance;
printf("Message from server:%f\n", distance);
return 0;
}
void read_mode(SOCKET ConnectSocket)
{
recvfrom(ConnectSocket, recvbuff, BUFF_SIZE, 0, &serSockAddr, &addrLen);
//接收数据
timing = strtod(recvbuff, NULL)/1000000;
//把字符型数据转换成整形
trans(timing); //转换并存储
}
最终效果如下图
后续会将其封装为dll文件进行GUI界面程序,大家批评指正。