DFRobot专区
直播中

HonestQiao

8年用户 520经验值
擅长:嵌入式技术
私信 关注

【FireBeetle Board ESP32-E IoT 开发板试用体验】iBeacon定位初阶

本帖最后由 HonestQiao 于 2021-9-8 19:00 编辑

FireBeetle Board ESP32-E IoT 开发板支持iBeacon,因此,这篇文章中,我们进行了iBeacon的基础应用:通过RSSI进行距离测算。本次的操作,是在Mac环境下的Arduino中进行的。在其他操作系统下面,代码没有差异,Arduino和串口的操作方法,根据系统具体而定。
为了方便同时操作两块ESP32开发版,我同时使用了Arduino和Arduino IDE两个编辑器,两者独立运行,分别对应一块开发版,可以同时进行烧录和串口监控运行状态。

通过本篇文章,你可以了解到:
1. 关于蓝牙测距的基础知识
2. 低功耗iBeacon发射端
3. iBeacon扫描端
4. ESP32中断与定时器
5. ESP32-C3板载三色LED颜色显示

下面进入正题:
1. 关于蓝牙测距的基础知识
我们先了解下,什么是iBeacon:
引用: iBeacon是Apple推出的一项低耗能蓝牙技术,由蓝牙设备发射包含指定信息的信号,再由移动设备接收信号,从而实现近场通信
这里有两个重点:一个是蓝牙技术,一个是低功耗。
通过蓝牙技术,可以进行近距离设备发现和近场通讯。
而低功耗,能够让设备以较小的功耗持续运行

然后,我们再了解一下蓝牙测距的知识:
引用: 任何无线电波,经过发射后,都会随着传播距离的增加,都会发生衰减。
而蓝牙信标发射的信号强度(rssi)与收发设备之间的距离,由于衰减的原因,在某种程度上是正相关的。
因此通过合理的参数设置和运算转化,可以通过探测到的rssi的值,来反推出发送设备与接收设备间的距离。

但是,需要给大家一点点冷静:因为这个衰减,受环境因素影响非常大。在不同的环境中,相关的经验参数,可能存在着较大的差异。
但是好在,距离与信号强度(rssi)是正相关的,在同一个环境中,如果干扰不多变化不大的化,还是可以用于非精准距离测量的,下面是一个基本的公示:
iShot2021-09-07 19.28.41.png
其中,A和n都是经验值,发射端和接收端相隔1米时的信号强度,n是环境衰减因子,需要通过反复测量和计算得到。关于这两个经验值的获取,在后续iBeacon接收端中会进行说明。
为了测量的更精准,还有应用更复杂,考虑因素更多的公示;同时,也会使用多个iBeacon发送设备,来实现三角定位(通过三个发射设备,来确定接收设备的具体位置)来实现更高的精度。
因为这篇文章,是初阶的,所以我们仅使用1块FireBeetle Board ESP32-E IoT 开发板来做iBeacon发射端,一个ESP32-C3来做接收端。
WechatIMG2776.jpeg WechatIMG2775.jpeg


2. 低功耗iBeacon发射端

