[OpenHarmony轻量系统]润和3861实现TCP电子琴③ 原创 精华

离北况归
发布于 2023-7-31 22:26
浏览
1收藏

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

@toc


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-north/open-armony-north/tree/master/润和3861轻量系统TCP电子琴 ,将源文件文件放置在命名为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开发板。

[OpenHarmony轻量系统]润和3861实现TCP电子琴③ -鸿蒙开发者社区

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);

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2023-7-31 22:26:55修改
3
收藏 1
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

样例demo下载链接访问受限的情况请问如何解决

回复
2023-8-1 10:18:36
hmyxd
hmyxd

注释很详细,好评

回复
2023-8-1 18:20:23
诺舒华吃西瓜
诺舒华吃西瓜

可以考虑放个歌什么的了

回复
2023-8-2 16:27:39
回复
    相关推荐