OpenHarmony开发者论坛

标题: [OpenHarmony轻量系统]润和3861实现TCP电子琴③ [打印本页]

作者: 离北况归    时间: 2023-10-17 15:32
标题: [OpenHarmony轻量系统]润和3861实现TCP电子琴③
[md]- 本文实现了用润和HiHope Pegasus 3861开发板 实现TCP电子琴,样例demo下载链接:https://gitee.com/from-north-to- ... 5%E5%AD%90%E7%90%B4
- 样例运行的OpenHarmony源码环境下载:https://gitee.com/HiSpark/hi3861_hdu_iot_application

---

通过本文您将了解:
1、HiHopePegasus 3861 开发环境选择
2、HiHopePegasus 3861 连接wifi
3、HiHopePegasus 3861 TCP 连接
4、HiHopePegasus 3861 环境监测板上蜂鸣器的控制


---

## 1. TCP电子琴样例运行效果

- 3861开发板作为TCP服务端与TCP客户端(自己的设备)连接。
- TCP客户端发送12345678,控制开发板上`环境拓展板上的蜂鸣器`发出duō lái mī fā suō lā xī duō 8种音调。

## 2. 样例运行步骤

- 2.1 下载 https://gitee.com/from-north-to- ... 5%E5%AD%90%E7%90%B4 ,将源文件文件放置在命名为TCP_keyboard_demo的文件夹下,将其放置在OpenHarmony轻量系统源码 applications\sample\wifi-iot\app目录下。
- 2.1 修改`net_params.h`文件的相关代码:
  
  - PARAM_HOTSPOT_SSID 设置为要连接的热点名称
  - PARAM_HOTSPOT_PSK 设置为要连接的热点秘码;
  - PARAM_SERVER_ADDR 设置为要连接的作为 TCP客户端的设备IP地址
  - PARAM_SERVER_PORT 设置 3861开发板(作为TCP服务端) TCP socket端口号
- 2.2 在源码 applications\sample\wifi-iot\app\BUILD.gn文件features 字段下添加"TCP_keyboard_demo:TCP_keyboard_demo",使样例demo加入编译。
- 2.2 根据3861开发板的ip(串口打印出来的)和`net_params.h`中填写的TCP socket端口号创建客户端,连接3861开发板。

