4

OpenHarmony设备开发之基于TCP遥控小车

 1 year ago
source link: https://www.51cto.com/article/718260.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

OpenHarmony设备开发之基于TCP遥控小车

作者:X丶昕雪 2022-09-07 15:35:49
本文主要介绍在hi3861使用TCP进行控制小车,在使用TCP遥控小车之前,需要连接好Wifi。
1758fcb58193358365a1896e663784cf197aff.png

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

基于TCP开发遥控小车

本文主要介绍在hi3861使用TCP进行控制小车,在使用TCP遥控小车之前,需要连接好wifi。

TCP传输控制协议,是一种提供可靠的数据传输的协议,是有连接的,按序传输数据的,面向字节流的,可靠稳定的协议。

TCP通讯设备分为了客户端和服务端,在本文中,在windows上建立服务端,hi3861作为客户端,两者连接手机的wifi进行TCP通讯(一定要在同一网络内)。下文主要介绍hi3861作为客户端建立tcp连接的方法。

客户端代码介绍

  • 客户端在连接TCP之前一定要确保连上wifi,而hi3861连接wifi需要亿点点时间,因此建议连接wifi后sleep()几秒钟,让hi3861连接上wifi。
  1. 首先创建Socket对象,创建客户端套接字对象。
  • socket()本次只需要关注参数一和参数二,参数一表示ipv4,参数二表示使用面向连接的套接字(TCP)。
  • 返回值:若创建失败,返回-1。
int socks;
socks=socket(AF_INET, SOCK_STREAM, 0);
  1. 创建sockaddr_in结构体对象,该对象存放服务端地址的参数,并初始化该对象的成员。
struct sockaddr_in sock_addr = {0};
    sock_addr.sin_family = AF_INET;     //ipv4
    sock_addr.sin_port = PP_HTONS(8888);        //IP端口
    sock_addr.sin_addr.s_addr = inet_addr("192.168.xx.xx"); //ip地址
  1. connect()连接函数,其功能是完成一个有连接协议的连接过程.上面两步创建的结构体对象都会在这一步使用到,这一步也是TCP连接最为关键的一步。
  • 返回值:若连接成功便返回0,失败则返回-1。
  • 参数一:指定数据发送的套接字。
  • 参数二:指定服务端的地址,使用sockaddr_in结构体对象。
  • 参数三:参数二结构体的长度connect(socks, (struct sockaddr *)&sock_addr, sizeof(sock_addr));上述步骤便完成了hi3861客户端和服务端的连接,我们接下来便可以快乐地和服务端进行收发数据,基于该无线连接的收发数据,我们可以做出各种有意思有趣的东西。
  1. API接口。
  • 发送数据
    函数:lwip_write(int s, const void *dataptr, size_t size);​参数一:套接字对象,参数二:发送的数据,参数三:数据长度。
    样例:
static const char *buf = "Hello! I'm HI3861 TCP client!!!!!!";
lwip_write(socks, buf, strlen(buf));
  • 接收数据
    函数:​lwip_read(int fildes, void *buf, size_t nbyte);​参数一:套接字对象,参数二:接收的数据,参数三:数据长度。
    样例:
char recv_buf[64];
(void)memset_s(recv_buf, sizeof(recv_buf), 0, sizeof(recv_buf));
lwip_read(socks, recv_buf, sizeof(recv_buf) - 1);
  • 超时机制
    在TCP连接中,recv等函数默认为阻塞模式,就是没有数据传输时便会一直停留在函数里,我们有时不希望一直停在这个函数内,便需要一种超时机制​setsockopt()​,到达一定时间后即使没有数据也会退出函数.函数:​int setsockopt(int s, int level, int optname, void* optval, socklen_t* optlen)。
  • 参数一:指向一个打开的套接口描述字。
  • 参数二:指定选项代码的类型|选项代码的类型|含义|| ---- | ---- ||SOL_SOCKET| 基本套接口||IPPROTO_IP| IPv4套接口||IPPROTO_IPV6|IPv6套接口||IPPROTO_TCP|TCP套接口|。
  • 参数三:选项名称SO_RCVTIMEO:设置接收超时时间。
  • 参数四:选项值。
  • 参数五:参数的长度样例:
struct timeval recev_timeout;
recev_timeout.tv_sec = 5;
recev_timeout.tv_usec = 0;
/* 5S Timeout */
ret_a = setsockopt(socks, SOL_SOCKET, SO_RCVTIMEO, recev_timeout, sizeof(recev_timeout));

该函数还有其它许多用法,但本文不过多介绍,需要了解更多可以baidu一下。

头文件以及一些宏定义:

// tcp
#include <stdio.h>
#include "lwip/sockets.h"
char recv_buf[64];
// io
#include "iot_gpio.h"
#include <hi_gpio.h>
#include <hi_io.h>
#define GPIO0 0
#define GPIO1 1
#define GPIO9 9
#define GPIO10 10

主函数中的代码:

