精华内容
下载资源
问答
  • ServiceNow 基础手册

    2018-11-21 15:17:01
    ServiceNow 平台基础说明和使用指南,希望对大家有所帮助
  • 利用ESP8266+ESPNOW实现多点无线通信

    千次阅读 2021-01-21 13:56:07
    #ifndef __ESPNOW_H__ #define __ESPNOW_H__ #ifdef __cplusplus extern "C" { #endif enum esp_now_role { ESP_NOW_ROLE_IDLE = 0,//未设置角色,不允许发送数据 ESP_NOW_ROLE_CONTROLLER,//控制方 ESP_NOW_...

    一.ESP8266简介

    ESP8266是乐鑫(Espressif)制作的WiFi芯片,可以将其理解为一块带有WiFi功能的MCU,就像是stm32一样,它也有GPIO、UART、SPI、I2C、I2S等硬件资源,它也可以跑RTOS等操作系统。

    基于乐鑫提供的ESP8266芯片,许多厂商设计了自己的WiFi模组,比较有名的是安信可(Ai-Thinker)的ESP系列模组,正点原子也制作了它自己的模组:ATK-ESP8266,除此之外还有非常非常多种类的WiFi模组,他们很多都是基于ESP8266芯片开发的。

    很多WiFi模组外都自带一个屏蔽罩,用来减少外界的电磁干扰,ATK-ESP8266使用的是板载PCB天线,除此之外还有陶瓷天线和IPEX天线等。

    我们可以把WiFi模组理解成MCU的最小系统板,可以直接用串口为它烧录程序(和51单片机比较相似)。一般WiFi模块出厂都自带了固件,它其实就是出厂时厂家给模块烧录的程序,我们可以在这个基础上用AT指令实现一些简单的功能,但是更复杂的功能就需要自己编程实现了。

    二.ESP8266开发

    开发ESP8266有很多种方式,可以使用乐鑫官方提供的ESP-IDF开发环境,基于官方SDK开发,也可以使用LUA语言开发,也可以使用Arduino方式开发,我使用的是Arduino方式开发。

    使用Arduino开发ESP8266的环境配置,网上有非常多的教程,我随便找了一个:【ESP8266之Arduino开发】一、环境配置

    在使用NodeMcu(可以理解为开发板)时,因为其自带了自动下载电路(见下图),所以直接插上USB就可以用Arduino IDE为其烧录程序,并且会自动运行烧录进去的程序。
    在这里插入图片描述
    要注意的是使用正点原子ATK-ESP8266模块时,IO_0引脚拉低才能进入烧录模式,IO_0拉高是运行模式(悬空应该也是运行模式),在改变IO_0的电平之后,一定要给模块复位,才能成功切换模式。

    三.ESP-NOW协议

    ESP-NOW 是由乐鑫开发的另一款协议,可以使多个设备在没有或不使用 Wi-Fi 的情况下进行通信。这种协议类似常见于无线鼠标中的低功耗 2.4GHz 无线连接——设备在进行通信之前要进行配对。配对之后,设备之间的连接是持续的、点对点的,并且不需要握手协议。

    有关ESP-NOW更详细的介绍可以查看官方的手册:ESP-NOW 用户指南,也可以看乐鑫在其SDK中的介绍:ESP-IDF编程指南,这应该是有关ESP-NOW所有的官方资料了。除此之外,该网站上有关使用Arduino开发ESP8266的教程也非常棒。

    利用ESP-NOW协议我们可以实现多设备点对点的双向通信。
    在这里插入图片描述
    ESP-NOW同样有Arduino的库文件espnow.h,我利用这个库文件编写了多节点相互通信的程序。

    四.实现多点通信

    1.获取WiFi模块的MAC地址

    首先我们需要将print_mac_address.ino文件烧录进WiFi模块,获取其MAC地址,其源代码如下。

    #include <ESP8266WiFi.h>
     
    void setup()
    {
      Serial.begin(115200);//设置串口波特率为115200
      WiFi.mode(WIFI_STA);//设置WiFi模式为STA,这里要与之后使用的模式相对应
    }
     
    void loop()
    {
      //每隔一秒钟打印一次MAC地址
      Serial.println(WiFi.macAddress());
      delay(1000);
    }
    

    打开串口调试助手,WiFi模块每秒钟会打印一次自己的MAC地址,将其记录下来。

    2.烧录通信程序

    我使用三个WiFi模块进行通讯,每个模块都会发送数据到另两个模块,这里就分析模块1的程序,另两个模块的程序非常相似,稍作更改即可。

    #include <ESP8266WiFi.h>
    #include <espnow.h>
    
    uint8_t esp_1_address[] = {0x80, 0x7D, 0x3A, 0x42, 0xD3, 0xEB};//模块1的mac地址
    uint8_t esp_2_address[] = {0x8C, 0xAA, 0xB5, 0x0D, 0x97, 0x2C};//模块2的mac地址
    uint8_t esp_3_address[] = {0x8C, 0xAA, 0xB5, 0x0D, 0x80, 0x7C};//模块3的mac地址
    
    //Callback when data is sent
    //发送信息时的回调函数,每次发送信息会自动调用该函数
    void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) 
    {
      //Serial.print("Last Packet Send Status: ");
      if (sendStatus == 0)//信息发送成功时
      {
        //打印接收方的mac地址
        Serial.print("deliver data to:  ");
        for(int i = 0; i < 5; ++i)
        {
          Serial.printf("%x:", *(mac_addr + i));
        }
        Serial.printf("%x", *(mac_addr + 5));
        Serial.println(" ");
        //Serial.println("Delivery success");
      }
      else{
        Serial.println("Delivery fail");
      }
    }
    
    // Callback when data is received
    //接收信息时的回调函数,每次接收信息会自动调用该函数
    void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) 
    {
      //在此处先通过mac地址判断是哪一个设备发送的数据,再进行数据解析(在主控中写代码时)
      //或者只是使用memcpy函数存储数据,在主函数中处理(类似于DMA的形式)
      //打印发送方的mac地址
      Serial.print("receive data from:  ");
      for(int i = 0; i < 5; ++i)
      {
        Serial.printf("%x:", *(mac + i));
      }
      Serial.printf("%x", *(mac + 5));
      Serial.println(" ");
      /*
      Serial.print("Bytes received: ");
      Serial.println(len);
      */
      //打印接收到的数据
      for(int i = 0; i < len; ++i)
      {
        Serial.printf("%c", *(incomingData + i));  
      }
      Serial.println(" ");
    }
    
    void setup() {
    
      Serial.begin(115200);//初始化串口,设置其波特率为115200
      
      WiFi.mode(WIFI_STA);//设置WIFI模式为STA
      WiFi.disconnect();//断开WIFI连接
      
      // Init ESP-NOW
      if (esp_now_init() != 0)//初始化espnow
      {
        Serial.println("Error initializing ESP-NOW");
        return;
      }
      else
      {
        Serial.println("esp_now init success");
      }
    
      // Set ESP-NOW Role
      //双向通信时需要设定角色为 ESP_NOW_ROLE_COMBO
      esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
    
      // Once ESPNow is successfully Init, we will register for Send CB to
      // get the status of Trasnmitted packet
      //执行完这个函数,每次发送数据就会自动调用回调函数了
      esp_now_register_send_cb(OnDataSent);
      
      // Register peer
      //与模块2和3配对
      esp_now_add_peer(esp_2_address, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
      esp_now_add_peer(esp_3_address, ESP_NOW_ROLE_COMBO, 2, NULL, 0);
      
      // Register for a callback function that will be called when data is received
      //执行完这个函数,每次接收数据就会自动调用回调函数了
      esp_now_register_recv_cb(OnDataRecv);
    }
    
    uint8_t data_to_send[] = {"test from esp8266_1"};//要发送的数据
    
    void loop() 
    {
        // Send message via ESP-NOW
        //向模块2和3发送数据
        esp_now_send(esp_2_address, data_to_send, sizeof(data_to_send));
        esp_now_send(esp_3_address, data_to_send, sizeof(data_to_send));
        delay(500);
    }
    

    分别将esp8266_1.inoesp8266_2.inoesp8266_3.ino烧录进模块1、2、3即可。

    效果如下图所示:
    在这里插入图片描述

    五.espnow库函数注释

    Arduino的espnow.h似乎没有官方文档,我把我研究的一小部分内容写成注释加进去,不保证完全正确,还是得以手册为准。

    #ifndef __ESPNOW_H__
    #define __ESPNOW_H__
    
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    enum esp_now_role {
    	ESP_NOW_ROLE_IDLE = 0,//未设置角色,不允许发送数据
    	ESP_NOW_ROLE_CONTROLLER,//控制方
    	ESP_NOW_ROLE_SLAVE,//被控制方
    	ESP_NOW_ROLE_COMBO,//控制方&被控制方双角色,双向通信时就用它
    	ESP_NOW_ROLE_MAX,//不懂
    };
    
    //回调函数
    typedef void (*esp_now_recv_cb_t)(u8 *mac_addr, u8 *data, u8 len);
    typedef void (*esp_now_send_cb_t)(u8 *mac_addr, u8 status);
    
    int esp_now_init(void);//初始化esp_now
    int esp_now_deinit(void);//取消esp_now的初始化
    
    int esp_now_register_send_cb(esp_now_send_cb_t cb);//使用该函数之后,接收到数据会自动调用接收回调函数,回调函数的写法可以参考我上面的代码
    int esp_now_unregister_send_cb(void);//与上面的函数作用相反
    
    int esp_now_register_recv_cb(esp_now_recv_cb_t cb);//使用该函数之后,发送数据后会自动调用发送回调函数,回调函数的写法可以参考我上面的代码
    int esp_now_unregister_recv_cb(void);//与上面的函数作用相反
    
    int esp_now_send(u8 *da, u8 *data, int len);//发送数据,MAC地址中传入NULL会广播
    
    int esp_now_add_peer(u8 *mac_addr, u8 role, u8 channel, u8 *key, u8 key_len);//与新设备配对
    int esp_now_del_peer(u8 *mac_addr);//将已配对的设备删除
    
    int esp_now_set_self_role(u8 role);//设定设备自己的角色
    int esp_now_get_self_role(void);//获取设备自己的角色
    
    int esp_now_set_peer_role(u8 *mac_addr, u8 role);//设定某个已配对设备的角色
    int esp_now_get_peer_role(u8 *mac_addr);//获取某个已配对设备的角色
    
    int esp_now_set_peer_channel(u8 *mac_addr, u8 channel);//设定某个已配对设备的WiFi通道
    int esp_now_get_peer_channel(u8 *mac_addr);//获取某个已配对设备的WiFi通道
    
    int esp_now_set_peer_key(u8 *mac_addr, u8 *key, u8 key_len);//设定某个已配对设备的密钥
    int esp_now_get_peer_key(u8 *mac_addr, u8 *key, u8 *key_len);//获取某个已配对设备的密钥
    
    u8 *esp_now_fetch_peer(bool restart);//不懂
    
    int esp_now_is_peer_exist(u8 *mac_addr);//检查已经配对的设备是否在线
    
    int esp_now_get_cnt_info(u8 *all_cnt, u8 *encrypt_cnt);//不懂
    
    int esp_now_set_kok(u8 *key, u8 len);//对通信的key进行加密,不设置时使用默认的PMK
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    
    展开全文
  • 日历laydate 终结版(增加laydate.now的使用)
  • espnow 例程解析

    千次阅读 2018-03-09 10:20:15
    1、什么是espnow 短数据传输、无连接的快速通讯技术2、应用范围智能照明控制(一)、 ESPNOW例程。下面的例程展示了怎样使用ESPNOW步骤:1、初始化wifiA、TCP/ip适配器初始化a、注册事件处理函数初始化。b、设置配置...

    1、什么是espnow

    短数据传输、无连接的快速通讯技术

    2、应用范围智能照明控制

    (一)、 ESPNOW例程。

    下面的例程展示了怎样使用ESPNOW

    步骤:

    1、初始化wifi

    A、TCP/ip适配器初始化

    a、注册事件处理函数初始化。

    b、设置配置信息

    c、选择存储类型

    d、选择wifi模式AP

    e、启动wifi

    f、启动wifi后设置通道,假如两个设备在同一个通道上就不需要设置

    2、初始化espnow

    a、创建个队列

    b、注册发送数据回调函数

    c、注册接受数据回调函数

    d、设置主秘钥

    e、添加广播点信息来点列表

    f、初始化发送参数

    g、创建espnow任务

    */

    #include <stdlib.h>

    #include <time.h>

    #include <string.h>

    #include <assert.h>

    #include "freertos/FreeRTOS.h"

    #include "freertos/semphr.h"

    #include "freertos/timers.h"

    #include "nvs_flash.h"

    #include "esp_event_loop.h"

    #include "tcpip_adapter.h"

    #include "esp_wifi.h"

    #include "esp_log.h"

    #include "esp_system.h"

    #include "esp_now.h"

    #include "rom/ets_sys.h"

    #include "rom/crc.h"

    #include "espnow_example.h"


    static const char *TAG = "espnow_example";


    static xQueueHandle example_espnow_queue;


    static uint8_t example_broadcast_mac[ESP_NOW_ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

    static uint16_t s_example_espnow_seq[EXAMPLE_ESPNOW_DATA_MAX] = { 0, 0 };


    static void example_espnow_deinit(example_espnow_send_param_t *send_param);

    1、事件处理函数

    static esp_err_t example_event_handler(void *ctx, system_event_t *event)

    {

      switch(event->event_id) {

      case SYSTEM_EVENT_STA_START:                    wifi启动完成

        ESP_LOGI(TAG, "WiFi started");

        break;

      default:

        break;

      }

      return ESP_OK;

    }


    2、wifi初始化

    static void example_wifi_init(void)

    {

      tcpip_adapter_init(); TCP/ip适配器初始化

      ESP_ERROR_CHECK( esp_event_loop_init(example_event_handler, NULL) ); 注册事件处理函数初始化。

      wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 获取wifi配置信息

      ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); 设置配置信息

      ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); 选择存储类型

      ESP_ERROR_CHECK( esp_wifi_set_mode(ESPNOW_WIFI_MODE) ); 选择wifi模式AP

      ESP_ERROR_CHECK( esp_wifi_start()); 启动wifi

      ESP_ERROR_CHECK( esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, 0) ); 启动wifi后设置通道,假如两个设备在同一个通道上就不需要设置

    }


    1、发送数据回调函数

    static void example_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status)

    {

      example_espnow_event_t evt;

      example_espnow_event_send_cb_t *send_cb = &evt.info.send_cb;


      if (mac_addr == NULL) {

        ESP_LOGE(TAG, "Send cb arg error");

        return;

      }

    设置发送事件,并添加到队列中去

      evt.id = EXAMPLE_ESPNOW_SEND_CB;

      memcpy(send_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);

      send_cb->status = status;

      if (xQueueSend(example_espnow_queue, &evt, portMAX_DELAY) != pdTRUE) {

        ESP_LOGW(TAG, "Send send queue fail");

      }

    }

    2、接受回调函数

    static void example_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len)

    {

      example_espnow_event_t evt;

      example_espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;


      if (mac_addr == NULL || data == NULL || len <= 0) {

        ESP_LOGE(TAG, "Receive cb arg error");

        return;

      }

    设置接受事件,并添加到队列中

      evt.id = EXAMPLE_ESPNOW_RECV_CB;

      memcpy(recv_cb->mac_addr, mac_addr, ESP_NOW_ETH_ALEN);

      recv_cb->data = malloc(len);

      if (recv_cb->data == NULL) {

        ESP_LOGE(TAG, "Malloc receive data fail");

        return;

      }

      memcpy(recv_cb->data, data, len);

      recv_cb->data_len = len;

      if (xQueueSend(example_espnow_queue, &evt, portMAX_DELAY) != pdTRUE) {

        ESP_LOGW(TAG, "Send receive queue fail");

        free(recv_cb->data);

      }

    }


    3、解析接收到的 ESPNOW数据(验证crc校验)

    int example_espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state, uint16_t *seq, int *magic)

    {

      example_espnow_data_t *buf = (example_espnow_data_t *)data;

      uint16_t crc, crc_cal = 0;


      if (data_len < sizeof(example_espnow_data_t)) {

        ESP_LOGE(TAG, "Receive ESPNOW data too short, len:%d", data_len);

        return -1;

      }


      *state = buf->state;

      *seq = buf->seq_num;

      *magic = buf->magic;

      crc = buf->crc;

      buf->crc = 0;

      crc_cal = crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len);


      if (crc_cal == crc) {

        return buf->type;

      }


      return -1;

    }


    4、准备 ESPNOW 发送的数据

    void example_espnow_data_prepare(example_espnow_send_param_t *send_param)

    {

      example_espnow_data_t *buf = (example_espnow_data_t *)send_param->buffer;

      int i = 0;


      assert(send_param->len >= sizeof(example_espnow_data_t));


      buf->type = IS_BROADCAST_ADDR(send_param->dest_mac) ? EXAMPLE_ESPNOW_DATA_BROADCAST : EXAMPLE_ESPNOW_DATA_UNICAST;

      buf->state = send_param->state;

      buf->seq_num = s_example_espnow_seq[buf->type]++;

      buf->crc = 0;

      buf->magic = send_param->magic;

      for (i = 0; i < send_param->len - sizeof(example_espnow_data_t); i++) {

        buf->payload[i] = (uint8_t)esp_random();

      }

      buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len);

    }

    1、espnow任务处理函数

    static void example_espnow_task(void *pvParameter)

    {

      example_espnow_event_t evt;

      uint8_t recv_state = 0;

      uint16_t recv_seq = 0;

      int recv_magic = 0;

      bool is_broadcast = false;

      int ret;


      vTaskDelay(5000 / portTICK_RATE_MS);

      ESP_LOGI(TAG, "Start sending broadcast data");


      /* Start sending broadcast ESPNOW data. */

      example_espnow_send_param_t *send_param = (example_espnow_send_param_t *)pvParameter; 1、获取发送参数

      if (esp_now_send(send_param->dest_mac, send_param->buffer, send_param->len) != ESP_OK) {

        ESP_LOGE(TAG, "Send error");

        example_espnow_deinit(send_param);

        vTaskDelete(NULL);

      } 3、开始发送数据


      while (xQueueReceive(example_espnow_queue, &evt, portMAX_DELAY) == pdTRUE) {  4、判断是否有事件产生

        switch (evt.id) {

          case EXAMPLE_ESPNOW_SEND_CB:       5、发送事件处理函数

          {

            example_espnow_event_send_cb_t *send_cb = &evt.info.send_cb;

            is_broadcast = IS_BROADCAST_ADDR(send_cb->mac_addr);


            ESP_LOGD(TAG, "Send data to "MACSTR", status1: %d", MAC2STR(send_cb->mac_addr), send_cb->status);


            if (is_broadcast && (send_param->broadcast == false)) {

              break;

            }


            if (!is_broadcast) {

              send_param->count--;

              if (send_param->count == 0) {

                ESP_LOGI(TAG, "Send done");

                example_espnow_deinit(send_param);

                vTaskDelete(NULL);

              }

            }


            /* Delay a while before sending the next data. */

            if (send_param->delay > 0) {

              vTaskDelay(send_param->delay/portTICK_RATE_MS);

            }


            ESP_LOGI(TAG, "send data to "MACSTR"", MAC2STR(send_cb->mac_addr));


            memcpy(send_param->dest_mac, send_cb->mac_addr, ESP_NOW_ETH_ALEN);

            example_espnow_data_prepare(send_param);


            /* Send the next data after the previous data is sent. */

            if (esp_now_send(send_param->dest_mac, send_param->buffer, send_param->len) != ESP_OK) {

              ESP_LOGE(TAG, "Send error");

              example_espnow_deinit(send_param);

              vTaskDelete(NULL);

            }

            break;

          }

          case EXAMPLE_ESPNOW_RECV_CB:    5、接受事件处理函数

          {

            example_espnow_event_recv_cb_t *recv_cb = &evt.info.recv_cb;


            ret = example_espnow_data_parse(recv_cb->data, recv_cb->data_len, &recv_state, &recv_seq, &recv_magic);

            free(recv_cb->data);

            if (ret == EXAMPLE_ESPNOW_DATA_BROADCAST) {

              ESP_LOGI(TAG, "Receive %dth broadcast data from: "MACSTR", len: %d", recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);


              /* If MAC address does not exist in peer list, add it to peer list. */

              if (esp_now_is_peer_exist(recv_cb->mac_addr) == false) {

                esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));

                if (peer == NULL) {

                  ESP_LOGE(TAG, "Malloc peer information fail");

                  example_espnow_deinit(send_param);

                  vTaskDelete(NULL);

                }

                memset(peer, 0, sizeof(esp_now_peer_info_t));

                peer->channel = CONFIG_ESPNOW_CHANNEL;

                peer->ifidx = ESPNOW_WIFI_IF;

                peer->encrypt = true;

                memcpy(peer->lmk, CONFIG_ESPNOW_LMK, ESP_NOW_KEY_LEN);

                memcpy(peer->peer_addr, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);

                ESP_ERROR_CHECK( esp_now_add_peer(peer) );

                free(peer);

              }


              /* Indicates that the device has received broadcast ESPNOW data. */

              if (send_param->state == 0) {

                send_param->state = 1;

              }


              /* If receive broadcast ESPNOW data which indicates that the other device has received

               * broadcast ESPNOW data and the local magic number is bigger than that in the received

               * broadcast ESPNOW data, stop sending broadcast ESPNOW data and start sending unicast

               * ESPNOW data.

               */

              if (recv_state == 1) {

                /* The device which has the bigger magic number sends ESPNOW data, the other one

                 * receives ESPNOW data.

                 */

                if (send_param->unicast == false && send_param->magic >= recv_magic) {

                 ESP_LOGI(TAG, "Start sending unicast data");

                 ESP_LOGI(TAG, "send data to "MACSTR"", MAC2STR(recv_cb->mac_addr));


                 /* Start sending unicast ESPNOW data. */

                  memcpy(send_param->dest_mac, recv_cb->mac_addr, ESP_NOW_ETH_ALEN);

                  example_espnow_data_prepare(send_param);

                  if (esp_now_send(send_param->dest_mac, send_param->buffer, send_param->len) != ESP_OK) {

                    ESP_LOGE(TAG, "Send error");

                    example_espnow_deinit(send_param);

                    vTaskDelete(NULL);

                  }

                  else {

                    send_param->broadcast = false;

                    send_param->unicast = true;

                  }

                }

              }

            }

            else if (ret == EXAMPLE_ESPNOW_DATA_UNICAST) {

              ESP_LOGI(TAG, "Receive %dth unicast data from: "MACSTR", len: %d", recv_seq, MAC2STR(recv_cb->mac_addr), recv_cb->data_len);


              /* If receive unicast ESPNOW data, also stop sending broadcast ESPNOW data. */

              send_param->broadcast = false;

            }

            else {

              ESP_LOGI(TAG, "Receive error data from: "MACSTR"", MAC2STR(recv_cb->mac_addr));

            }

            break;

          }

          default:

            ESP_LOGE(TAG, "Callback type error: %d", evt.id);

            break;

        }

      }

    }


    static esp_err_t example_espnow_init(void)

    {

      example_espnow_send_param_t *send_param;

      example_espnow_queue = xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(example_espnow_event_t)); 创建个队列

      if (example_espnow_queue == NULL) {

        ESP_LOGE(TAG, "Create mutex fail");

        return ESP_FAIL;

      }


      /* Initialize ESPNOW and register sending and receiving callback function. */

      ESP_ERROR_CHECK( esp_now_init() ); 初始哈espnow

      ESP_ERROR_CHECK( esp_now_register_send_cb(example_espnow_send_cb) ); 注册发送数据回调函数

      ESP_ERROR_CHECK( esp_now_register_recv_cb(example_espnow_recv_cb) );注册接受数据回调函数


      

      ESP_ERROR_CHECK( esp_now_set_pmk((uint8_t *)CONFIG_ESPNOW_PMK) );设置主秘钥


      /* Add broadcast peer information to peer list. */

      esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));

      if (peer == NULL) {

        ESP_LOGE(TAG, "Malloc peer information fail");

        vSemaphoreDelete(example_espnow_queue);

        esp_now_deinit();

        return ESP_FAIL;

      }

      memset(peer, 0, sizeof(esp_now_peer_info_t));

      peer->channel = CONFIG_ESPNOW_CHANNEL;

      peer->ifidx = ESPNOW_WIFI_IF;

      peer->encrypt = false;

      memcpy(peer->peer_addr, example_broadcast_mac, ESP_NOW_ETH_ALEN);

      ESP_ERROR_CHECK( esp_now_add_peer(peer) ); 添加广播点信息来点列表

      free(peer);


      /* Initialize sending parameters. */

      send_param = malloc(sizeof(example_espnow_send_param_t));

      memset(send_param, 0, sizeof(example_espnow_send_param_t));

      if (send_param == NULL) {

        ESP_LOGE(TAG, "Malloc send parameter fail");

        vSemaphoreDelete(example_espnow_queue);

        esp_now_deinit();

        return ESP_FAIL;

      }

      send_param->unicast = false;

      send_param->broadcast = true;

      send_param->state = 0;

      send_param->magic = esp_random();

      send_param->count = CONFIG_ESPNOW_SEND_COUNT;

      send_param->delay = CONFIG_ESPNOW_SEND_DELAY;

      send_param->len = CONFIG_ESPNOW_SEND_LEN;

      send_param->buffer = malloc(CONFIG_ESPNOW_SEND_LEN);

      if (send_param->buffer == NULL) {

        ESP_LOGE(TAG, "Malloc send buffer fail");

        free(send_param);

        vSemaphoreDelete(example_espnow_queue);

        esp_now_deinit();

        return ESP_FAIL;

      }

      memcpy(send_param->dest_mac, example_broadcast_mac, ESP_NOW_ETH_ALEN);

      example_espnow_data_prepare(send_param);初始化发送参数


      xTaskCreate(example_espnow_task, "example_espnow_task", 2048, send_param, 4, NULL);

    创建espnow任务

      return ESP_OK;

    }

    5、释放资源

    static void example_espnow_deinit(example_espnow_send_param_t *send_param)

    {

      free(send_param->buffer);

      free(send_param);

      vSemaphoreDelete(example_espnow_queue);

      esp_now_deinit();

    }


    void app_main()

    {

      // 1、nvs初始化

      esp_err_t ret = nvs_flash_init();

      if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {

        ESP_ERROR_CHECK( nvs_flash_erase() );

        ret = nvs_flash_init();

      }

      ESP_ERROR_CHECK( ret );

    // 2、wifi初始化

      example_wifi_init();

    // 3 espnow初始化

      example_espnow_init();

    }


    展开全文
  • DateTime.Now.ToString() 格式化大全

    千次阅读 2020-08-06 17:12:57
    System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString("d"); //2008年4月24日 16:30:15 System.DateTime.Now.ToString("F"); //2008年4月24日 16:30 System.DateTime.Now.ToString...
         //2008年4月24日
         System.DateTime.Now.ToString("D");
         //2008-4-24
         System.DateTime.Now.ToString("d");
         //2008年4月24日 16:30:15
         System.DateTime.Now.ToString("F");
         //2008年4月24日 16:30
         System.DateTime.Now.ToString("f");
         //2008-4-24 16:30:15
         System.DateTime.Now.ToString("G");
         //2008-4-24 16:30
         System.DateTime.Now.ToString("g");
         //16:30:15
         System.DateTime.Now.ToString("T");
         //16:30
         System.DateTime.Now.ToString("t");
         //2008年4月24日 8:30:15
         System.DateTime.Now.ToString("U");
         //2008-04-24 16:30:15Z
         System.DateTime.Now.ToString("u");
         //4月24日
         System.DateTime.Now.ToString("m");
         System.DateTime.Now.ToString("M");
         //Tue, 24 Apr 2008 16:30:15 GMT
         System.DateTime.Now.ToString("r");
         System.DateTime.Now.ToString("R");
         //2008年4月
         System.DateTime.Now.ToString("y");
         System.DateTime.Now.ToString("Y");
         //2008-04-24T15:52:19.1562500+08:00
         System.DateTime.Now.ToString("o");
         System.DateTime.Now.ToString("O");
         //2008-04-24T16:30:15
         System.DateTime.Now.ToString("s");
         //2008-04-24 15:52:19
         System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff");
         //2008年04月24 15时56分48秒
         System.DateTime.Now.ToString("yyyy年MM月dd HH时mm分ss秒");
         //星期二, 四月 24 2008
         System.DateTime.Now.ToString("dddd, MMMM dd yyyy");
         //二, 四月 24 ’08
         System.DateTime.Now.ToString("ddd, MMM d \"’\"yy");
         //星期二, 四月 24
         System.DateTime.Now.ToString("dddd, MMMM dd");
         //4-08
         System.DateTime.Now.ToString("M/yy");
         //24-04-08
         System.DateTime.Now.ToString("dd-MM-yy");
         //字符型转换转为字符串
         12345.ToString("n");  //生成 12,345.00
         12345.ToString("C"); //生成 ¥12,345.00
         12345.ToString("e"); //生成 1.234500e+004
         12345.ToString("f4"); //生成 12345.0000
         12345.ToString("x"); //生成 3039 (16进制)
         12345.ToString("p"); //生成 1,234,500
         //本年度销售额、本季度利润、本月新增客户 
        //今天
         DateTime.Now.Date.ToShortDateString();
         //昨天,就是今天的日期减一
         DateTime.Now.AddDays(-1).ToShortDateString();
         //明天,同理,加一
         DateTime.Now.AddDays(1).ToShortDateString();
         //本周(要知道本周的第一天就得先知道今天是星期几,从而得知本周的第一天就是几天前的那一天,要注意的是这里的每一周是从周日始至周六止
         DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
         DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
         //如果你还不明白,再看一下中文显示星期几的方法就应该懂了
         //由于DayOfWeek返回的是数字的星期几,我们要把它转换成汉字方便我们阅读,有些人可能会用switch来一个一个地对照,其实不用那么麻烦的             
         string[] Day = new string[]{ "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
         Day[Convert.ToInt16(DateTime.Now.DayOfWeek)];
         //上周,同理,一个周是7天,上周就是本周再减去7天,下周也是一样
         DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
         DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
         //下周
         DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
         DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
         //本月,很多人都会说本月的第一天嘛肯定是1号,最后一天就是下个月一号再减一天。当然这是对的
         //一般的写法
         DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + "1"; //第一天
         DateTime.Parse(DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + "1").AddMonths(1).AddDays(-1).ToShortDateString();//最后一天
         //巧用C#里ToString的字符格式化更简便
         DateTime.Now.ToString("yyyy-MM-01");
         DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(1).AddDays(-1).ToShortDateString();
         //上个月,减去一个月份
         DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(-1).ToShortDateString();
         DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
         //下个月,加去一个月份
         DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(1).ToShortDateString();
         DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(2).AddDays(-1).ToShortDateString();
         //7天后
         DateTime.Now.Date.ToShortDateString();
         DateTime.Now.AddDays(7).ToShortDateString();
         //7天前
         DateTime.Now.AddDays(-7).ToShortDateString();
         DateTime.Now.Date.ToShortDateString();
         //本年度,用ToString的字符格式化我们也很容易地算出本年度的第一天和最后一天
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).ToShortDateString();
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(1).AddDays(-1).ToShortDateString();
         //上年度,不用再解释了吧
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(-1).ToShortDateString();
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddDays(-1).ToShortDateString();
         //下年度
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(1).ToShortDateString();
         DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(2).AddDays(-1).ToShortDateString();
         //本季度,很多人都会觉得这里难点,需要写个长长的过程来判断。其实不用的,我们都知道一年四个季度,一个季度三个月
         //首先我们先把日期推到本季度第一个月,然后这个月的第一天就是本季度的第一天了
         DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
         //同理,本季度的最后一天就是下季度的第一天减一
         DateTime.Parse(DateTime.Now.AddMonths(22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
         //下季度,相信你们都知道了。。。。收工
         DateTime.Now.AddMonths(22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
         DateTime.Parse(DateTime.Now.AddMonths(6 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
         //上季度
         DateTime.Now.AddMonths(-22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
         DateTime.Parse(DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();

     

    展开全文
  • 常见的无线通讯方式有蓝牙、WiFi、LoRa、NB-IoT 等,本教程将重点介绍乐鑫科技开发的另一种无线通讯协议:ESP-NOW,通过本教程的学习,你将了解到如何将 ESP-NOW 技术应用到我们的 DIY 项目中。 硬件准备 任意 ESP...

    用 Arduino 玩转 ESP32 系列历史文章目录:

    封面图片

    在学习 Arduino 开发的过程中,无线通讯是我们学习道路上一道必过的坎,无线通讯摆脱了线材的束缚,使用更加灵活且通讯距离根据不同无线模块可达几十米甚至是数公里。常见的无线通讯方式有蓝牙、WiFi、LoRa、NB-IoT 等,本教程将重点介绍乐鑫科技开发的另一种无线通讯协议:ESP-NOW,通过本教程的学习,你将了解到如何将 ESP-NOW 技术应用到我们的 DIY 项目中。

    硬件准备

    • 任意 ESP32 开发板;

    开发环境

    我们使用 Arduino 软件来编写本项目的程序。至于如何在 Arduino 中配置 ESP32 的开发环境,不在本文的介绍范围,请自行查阅相关资料。

    什么是 ESP-NOW?

    ESP-NOW 是由乐鑫开发的另一款无线通信协议,可以使多个设备在没有或不使用 Wi-Fi 的情况下进行通信。这种协议类似常见于无线鼠标中的低功耗 2.4GHz 无线连接——设备在进行通信之前要进行配对。配对之后,设备之间的连接是持续的、点对点的,并且不需要握手协议。它是一种短数据传输、无连接的快速通信技术,可以让低功耗控制器直接控制所有智能设备而无需连接路由器,适用于智能灯、遥控控制、传感器数据回传等场景。

    使用了 ESP-NOW 通信之后,如果某一个设备突然断电之后,只要它一旦重启,就是自动连接到对应的节点中重新进行通信。

    ESP-NOW 支持如下特性:

    • 单播包加密或单播包不加密通信;
    • 加密配对设备和非加密配对设备混合使用;
    • 可携带最长为 250 字节的有效 payload 数据;
    • 支持设置发送回调函数以通知应用层帧发送失败或成功。

    同样,ESP-NOW 也存在一些限制:

    • 暂时不支持广播包;
    • 加密配对设备有限制,Station 模式下最多支持10 个加密配对设备;SoftAP 或 SoftAP + Station 混合模式下最多支持 6 个加密配对设备。非加密配对设备支持若干,与加密设备总数和不超过 20 个;
    • 有效 payload 限制为 250 字节。

    ESP-NOW 通信方式

    ESP-NOW 支持多种通信方式:

    一对一单向通信

    一对一单向通信是最简单的通信方式,也就是一个设备负责发送数据,另一个设备负责接收数据,如下图所示:

    ESP_NOW_one_way_communication_two_boards

    一对多单向通信

    一对多单向通信是指一个设备负责发送数据,多个设备负责接收数据。其中数据发送端就类似与遥控器,数据接收端可以负责分别控制不同的设备,如下图所示:

    ESP_NOW_one_master_multiple_slaves

    多对一单向通信

    多对一单向通信是指一个设备专门负责接收数据,其余设备则向它发送数据。这种场景主要应用于多个设备采集不同的传感器数据,然后向中心或者总控制器汇总数据,如下图所示:

    ESP_NOW_one_slave_multiple_masters

    双向通信

    相对于单向通信,双向通信是指通信的双方既可以发送数据、又可以接收数据。一对一双向通信如下图所示:

    ESP_NOW_two_way_communication_two_boards

    在双向通信中,也可以加入更多的设备,进行两两之间的数据交互,如下图所示:

    ESP_NOW_multiple_boards_two_way_communication

    当然以上的这些通信,不仅仅限于 ESP32 开发板之间的通信,所有支持 ESP-NOW 的设备之间都可以进行通信,比如 ESP32 与 ESP32 之间、ESP8266 与 ESP8266 之间、甚至 ESP32 与 ESP8266 之间,都可以进行 ESP-NOW 无线通信。

    下面我们将通过实际程序来介绍如何使用 ESP-NOW 进行通信,此处以 ESP32 为例,其他开发板方法类似。

    获取设备 MAC 地址

    ESP-NOW 是点对点的通讯方式,在发送数据时需要指定接收设备,这好比你给对方发送 QQ 消息必须知道对方的 QQ 号一样。在这里我们一般通过设备的 MAC 地址作为区分不同接收设备的凭证。那什么是 MAC 地址呢?MAC 地址也叫物理地址、硬件地址,每个设备的 MAC 地址在出厂时都是不同的。

    下面我们通过 Arduino 代码来获取 ESP32 开发板的 MAC 地址:

    #include <WiFi.h>
    
    void setup() {
      Serial.begin(9600);
      Serial.println();
    #ifdef ESP8266
      Serial.print("ESP8266 Board MAC Address:  ");
      Serial.println(WiFi.macAddress());
    #elif defined ESP32
      WiFi.mode(WIFI_MODE_STA);
      Serial.print("ESP32 Board MAC Address:  ");
      Serial.println(WiFi.macAddress());
    #endif
    }
    
    void loop() {
    
    }
    

    上传程序,打开串口监视器,就可获得不同开发板的 MAC 地址:

    获取ESP32的MAC地址

    其中 24:6F:28:88:62:80 就是该 ESP32 开发板的 MAC 地址,该地址由 6 位 16 进制数构成,每一块开发板都有对应独一无二的 MAC 地址。我们记录下这个 MAC 地址,后面会用到。

    当然在 ESP-NOW 通信中,不止一块开发板,我们用同样的方式,记录下其他开发板的 MAC 地址。

    ESP-NOW 数据发送

    获取到 MAC 地址后,我们先来看看如何编写发送数据的程序。

    这里以掌控板为例,分别将掌控板上的光线传感器和声音传感器数据发送到另一块掌控板上。先来看一下完整的程序再进行讲解:

    #include <WiFi.h>
    #include <esp_now.h>
    
    // 设置掌控板声音传感器与光线传感器引脚编号
    const int soundPin = 36;
    const int lightPin = 39;
    
    // 设置数据结构体
    typedef struct struct_message {
      String board_name;
      double light;
      double sound;
    } struct_message;
    
    struct_message myData;
    
    // 接收设备的 MAC 地址
    uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x88, 0x62, 0x80};
    
    // 数据发送回调函数
    void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
      char macStr[18];
      Serial.print("Packet to: ");
      snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
               mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
      Serial.println(macStr);
      Serial.print("Send status: ");
      Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
      Serial.println();
    }
    
    void setup() {
      Serial.begin(9600);
    
      // 初始化 ESP-NOW
      WiFi.mode(WIFI_STA);
      if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
      }
    
      // 设置发送数据回调函数
      esp_now_register_send_cb(OnDataSent);
    
      // 绑定数据接收端
      esp_now_peer_info_t peerInfo;
      memcpy(peerInfo.peer_addr, broadcastAddress, 6);
      peerInfo.channel = 0;
      peerInfo.encrypt = false;
    
      // 检查设备是否配对成功
      if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
      }
    }
    
    void loop() {
      // 设置要发送的数据
      myData.board_name = "mPython_#1";
      myData.light = analogRead(lightPin);
      myData.sound = analogRead(soundPin);
    
      // 发送数据
      esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
      
      // 检查数据是否发送成功
      if (result == ESP_OK) {
        Serial.println("Sent with success");
      }
      else {
        Serial.println("Error sending the data");
      }
      delay(1000);
    }
    

    该例子演示的是将其中一块 ESP32 开发板(此处以掌控板为例)检测到的数据发送给另一块 ESP32 开发板。

    首先在开头引入了 ESP-NOW 相关的头文件:WiFi.hesp_now.h。然后定义了传感器的引脚和一个名为 myData 的结构体,该结构体由 3 个不同数据组成,分别是开发板名称(board_name),光线值(light)与声音值(sound),其中开发板名称为字符串类型,光线值与声音值为浮点型数据。若我们同时有多个传感器数据检测端,可以通开发板名称来区分来自设备的数据。

    接着用uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x88, 0x62, 0x80} 定义了接收设备的 MAC 地址。

    除此之外,我们注册了一个 OnDataSent() 的数据发送回调函数,该函数反馈了 ESP-NOW 数据的发送状态,该例子每隔一秒将光线值和声音值发送到指定 MAC 地址的开发板。

    setup() 中,我们先是初始化了 ESP-NOW 相关的功能,然后设置了发送数据的回调函数、以及绑定了数据接收端的 MAC 地址。

    loop() 中,我们不断读取光线值和声音值,并将他们赋值给 myData 结构体,然后将它们发送到接收端,并且去判断数据是否发送成功。

    ESP-NOW 数据接收

    接下来我们看看接收端的程序如何编写。

    编写如下程序,上传到另一块掌控板(前面打印过 MAC 地址的那块掌控板)中。

    #include <WiFi.h>
    #include <esp_now.h>
    
    // 设置数据结构体
    typedef struct struct_message {
      String board_name;
      double light;
      double sound;
    } struct_message;
    
    struct_message myData;
    
    // 数据接收回调函数
    void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
      memcpy(&myData, incomingData, sizeof(myData));
      Serial.print("board_name: ");
      Serial.println(myData.board_name);
      Serial.print("light: ");
      Serial.println(myData.light);
      Serial.print("sound:");
      Serial.println(myData.sound);
      Serial.println();
    }
    
    void setup() {
      Serial.begin(9600);
    
      // 初始化 ESP-NOW
      WiFi.mode(WIFI_STA);
      if (esp_now_init() != 0) {
        Serial.println("Error initializing ESP-NOW");
        return;
      }
      
      // 设置接收数据回调函数
      esp_now_register_recv_cb(OnDataRecv);
    }
    
    void loop() {
    
    }
    

    同样,我们在开头引入了 ESP-NOW 相关的头文件:WiFi.hesp_now.h。然后定义了传感器的引脚和一个名为 myData 的结构体,该结构体由 3 个不同数据组成,分别是开发板名称(board_name),光线值(light)与声音值(sound),与数据发送端定义的一模一样。

    我们注册了一个 OnDataRecv() 的数据接收回调函数,该函数反馈了 ESP-NOW 数据的接收状态,当接收到来自其他开发板的消息时,将消息保存到结构体 myData 中,并在串口中打印出接收到的消息。

    这里 ESP-NOW 的消息的接收属于无阻塞的接收方式,不受延时函数 delay() 的影响,这意味着 loop() 里面可以执行其他任务而不会影响到板间的通讯,同一块板子既可以当做接收方亦可以当做发送方互不影响。这里可以同时接收来自多块板子的信息,但前提是保持相同的结构体,当然你也可以不用结构体用普通的单一类型的数据类型比如字符串之类的,这里用结构体的原因是需要发送的数据类型有多个,使用结构体相对灵活。

    实验结果

    在两块 ESP32 开发板中分别上传发送和接收的程序,然后打开串口监视器来查看一下效果。

    发送端串口监视器如下图:

    发送端数据效果

    接收端串口监视器如下图:

    接收端数据效果

    可以看到发送端设备和接收端设备都正常运行,并且在串口中输出了相应的信息。

    小结

    至此,ESP-NOW 的简单应用已经讲完了,我们又学了一种新的无线通信方式。上面只是简单演示了一对一数据发送和接收的示例,其实一对多、多对一、多对多的数据发送和接收也是一样的道理,只需增加相应的代码即可。

    你可以试试将教程里的数据发送时间间隔改小一点,看看 ESP-NOW 速度究竟有多快。在以后的项目中,如果需要大量运用 ESP 系列开发板时,可以借助 ESP-NOW 技术可以让所有的 DIY 项目有机的联系起来,从而实现真正的万物相连,这个具体的应用我们将在以后的学习中逐步为大家进行讲解。

    下期见!

    参考资料:https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/

    展开全文
  • 1 ESP NOW 1.1 ESP NOW简介 1.2 ESP NOW帧格式 1.3 ESP NOW安全性 1.4 ESP NOW初始化与反初始化 1.5 添加配对设备 1.6 发送ESP-NOW数据 1.7 接收ESP-NOW数据 1.8 ESP-NOW API参考 2 ESP-MDF对ESP-NOW的应用...
  • ESP8266相互通讯(ESP-NOW

    千次阅读 2021-01-25 21:39:55
    ESP8266 一.简介 这篇给大家分享一下多...先说一下ESP-NOW,它是Espressif开发的一种协议,它使多个设备无需使用Wi-Fi即可相互通信。该协议类似于低功率的2.4GHz无线连接。设备之间需要进行配对,然后才能进行通信。配
  • [django]django模型中auto_now和auto_now_add

    千次阅读 2020-06-12 11:37:33
    update_time = models.DateTimeField('更新时间', default=timezone.now) create_time= models.DateTimeField('创建时间', auto_now_add=True) auto_now无论是你添加还是修改对象,时间为你添加或者修改的时间。 ...
  • java now_Java即时类| now()示例方法

    千次阅读 2020-07-31 12:59:25
    java now Instant Class now()方法 (Instant Class now() method) Syntax: 句法: public static Instant now(); public static Instant now(Clock cl); now() method is available in java.time package. ....
  • DateTime.Now.ToString()总结

    千次阅读 2019-02-08 14:13:40
    DateTime.Now.Date.ToShortDateString(); //昨天,就是今天的日期减一 DateTime.Now.AddDays(-1).ToShortDateString(); //明天,同理,加一 DateTime.Now.AddDays(1).ToShortDateString(); //2010年1月1日 星期三...
  • c#的DateTime.Now函数详解

    千次阅读 2018-07-19 17:35:00
    c#的DateTime.Now函数详解   // 2008年4月24日 System. DateTime .Now.ToString( " D " ); // 2008-4-24 System.DateTime.Now.ToString( " d " ); ...
  • System.DateTime.Now.ToString("D"); //2008-4-24System.DateTime.Now.ToString("d"); //2008年4月24日 16:30:15System.DateTime.Now.ToString("F"); //2008年4月24日 16:30System.DateTime.Now.ToS...
  • 关闭线程池 shutdown 和 shutdownNow 的区别 文章目录关闭线程池 shutdown 和 shutdownNow 的区别前言项目环境1.线程池示例2.shutdown3.isShutdown4.isTerminated5.awaitTermination6.shutdownNow7.shutdown 和 ...
  • MySQL now()函数

    千次阅读 2018-09-08 11:43:25
    转载自 MySQL now()函数 MySQL NOW()函数简介 MySQL NOW()函数以"YYYY-MM-DD HH:MM:DD"或"YYYYMMDDHHMMSS.uuuuuuu"格式的字符串或数字返回配置的时区中的当前日期和时间。 NOW()函数的返回...
  • 【ESP8266】ESP8266使用ESP-NOW入门教程

    万次阅读 热门讨论 2017-07-09 20:49:55
    ESP8266有很多好玩的技术,比如sniffer、smartconfig。这一次就介绍的是ESP-NOW
  • daemon not running; starting now at tcp:5037

    万次阅读 2020-02-22 13:41:51
    starting now at tcp:5037 【原因】5037端口被占用 【方法】找出5037端口占用的应用,关闭掉该应用进程 打开cmd命令窗口输入 netstat -ano | findstr “5037” 这里是10236占用程序 继续输入taskkill -f -pid ...
  • 进入mysql命令行。 方法1 查看时区设置: show variables like '%zone%'; select @@time_zone;...两者保持与系统时间一致,如果不一致进行如下修改: ...定位到[mysqld]所在的位置,在它的下面加上 default-time-zone ...
  • datetime.datetime.now() Print Now with datetime.now() Function 使用datetime.now()函数立即打印 We can see that every time we execute the now() function it returns different date time information where...
  • remove logo now注册码

    千次阅读 2019-08-10 16:37:40
    remove logo now注册码是用来激活破解一款非常好用的视频水印去除工具remove logo now的激活注册码,也可以说是序列号。我们知道这款软件由于涉及版权问题,需要收费购买使用,试用版只能免费试用一段时间,而且有些...
  • 如果您已经通过有线电视提供商(HBO Go)或HBO先前的产品(HBO Now)订阅了HBO,则基本分类如下: HBO Max ($14.99 per month): The new stand-alone streaming service from WarnerMedia includes everything on HBO ...
  • auto_now 和auto_now_add的区别

    千次阅读 2019-06-21 20:49:54
    auto_now 和auto_now_add的区别 ** auto_now=Ture,字段保存时会自动保存当前时间,但要注意每次对其实例执行save()的时候都会将当前时间保存,也就是不能再手动给它存非当前时间的值。每一次执行修改等动作,时间...
  • [转]c#中DateTime.Now函数的使用详解

    千次阅读 2017-08-04 10:22:11
    //2008年4月24日 System.DateTime.Now.ToString(“D”); //2008-4-24 System.DateTime.Now.ToString(“d”); //2008年4月24日 16:30:15 System.DateTime.Now.ToString(“F”); //2008年4月24日
  • 3.4.10/src/java/test/org/apache/zookeeper/test/QuorumUtil.java tar: 归档文件中异常的 EOF tar: 归档文件中异常的 EOF tar: Error is not recoverable: exiting now 解决方案有两种。 方案一:去掉解压参数中的...
  • react中脚手架 Nowa

    千次阅读 2018-08-08 17:40:24
    一:准备工作:在安装 nowa 之前请先确保已经安装有 nodejs 和 npm。 必须使用 nodejs&amp;amp;gt;=4.0 版本,强烈建议使用 npm&amp;amp;gt;=3.0 版本。 可以通过 node -v 和 npm -v 来查看 nodejs 和 npm...
  • 使用User.objects.update方法时,设置的default=datetime.now和auto_now=True都不会生效,由于设置了auto_now=True的字段不能手动修改,此时只能使用save方法修改数据,这对于多个数据的更新是不友好的。 因此...
  • DateTime.Now函数详解 所有用法

    千次阅读 2016-07-29 14:04:01
    //2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString("d"); //2008年4月24日 16:30:15 System.DateTime.Now.ToString("F"); //2008年4月24日 16:30 S
  • Everybody dance now 简析+代码

    千次阅读 热门讨论 2019-02-04 17:13:05
    Everybody dance now 简析+代码 Reference 参考了知乎-Everybody dance now 简析 Github代码 作者将本文的方法分为三个阶段:首先对输入的视频进行姿态估计,然后,规范化姿态;最后将规范化的姿态映射会目标...
  • No executable file now. No symbol file now. 的问题,究其原因主要有三点。 1.file 后面没有添加文件名,调试程序需要在gdb端加载,所以需要在gdb(pc端)拷贝并在 file命令后加入程序名称,例如要调试test_debug...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,539,518
精华内容 615,807
关键字:

now