![image.png](https://dl-harmonyos.51cto.com/i ... rocess=image/resize,w_537,h_382)

## 3. 环境监测板上蜂鸣器与主控芯片(Pegasus)引脚的对应关系

- GPIO9/PWM0

## 4. 源码分析

### 4.1 文件说明

| 文件名             | 说明                                                        |
| ------------------ | ----------------------------------------------------------- |
| BUILD.gn           | 构建脚本   |
| demo_entry_cmsis.c | wifi和tcp连接的部分       |
| net_common.h       | 系统网络接口头文件      |
| net_demo.h         | demo脚手架头文件     |
| net_params.h       | 网络参数,包括WiFi热点信息,tcp 客户端的ip 、tcp连接的端口号  |
| tcp_server_test.c  | 3861开发板作为TCP服务端收发数据、电子琴的实现代码               |
| wifi_connecter.c   | WiFi STA模式API的封装实现文件|
| wifi_connecter.h   | WiFi STA模式API的封装头文件|

### 4.2 tcp_server_test.c文件解析

```
#include <errno.h>
#include <stdio.h>
#include <string.h>

#include <unistd.h>

//TCP连接的部分
#include "net_demo.h"
#include "net_common.h"

/********************环境监测板上蜂鸣器的部分*********************************/
#include "iot_gpio.h"
#include "iot_pwm.h"
#include "hi_pwm.h"
#include "hi_io.h"
#define BEEP_PIN_NAME 9
#define BEEP_PIN_FUNCTION 5
#define WIFI_IOT_PWM_PORT_PWM0 0
#define BEEP_PWM_DUTY 50

/*********************************************************************/

#define DELAY_1S  (1)

void TcpServerTest(unsigned short port)
{

/********************环境监测板上蜂鸣器的部分*********************************/
    // 初始化蜂鸣器
    // 蜂鸣器:GPIO9/PWM0
    // 环境监测板上蜂鸣器与主控芯片(Pegasus)引脚的对应关系 GPIO9/PWM0
    // IoTGpioInit用于初始化 GPIO 设备
    IoTGpioInit(BEEP_PIN_NAME);
    // hi_io_set_func 用于 配置某个IO的复用功能
    hi_io_set_func(BEEP_PIN_NAME, BEEP_PIN_FUNCTION);
    // IoTGpioSetDir 用于 设置 GPIO 引脚的方向
    IoTGpioSetDir(BEEP_PIN_NAME, IOT_GPIO_DIR_OUT);
    // IoTPwmInit 用于 初始化 PWM 设备
    IoTPwmInit(WIFI_IOT_PWM_PORT_PWM0);

/***************************************************************************************/

    ssize_t retval = 0;
    int backlog = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
    int connfd = -1;

    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);  // 端口号,从主机字节序转为网络字节序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入, 0.0.0.0

/*************************************绑定端口****************************************************/
    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (retval < 0) {
        printf("_______________________________________\r\n");
        printf("bind failed, %ld!\r\n", retval);
        
        //关闭socket
        printf("do_cleanup...\r\n");
        close(sockfd);
    }else{
    printf("_______________________________________\r\n");
    printf("bind to port %hu success!\r\n", port);
    }

/***********************************************************************************************/

    retval = listen(sockfd, backlog); // 开始监听
    if (retval < 0) {
        printf("_______________________________________\r\n");
        printf("listen failed!\r\n");
        
        //关闭socket
        printf("do_cleanup...\r\n");
        close(sockfd);
    }else{
    printf("_______________________________________\r\n");
    printf("listen with %d backlog success!\r\n", backlog);
    }

/**************************************接受客户端连接*********************************************************/

    // 接受客户端连接,成功会返回一个表示连接的 socket , clientAddr 参数将会携带客户端主机和端口信息 ;失败返回 -1
    // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
    //  UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
    //  鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型
    //     liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
    connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
    if (connfd < 0) {
        printf("accept failed, %d, %d\r\n", connfd, errno);

        //关闭socket
        printf("do_cleanup...\r\n");
        close(sockfd);
    }else{
    printf("_______________________________________\r\n");
    printf("accept success, connfd = %d!\r\n", connfd);
    printf("client addr info: host = %s, port = %hu\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
    }

/***********************************socket收、发的部分************************************************************/

  // 后续 收、发 都在 表示连接的 socket 上进行;
    while (1) {
       char request[128] = "";
       //接收客户端发送过来的数据
       retval = recv(connfd, request, sizeof(request), 0);
       if (retval < 0) {
           printf("_______________________________________\r\n");
           printf("recv request failed, %ld!\r\n", retval);

           //关闭与客户端的连接
           printf("do_disconnect...\r\n");
           sleep(DELAY_1S);
           close(connfd);
           sleep(DELAY_1S); // for debug
        }else{
           printf("_______________________________________\r\n");
           printf("The data received from the client is %s \r\n", request);
        }

        //发送数据到客户端
        retval = send(connfd, request, strlen(request), 0);
        if (retval <= 0) {
           printf("_______________________________________\r\n");
           printf("send response failed, %ld!\r\n", retval);
           
           //关闭与客户端的连接
           printf("do_disconnect...\r\n");
           sleep(DELAY_1S);
           close(connfd);
           sleep(DELAY_1S); // for debug
        }else{
           printf("The data responsed to the client is %s\r\n", request);
        }
     
/************************tcp 客户端发送12345678控制不同的音调****************************/
      int i=atoi(request); // 将字符串request转换成int类型
      hi_pwm_set_clock(PWM_CLK_XTAL); // 设置时钟源为晶体时钟(40MHz,默认时钟源160MHz)
            switch (i)
            {
             case 1:
          printf("Tone is 1\n" );

        /**
          * IoTPwmStart 根据给定的输出频率和占空比启动指定端口的 PWM 信号输出。
          * - port 指示 PWM 设备的端口号
          * - 占空比 表示 PWM 信号输出的占空比。值范围为 1 到 99。
          * - 频率 指示 PWM 信号输出的频率。
        **/
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 2500);  //通过调节PWM 信号输出的频率控制蜂鸣器声调(调到2000听不到蜂鸣器声音)
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;  

             case 2:
          printf("Tone is 2\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 3000);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;       

             case 3:

          printf("Tone is 3\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 3500);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

             case 4:
          printf("Tone is 3\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 4000);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

             case 5:
          printf("Tone is 5\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 4500);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

             case 6:
          printf("Tone is 6\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 5000);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

             case 7:
          printf("Tone is 7\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 5500);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

       case 8:
          printf("Tone is 8\n");
          IoTPwmStart(WIFI_IOT_PWM_PORT_PWM0, BEEP_PWM_DUTY, 6000);
          usleep(500000);//音长
          IoTPwmStop(WIFI_IOT_PWM_PORT_PWM0);
          break;

             default:break;
        }
/***********************************************************************************************/

       usleep(10);
    }

/***********************************************************************************************/

}

SERVER_TEST_DEMO(TcpServerTest);
```



[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5