基于RK3399&ESP8285自动售货柜项目—②MP08开发板端代码详解

本系列文章将详细讲解该基于RK3399及ESP8285自动售货柜的完整实现方法,从硬件连接到网络通信再到软件实现,本产品所用开发板为RK3399以及MP08_2019/11/03 , 如有疑问与见解,可随时留言或评论

本系列以往文章列表:

①基于RK3399&ESP8285自动售货柜项目—ESP8266(8285)程序编写与烧录 (zsxq.com)

文章目录

  • 基于RK3399&ESP8285自动售货柜项目—②MP08开发板端代码详解
  • 一、ESP开发代码结构
  • 二、本项目MP09开发板端代码实现
    • 2.1MP08开发板原理图
    • 2.274HC595D驱动方式
    • 2.3MP08—TCP_Client代码实现
    • 2.4MP08完整代码
    • 2.5编译烧录及运行结果

上一篇我们讲解了如何搭建AiThinkIDE开发环境以及编写和烧录程序,那么这一篇我们来详细讲解本项目在MP08开发板上的代码实现原理,如果你手上也有这块板子,可以完全按照本系列文章来进行项目的实现

一、ESP开发代码结构

由于本项目不用过多深入学习ESP_SDK,故只用知道如何利用结构框架去编写想要的功能即可

我们先来看看官方例程代码:

/*跟其他C代码一样,这里放头文件,注意:AiThinkIDE没有标准C库函数,故没有如stdio.h 或者 string。h等,不要包含他们*/
#include "driver/uart.h"  //串口0需要的头文件
#include "osapi.h"  //串口1需要的头文件
#include "user_interface.h" //WIFI连接需要的头文件
#include "gpio.h"  //端口控制需要的头文件
#include "user_config.h"/*这一长段条件编译不用管他是干嘛的,写程序放进来就行*/
#if ((SPI_FLASH_SIZE_MAP == 0) || (SPI_FLASH_SIZE_MAP == 1))
#error "The flash map is not supported"
#elif (SPI_FLASH_SIZE_MAP == 2)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0xfb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0xfc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0xfd000
#elif (SPI_FLASH_SIZE_MAP == 3)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x1fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x1fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x1fd000
#elif (SPI_FLASH_SIZE_MAP == 4)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x3fd000
#elif (SPI_FLASH_SIZE_MAP == 5)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x1fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x1fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x1fd000
#elif (SPI_FLASH_SIZE_MAP == 6)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x3fd000
#else
#error "The flash map is not supported"
#endifvoid ICACHE_FLASH_ATTR user_init(void)
{//相当于main函数,一般放各类软硬件的初始化代码,为程序入口
}//这个结构体定义也必须要,不用管他是干嘛的,SDK3.0规定必须要这一段
static const partition_item_t at_partition_table[] = {{ SYSTEM_PARTITION_BOOTLOADER,                       0x0,                                                0x1000},{ SYSTEM_PARTITION_OTA_1,                           0x1000,                                             SYSTEM_PARTITION_OTA_SIZE},{ SYSTEM_PARTITION_OTA_2,                        SYSTEM_PARTITION_OTA_2_ADDR,                        SYSTEM_PARTITION_OTA_SIZE},{ SYSTEM_PARTITION_RF_CAL,                       SYSTEM_PARTITION_RF_CAL_ADDR,                       0x1000},{ SYSTEM_PARTITION_PHY_DATA,                        SYSTEM_PARTITION_PHY_DATA_ADDR,                     0x1000},{ SYSTEM_PARTITION_SYSTEM_PARAMETER,                SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR,             0x3000},
};//这一个函数也要放进来,直接复制就行
void ICACHE_FLASH_ATTR user_pre_init(void)
{if(!system_partition_table_regist(at_partition_table, sizeof(at_partition_table)/sizeof(at_partition_table[0]),SPI_FLASH_SIZE_MAP)) {os_printf("system_partition_table_regist fail\r\n");while(1);}
}

可以看到,整个代码结构就由这几部分构成,我们主要编写user_init函数里的内容,并且也可以自己定义想要的函数,函数名前的ICACHE_FLASH_ATTR表示的是函数地址存储位置在flash里,最好都加上

