1、效果描述:
通过简单的 Android APP 实现与 ESP32 的双向蓝牙通信。
2、实现步骤
Step 1:ESP32 硬件支持
1、支持蓝牙 4.0 以上协议的安卓手机;
2、支持 Micro USB 的 ESP32 dev board;
Step 2:配置 Arduino IDE 环境
1、下载 Arduino IDE:https://www.arduino.cc/en/Main/Software;
2、安装 ESP32 支持包:https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/windows.md
根据网站步骤安装 GIT 工具,并根据提示下载 BLE 支持开发包
在 Arduino 编写实例:
/*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
Create a BLE server that, once we receive a connection, will send periodic notifications.
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
The design of creating the BLE server is:
- Create a BLE Server
- Create a BLE Service
- Create a BLE Characteristic on the Service
- Create a BLE Descriptor on the characteristic
- Start the service.
- Start advertising.
In this example rxValue is the data received (only accessible inside that function).
And txValue is the data to be sent, in this example just a byte incremented every second.
*/
include <BLEDevice.h>
include <BLEServer.h>
include <BLEUtils.h>
include <BLE2902.h>
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.
//std::string rxValue; // Could also make this a global var to access it in loop()
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
// Do stuff based on the command received from the app
if (rxValue.find("A") != -1) {
Serial.print("Turning ON!");
digitalWrite(LED, HIGH);
}
else if (rxValue.find("B") != -1) {
Serial.print("Turning OFF!");
digitalWrite(LED, LOW);
}
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
// Create the BLE Device
BLEDevice::init("ESP32 UART Test"); // Give it a name
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
// Fabricate some arbitrary junk for now...
txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!
// Let's convert the value to a char array:
char txString[8]; // make sure this is big enuffz
dtostrf(txValue, 1, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer
// pCharacteristic->setValue(&txValue, 1); // To send the integer value
// pCharacteristic->setValue("Hello!"); // Sending a test message
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
Serial.print("*** Sent Value: ");
Serial.print(txString);
Serial.println(" ***");
// You can add the rxValue checks down here instead
// if you set "rxValue" as a global var at the top!
// Note you will have to delete "std::string" declaration
// of "rxValue" in the callback function.
// if (rxValue.find("A") != -1) {
// Serial.println("Turning ON!");
// digitalWrite(LED, HIGH);
// }
// else if (rxValue.find("B") != -1) {
// Serial.println("Turning OFF!");
// digitalWrite(LED, LOW);
// }
}
delay(1000);
}
Step 3:下载安装 APP 测试工具
可以在资源栏下载:https://download.csdn.net/download/liwei16611/10526621
3、代码解释
3.1、库文件:
include <BLEDevice.h>
include <BLEServer.h>
include <BLEUtils.h>
include <BLE2902.h>
创建 BLE 设备:
BLEDevice::init("ESP32 UART Test"); // Give it a name
创建 BLE server:
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
创建 BLE service:
BLEService *pService = pServer->createService(SERVICE_UUID);
添加 characteristics:
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
启动广播:
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
3.2、定义 service 和 characteristic UUID:TX | RX
define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
3.3、蓝牙连接回调函数
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
3.4、数据接收回调函数
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();</p><p> if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");</p><p> for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}</p><p> Serial.println();</p><p> // Do stuff based on the command received from the app
if (rxValue.find("A") != -1) {
Serial.print("Turning ON!");
digitalWrite(LED, HIGH);
}
else if (rxValue.find("B") != -1) {
Serial.print("Turning OFF!");
digitalWrite(LED, LOW);
}</p><p> Serial.println();
Serial.println("*********");
}
}
};
从《天道》的角度谈谈产品规划
原创2023-02-24 21:05·产品人卫朋
今天主要借用《天道》中丁元英的商业案例来谈谈产品规划这个话题。
《天道》这部被众人追捧的影视剧来源于豆豆的成名作《遥远的救世主》。
如果没有全局做过产品或者市场的规划,而且是初次接触这部剧。
你就会惊叹于主人公的组局、布局,以及成局的能力。
从互联网拥簇的评论声中,也可见一斑。
剧中的丁元英甚至都有一种被神化的趋势。
而随着个人知识和阅历的增加,再加上每年也都要做产品规划。
也逐渐对这部剧或者这本书有了一些新的认识。
究其本质,这是一种战略性的思维,也是一种规划的能力。
更是一种市场与内部能力的匹配过程。
笔者之前也分享过这块的内容,也看到了一些质疑。
怎么能用虚拟的案例做讲解呢?
其实这么做的原因主要有两点考虑:
首先,这部剧中的商业案例的整体逻辑是自洽的,而且也符合当时的商业环境。
其次,整部剧将整个商业案例完整地呈现了出来,也包括其中很多的决策细节。
这就要比分析现实案例直观得多,也更加有指导意义。
再回到产品规划这个话题上来。
产品规划从本质上来说是一种推演能力,也就是根据第一性原则推演产品从0到1、从1到100的一个过程。
如果说一款产品是一个点的话,那产品规划便是通过构造一种系统能力以达成企业最终的商业目的。
第一性原理是埃隆·马斯克非常推崇的一种思维模型。
通常来说,企业愿景对应的便是企业的第一性原则。
围绕第一性原则可以激发资源优势、制定细分市场目标,最终实现企业目标。
下面以影视剧中丁元英操盘的格律诗音响项目为例,谈谈产品规划。
格律诗音响公司的企业愿景是实现王庙村生产力和市场的对接,最终实现农户脱贫。
这是企业的愿景,同时也是丁元英承诺要给红颜知己芮小丹创造的神话。
启动一个项目或产品,资源和人力配置是你首先要考虑的。
企业在不同的发展周期,对人的要求是有很大差异的。
丁元英在分析完这些人的本质之后,并没有把自己的全套计划完整地告诉原始这些人。
而是通过市场的变化来淘汰掉一部分人。
因为这部分人现在不淘汰掉,在以后的市场变化中,可能会给公司带来毁灭性的灾难。
下面就先梳理一下其中的关键人物:
丁元英作为格律诗音响项目的唯一操盘手,全局规划了整个项目。
他的优势是自己在欧洲的人脉和战略规划能力,以及在欧阳雪等人心中的影响力。
同时,作为发烧级音乐玩家,他对音箱的独特见解也为他们打造差异化的产品起到了关键助力作用。
差异化的意思是相比于竞争对手,你的独特优势或者护城河,没有这个前提,整个策略也就无从谈起,这为他们赢得了时间上的先机。
在音响这个市场,竞品已经很成功了,而且他们提供的价值点已经被用户接受。
如果按照他们的价值点去做产品,你就永远只能跟在他们身后。
这时候就需要找一个跟他们不一样的价值点,做差异化。
欧阳雪这个人呢,做事很踏实,很讲义气,不贪心。优势是人脉、资金和社会地位。
这个人的价值在于她对格律诗的绝对控股,这样就可以确保关键决策权的归属。
由于每个人的认知水平的限制,很多时候不同个体看到的终局是有极大差异的,这个时候你就需要考虑如何增加成事的确定性。
如果开公司的话,股权的分配问题是你优先要考虑的。
不赚钱的时候,大家还都能力出一孔。一旦公司有起色,每个人就开始有自己的诉求,不确定性也就随之而来。
肖亚文见过世面,知道公司怎么运行,知道商务谈判和商务合作的事情,是很精明的职场人物。
而冯世杰和叶晓明想成就一番事业,但没有机会,能够脚踏实地的做事情,但眼光欠缺。刘冰是小人物,唯利是图,关键时刻不能顶上,迟早会被淘汰。
叶晓明,冯世杰,刘冰这三个人的优势就是懂音乐,会组装,可以作为高级技术工。
同时,这三人和王庙村农民有一定的关系,可以作为连接的纽带,核心竞争力是技术和人脉。
乐圣公司的掌舵人是林雨峰(竞争对手),但太过刚硬,只知道进攻,不懂防守,考虑问题存在漏洞。
这就有点类似竞争分析了,通过分析竞争对手的漏洞,找到破局点,制定商业竞争策略。
接下来就需要统一思想了:
想要以小博大,达成乐圣跟王庙村合作的目的,就必须把优势发挥到最大效果。
这才有几次股东开会,召集农民兄弟一起开会等,就是为了统一思想。
市场的生存竞争非常残酷,胜负往往就在毫厘之间,微弱的优势都可能成为关键一环,你比他多一口气,你就是赢家。
最后,丁元英就把这些人的优势资源整合起来,按照需要组建公司,精心规划。
详细案例分析可以参阅笔者之前的文章。
卫朋
人人都是产品经理受邀专栏作家,CSDN 嵌入式领域新星创作者、资深技术博主。2020 年 8 月开始写产品相关内容,截至目前,人人都是产品经理单渠道阅读 56 万+,鸟哥笔记单渠道阅读200 万+,CSDN 单渠道阅读 210 万+,51CTO单渠道阅读 180 万+。
卫朋入围2021/2022年人人都是产品经理平台年度作者,光环国际学习社区首批原创者、知识合作伙伴,商业新知 2021 年度产品十佳创作者,腾讯调研云2022年达人榜第三名。
文章被人人都是产品经理、CSDN、华为云、运营派、产品壹佰、鸟哥笔记、光环国际、商业新知、腾讯调研云等头部垂直类媒体转载。文章见仁见智,各位看官可策略性选择对于自己有用的部分。