发射端,我们使用一块FireBeetle Board ESP32-E IoT开发板,这个开发板支持iBeacon和低功耗运行。
这部分的代码,我们直接使用Arduino的例子->FireBeetle Board ESP32-E的例子->ESP32 BLE Arduino->BLE_iBeacon,具体操作如下:
iShot2021-09-07 19.40.40.png
具体代码如下:
  1. /*
  2.    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
  3.    Ported to Arduino ESP32 by PCBreflux
  4. */


  5. /*
  6.    Create a BLE server that will send periodic iBeacon frames.
  7.    The design of creating the BLE server is:
  8.    1. Create a BLE Server
  9.    2. Create advertising data
  10.    3. Start advertising.
  11.    4. wait
  12.    5. Stop advertising.
  13.    6. deep sleep

  14.    创建一个蓝牙服务,将会周期性的发送iBeacon帧。
  15.    具体功能如下:
  16.    1. 创建蓝牙服务
  17.    2. 创建广告信息
  18.    3. 开始广告
  19.    4. 等待
  20.    5. 停止广告
  21.    6. 深度睡眠
  22.    
  23. */

  24. #include "sys/time.h"

  25. #include "BLEDevice.h"
  26. #include "BLEUtils.h"
  27. #include "BLEBeacon.h"
  28. #include "esp_sleep.h"

  29. #define GPIO_DEEP_SLEEP_DURATION     5  // sleep x seconds and then wake up
  30. RTC_DATA_ATTR static time_t last;        // remember last boot in RTC Memory
  31. RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory

  32. #ifdef __cplusplus
  33. extern "C" {
  34. #endif

  35. uint8_t temprature_sens_read();
  36. //uint8_t g_phyFuns;

  37. #ifdef __cplusplus
  38. }
  39. #endif

  40. // See the following for generating UUIDs:
  41. // https://www.uuidgenerator.net/
  42. BLEAdvertising *pAdvertising;
  43. struct timeval now;

  44. // 该发射端的UUID
  45. #define BEACON_UUID           "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)

  46. // 设置Beacon帧信息
  47. void setBeacon() {

  48.   BLEBeacon oBeacon = BLEBeacon();
  49.   oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!)
  50.   oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
  51.   oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16);
  52.   oBeacon.setMinor(bootcount&0xFFFF);
  53.   BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  54.   BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
  55.   
  56.   oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04
  57.   
  58.   std::string strServiceData = "";
  59.   
  60.   strServiceData += (char)26;     // Len
  61.   strServiceData += (char)0xFF;   // Type
  62.   strServiceData += oBeacon.getData();
  63.   oAdvertisementData.addData(strServiceData);
  64.   
  65.   pAdvertising->setAdvertisementData(oAdvertisementData);
  66.   pAdvertising->setScanResponseData(oScanResponseData);

  67. }

  68. void setup() {

  69.    
  70.   Serial.begin(115200);
  71.   gettimeofday(&now, NULL);

  72.   Serial.printf("start ESP32 %dn",bootcount++);

  73.   Serial.printf("deep sleep (%lds since last reset, %lds since last boot)n",now.tv_sec,now.tv_sec-last);

  74.   last = now.tv_sec;
  75.   
  76.   // Create the BLE Device
  77.   BLEDevice::init("");

  78.   // Create the BLE Server
  79.   // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage

  80.   pAdvertising = BLEDevice::getAdvertising();
  81.   
  82.   setBeacon();
  83.    // Start advertising
  84.   pAdvertising->start();
  85.   Serial.println("Advertizing started...");
  86.   delay(100);
  87.   pAdvertising->stop();
  88.   Serial.printf("enter deep sleepn");
  89.   esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
  90.   Serial.printf("in deep sleepn");
  91. }

  92. void loop() {
  93. }
在上面的代码中,会发送广告信息,我们不用管它。
关键在于iBeacon帧的设置setBeacon(),以及这个设备的BEACON_UUID,该UUID值,可以进行修改;再就是esp_deep_sleep()实现深度睡眠。
设置后代码后,我们把FireBeetle Board ESP32-E IoT开发板连上电脑的USB口,按照如下步骤进行设置:
1)选择开发版:
iShot2021-09-07 19.52.33.png
2)设置调试信息级别:
iShot2021-09-07 19.52.55.png
3)选择串口:
iShot2021-09-07 19.54.14.png
4)编译代码:
iShot2021-09-07 19.57.23.png
5)下载代码:
iShot2021-09-07 19.59.37.png
6)运行监控:
iShot2021-09-07 20.10.50.png

3. iBeacon扫描端

扫描/接收端,我们使用一块ESP32-C3-Mini1 开发板,这个开发板支持蓝牙,并有一个板载三色LED,便于我们显示不同的状态的。
这部分的代码,我们直接使用Arduino的例子->ESP32 C3 Dev Module的例子->ESP32 BLE Arduino->BLE_Beacon_Scanner,具体操作如下:
iShot2021-09-08 17.50.29.png
这个例子,用于基础的Beacon和iBeacon扫描,为了适应我们的需要,进行了适当的修改,具体代码如下:
  1. /*
  2.    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
  3.    Ported to Arduino ESP32 by Evandro Copercini
  4.    Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo
  5. */

  6. #include

  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include

  14. #include "esp_system.h"
  15. #include "led_strip.h"

  16. #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))

  17. // RSSI经验参数
  18. #define A 66
  19. #define n 2.0

  20. // 目标SSID
  21. #define IBEACON_MY_SSID "8ec76ea3-6668-48da-9866-75be8bc86f4d"

  22. // ESP32-C3板载LED
  23. #define CONFIG_BLINK_LED_RMT_CHANNEL 0
  24. #define BLINK_GPIO 8

  25. // 延时时间
  26. #define TIME_DELAY 500

  27. // 循环处理参数
  28. static uint8_t s_loop = 0;
  29. static uint8_t s_led_idx = 0;

  30. // LED处理
  31. static uint8_t s_led_state = 0;
  32. static led_strip_t *pStrip_a;

  33. static unsigned long ms = 0;

  34. // Beacon扫描时间
  35. int scanTime = 5;  //In seconds

  36. // 延时计数,防止发射端睡眠时被认为掉线
  37. int delaymax = 30;

  38. // 蓝牙
  39. BLEScan *pBLEScan;
  40. static float dis = 0;

  41. hw_timer_t *timer = NULL;
  42. volatile SemaphoreHandle_t timerSemaphore;
  43. portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

  44. volatile uint32_t isrCounter = 0;
  45. volatile uint32_t lastIsrAt = 0;

  46. // 通过RSSI计算距离
  47. float calcDistByRSSI(int rssi)
  48. {
  49.   int iRssi = abs(rssi);
  50.   float power = (iRssi-A)/(10*n);
  51.   return pow(10, power);
  52. }

  53. // 定时器设置
  54. void ARDUINO_ISR_ATTR onTimer() {
  55.   // 定时器触发时,将设置信号量,以便loop部分检测使用
  56.   // Increment the counter and set the time of ISR
  57.   portENTER_CRITICAL_ISR(&timerMux);
  58.   isrCounter++;
  59.   lastIsrAt = millis();
  60.   portEXIT_CRITICAL_ISR(&timerMux);
  61.   // Give a semaphore that we can check in the loop
  62.   xSemaphoreGiveFromISR(timerSemaphore, NULL);
  63.   // It is safe to use digitalRead/Write here if you want to toggle an output
  64. }

  65. // 点亮LED
  66. static void blink_led(void) {
  67.   /* If the addressable LED is enabled */
  68.   if (s_led_state) {
  69.     Serial.print("LED ONn");
  70.     /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
  71.     if(s_led_idx>0) {
  72.       // 正常状态为绿色
  73.       pStrip_a->set_pixel(pStrip_a, 0, 0, 32, 0);
  74.     } else {
  75.       // 白色
  76.       pStrip_a->set_pixel(pStrip_a, 0, 32, 32, 32);
  77.     }
  78.     /* Refresh the strip to send data */
  79.     pStrip_a->refresh(pStrip_a, 100);
  80.   } else {
  81.     Serial.print("LED OFFn");
  82.     /* Set all LED off to clear all pixels */
  83.     // pStrip_a->clear(pStrip_a, 50);
  84.     // 红色
  85.     pStrip_a->set_pixel(pStrip_a, 0, 32, 0, 0);
  86.     pStrip_a->refresh(pStrip_a, 100);
  87.   }
  88. }

  89. // 设置LED
  90. static void configure_led(void) {
  91.   Serial.print("configured to blink addressable LED!");
  92.   pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, BLINK_GPIO, 1);
  93.   pStrip_a->clear(pStrip_a, 50);
  94. }

  95. // 蓝牙发现处理
  96. class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  97.   void onResult(BLEAdvertisedDevice advertisedDevice) {
  98.     if (advertisedDevice.haveName()) {
  99.       Serial.print("Device name: ");
  100.       Serial.println(advertisedDevice.getName().c_str());
  101.       Serial.println("");
  102.     }

  103.     if (advertisedDevice.haveServiceUUID()) {
  104.       return;
  105.       // BLEUUID devUUID = advertisedDevice.getServiceUUID();
  106.       // Serial.print("Found ServiceUUID: ");
  107.       // Serial.println(devUUID.toString().c_str());
  108.       // Serial.println("");
  109.     } else {
  110.       if (advertisedDevice.haveManufacturerData() == true) {
  111.         std::string strManufacturerData = advertisedDevice.getManufacturerData();

  112.         uint8_t cManufacturerData[100];
  113.         strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);

  114.         // iBeacon帧检测
  115.         if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00) {
  116.           Serial.println("Found an iBeacon!");
  117.           BLEBeacon oBeacon = BLEBeacon();
  118.           oBeacon.setData(strManufacturerData);
  119.           Serial.printf("iBeacon Framen");
  120.           dis = calcDistByRSSI(advertisedDevice.getRSSI());
  121.           Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d RSSI: %d Dis:%0.3fn", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower(), advertisedDevice.getRSSI(), dis);
  122.           // 目标SSID检测
  123.           if (strcmp(oBeacon.getProximityUUID().toString().c_str(), IBEACON_MY_SSID) == 0) {
  124.             Serial.printf("********iBeacon ssid found********n");
  125.             s_led_idx = delaymax;
  126.           }
  127.         } else {
  128.           return;
  129.           // Serial.println("Found another manufacturers beacon!");
  130.           // Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
  131.           // for (int i = 0; i < strManufacturerData.length(); i++) {
  132.           //   Serial.printf("[%X]", cManufacturerData[i]);
  133.           // }
  134.           // Serial.printf("n");
  135.         }
  136.       }
  137.     }
  138.     return;

  139.     // uint8_t *payLoad = advertisedDevice.getPayload();

  140.     // BLEUUID checkUrlUUID = (uint16_t)0xfeaa;

  141.     // if (advertisedDevice.getServiceUUID().equals(checkUrlUUID)) {
  142.     //   if (payLoad[11] == 0x10) {
  143.     //     Serial.println("Found an EddystoneURL beacon!");
  144.     //     BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
  145.     //     std::string eddyContent((char *)&payLoad[11]);  // incomplete EddystoneURL struct!

  146.     //     foundEddyURL.setData(eddyContent);
  147.     //     std::string bareURL = foundEddyURL.getURL();
  148.     //     if (bareURL[0] == 0x00) {
  149.     //       size_t payLoadLen = advertisedDevice.getPayloadLength();
  150.     //       Serial.println("DATA-->");
  151.     //       for (int idx = 0; idx < payLoadLen; idx++) {
  152.     //         Serial.printf("0x%08X ", payLoad[idx]);
  153.     //       }
  154.     //       Serial.println("nInvalid Data");
  155.     //       return;
  156.     //     }

  157.     //     Serial.printf("Found URL: %sn", foundEddyURL.getURL().c_str());
  158.     //     Serial.printf("Decoded URL: %sn", foundEddyURL.getDecodedURL().c_str());
  159.     //     Serial.printf("TX power %dn", foundEddyURL.getPower());
  160.     //     Serial.println("n");
  161.     //   } else if (payLoad[11] == 0x20) {
  162.     //     Serial.println("Found an EddystoneTLM beacon!");
  163.     //     BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
  164.     //     std::string eddyContent((char *)&payLoad[11]);  // incomplete EddystoneURL struct!

  165.     //     eddyContent = "01234567890123";

  166.     //     for (int idx = 0; idx < 14; idx++) {
  167.     //       eddyContent[idx] = payLoad[idx + 11];
  168.     //     }

  169.     //     foundEddyURL.setData(eddyContent);
  170.     //     Serial.printf("Reported battery voltage: %dmVn", foundEddyURL.getVolt());
  171.     //     Serial.printf("Reported temperature from TLM class: %.2fCn", (double)foundEddyURL.getTemp());
  172.     //     int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
  173.     //     float calcTemp = temp / 256.0f;
  174.     //     Serial.printf("Reported temperature from data: %.2fCn", calcTemp);
  175.     //     Serial.printf("Reported advertise count: %dn", foundEddyURL.getCount());
  176.     //     Serial.printf("Reported time since last reboot: %dsn", foundEddyURL.getTime());
  177.     //     Serial.println("n");
  178.     //     Serial.print(foundEddyURL.toString().c_str());
  179.     //     Serial.println("n");
  180.     //   }
  181.     // }
  182.   }
  183. };

  184. void setup() {
  185.   Serial.begin(115200);
  186.   Serial.println("Scanning...");

  187.   // 配置LED
  188.   configure_led();

  189.   // 创建信号量
  190.   timerSemaphore = xSemaphoreCreateBinary();

  191.   // 定时器设置
  192.   timer = timerBegin(0, 80, true);
  193.   timerAttachInterrupt(timer, &onTimer, true);
  194.   timerAlARMWrite(timer, 1000 * 1000, true);
  195.   timerAlarmEnable(timer);

  196.   // 蓝牙初始化
  197.   BLEDevice::init("");
  198.   pBLEScan = BLEDevice::getScan();  //create new scan
  199.   pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  200.   pBLEScan->setActiveScan(true);  //active scan uses more power, but get results faster
  201.   pBLEScan->setInterval(100);
  202.   pBLEScan->setWindow(99);  // less or equal setInterval value
  203. }

  204. void loop() {
  205.   ms = millis();
  206.   // put your main code here, to run repeatedly:
  207.   if (s_loop==0) {
  208.     // 蓝牙扫描
  209.     BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  210.     Serial.print("Devices found: ");
  211.     Serial.println(foundDevices.getCount());
  212.     Serial.println("Scan done!");
  213.     pBLEScan->clearResults();  // delete results fromBLEScan buffer to release memory
  214.   }
  215.   s_loop++;
  216.   if(s_loop==8) {
  217.     // 每循环8次,进行1次扫描
  218.     s_loop = 0;
  219.   }
  220.   // If Timer has fired
  221.   if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE) {
  222.     // 状态和延时次数处理
  223.     if (s_led_idx > 0) {
  224.       s_led_idx--;
  225.     }
  226.     if (s_led_idx > 0) {
  227.       // 检测到的情况下,常亮绿色
  228.       s_led_state = 1;
  229.     } else {
  230.       // 没有检测到的情况下,红白切换
  231.       s_led_state = !s_led_state;
  232.     }

  233.     uint32_t isrCount = 0, isrTime = 0;
  234.     // Read the interrupt count and time
  235.     portENTER_CRITICAL(&timerMux);
  236.     isrCount = isrCounter;
  237.     isrTime = lastIsrAt;
  238.     portEXIT_CRITICAL(&timerMux);
  239.     // Print it
  240.     Serial.print("onTimer no. ");
  241.     Serial.print(isrCount);
  242.     Serial.print(" at ");
  243.     Serial.print(isrTime);
  244.     Serial.print(" ms");
  245.     Serial.print(" loop:");
  246.     Serial.print(s_loop);
  247.     Serial.print(" idx:");
  248.     Serial.print(s_led_idx);
  249.     Serial.print(" state:");
  250.     Serial.print(s_led_state);

  251.     Serial.println(" ");
  252.     blink_led();
  253.     // timerWrite(timer, 0);
  254.   }

  255.   // 延时处理,去掉本轮处理已经用掉 的时间
  256.   ms = millis() - ms;
  257.   if(ms>TIME_DELAY) {
  258.     ms = 0;
  259.   } else {
  260.     ms = TIME_DELAY - ms;
  261.   }
  262.   delay(ms);  
  263. }
以上代码中,需要使用led_strip.h,在附件中一并提供。
在标准示例代码的基础上,我们添加了几个部分:
1)LED的处理,包括设置和点亮处理;当检测到对应的设备后,常亮绿色显示,否则红白交替显示。对应的函数为configure_led()、blink_led(),用于设置和控制板载3色LED
2)定时器的处理:我们需要做LED交替显示,同时又要进行蓝牙Beacon扫描,所以通过定时器配合,来进行信号量的设置,从而在loop中,根据信号量的情况,来进行LED的控制。对应的函数为onTimer()
3)RSSI测距基本算法,对应的函数为calcDistByRSSI()
这个代码中,做了详细的注释,大家可以仔细查看。

在Arduino IDE的操作步骤如下:
选择开发版:
iShot2021-09-08 17.53.02.png
选择串口和设置:
iShot2021-09-08 17.53.34.png
编译下载:
iShot2021-09-08 17.53.41.png
运行监控:
iShot2021-09-08 17.56.59.png
上述运行解控界面中,如下部分,显示了搜索到的iBeacon信息:
  1. Found an iBeacon!
  2. iBeacon Frame
  3. ID: 004C Major: 0 Minor: 91 UUID: 8ec76ea3-6668-48da-9866-75be8bc86f4d Power: 0 RSSI: -30 Dis:0.016
  4. ********iBeacon ssid found********
其中,Dis就表示位置信息。
在本部分的代码中,包含如下的经验设置和距离计算函数:
  1. // RSSI经验参数
  2. #define A 66
  3. #define n 2.0
这两个经验值,可以通过运行时,上述iBeacon Frame值来设置。1)将设备相距1米放置,获取此时的rssi值,设为A
2)通过在电脑上,利用上述函数,调整n的值,使得计算结果接近1
3)然后将设备分别放置0.5米和2米,获取rssi值,并且调整n,使得结果接近距离值
以上需要多次取样,进行计算,以使得结果尽可能的准确。

4. ESP32中断与定时器
。。。
ESP32 芯片提供两组硬件定时器,每组包含两个通用硬件定时器。
通过下面的代码,可以很容易使用定时器:
  1. // 定时器设置
  2. void ARDUINO_ISR_ATTR onTimer() {
  3.   isrCounter++;
  4.   //定时器逻辑处理,可以写自己的代码
  5. }

  6. //setup中设置
  7.   // 定时器设置
  8.   timer = timerBegin(0, 80, true);
  9.   timerAttachInterrupt(timer, &onTimer, true);
  10.   timerAlarmWrite(timer, 1000 * 1000, true);
  11.   timerAlarmEnable(timer);
因为Ardunio中,ESP32定时器的处理,设计到中断,因此,在定时器触发后,处理逻辑需要快准狠,不能调用任何会阻塞 CPU 的 API,否则会导致混乱。因此,上面的代码中,我们通过在定时触发处理逻辑中设置信号量,然后在loop逻辑中进行检测和处理,避免了对中断的影响。

5. ESP32-C3板载三色LED颜色显示
ESP32-C3板载LED的显示,需要通过pixel方式进行处理,其基本代码来源于ESP-IDF中的例子。
主要的调用方式如下:
  1. #include "led_strip.h"

  2. // RMT通道
  3. #define CONFIG_BLINK_LED_RMT_CHANNEL 0
  4. // GPIO针脚
  5. #define BLINK_GPIO 8

  6. // 定义处理句柄
  7. static led_strip_t *pStrip_a;

  8. // 初始化
  9. pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, BLINK_GPIO, 1);

  10. // 清除显示
  11. pStrip_a->clear(pStrip_a, 50);

  12. // 设置颜色
  13. /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
  14. pStrip_a->set_pixel(pStrip_a, 0, 32, 0, 0);
  15. pStrip_a->set_pixel(pStrip_a, 0, 0, 32, 0); //绿色

  16. // 刷新显示
  17. pStrip_a->refresh(pStrip_a, 100);

6. 扩展研究:
在本文中,我们只使用了1块iBeacon发射设备,并且使用了最基础的RSSI距离算法。在实际应用中,会布置多个iBacon设备,从而同时通过多个设备,来提高定位精度。以及使用更为优化的算法,来提高精度减小误差。

7. 实际效果:见视频


实际效果

更多回帖

发帖
×
20
完善资料,
赚取积分