编写代码我们还需要去下载几个官方文档,里面有各种API函数用法介绍,本质跟STM32库函数差不多

ESP8266文档中心 | 安信可科技 (ai-thinker.com)

二、本项目MP09开发板端代码实现

2.1MP08开发板原理图

该原理图为我用万用表徒手测并绘制,仅供引脚走线参考使用,电阻电容等均未调整数值

通过原理图我们可以看到

  • 每个减速电机得三个引脚分别接在了L、C、H线上
  • 其中L引脚由原理图中间的74HC595D控制器的Q0-Q7控制
  • C引脚由ESP_IO12控制
  • H引脚由ESP_IO2控制

知道了电机由哪几个引脚控制,我们就可以往上进行推理,可知要想选择开启哪个电机就得控制74HC595D的Q0-Q7哪个引脚,所以我们需要找到74HC595D芯片手册来查看如何控制

2.274HC595D驱动方式

74HC595D数据手册

通过数据手册,我们可以知道,要想给Q0-Q7输出想要的信号值,就得在SER串行数据输入端输入相应的值并锁存到锁存寄存器里

所以,驱动方式总结如下:

  1. 设置SER串行数据输入引脚电平
  2. 拉高SCK,使SER数据被移位进入八位移位寄存器
  3. 重复以上两个步骤共8次,发送8位数据(1Byte)
  4. 拉高RCK,使得八位移位寄存器中的数据被送到八位锁存器里
  5. 锁存器里的数据将会自动发送到Q0-Q7各个引脚

提示:当我们想驱动Q3和Q5引脚输出高电平,我们的8位数据就应该为00101000,也就是0x28

根据以上信息,我们可以写出以下代码:

在看代码前,我们需要了解几个官方API函数:

  • os_printf:跟标准C库函数printf一样,但这里必须用os_printf
  • os_delay_us:官方给的专用微秒延时API
  • system_soft_wdt_feed:看门狗喂狗函数,不喂好像也没事,最好加上,安信可官方说默认开启了看门狗
  • GPIO_OUTPUT_SET(GPIO_ID_PIN(x),1):GPIO口输出电平控制宏,x为引脚编号,后面的1为高电平,0则为低电平
  • PIN_FUNC_SELECT:引脚功能选择宏函数
  • API函数及其具体用法可参照ESP8266_SDK_API参考指南
void delay_ms(uint32_t ms)
{while(ms--){os_delay_us(1000);//os_delay_us为官方APIsystem_soft_wdt_feed();//喂狗}
}//发送数据函数
void hc595d_send_byte(uint8_t data)
{uint8_t i;for(i = 0;i < 8;i++){if(data & (0x80>>i)){GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1);//IO4高电平}else{GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0);//IO4低电平}GPIO_OUTPUT_SET(GPIO_ID_PIN(13),0);//先拉低os_delay_us(5);//适当延时GPIO_OUTPUT_SET(GPIO_ID_PIN(13),1);//上升沿将一位数据移入移位寄存器os_delay_us(5);//适当延时}
}
//锁存函数
void hc595d_latch_data(void)
{GPIO_OUTPUT_SET(GPIO_ID_PIN(15),0);//先拉低os_delay_us(5);//适当延时GPIO_OUTPUT_SET(GPIO_ID_PIN(15),1);//上升沿将数据送入锁存寄存器os_delay_us(5);//适当延时
}void driver_motor(uint8_t j)
{/** HC595D ESP_IO12    ESP_IO2* MOTOR_L    MOTOR_C     MOTOR_H     转向* 1       1           0           逆时针* 1      0           0           x* 1        0           1           x* 1        1           1           逆时针* */hc595d_send_byte(j);//发送1byte数据hc595d_latch_data();//锁存GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);GPIO_OUTPUT_SET(GPIO_ID_PIN(2),0);GPIO_OUTPUT_SET(GPIO_ID_PIN(5),j%2);//led监视os_printf("j:%2d on\r\n",j);//售货机转1秒就停止delay_ms(1000);GPIO_OUTPUT_SET(GPIO_ID_PIN(12),0);
}void user_init(void)
{system_soft_wdt_feed();//喂狗PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);//IO4-SERPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U,FUNC_GPIO15);//IO15-RCKPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U,FUNC_GPIO13);//IO13-SCKPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12);//IO12-MOTOR_CPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);//IO2-MOTOR_HPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);//IO5-LED
}

以上就是如何去驱动74HC595D来控制MP08开发板上8个电机的方法

现在,我们来考虑售货机通信方面的问题,从这里开始呢,就可以根据不同的方式来去控制MP08售货机板子

  • 第一种方法:利用RK3399和MP08进行TCP连接,这样我们可以在RK3399板子上对MP08进行可视化操作

  • 第二种方法:无需其他外设,只需一部手机,我们可以在手机端连接MP08上的ESP8285,进行操控

  • 第三种方法:MP08上的ESP8285连接WiFi,然后连接上云服务器,手机端通过云服务器来进行远程发送数据去控制MP08

……方法非常多,远不止这几种,我们这里采用第一种方法

2.3MP08—TCP_Client代码实现

这里我们将MP08上的ESP8285作为TCP客户端连接RK3399的TCP服务端、

tcp_client.c

#include "user_config.h"
#include "driver/uart.h"  //串口0需要的头文件
#include "osapi.h"  //串口1需要的头文件
#include "user_interface.h" //WIFI连接需要的头文件
#include "espconn.h"//TCP连接需要的头文件
#include "mem.h" //系统操作需要的头文件
#include "gpio.h"os_timer_t checkTimer_wifistate;
struct espconn user_tcp_conn;uint8_t my_atoi(char *pdata,unsigned short len)
{uint8_t ret = 0;os_printf("len = %d\r\n",len);while(len--){ret *= 10;ret += *pdata++ - '0';}os_printf("ret = %d\r\n",ret);return ret;
}//将输入的点击编号转化为二进制
//如驱动1号电机Q0,则为00000001->0x01
//如驱动8号电机Q7,则为10000000->0x80
uint8_t to_binaray(uint8_t num)
{uint8_t ret = 0;switch(num){case 1:ret = 1;break;case 2:ret = 2;break;case 3:ret = 4;break;case 4:ret = 8;break;case 5:ret = 16;break;case 6:ret = 32;break;case 7:ret = 64;break;case 8:ret = 128;break;default:break;}return ret;
}//tcp发送数据回调函数
void ICACHE_FLASH_ATTR user_tcp_sent_cb(void *arg)  //发送
{os_printf("发送数据成功!");
}
//tcp断开后的回调函数
void ICACHE_FLASH_ATTR user_tcp_discon_cb(void *arg)  //断开
{os_printf("断开连接成功!");
}
//tcp收到数据后的回调函数
void ICACHE_FLASH_ATTR user_tcp_recv_cb(void *arg,  //接收char *pdata, unsigned short len) {os_printf("收到数据:%s\r\n", pdata);driver_motor(to_binaray(my_atoi(pdata,len)));//电机驱动espconn_sent((struct espconn *) arg, "0", strlen("0"));
}
//注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连
void ICACHE_FLASH_ATTR user_tcp_recon_cb(void *arg, sint8 err)
{os_printf("连接错误,错误代码为%d\r\n", err);espconn_connect((struct espconn *) arg);
}
//注册 TCP 连接成功建立后的回调函数
void ICACHE_FLASH_ATTR user_tcp_connect_cb(void *arg)
{struct espconn *pespconn = arg;espconn_regist_recvcb(pespconn, user_tcp_recv_cb);  //接收espconn_regist_sentcb(pespconn, user_tcp_sent_cb);  //发送espconn_regist_disconcb(pespconn, user_tcp_discon_cb);  //断开espconn_sent(pespconn, "8226", strlen("8226"));os_printf("连接服务器成功!\r\n");
}void ICACHE_FLASH_ATTR my_station_init(struct ip_addr *remote_ip,struct ip_addr *local_ip, int remote_port) {user_tcp_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));  //分配空间user_tcp_conn.type = ESPCONN_TCP;  //设置类型为TCP协议os_memcpy(user_tcp_conn.proto.tcp->local_ip, local_ip, 4);os_memcpy(user_tcp_conn.proto.tcp->remote_ip, remote_ip, 4);user_tcp_conn.proto.tcp->local_port = espconn_port();  //本地端口user_tcp_conn.proto.tcp->remote_port = remote_port;  //目标端口//注册连接成功回调函数和重新连接回调函数espconn_regist_connectcb(&user_tcp_conn, user_tcp_connect_cb);//注册 TCP 连接成功建立后的回调函数espconn_regist_reconcb(&user_tcp_conn, user_tcp_recon_cb);//注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连//启用连接espconn_connect(&user_tcp_conn);
}//连接局域网wifi,连接tcp服务器
void Check_WifiState(void) {uint8 getState;getState = wifi_station_get_connect_status();//查询 ESP8266 WiFi station 接口连接 AP 的状态if (getState == STATION_GOT_IP) {os_printf("WIFI连接成功!\r\n");os_timer_disarm(&checkTimer_wifistate);struct ip_info info;const char remote_ip[4] = { 192, 168, 31, 116 };//目标IP地址wifi_get_ip_info(STATION_IF, &info);   //查询 WiFi模块的 IP 地址my_station_init((struct ip_addr *) remote_ip, &info.ip, 6000);//连接到目标服务器的6000端口}
}void tcp_client_init() //初始化
{wifi_set_opmode(0x01); //设置为STATION模式struct station_config stationConf;os_strcpy(stationConf.ssid, "Xiaomi_9908");     //改成你自己的   路由器的用户名 os_strcpy(stationConf.password, "20010624w"); //改成你自己的   路由器的密码wifi_station_set_config(&stationConf);    //设置WiFi station接口配置,并保存到 flashwifi_station_connect();   //连接路由器os_timer_disarm(&checkTimer_wifistate);  //取消定时器定时os_timer_setfn(&checkTimer_wifistate, (os_timer_func_t *) Check_WifiState,NULL);   //设置定时器回调函数os_timer_arm(&checkTimer_wifistate, 500, 1); //启动定时器,单位:毫秒
}

在此代码中,如有不了解的API函数,可随时查阅ESP8266_SDK_API参考指南,里面对每个API都有用法讲解,但不够清晰,可参照该代码进行理解

注意:

  • WiFi名和密码需要更改成和RK3399同局域网的WiFi
  • 目标IP地址需要更改为RK3399的ip地址,可输入ipconfig查询

2.4MP08完整代码

将以下代码替换到上一篇文章所创建工程的user_main.c

#include "driver/uart.h"  //串口0需要的头文件
#include "osapi.h"  //串口1需要的头文件
#include "user_interface.h" //WIFI连接需要的头文件
#include "gpio.h"  //端口控制需要的头文件
#include "user_config.h"#if ((SPI_FLASH_SIZE_MAP == 0) || (SPI_FLASH_SIZE_MAP == 1))
#error "The flash map is not supported"
#elif (SPI_FLASH_SIZE_MAP == 2)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0xfb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0xfc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0xfd000
#elif (SPI_FLASH_SIZE_MAP == 3)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x1fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x1fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x1fd000
#elif (SPI_FLASH_SIZE_MAP == 4)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x3fd000
#elif (SPI_FLASH_SIZE_MAP == 5)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x1fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x1fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x1fd000
#elif (SPI_FLASH_SIZE_MAP == 6)
#define SYSTEM_PARTITION_OTA_SIZE                           0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                         0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                      0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR              0x3fd000
#else
#error "The flash map is not supported"
#endifvoid delay_ms(uint32_t ms)
{while(ms--){os_delay_us(1000);system_soft_wdt_feed();//喂狗}
}//发送数据函数
void hc595d_send_byte(uint8_t data)
{uint8_t i;for(i = 0;i < 8;i++){if(data & (0x80>>i)){GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1);//IO4高电平}else{GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0);//IO4低电平}GPIO_OUTPUT_SET(GPIO_ID_PIN(13),0);//先拉低os_delay_us(5);//适当延时GPIO_OUTPUT_SET(GPIO_ID_PIN(13),1);//上升沿将一位数据移入移位寄存器os_delay_us(5);//适当延时}
}
//锁存函数
void hc595d_latch_data(void)
{GPIO_OUTPUT_SET(GPIO_ID_PIN(15),0);//先拉低os_delay_us(5);//适当延时GPIO_OUTPUT_SET(GPIO_ID_PIN(15),1);//上升沿将数据送入锁存寄存器os_delay_us(5);//适当延时
}void driver_motor(uint8_t j)
{/** 译码器    ESP_IO12    ESP_IO2* MOTOR_L    MOTOR_C     MOTOR_H     转向* 1       1           0           逆时针* 1      0           0           x* 1        0           1           x* 1        1           1           逆时针* */hc595d_send_byte(j);//发送1byte数据hc595d_latch_data();//锁存GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);GPIO_OUTPUT_SET(GPIO_ID_PIN(2),0);GPIO_OUTPUT_SET(GPIO_ID_PIN(5),j%2);//led监视os_printf("j:%2d on\r\n",j);delay_ms(1000);GPIO_OUTPUT_SET(GPIO_ID_PIN(12),0);
}void user_init(void)
{system_soft_wdt_feed();//喂狗PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);//IO4-SERPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U,FUNC_GPIO15);//IO15-RCKPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U,FUNC_GPIO13);//IO13-SCKPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12);//IO12-MOTOR_CPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);//IO2-MOTOR_HPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);//IO5-LED//8266作为TCP客户端,目标端口为6000,IP地址见串口打印,此要先获取Tcp服务端的ip地址tcp_client_init();
}static const partition_item_t at_partition_table[] = {{ SYSTEM_PARTITION_BOOTLOADER,                      0x0,                                                0x1000},{ SYSTEM_PARTITION_OTA_1,                           0x1000,                                             SYSTEM_PARTITION_OTA_SIZE},{ SYSTEM_PARTITION_OTA_2,                        SYSTEM_PARTITION_OTA_2_ADDR,                        SYSTEM_PARTITION_OTA_SIZE},{ SYSTEM_PARTITION_RF_CAL,                       SYSTEM_PARTITION_RF_CAL_ADDR,                       0x1000},{ SYSTEM_PARTITION_PHY_DATA,                        SYSTEM_PARTITION_PHY_DATA_ADDR,                     0x1000},{ SYSTEM_PARTITION_SYSTEM_PARAMETER,                SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR,             0x3000},
};void ICACHE_FLASH_ATTR user_pre_init(void)
{if(!system_partition_table_regist(at_partition_table, sizeof(at_partition_table)/sizeof(at_partition_table[0]),SPI_FLASH_SIZE_MAP)) {os_printf("system_partition_table_regist fail\r\n");while(1);}
}

将以下代码加入到smart_config->user中

更改头文件user_config.h

#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__void delay_ms(unsigned int ms);
void hc595d_send_byte(unsigned char data);
void hc595d_latch_data(void);
void driver_motor(unsigned char j);void tcp_client_init();#endif

2.5编译烧录及运行结果

编译方法:保存(一定要先保存)-> Clean -> Build

编译结果

烧录方式见上一篇文章讲解基于RK3399&ESP8285自动售货柜项目—ESP8266(8285)程序编写与烧录 (zsxq.com)

运行结果

开启RK3399-TCP服务器后

参照本篇只需实现能够连接上WiFi即可,如要连接TCP服务器,下篇将会详细讲解RK3399服务器端代码,以及交互界面的制作,最终将完整实现本产品的制作

基于RK3399ESP8285自动售货柜项目—MP08开发板端代码详解相关推荐

  1. 基于RK3399ESP8285自动售货柜项目—ESP8266(8285)程序编写与烧录

    基于RK3399&ESP8285自动售货柜项目-ESP8266(8285)程序编写与烧录 本系列文章讲详细讲解该基于RK3399及ESP8285自动售货柜的完整实现方法,从硬件连接到网络通信再 ...

  2. linux内核移植与开发板,Linux 2.6.36内核移植飞凌OK6410开发板完整步骤详解

    Linux 2.6.36内核移植飞凌OK6410开发板完整步骤详解 [复制链接] 今天终于让Linux内核在飞凌的板子上跑起来了,想来也是艰辛,为了移植成功,断断续续做了将近两个月的努力,期间郁闷不可 ...

  3. 基于Tomcat5.0和Axis2开发Web Service代码详解

    本文将详细介绍HelloWorld中使用的server和client端代码.阅读之前,你应该首先了解SOAP1.1协议.<?xml:namespace prefix = o ns = " ...

  4. 黑金AX301开发板SPI通信详解

    前言: 对黑金的AX301开发板的SPI工程进行了波形仿真,写一下自己的理解. 背景: 项目地址: https://download.csdn.net/download/a792544191/1287 ...

  5. 基于 xilinx vivado 的PCIE ip核设置与例程代码详解

    1.概述 本文是用于总结PCIE ip例程的学习成果.主要是从ip的设置,ip核的例程代码构成及其来源两方面介绍pcie的使用情况. 2.参考文档 <pg054-7series-pcie> ...

  6. 基于Wi-Fi指纹和深度神经网络的室内定位系统设计代码详解(一)

    本文讲解的代码可在GitHub上获取 https://github.com/kyeongsoo/can405_indoor_localization 首先我们需要知道为什么要通过WIFI指纹实现室内定 ...

  7. 自动售货机方案/设计/开发/项目

    随着物联网和大数据时代的到来,人工智能的兴起,智能设备已环绕在人们衣食住行的各个方面.自助售货机解决方案是解决线上消费和线下体验的核心枢纽,加上定制化的运营模式和大数据的收集分析,让传统细分行业零售厂 ...

  8. 在基于乐鑫芯片的用户定制开发板上开发 UI

    在上一篇文章中,我们介绍了 SquareLine Studio 可视化 UI 开发工具,以及如何使用它来开发 UI.目前,它只适用于乐鑫官方推出自研的开发板.如果您想使用 SquareLine Stu ...

  9. FPGA项目开发:204B实战应用-LMK04821代码详解(二)

    大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分.大侠可以关注FPGA技术江湖,在"闯荡江湖"."行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢. ...

最新文章

  1. go语言中没有隐藏的this指针
  2. AC日记——任务查询系统 洛谷 P3168
  3. Codeforces 757C - Felicity is Coming!
  4. 【PAT乙级】1060 爱丁顿数 (25 分)
  5. boost::python模块包装几个 C++ 函数 将二维数组操作为采用 NumPy 数组的 Python 函数作为参数
  6. (翻译).NET应用架构
  7. mysql 系统月份_MySQL里求给定的时间是所在月份的第几个星期
  8. boost安装_Boost编译与使用
  9. Redis复制与可扩展集群搭建
  10. Jmeter 安装各个历史版本
  11. Linux系统下下载Tomcat详细步骤。
  12. MBI5020 16位恒流驱动芯片
  13. android 木马行为监控,基于行为分析的Android手机木马检测技术研究
  14. 数模论文写作方法2|摘要的技巧
  15. 车联网智能终端GB/T 32960国标协议规范 、国标新能源车联网终端GB/T32960标准T-BOX应用
  16. 目前股指期货保证金(目前股指期货保证金是多少)
  17. 一文速学-玩转MySQL中INTERVAL关键字和INTERVAL()函数用法讲解
  18. 荣耀4a鸿蒙,华为荣耀4A上手评测:599元也可以很拉轰
  19. 微信竟可以查出行轨迹了,预计又一波情侣要分手?
  20. JS 转换数字/日期大全

热门文章

  1. Ubuntu服务器上安装Anaconda环境以及Vim的简单使用
  2. 物业管理系统源码(含access数据库)
  3. STM32单片机入门例程(1.GPIO端口硬件结构)
  4. php crypt mysql password_php crypt函数加密和解密的实例分享
  5. php的crypt,php中crypt()函数的定义和用法汇总
  6. 开学必备清单好物大合集!超适合学生党开学的实用好物大全
  7. AE插件怎么安装?ae插件.jsx安装后找不到怎么办?ae插件安装教程
  8. 走廊上的相机安装及调试方法
  9. Keras学习之tensor张量
  10. 计算机组成原理8路复用器,计算机多路复用器