开发板漂流计划 HarmonyOSAPP控制超声波小车

愿君学长松,慎勿作桃李。这篇文章主要讲述开发板漂流计划 HarmonyOSAPP控制超声波小车相关的知识,希望能为你提供帮助。
【开发板漂流计划】 HarmonyOSAPP控制超声波小车 1.超声波小车介绍
①.本项目采用的开发套件为HiSpark Wi-Fi IoT智能小车 ②.项目预览

开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

视频链接:https://www.bilibili.com/video/BV1pS4y1Y72j/
代码开源地址:https://gitee.com/yukoyu/harmony-wifi-car
③.框架图
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

④.HarmonyOS采用 java方式开发 2.小车端开发
①.新建文件夹路径:openharmony\\applications\\sample\\wifi-iot\\app\\
mkdir wificar

②.编写小车电机驱动
路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\robot_l9110s.c

代码:
#define GPIO0 0 #define GPIO1 1 #define GPIO9 9 #define GPIO10 10 #define GPIOFUNC 0 #define PWM_FREQ_FREQUENCY(60000)void gpio_control (unsigned intgpio, IotGpioValue value) hi_io_set_func(gpio, GPIOFUNC); IoTGpiosetDir(gpio, IOT_GPIO_DIR_OUT); IoTGpioSetOutputVal(gpio, value); //后退 void car_backward(void) gpio_control(GPIO0, IOT_GPIO_VALUE0); gpio_control(GPIO1, IOT_GPIO_VALUE1); gpio_control(GPIO9, IOT_GPIO_VALUE0); gpio_control(GPIO10, IOT_GPIO_VALUE1); //前进 void car_forward(void) gpio_control(GPIO0, IOT_GPIO_VALUE1); gpio_control(GPIO1, IOT_GPIO_VALUE0); gpio_control(GPIO9, IOT_GPIO_VALUE1); gpio_control(GPIO10, IOT_GPIO_VALUE0); //左转 void car_left(void) gpio_control(GPIO0, IOT_GPIO_VALUE0); gpio_control(GPIO1, IOT_GPIO_VALUE0); gpio_control(GPIO9, IOT_GPIO_VALUE1); gpio_control(GPIO10, IOT_GPIO_VALUE0); //右转 void car_right(void) gpio_control(GPIO0, IOT_GPIO_VALUE1); gpio_control(GPIO1, IOT_GPIO_VALUE0); gpio_control(GPIO9, IOT_GPIO_VALUE0); gpio_control(GPIO10, IOT_GPIO_VALUE0); //停止转动 void car_stop(void) gpio_control(GPIO0, IOT_GPIO_VALUE1); gpio_control(GPIO1, IOT_GPIO_VALUE1); gpio_control(GPIO9, IOT_GPIO_VALUE1); gpio_control(GPIO10, IOT_GPIO_VALUE1);

③.编写舵机驱动
路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\robot_sg90.c

代码:
#define GPIO2 2 void set_angle( unsigned int duty) IoTGpioInit(GPIO2); IoTGpioSetDir(GPIO2, IOT_GPIO_DIR_OUT); IoTGpioSetOutputVal(GPIO2, IOT_GPIO_VALUE1); hi_udelay(duty); IoTGpioSetOutputVal(GPIO2, IOT_GPIO_VALUE0); hi_udelay(20000 - duty); //控制电机转动角度参数范围 1000< time< 2000 void custom(int time)for (int i = 0; i < 10; i++) set_angle(time);

④.编写超声波驱动
路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\robot_hcsr04.c

代码:
#define GPIO_8 8 #define GPIO_7 7 #define GPIO_FUNC 0 extern int cmm; void GetDistance(float *distance) static unsigned long start_time = 0, time = 0; IotGpioValue value = https://www.songbingjia.com/android/IOT_GPIO_VALUE0; unsigned int flag = 0; IoTWatchDogDisable(); hi_io_set_func(GPIO_8, GPIO_FUNC); IoTGpioSetDir(GPIO_8, IOT_GPIO_DIR_IN); IoTGpioSetDir(GPIO_7, IOT_GPIO_DIR_OUT); IoTGpioSetOutputVal(GPIO_7, IOT_GPIO_VALUE1); hi_udelay(20); IoTGpioSetOutputVal(GPIO_7, IOT_GPIO_VALUE0); while (1) IoTGpioGetInputVal(GPIO_8, & value); if ( value == IOT_GPIO_VALUE1 & & flag == 0) start_time = hi_get_us(); flag = 1; if (value == IOT_GPIO_VALUE0 & & flag == 1) time = hi_get_us() - start_time; start_time = 0; break; *distance = time * 0.034 / 2; printf("distance is %f\\r\\n",*distance); return ;

⑤.编写wifi和socket server
路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\wifi_sockets.c

代码:
// 接收、发送的数据 static char request[256] = ""; // 未连接热点=0,已连接热点=1 static int g_connected = 0; int connfd = -1; // 输出连接信息字符串 // 打印内容样例--> bssid: 38:47:BC:49:01:FA, rssi: 0, connState: 0, reason: 0, ssid: MyMobile void PrintLinkedInfo(WifiLinkedInfo* info) if (!info) return; static char macAddress[32] = 0; unsigned char* mac = info-> bssid; snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %srn", macAddress, info-> rssi, info-> connState, info-> disconnectedReason, info-> ssid); // 连接状态改变事件处理 void OnWifiConnectionChanged(int state, WifiLinkedInfo* info) if (!info) return; // 输出类似内容:OnWifiConnectionChanged 31, state = 1, info = printf("%s %d, state = %d, info = rn", __FUNCTION__, __LINE__, state); PrintLinkedInfo(info); // 根据连接状态设置g_connected if (state == WIFI_STATE_AVALIABLE) g_connected = 1; else g_connected = 0; // 扫描状态改变事件处理 void OnWifiScanStateChanged(int state, int size) printf("%s %d, state = %X, size = %drn", __FUNCTION__, __LINE__, state, size); void DisconnectTcpSocket(int connfd) sleep(1); printf("do_disconnect...rn"); lwip_close(connfd); sleep(1); // for debugvoid CloseTcpSocket(int socketfd) printf("do_cleanup...rn"); lwip_close(socketfd); static void TcpServerHandler(void) ssize_t retval = 0; unsigned short port = 20222; // 创建一个通信的Socket,并返回一个Socket文件描述符。第一个参数IpV4,第二个参数SOCK_STREAM类型,第三个指用到的协议 int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 客户端地址和地址长度 struct sockaddr_in clientAddr = 0; socklen_t clientAddrLen = sizeof(clientAddr); // 服务端地址 struct sockaddr_in serverAddr = 0; serverAddr.sin_family = AF_INET; // htons是将整型变量从主机字节顺序转变成网络字节顺序,就是整数在地址空间存储方式变为高位字节存放在内存的低地址处 serverAddr.sin_port = htons(port); // 监听本机的所有IP地址,INADDR_ANY=0x0 // 将主机数转换成无符号长整型的网络字节顺序 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务端绑定端口 retval = bind(sockfd, (struct sockaddr *)& serverAddr, sizeof(serverAddr)); if (retval < 0) printf("bind failed, %ld!rn", retval); CloseTcpSocket(sockfd); return; printf("bind to port %d success!rn", port); // 开始监听,backlog指Pending连接队列增长到的最大长度。队列满了,再有新连接请求到达,则客户端ECONNREFUSED错误。如果支持重传,则请求忽略。 int backlog = 1; retval = listen(sockfd, backlog); if (retval < 0) printf("listen failed!rn"); CloseTcpSocket(sockfd); return; printf("listen with %d backlog success!rn", backlog); int outerFlag = 1; while (outerFlag) // 接受客户端连接,成功会返回一个表示连接的 socket。clientAddr参数将会携带客户端主机和端口信息;失败返回 -1 // 从Pending连接队列中获取第一个连接,根据sockfd的socket协议、地址族等内容创建一个新的socket文件描述,并返回。 // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接, // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接 // 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型liteos-m内核之上,可以使用“每个连接一个线程”的并发模型 connfd = accept(sockfd, (struct sockaddr *)& clientAddr, & clientAddrLen); if (connfd < 0) printf("accept failed, %d, %drn", connfd, errno); CloseTcpSocket(sockfd); //outerFlag = 0; printf("accept success, connfd = %d !rn", connfd); // inet_ntoa:网络地址转换成“.”点隔的字符串格式。ntohs:16位数由网络字节顺序转换为主机字节顺序。 printf("client addr info: host = %s, port = %drn", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port)); int innerFlag = 1; // 接收消息,然后发送回去 while (innerFlag) // 后续 收、发 都在 表示连接的 socket 上进行; // 在新的Socket文件描述上接收信息. retval = recv(connfd, request, sizeof(request), 0); if (retval < 0) printf("recv request failed, %ld!rn", retval); innerFlag = 0; else if (retval == 0) // 对方主动断开连接 printf("client disconnected!rn"); innerFlag = 0; else //printf("recv request%s from client done!rn", request); // 发送数据 printf("cc = %d %d %d \\r\\n",request[0],request[1],request[2]); if (retval < = 0) printf("send response failed, %ld!rn", retval); innerFlag = 0; if(retval == 3 & & request[0] == -86)if(request[1] = 0x00) retval = send(connfd, "aaok", strlen("aaok"), 0); if(request[1] = 0x01)switch (request[2])case 1: car_forward(); break; case 2: car_right(); break; case 3: car_backward(); break; case 4: car_left(); break; case 0: car_stop(); break; //printf("send response%s to client done!rn", request); // 清空缓冲区 memset(& request, 0, sizeof(request)); if(innerFlag == 0)DisconnectTcpSocket(connfd); //outerFlag = 0; CloseTcpSocket(sockfd); void *TcpServerTask(void *arg) (void)arg; // 先定义两个Wifi监听器,一个连接改变、一个状态改变 WifiEvent eventListener = .OnWifiConnectionChanged = OnWifiConnectionChanged, .OnWifiScanStateChanged = OnWifiScanStateChanged ; // 等待10个系统Ticks。每个ticks多少个us,计算方式= 1000 * 1000 / osKernelGetTickFreq() osDelay(10); // 注册监听器 WifiErrorCode errCode = RegisterWifiEvent(& eventListener); printf("RegisterWifiEvent: %drn", errCode); // 设置Wifi热点信息 WifiDeviceConfig apConfig = ; strcpy(apConfig.ssid, "PDCN"); strcpy(apConfig.preSharedKey, "1234567888"); apConfig.securityType = WIFI_SEC_TYPE_PSK; int netId = -1; // 启用Wifi errCode = EnableWifi(); printf("EnableWifi: %drn", errCode); osDelay(10); // 设置Wifi热点配置信息,返回生成的网络Id-netId。 errCode = AddDeviceConfig(& apConfig, & netId); printf("AddDeviceConfig: %drn", errCode); // 根据网络Id连接到Wifi热点 g_connected = 0; errCode = ConnectTo(netId); printf("ConnectTo(%d): %drn", netId, errCode); // 未连接完成,则一直等待。g_connected状态会在事件中设置。 while (!g_connected) osDelay(10); printf("g_connected: %drn", g_connected); osDelay(50); // 联网业务开始,找到netifname=wlan0的netif。 struct netif* iface = netifapi_netif_find("wlan0"); if (iface) // 启动DHCP客户端,获取IP地址 err_t ret = netifapi_dhcp_start(iface); printf("netifapi_dhcp_start: %drn", ret); // 等待DHCP服务器反馈给予地址 osDelay(300); // 执行线程安全的网络方法,第二个参数是voidFunc,第三个参数是errFunc。如果没有errFunc,那么就执行voidFunc。 // netifapi_dhcp_start/netifapi_dhcp_stop等都是调用的netifapi_netif_common方法。 // dhcp_clients_info_show显示信息 /* server : server_id : 192.168.0.1 mask : 255.255.255.0, 1 gw : 192.168.0.1 T0 : 3600 T1 : 1800 T2 : 3150 clients < 1> : mac_idx macaddrstateleasetriesrto 0b4c9b9af69f8192.168.0.1010012 */ ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL); printf("netifapi_netif_common: %drn", ret); TcpServerHandler(); // 联网业务结束,断开DHCP err_t ret = netifapi_dhcp_stop(iface); printf("netifapi_dhcp_stop: %drn", ret); // 断开Wifi热点连接 Disconnect(); // 移除Wifi热点的配置 RemoveDevice(netId); // 关闭Wifi errCode = DisableWifi(); printf("DisableWifi: %drn", errCode); osDelay(200); void WifiSockets(void)osThreadAttr_t wifisocket; wifisocket.name = "TcpServerTask"; wifisocket.attr_bits = 0U; wifisocket.cb_mem = NULL; wifisocket.cb_size = 0U; wifisocket.stack_mem = NULL; wifisocket.stack_size = 10240; wifisocket.priority = 25; if (osThreadNew(TcpServerTask, NULL, & wifisocket) == NULL) printf("[Ssd1306TestDemo] Falied to create TcpServerTask!\\n"); APP_FEATURE_INIT(WifiSockets);

⑥.编写主控制代码
路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\robot_control.c

代码:
static char data[128] = ""; extern int connfd; void *RobotCarTestTask(void* param)(void)param; float cmm = 0.0; printf("switch\\r\\n"); int i= 0; int flag = 0; while (1) custom((i%11)*100 + 1000); GetDistance(& cmm); sprintf(data,"\\"angle\\": %d,\\"cm\\":%f",i,cmm); send(connfd, data, strlen(data), 0); //发送距离到APP //printf("\\r\\n cos = %dcm =%f\\r\\n",i,cmm); if(flag == 0)i++; if(i%10 == 0)flag = 1; else i--; if(i%11 == 0)flag = 0; osDelay(25); //延时 250msvoid RobotCarDemo(void)osThreadAttr_t attr; attr.name = "RobotCarTestTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 10240; attr.priority = 25; if (osThreadNew(RobotCarTestTask, NULL, & attr) == NULL) printf("[Ssd1306TestDemo] Falied to create RobotCarTestTask!\\n"); APP_FEATURE_INIT(RobotCarDemo);

⑦.编写编译描述文件路径:openharmony\\applications\\sample\\wifi-iot\\app\\wificar\\BUILD.gn
代码:
static_library("car_wifi") sources = [ "robot_l9110s.c", "robot_sg90.c", "robot_control.c", "robot_hcsr04.c", "wifi_sockets.c", ] deps =[ ] include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/kal/cmsis", "//base/iot_hardware/peripheral/interfaces/kits", "//device/hisilicon/hispark_pegasus/hi3861_adapter/hals/communication/wifi_lite/wifiservice", "//device/hisilicon/hispark_pegasus/hi3861_adapter/kal", "//device/hisilicon/hispark_pegasus/sdk_liteos/third_party/lwip_sack/include", "//foundation/communication/wifi_lite/interfaces/wifiservice" ]

⑧.加入编译路径:openharmony\\applications\\sample\\wifi-iot\\app\\BUILD.gn
代码:
import("//build/lite/config/component/lite_component.gni")lite_component("app") features = [ "wificar:car_wifi" ]

⑨.编译 1).设置编译路径
hb set .(英文字符)

2).选择wifiiot_hispark_pegasus 3).执行编译
hb build -f

4).输出路径
openharmony\\out\\hispark_pegasus\\wifiiot_hispark_pegasus

⑩.烧录
参考烧录:https://ost.51cto.com/posts/11118
4.HarmonyOS 端开发
①.新建项目 打开 DevEco Studio 3.0.0.800 选择File -> New -> New Project 选择
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

选择
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

点击Finish ②.应用签名 1).复制bundleName
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

2).打开链接https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/myProject
3).点击添加项目
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

4).输入项目名
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

5).点击添加应用
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

6).如图设置
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

7).点击
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

8).登录
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

9).获取签名(未连接手机)
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

9).获取签名(连接手机),点击Try Again,获取成功
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

③.导入gson包
implementation com.google.code.gson:gson:2.8.9

开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

④.打开网络权限
"reqPermissions": [ "name":"ohos.permission.GET_NETWORK_INFO", "name":"ohos.permission.SET_NETWORK_INFO", "name":"ohos.permission.INTERNET" ],

开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

⑤.UI设置这里对UI就不展开讲了
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

⑥.编写代码
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

编写文件:Elements.java代码:
package com.example.wificardemo.slice; public class Elements int angle = 0; float cm = 0;

编写文件:MainAbilitySlice.java代码:
package com.example.wificardemo.slice; import com.example.wificardemo.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.Button; import ohos.agp.components.Component; import ohos.agp.components.ProgressBar; import ohos.agp.components.TextField; import ohos.global.resource.Resource; import ohos.hiviewdfx.HiLog; import ohos.hiviewdfx.HiLogLabel; import java.util.List; public class MainAbilitySlice extends AbilitySlice private static final HiLogLabel hilog = new HiLogLabel(HiLog.DEBUG ,0x0000, "test0002"); SocketTest ST = null; ProgressBar[] PB = new ProgressBar[11]; @Override public void onStart(Intent intent) int pbs[] = ResourceTable.Id_progressbar,ResourceTable.Id_progressbar1,ResourceTable.Id_progressbar2,ResourceTable.Id_progressbar3,ResourceTable.Id_progressbar4,ResourceTable.Id_progressbar5,ResourceTable.Id_progressbar6,ResourceTable.Id_progressbar7,ResourceTable.Id_progressbar8,ResourceTable.Id_progressbar9,ResourceTable.Id_progressbar10; super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); Button connects = findComponentById(ResourceTable.Id_connect_car); Button bt1 = findComponentById(ResourceTable.Id_button1); Button bt2 = findComponentById(ResourceTable.Id_button2); Button bt3 = findComponentById(ResourceTable.Id_button3); Button bt4 = findComponentById(ResourceTable.Id_button4); Button bt5 = findComponentById(ResourceTable.Id_button5); TextField text_field = findComponentById(ResourceTable.Id_text_field); for(int i = 0; i< 11; i++)PB[i] = (ProgressBar)findComponentById(pbs[i]); bt1.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) ST.sockerSend(1,1); ); bt2.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) ST.sockerSend(1,4); ); bt3.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) ST.sockerSend(1,0); ); bt4.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) ST.sockerSend(1,2); ); bt5.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) ST.sockerSend(1,3); ); connects.setClickedListener(new Component.ClickedListener() @Override public void onClick(Component component) if(ST !=null)ST = null; //释放try ST = new SocketTest(MainAbilitySlice.this,text_field.getText().toString(),20222); ST.start(); Thread.sleep(200); //ST.sockerSend(5,0,0); catch (Exception e) e.printStackTrace(); ); //Socker 接收回调函数 public void socketCallback(Elements con) getUITaskDispatcher().asyncDispatch(new Runnable() @Override public void run() PB[con.angle].setProgressValue(con.cm> 100 ? 100:(int)con.cm); ); @Override public void onActive() super.onActive(); @Override public void onForeground(Intent intent) super.onForeground(intent);

编写文件:SocketTest.java代码:
package com.example.wificardemo.slice; import com.google.gson.Gson; import ohos.hiviewdfx.HiLog; import ohos.hiviewdfx.HiLogLabel; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class SocketTest extends Thread private static final HiLogLabel hilog = new HiLogLabel(HiLog.DEBUG ,0x0000, "test0002"); Socket socket = null; String host =""; int port = 0; InputStream inputStream = null; OutputStream outputStream=null; public boolean flag; MainAbilitySlice mains = null; public SocketTest(MainAbilitySlice mains,String host,int port) this.mains = mains; this.host = host; this.port = port; public void sockerSend(int a,int b) if(socket != null & & outputStream != null)new Thread(new Runnable() @Override public void run() try byte[] data =https://www.songbingjia.com/android/new byte[3]; data[0] = (byte) 0xaa; data[1] = (byte) a; data[2] = (byte) b; //data[3] = (byte) c; outputStream.write(data); outputStream.flush(); catch (IOException e) e.printStackTrace(); ).start(); else@Override public void run() try flag = true; while (flag)socket = new Socket(host, port); outputStream = socket.getOutputStream(); inputStream =socket.getInputStream(); init1(); socket.close(); catch (IOException e) System.out.println("net erorr!"+e); public void init1() try byte[] b = new byte[1024]; while (flag)int n = inputStream.read(b); if(n !=-1)byte[] data = https://www.songbingjia.com/android/new byte[n]; for (int i=0; i< n; i++)data[i] = b[i]; String str = new String(data); Gson gson = new Gson(); HiLog.debug(hilog,"net !"+str,""); if(n > 10) mains.socketCallback(gson.fromJson(str, Elements.class)); else break; catch (Exception e) HiLog.debug(hilog,"net erorr!"+e,"");

⑦.点击RUN 安装到手机 5.测试
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

【开发板漂流计划 HarmonyOSAPP控制超声波小车】
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

视频链接:https://www.bilibili.com/video/BV1pS4y1Y72j/
代码开源地址:https://gitee.com/yukoyu/harmony-wifi-car
测试成功!附件链接:https://ost.51cto.com/resource/1864
想了解更多关于鸿蒙的内容,请访问:
51CTO OpenHarmony技术社区
https://ost.51cto.com/#bkwz
::: hljs-center
开发板漂流计划 HarmonyOSAPP控制超声波小车

文章图片

:::

    推荐阅读