//连接好wifi后
/**********************************************/
    sleep(5);   
    struct sockaddr_in sock_addr = {0};
    int s;
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = PP_HTONS(_PROT_);
    sock_addr.sin_addr.s_addr = inet_addr(IP_argv[0]);
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0)
    {
        printf("socket false\n");
    }
    int ret_a;
    ret_a = connect(s, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
    if (ret_a != 0)
    {
        printf("connect false\n");
    }
    my_car_init();      //小车电机的IO口初始化
    while (1)
    {
        (void)memset_s(recv_buf, sizeof(recv_buf), 0, sizeof(recv_buf));
        ret_a = lwip_read(s, recv_buf, sizeof(recv_buf) - 1);       //等待接收服务端发送数据
        printf("server:%d!\n", recv_buf[0]);
    //判断接收的数据是何按键,49对应前进键,50对应后退键,51左键,52右键
        if (recv_buf[0] == 49)
        {
            car_forward();
            printf("car_forward!\n");
        }
        else if (recv_buf[0] == 50)
        {
            car_stop();
            printf("car stop!");
        }
        else if (recv_buf[0] == 51)
        {
            car_left();
        }
        else if (recv_buf[0] == 52)
        {
            car_right();
        }
    }

小车控制的代码:

#define GPIO0 0
#define GPIO1 1
#define GPIO9 9
#define GPIO10 10
void my_car_init(void)
{
    //IO口初始化
    IoTGpioInit(GPIO0);
    IoTGpioInit(GPIO1);
    IoTGpioInit(GPIO10);
    IoTGpioInit(GPIO9);
    //IO口复用
    hi_io_set_func(GPIO0, HI_IO_FUNC_GPIO_0_GPIO); //在hi_io.h里有定义
    hi_io_set_func(GPIO1, HI_IO_FUNC_GPIO_1_GPIO);
    hi_io_set_func(GPIO10, HI_IO_FUNC_GPIO_10_GPIO);
    hi_io_set_func(GPIO9, HI_IO_FUNC_GPIO_9_GPIO);
    //IO口功能设置,输入or输出
    IoTGpioSetDir(GPIO0, 1);    //1为output输出
    IoTGpioSetDir(GPIO1, 1);
    IoTGpioSetDir(GPIO10, 1);
    IoTGpioSetDir(GPIO9, 1);
    //IO口输出电平
    IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE1);        //VALUE1为高电平,VALUE0为低电平
    IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE1);
}
void car_stop(void)
{
    IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE1); //左轮
    IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE1); //左轮
    IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1); //右轮
    IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE1); //右轮
}
void car_forward(void)
{
    IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE0);
    IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE0);
}
void car_left(void)
{
    IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE0);
    IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE0);
    IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE0);
}
void car_right(void)
{
    IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE0);
    IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1);
    IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE1);
}

win10中的服务端:

编译gcc -o server server.c -lwsock32。

运行软件./server IP地址 端口。

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>
#include <conio.h>
int key;
int startup(int _port, const char *_ip)
{
    WSADATA ws;
    WSAStartup(MAKEWORD(2, 2), &ws);
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = inet_addr(_ip);
    int len = sizeof(local);
    if (bind(sock, (struct sockaddr *)&local, len) < 0) //绑定
    {
        perror("bind");
        exit(2);
    }

    if (listen(sock, 5) < 0) //允许连接的最大数量为5,监听
    {
        perror("listen");
        exit(3);
    }
    return sock;
}
int main(int argc, const char *argv[])
{
    int listen_sock = startup(atoi(argv[2]), argv[1]); //初始化
    //用来接收客户端的socket地址结构体
    struct sockaddr_in remote;
    int len = sizeof(struct sockaddr_in);
    while (1)
    {
        int sock = accept(listen_sock, (struct sockaddr *)&remote, &len); //连接
        if (sock < 0)
        {
            perror("accept");
            continue;
        }
        printf("get a client, ip:%s, port:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
        while (1)
        {
            key = _getch();
            if (key > 31 && key < 127) /*如果不是特殊键*/
            {
                printf("按了 %c 键\n", key);
                continue;
            }
            key = _getch();
            if (key == 72)
            {
                send(sock, "1", 2, 0);
                printf("按了 %c 上键\n", key);
            }
            else if (key == 80)
            {
                send(sock, "2", 2, 0);
                printf("按了 %c 下键\n", key);
            }
            else if (key == 75)
            {
                send(sock, "3", 2, 0);
                printf("按了 %c 左键\n", key);
            }
            else if (key == 77)
            {
                send(sock, "4", 2, 0);
                printf("按了 %c 右键\n", key);
            }
     
        }
    }
    return 0;
}
【FFH】OpenHarmony设备开发(二)-基于TCP遥控小车-开源基础软件社区
【FFH】OpenHarmony设备开发(二)-基于TCP遥控小车-开源基础软件社区

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

责任编辑:jianghua 来源: 鸿蒙社区

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK