#打卡不停更#【FFH】OpenHarmony设备开发(八)- 遥控小车 原创 精华
X丶昕雪
发布于 2022-10-22 15:13
浏览
4收藏
前言
智能小车设备可以接收手机发送的操控指令,得以完成手机操控小车。智能小车还实现无感连接,无论哪一个智能小车设备,手机只需要对着智能小车上的标签碰一碰,即可连接到该小车并自动打开相对应的操作软件,对该小车进行控制,操作简单易懂,易于上手。
实现方式
- 3861遥控小车控制两个电机,并打开热点以供手机连接
- NFC标签写入遥控小车的SSID,PSK,IP地址
- 手机碰一碰小车上的NFC标签,即可一键连接小车建立TCP连接,与此同时拉起小车控制软件,最终完成对小车的控制。
工程版本
- 系统版本/API版本:OpenHarmony 3.1 release
- IDE版本:DevEco Device Tool Release v3.1.200
源代码
头文件
对于下面要用到的API接口,我们要引用的头文件有以下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
//os
#include "cmsis_os2.h"
#include "ohos_init.h"
//wifi and tcp
#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "wifi_error_code.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
// io
#include "iot_gpio.h"
#include <hi_gpio.h>
#include <hi_io.h>
控制
小车轮子控制:
GPIO0和GPIO1控制左轮,GPIO9和GPIO10控制右轮
GPIO0和GPIO9使能是正方向,GPIO1和GPIO10使能是反方向,同时使能便是停止
#define GPIO0 0
#define GPIO1 1
#define GPIO9 9
#define GPIO10 10
void my_car_init(void)
{
//初始化
IoTGpioInit(GPIO0);
IoTGpioInit(GPIO1);
IoTGpioInit(GPIO10);
IoTGpioInit(GPIO9);
//IO模式
hi_io_set_func(GPIO0, 0);
hi_io_set_func(GPIO1, 0);
hi_io_set_func(GPIO10, 0);
hi_io_set_func(GPIO9, 0);
//输出模式
IoTGpioSetDir(GPIO0, 1);
IoTGpioSetDir(GPIO1, 1);
IoTGpioSetDir(GPIO10, 1);
IoTGpioSetDir(GPIO9, 1);
car_stop();
}
void car_backward(void)
{
IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE0); //左
IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE1);
IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE0); //右轮
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);
}
void car_stop(void)
{
IoTGpioSetOutputVal(GPIO0, IOT_GPIO_VALUE1);
IoTGpioSetOutputVal(GPIO1, IOT_GPIO_VALUE1);
IoTGpioSetOutputVal(GPIO9, IOT_GPIO_VALUE1);
IoTGpioSetOutputVal(GPIO10, IOT_GPIO_VALUE1);
}
通信
WIFI
- 回调函数配置
- WIFI_AP配置
- 注册netif结构体
- 配置netif(配置DHCP)
- 关闭再打开DHCP(必须先关闭再重新打开)
#define AP_SSID "FSR"
#define AP_PSK "12345678"
#define _PROT_ 8888
#define TCP_BACKLOG 10
static struct netif *g_lwip_netif = NULL;
static int g_apEnableSuccess = 0;
WifiEvent g_wifiEventHandler = {0};
WifiErrorCode error;
//注册wifi事件的回调函数
g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
//指定WiFi回调函数
error = RegisterWifiEvent(&g_wifiEventHandler);
//设置指定的热点配置
HotspotConfig config = {0};
//初始化热点相关配置
strcpy(config.ssid, AP_SSID);
strcpy(config.preSharedKey, AP_PSK);
config.securityType = WIFI_SEC_TYPE_PSK;
config.band = HOTSPOT_BAND_TYPE_2G; // 2.4GHz
config.channelNum = 7;
//配置wifi热点
error = SetHotspotConfig(&config);
error = EnableHotspot();
//启动dhcp
g_lwip_netif = netifapi_netif_find("ap0");
if (g_lwip_netif)
{
ip4_addr_t bp_gw;
ip4_addr_t bp_ipaddr;
ip4_addr_t bp_netmask;
IP4_ADDR(&bp_gw, 192, 168, 1, 1); /* input your gateway for example: 192.168.1.1 */
IP4_ADDR(&bp_ipaddr, 192, 168, 1, 1); /* input your IP for example: 192.168.1.1 */
IP4_ADDR(&bp_netmask, 255, 255, 255, 0); /* input your netmask for example: 255.255.255.0 */
netifapi_netif_set_addr(g_lwip_netif, &bp_ipaddr, &bp_netmask, &bp_gw);
//关闭
netifapi_dhcps_stop(g_lwip_netif);
netifapi_dhcps_start(g_lwip_netif, 0, 0);
}
TCP
//在sock_fd 进行监听,在 new_fd 接收新的链接
int sock_fd, new_fd;
char recvbuf[10];
/****************以下为TCP服务器代码***************/
struct sockaddr_in server_sock;
//客户端地址信息
struct sockaddr_in client_sock;
int sin_size;
struct sockaddr_in *cli_addr;
//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket is error\r\n");
exit(1);
}
bzero(&server_sock, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
server_sock.sin_port = htons(_PROT_);
//调用bind函数绑定socket和地址
if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
{
perror("bind is error\r\n");
exit(1);
}
//调用listen函数监听(指定port监听)
if (listen(sock_fd, TCP_BACKLOG) == -1)
{
perror("listen is error\r\n");
exit(1);
}
printf("start accept\n");
//调用accept函数从队列中
while (1)
{
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
{
perror("accept");
continue;
}
cli_addr = malloc(sizeof(struct sockaddr));
printf("accept addr\r\n");
if (cli_addr != NULL)
{
memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
}
//处理目标
ssize_t ret;
while (1)
{
//连接成功,接收客户端发送来的数据
//清理接收缓存
(void)memset_s(recvbuf, sizeof(recvbuf), 0, sizeof(recvbuf));
//接收
if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
{
printf("recv error \r\n");
}
else
{
printf("server:%d!\n", recvbuf[0]);
}
if (recvbuf[0] == '1')
{
car_forward();
printf("car_forward!\n");
}
else if (recvbuf[0] == '2')
{
car_backward();
printf("car back!");
}
else if (recvbuf[0] == '3')
{
car_left();
}
else if (recvbuf[0] == '4')
{
car_right();
}
else if (recvbuf[0] == '0')
{
car_stop();
}
}
close(new_fd);
}
/*********************END********************/
线程创建以及WiFi回调函数
/ WIFI连入的线程
static void HotspotStaJoinTask(void)
{
static char macAddress[32] = {0};
StationInfo stainfo[WIFI_MAX_STA_NUM] = {0};
StationInfo *sta_list_node = NULL;
unsigned int size = WIFI_MAX_STA_NUM;
//获取当前接入到该AP的所有STA站点信息
error = GetStationList(stainfo, &size);
if (error != WIFI_SUCCESS)
{
printf("HotspotStaJoin:get list fail, error is %d.\r\n", error);
return;
}
sta_list_node = stainfo;
//打印出每个STA站点的MAC地址
for (uint32_t i = 0; i < size; i++, sta_list_node++)
{
unsigned char *mac = sta_list_node->macAddress;
snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("HotspotSta[%d]: macAddress=%s.\r\n", i, macAddress);
}
g_apEnableSuccess++;
}
//绑定STA站点加入回调函数
static void OnHotspotStaJoinHandler(StationInfo *info)
{
if (info == NULL)
{
printf("HotspotStaJoin:info is null.\r\n");
}
else
{
//创建连接线程
printf("New Sta Join\n");
osThreadAttr_t attr;
attr.name = "HotspotStaJoinTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 2048;
attr.priority = 24;
if (osThreadNew((osThreadFunc_t)HotspotStaJoinTask, NULL, &attr) == NULL)
{
printf("HotspotStaJoin:create task fail!\r\n");
}
}
return;
}
// STA退出回调函数
static void OnHotspotStaLeaveHandler(StationInfo *info)
{
if (info == NULL)
{
printf("HotspotStaLeave:info is null.\r\n");
}
else
{
static char macAddress[32] = {0};
unsigned char *mac = info->macAddress;
snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("HotspotStaLeave: macAddress=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
g_apEnableSuccess--;
}
return;
}
//状态改变回调函数
static void OnHotspotStateChangedHandler(int state)
{
printf("HotspotStateChanged:state is %d.\r\n", state);
if (state == WIFI_HOTSPOT_ACTIVE) // state=1表示已启用WIFI AP模式
{
printf("wifi hotspot active.\r\n");
}
else // state=0表示WIFI AP模式已禁用
{
printf("wifi hotspot noactive.\r\n");
}
}
static void Wifi_AP_Demo(void)
{
osThreadAttr_t attr;
attr.name = "WifiAPTask";
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((osThreadFunc_t)WifiAPTask, NULL, &attr) == NULL)
{
printf("Falied to create WifiAPTask!\r\n");
}
}
SYS_RUN(Wifi_AP_Demo);
效果
因API8暂未开放NFC读取,因此NFC模块部分尚未编写,当前只在软件内固定连接WiFi以及ip,打开软件即可控制小车.
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-11-1 09:44:16修改
赞
4
收藏 4
回复
相关推荐
期待NFC模块完成后的效果
不错不错,很详细