- 2024-11-21
-
回复了主题帖:
入围名单公布:嵌入式工程师AI挑战营(进阶)的挑战者们,领取板卡啦
个人信息已确认,领取板卡,可继续完成任务。
-
加入了学习《MIT 6.622 Power Electronics》,观看 DC-DC, Part 2
- 2024-11-18
-
回复了主题帖:
嵌入式工程师AI挑战营(进阶):在RV1106部署InsightFace算法的多人实时人脸识别实战
申请理由:
InsightFace 主要依赖于 ArcFace 技术,这是一种基于角度度量的人脸识别方法。ArcFace 通过学习特征的角度信息,能够提供更高的识别准确率,尤其是在处理低质量图像或复杂背景时,表现非常出色。
使用 RV1106 的 SDK 和工具链(如 Rockchip 的 RKNN Toolkit)来优化和部署模型。使用 TensorFlow Lite 或 PyTorch,安装 OpenCV 和 dlib 等库用于图像处理和人脸检测。InsightFace 提供了多个预训练模型。选择一个适合实时处理的轻量级模型,如 ResNet 或 MobileFaceNet。
优化模型。使用 TensorFlow Lite 或 ONNX 格式来将模型转换为适合移动端或嵌入式设备的轻量级格式。使用 Quantization(量化)等方法来减少模型大小和计算量,尤其是对于硬件加速的 NPU 可以提高推理速度。使用 RKNN Toolkit 将模型转换为 RV1106 可识别的格式,并利用 NPU 提供的加速。
计划部署的应用:
智能零售与客户分析:在零售店、商场等环境中进行顾客分析,识别回头客、分析顾客行为、统计顾客停留时长等
- 2024-06-20
-
加入了学习《【DigiKey创意大赛】多通道微型气相色谱采集单元》,观看 多通道微型气相色谱采集单元
- 2024-05-23
-
发表了主题帖:
【2023 DigiKey大赛参与奖】开箱帖:ESP32 BASIC COER
- 2024-02-22
-
发表了主题帖:
【STEVAL-WESU1】第二周 基础功能测试
本帖最后由 许大锤 于 2024-2-22 09:28 编辑
由于过年,以及软件不适配等因素,第二周测评姗姗来迟。
APP
WESU1有一款手机端软件,但由于这个软件很久没有更新,按照教程无法从谷歌商店中下载(提示手机版Android本太高),IOS端又不支持我所在的地区,本以为项目无法进行下去,但功夫不负有心人我找到了配套App的APK,我将它放在附件中。
初体验
首先是将板子通过USB接通电源
然后通过BLE蓝牙与手机配对,这时弹出提示,说板子程序固件有些低,直接继续就行,体验其基础功能。
点击侧边栏,能看到功能选项,还是十分丰富的。
我先点击了Environment,但发现这里显示的温度高达31.2摄氏度,但目前环境温度为25摄氏度,这个明显不准确,可能需要再程序中调整。
我又对其他功能进行了体验,如下:
能感觉出传感器还是很灵敏的,有些体验需要穿戴到身上才能体验,目前无法进行。
装配
先是剪下方向标尺;
然后安装锂电池;
放入盒子中;
充电;
出现问题
经过了一夜的充电,仍然无法仅仅通过锂电池供电,由于这个产品是2017年的,有可能是锂电池已损坏,也有有可能是我连接问题导致充电失败,由于网上资料甚少,目前该问题无法解决,我准备先买一个同款锂电池,再进行后续研究。
下周计划
个人穿戴体验一周
- 2024-01-24
-
发表了主题帖:
【STEVAL-WESU1】第一周 开箱
# 1. 计划
第一周:开箱;
第二周:基础功能测试;
第三周:体验一周,写体验感受;
第四周:针对传感器进行二次开发;
第五周:二次开发和优化;
第六周:根据二次开发后的内容,制作手机端应用程序。
第七和八周:开发体验和心得
# 2. 传感器介绍
STEVAL-WESU1 是一款经过开发和优化的参考设计,旨在帮助设计人员在可穿戴和便携式应用中实施最新技术。
硬件的小外形尺寸使其可以封装在表带中,因此用户可以体验真正的活动监测系统并立即开始欣赏传感器数据采集以及所有嵌入式硬件和固件功能,也感谢 Apple Store™ 和 Google Play™ 商店免费提供 ST WeSU 应用程序。 这些应用程序基于 BlueST SDK(可在 GitHub 上获取)。
高级用户还可以进一步缩小硬件外形尺寸; 请参阅 STEVAL-WESU1 用户手册了解更多详细信息。
STEVAL-WESU1 固件包基于 STM32Cube 软件技术构建,因此可以轻松通过进一步的算法进行增强。 它在 STM32L151VEY6 上运行,包括用于管理三个传感器(LSM6DS3、LIS3MDL 和 LPS25HB)、蓝牙低功耗网络处理器(BlueNRG-MS)和电池管理 IC(STC3115 和 STNS01)的驱动程序。
https://www.st.com/en/evaluation-tools/steval-wesu1.html
**特性**
适用于可穿戴运动传感应用的紧凑型解决方案,具有一整套固件示例
提供 iOS 和 Android 应用程序
主要成分:
STM32L151VEY6 – 32位超低功耗MCU
LSM6DS3 – 3D 加速度计 + 3D 陀螺仪
LIS3MDL – 3 轴磁力计
LPS25HB – MEMS 压力传感器
BlueNRG-MS – BLE 网络处理器
BALF-NRG-01D3 - 具有集成谐波滤波器的 50 Ω 巴伦
STNS01 – 锂离子线性电池充电器
STC3115 – 电量计IC
包含 100 mAh 锂离子电池,经过 UN38.3 测试和认证
用于充电的 Micro USB 连接器
用于调试和编程功能的 SWD 连接器
包括带塑料外壳的表带
经过 FCC (FCC ID: S9N-WESU1) 和 IC (IC: 8976C-WESU1) 全面测试和认证
符合 RoHS 标准
# 3. 开箱
- 2024-01-18
-
回复了主题帖:
测评入围名单(最后一批):年终回炉,FPGA、AI、高性能MCU、书籍等42个测品
个人信息无误,确认可以完成评测计划
- 2024-01-12
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统,作品提交
植物情绪监测与交互系统
作者:许大锤
一、作品简介(100-200字)
(设计名称、作品照片、项目用到的板卡、芯片、模块等介绍,作品功能介绍等)
设计名称
植物情绪监测与交互系统
项目用到的板卡、芯片、模块
Raspberry pi 4B,LM35 Temperatures sensor,LDR module,Moisture sensor, LCD Module,ADS115 ADC,面包板,杜邦线若干
作品功能介绍
本作品实现植物情绪检测的功能,目前而言对于植物的情绪状态的研究很少,许多研究者觉得植物压根没有情绪状态,但最近的一些研究表明植物本身是存在情绪的,我个人也倾向于植物拥有情绪的说法,但想获得植物的情绪很难,有些研究采用超声波或电磁波等方式检测植物情绪,对于我来说资源和能力尚不满足,所以我采用一些间接的方式,或者说是我个人主观臆断的方式进行植物检测,具体功能如下:
水分监测:通过土壤湿度传感器检测土壤的湿度。土壤过干或过湿都可能对植物造成压力。
光照监测:使用光照传感器来监测植物所接受的光照量。不同的植物对光照的需求不同,光照不足或过度都会影响植物的健康。
温度和湿度监测:环境温度和湿度也对植物的生长有重要影响。可以使用温湿度传感器来监测这些参数。本项目数据采集家用的BLE蓝牙温湿度计(秒秒测蓝牙温湿度计)。
用户与植物交互:这部分我设计比较简单,就是当用户触碰到植物的叶片,无论植物处于何种状态,系统会判定植物情绪很好。
外网访问:由于树莓派可以连接互联网,本项目采用内网穿透技术,利用阿里云服务器,实现了外网访问树莓派,从而实现随时随地获取植物信息的功能。
二、系统框图(图文结合)
(设计思路、系统软硬件介绍及实现框图,以图文结合的展示)
图1 硬件连接设计图
图2 实物连接图
设计思路:采用ADC获取土壤湿度传感器、温度传感器、LDR亮度传感器以及植物电位信息变化(用于判断植物是否被触摸),利用树莓派自身的蓝牙模块,获取家用BLE蓝牙温湿度计中的信息,从而主观判断植物的情绪,并采用彩色LCD模块显示动态表情。由于设置了内网穿透,即使身在异地也能随时了解植物此刻的情绪状态。
三、各部分功能说明(图文结合)
(各部分实现的功能说明及讲解,以图文结合的展示)
项目代码采用python,代码运行前请确保树莓派打开了I2C,SPI和GPIO。主程序为sensor.py。
情绪展现
情绪来源:LM35 Temperatures sensor,LDR module,Moisture sensor和触碰植物。
彩色LCD生动地展现情绪(60帧动图):
Thirsty:每当土壤湿度对植物来说太低时。
Hot:温度过高时。
Freeze:温度太低时。
Sleepy:光线第的时候。
Savory:给植物浇水(土壤湿度快速升高)。
Happy:白天且环境适宜植物生长,或者人触碰植物叶片时。
传感器测试与标定
本项目传感器信息的获取要通过ADS1115 16位ADC(I2C),进行模数转换,所以应该先对ADS1115进行测试,在代码文件calibration.py即可进行,能跑通则证明硬件系统连接无误。如果跑不通,请检查连线,或检查树莓派是否开启I2C。
由于传感器本身和环境不同,要对获取的值进行矫正,需要标定土壤湿度传感器和LDR,代码都对两者做了归一化处理,只需要将sensor中“LDR_Percent = _map(LDR_Value, 34000, 50, 0, 100)“的34000和50,以及Moisture_Percent = _map(Moisture_Value, 17539, 7148, 0, 100)中17539和7148,换成标定值即可。
获取BLE蓝牙温湿度计的值
这并不在原本计划中,但我发现家用的温湿度计的精度能到小数点后3位(虽然我们在屏幕上是1位),而且个人感觉更准确,所以采用代码的方式获取蓝牙中的信息,通过不断探索,成功获取了温湿度计的值,代码在temperatureMOC.py中。
作品源码
(可下载的项目源码及说明,源码请上传到EEWorld下载中心,下载链接粘贴到作品文档和作品提交帖中)
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统 代码及相关文件-编程语言相关资料下载-EEWORLD下载中心
五、作品功能演示视频
(视频简介+链接,视频链接:可上传到EEWorld大学堂,观看链接粘贴到作品文档和作品提交帖中,也可直接上传到作品帖中)
植物情绪监测与交互系统功能演示。
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统-EEWORLD大学堂
六、项目总结
(项目文字总结+帖子分享链接汇总)
在本项目中,我设计并实现了一个植物情绪监测与交互系统。通过使用各种传感器和模块,我能够监测植物的土壤湿度、光照、温度和湿度,并通过彩色LCD模块展示植物的情绪状态。此外,我还实现了用户与植物的交互功能,当用户触碰植物叶片时,系统会判定植物情绪很好。
在项目中,我使用了Raspberry Pi 4B作为主控板,LM35温度传感器、LDR亮度传感器、土壤湿度传感器和ADS1115 ADC模块等作为传感器和模块。通过树莓派的蓝牙模块,我还能够获取家用BLE蓝牙温湿度计中的信息,从而更准确地判断植物的情绪状态。
通过本项目,我学到了很多关于植物情绪检测和交互设计的知识。尽管目前对于植物情绪状态的研究还不够深入,但我个人认为植物是拥有情绪的。通过这个项目,我能够更好地了解和关心植物的生长环境,从而提供更好的照顾和养护。
在项目中遇到了一些挑战,比如传感器的标定和数据处理等方面。通过不断的尝试和调试,我成功地解决了这些问题,并获得了满意的结果。
帖子分享链接:
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统,开箱~ - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统(开发第一周) - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)
Pyrhon获取小米蓝牙温湿度计中的数据信息 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统,不同表情动画 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)
【DigiKey“智造万物,快乐不停”创意大赛】树莓派驱动SPI协议的LCD屏,展示动态表情 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)
七、其他
作品提交文档:
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】树莓派驱动SPI协议的LCD屏,展示动态表情
本帖最后由 许大锤 于 2024-1-12 09:54 编辑
## 一、引言
在这篇文章中,我们将探讨如何利用树莓派的强大功能,结合SPI协议的LCD屏幕,来创建一个能显示动态表情的装置。
本文所有代码见[【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统](https://download.eeworld.com.cn/detail/%E8%AE%B8%E5%A4%A7%E9%94%A4/630752?u_atoken=2425c4110f81a841a636199f67abfd97&u_asession=014u4gQALPxpN7ytyW5FJ8crug2kSUXS4edktof7RObaZjVOVWPQCU6tiW-BixqukMdlmHJsN3PcAI060GRB4YZGyPlBJUEqctiaTooWaXr7I&u_asig=05Ju4pRRMDauGGVqy-c_gQE7Ol_K6HQBNHn_YtXFyr6_L00G8dZKxcTYlNbCV5Exe4UURK19hOo4oL_IPyMRbQbNsHrrBhiPo9_m9CV896bfCB5HfFoksTcQUZpCrC1uprvD5jbYvKA2ozrY4PkTdVuLE5lZd9rh-yutEFCeJFz5xg2QMxYs6lyXb1lFWKql56_4YxICx1iFg-yEQACd0mxXArXkJeQ7K2bSdUeD2m2m1lgF0jF3gtQzLqEc-Wy4Fwc2YVD0zX8dqKTbEGj-UVKhL8GhFz7FQUW1IT6IodSzUDBUI68plDLSuUmnNuPC0TLleCZk2CTPHc0PHO26mlZw&u_aref=X7Y0RGBZLdcpy%2BVTBub65EiCVq0%3D "【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统")中lib和emotion文件夹中的python文件。
## 二、硬件要求和设置
本项目需要以下硬件:树莓派(任何型号)、支持SPI协议的LCD屏幕以及适当的连接线。
连接LCD屏幕到树莓派的过程相对简单。首先,将屏幕的SPI接口连接到树莓派的GPIO针脚上,确保正确连接电源线和地线。
本文采用的树莓派4B,具体连线如下图:
## 三、软件设置
### 第1步:安装Raspbian操作系统
1. **下载Raspbian镜像**:访问树莓派官方网站下载最新版本的Raspbian操作系统镜像。
2. **准备SD卡**:使用SD卡格式化工具(如SD Card Formatter)格式化SD卡。
3. **写入Raspbian镜像**:使用镜像写入工具(如Balena Etcher)将Raspbian镜像写入SD卡。
4. **启动树莓派**:将SD卡插入树莓派,连接电源、显示器、键盘和鼠标,然后启动。
5. **基本设置**:按照屏幕上的提示完成基本设置,包括设置国家、语言、时区、Wi-Fi网络和密码等。
### 第2步:启用SPI接口
在树莓派上使用SPI接口的LCD屏幕之前,需要确保SPI接口已经启用。
1. **打开终端**:在树莓派的桌面环境中打开终端。
2. **运行配置工具**:输入以下命令启动树莓派配置工具:
```bash
sudo raspi-config
```
3. **启用SPI**:
- 在配置菜单中,选择“Interface Options”。
- 然后找到并选择“SPI”选项。
- 选择“Yes”来启用SPI接口。
- 确认更改并退出配置工具。
4. **重启树莓派**:更改生效前需要重启树莓派。
```bash
sudo reboot
```
### 第3步:安装LCD屏幕驱动和必要的软件库
- 确保Python已安装。树莓派通常预装了Python。
- 安装图形处理库,如Pillow和Pygame,用于处理和显示图像。
```bash
sudo apt-get update
sudo apt-get install python3-pip
pip3 install pillow pygame
```
## 四、将动图转换成多张单帧图片
### 第1步:获取动图
如果你可以自己做动图,那自然就有单帧的图片,但绝大多人并不掌握这个技能,所以需要我们找到一些没有版权的动图片进行转换。
我推荐去[花瓣网](https://huaban.com/ "花瓣网"),这里有丰富的设计资源,我找到一组动态表情,就以它做示范。
### 第2步:拆帧
网上有许多在线拆帧工具,我就以[在线GIF图片帧拆分工具](https://uutool.cn/gif2img/ "在线GIF图片帧拆分工具")就可以成功拆帧,把压缩包下载下来即可。
### 第3步:帧图片处理
从网上下载的动图往往尺寸并不满足LCD屏幕的需求,而且不同尺寸也的屏幕需要相应尺寸的屏幕才能有良好的显示,所以要对图片进行处理,我使用的是1.54寸屏幕,分辨率是240*240。
批量修改图片尺寸:
```python
from PIL import Image
import os
def resize_images(folder_path, new_width, new_height):
for filename in os.listdir(folder_path):
if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
img_path = os.path.join(folder_path, filename)
with Image.open(img_path) as img:
img = img.resize((new_width, new_height))
img.save(img_path)
# 使用示例
folder_path = 'path/to/your/folder' # 替换为你的图片文件夹路径
new_width = 240 # 新的宽度
new_height = 240 # 新的高度
resize_images(folder_path, new_width, new_height)
```
对于一些项目,需要的是24位图像,而动图可能是32位,需要批量修改图片位数:
```python
from PIL import Image
import os
def convert_and_replace_images(folder_path):
for filename in os.listdir(folder_path):
if filename.endswith(('.png', '.PNG')):
file_path = os.path.join(folder_path, filename)
with Image.open(file_path) as img:
# 转换为RGB格式(24位)
rgb_img = img.convert('RGB')
new_filename = os.path.splitext(filename)[0] + '.png'
new_file_path = os.path.join(folder_path, new_filename)
# 保存新图像并替换旧文件
rgb_img.save(new_file_path)
# 如果需要,删除原始PNG文件
os.remove(file_path)
# 使用示例
folder_path = 'path/to/your/folder' # 替换为你的文件夹路径
convert_and_replace_images(folder_path)
```
我们也可以更改动态表情的背景颜色,以下是白色转成黑色的示例:
```python
from PIL import Image
import os
def replace_white_background(folder_path):
for filename in os.listdir(folder_path):
if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
file_path = os.path.join(folder_path, filename)
with Image.open(file_path) as img:
data = img.getdata()
new_data = []
for item in data:
# 判断颜色是否足够接近白色
if item[0] > 200 and item[1] > 200 and item[2] > 200:
# 将白色替换为黑色
new_data.append((0, 0, 0, item[3]))
else:
new_data.append(item)
img.putdata(new_data)
img.save(file_path)
# 使用示例
folder_path = 'path/to/your/folder' # 替换为你的文件夹路径
replace_white_background(folder_path)
```
### 第4步:SPI驱动:
这部分网上有许多资料,这是我采用的方法:
```python
import os
import sys
import time
import spidev
import logging
import numpy as np
class RaspberryPi:
def __init__(self,spi=spidev.SpiDev(0,0),spi_freq=40000000,rst = 27,dc = 25,bl = 18,bl_freq=1000,i2c=None,i2c_freq=100000):
import RPi.GPIO
self.np=np
self.RST_PIN= rst
self.DC_PIN = dc
self.BL_PIN = bl
self.SPEED =spi_freq
self.BL_freq=bl_freq
self.GPIO = RPi.GPIO
#self.GPIO.cleanup()
self.GPIO.setmode(self.GPIO.BCM)
self.GPIO.setwarnings(False)
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
self.GPIO.setup(self.BL_PIN, self.GPIO.OUT)
self.GPIO.output(self.BL_PIN, self.GPIO.HIGH)
#Initialize SPI
self.SPI = spi
if self.SPI!=None :
self.SPI.max_speed_hz = spi_freq
self.SPI.mode = 0b00
def digital_write(self, pin, value):
self.GPIO.output(pin, value)
def digital_read(self, pin):
return self.GPIO.input(pin)
def delay_ms(self, delaytime):
time.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
if self.SPI!=None :
self.SPI.writebytes(data)
def bl_DutyCycle(self, duty):
self._pwm.ChangeDutyCycle(duty)
def bl_Frequency(self,freq):
self._pwm.ChangeFrequency(freq)
def module_init(self):
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
self.GPIO.setup(self.BL_PIN, self.GPIO.OUT)
self._pwm=self.GPIO.PWM(self.BL_PIN,self.BL_freq)
self._pwm.start(100)
if self.SPI!=None :
self.SPI.max_speed_hz = self.SPEED
self.SPI.mode = 0b00
return 0
def module_exit(self):
logging.debug("spi end")
if self.SPI!=None :
self.SPI.close()
logging.debug("gpio cleanup...")
self.GPIO.output(self.RST_PIN, 1)
self.GPIO.output(self.DC_PIN, 0)
self._pwm.stop()
time.sleep(0.001)
self.GPIO.output(self.BL_PIN, 1)
#self.GPIO.cleanup()
```
我们已经有了LCD驱动配置文件,接下来对不同尺寸的LCD进行适配。我以1.54寸屏幕举例:
```python
import time
from . import lcdconfig
class LCD_1inch54(lcdconfig.RaspberryPi):
width = 240
height = 240
def command(self, cmd):
self.digital_write(self.DC_PIN, self.GPIO.LOW)
self.spi_writebyte([cmd])
def data(self, val):
self.digital_write(self.DC_PIN, self.GPIO.HIGH)
self.spi_writebyte([val])
def reset(self):
"""Reset the display"""
self.GPIO.output(self.RST_PIN,self.GPIO.HIGH)
time.sleep(0.01)
self.GPIO.output(self.RST_PIN,self.GPIO.LOW)
time.sleep(0.01)
self.GPIO.output(self.RST_PIN,self.GPIO.HIGH)
time.sleep(0.01)
def Init(self):
"""Initialize dispaly"""
self.module_init()
self.reset()
self.command(0x36)
self.data(0x70) #self.data(0x00)
self.command(0x3A)
self.data(0x05)
self.command(0xB2)
self.data(0x0C)
self.data(0x0C)
self.data(0x00)
self.data(0x33)
self.data(0x33)
self.command(0xB7)
self.data(0x35)
self.command(0xBB)
self.data(0x19)
self.command(0xC0)
self.data(0x2C)
self.command(0xC2)
self.data(0x01)
self.command(0xC3)
self.data(0x12)
self.command(0xC4)
self.data(0x20)
self.command(0xC6)
self.data(0x0F)
self.command(0xD0)
self.data(0xA4)
self.data(0xA1)
self.command(0xE0)
self.data(0xD0)
self.data(0x04)
self.data(0x0D)
self.data(0x11)
self.data(0x13)
self.data(0x2B)
self.data(0x3F)
self.data(0x54)
self.data(0x4C)
self.data(0x18)
self.data(0x0D)
self.data(0x0B)
self.data(0x1F)
self.data(0x23)
self.command(0xE1)
self.data(0xD0)
self.data(0x04)
self.data(0x0C)
self.data(0x11)
self.data(0x13)
self.data(0x2C)
self.data(0x3F)
self.data(0x44)
self.data(0x51)
self.data(0x2F)
self.data(0x1F)
self.data(0x1F)
self.data(0x20)
self.data(0x23)
self.command(0x21)
self.command(0x11)
self.command(0x29)
def SetWindows(self, Xstart, Ystart, Xend, Yend):
#set the X coordinates
self.command(0x2A)
self.data(0x00) #Set the horizontal starting point to the high octet
self.data(Xstart & 0xff) #Set the horizontal starting point to the low octet
self.data(0x00) #Set the horizontal end to the high octet
self.data((Xend - 1) & 0xff) #Set the horizontal end to the low octet
#set the Y coordinates
self.command(0x2B)
self.data(0x00)
self.data((Ystart & 0xff))
self.data(0x00)
self.data((Yend - 1) & 0xff )
self.command(0x2C)
def ShowImage(self,Image):
"""Set buffer to value of Python Imaging Library image."""
"""Write display buffer to physical display"""
imwidth, imheight = Image.size
print(f"Image{imwidth} and {imheight}")
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display \
({0}x{1}).' .format(self.width, self.height))
img = self.np.asarray(Image)
pix = self.np.zeros((self.width,self.height,2), dtype = self.np.uint8)
pix[...,[0]] = self.np.add(self.np.bitwise_and(img[...,[0]],0xF8),self.np.right_shift(img[...,[1]],5))
pix[...,[1]] = self.np.add(self.np.bitwise_and(self.np.left_shift(img[...,[1]],3),0xE0),self.np.right_shift(img[...,[2]],3))
pix = pix.flatten().tolist()
self.SetWindows ( 0, 0, self.width, self.height)
self.digital_write(self.DC_PIN,self.GPIO.HIGH)
for i in range(0,len(pix),4096):
self.spi_writebyte(pix[i:i+4096])
def clear(self):
"""Clear contents of image buffer"""
_buffer = [0xff]*(self.width * self.height * 2)
self.SetWindows ( 0, 0, self.width, self.height)
self.digital_write(self.DC_PIN,self.GPIO.HIGH)
for i in range(0,len(_buffer),4096):
self.spi_writebyte(_buffer[i:i+4096])
```
如果换其他尺寸,例如是1.47,则修改分辨率和senWindows函数即可。
```python
width = 172
height = 320
#----略-----#
def SetWindows(self, Xstart, Ystart, Xend, Yend):
#set the X coordinates
self.command(0x2A)
self.data((Xstart)>>8& 0xff) #Set the horizontal starting point to the high octet
self.data((Xstart+34) & 0xff) #Set the horizontal starting point to the low octet
self.data((Xend-1+34)>>8& 0xff) #Set the horizontal end to the high octet
self.data((Xend-1+34) & 0xff) #Set the horizontal end to the low octet
#set the Y coordinates
self.command(0x2B)
self.data((Ystart)>>8& 0xff)
self.data((Ystart) & 0xff)
self.data((Yend-1)>>8& 0xff)
self.data((Yend-1) & 0xff)
self.command(0x2C)
```
对于绝大多尺寸在代码文件中都有适配。
## 五、运行
实现代码:
```python
import os
import sys
import logging
import spidev as SPI
sys.path.append("..")
from lib import LCD_1inch54
from PIL import Image,ImageDraw,ImageFont
import socket
# Raspberry Pi pin configuration:
RST = 27
DC = 25
BL = 18
bus = 0
device = 0
logging.basicConfig(level=logging.DEBUG)
directory = os.getcwd()
doInterrupt = 0
showOn = 0
def show(emotion):
global doInterrupt, showOn, disp
try:
disp = LCD_1inch54.LCD_1inch54(spi=SPI.SpiDev(bus, device),spi_freq=90000000,rst=RST,dc=DC,bl=BL)
disp.Init() # Initialize library.
#disp.clear() # Clear display.
bg = Image.new("RGB", (disp.width, disp.height), "BLACK")
draw = ImageDraw.Draw(bg)
# display with hardware SPI:
for i in range(180):
if (doInterrupt==1):
doInterrupt = 0
break
else:
image = Image.open(directory+'/emotion/'+emotion+'/frame'+str(i)+'.png')
image = image.rotate(180)
disp.ShowImage(image)
showOn = 0
disp.module_exit()
logging.info("quit:")
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
disp.module_exit()
logging.info("quit:")
exit()
def main():
while True:
global doInterrupt, showOn
previousData = 'freeze'
show('savory')
```
[localvideo]adc38523cca37a336916eb6f3b170eb3[/localvideo]
-
发表了日志:
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统,不同表情动画
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统,不同表情动画
本帖最后由 许大锤 于 2024-1-12 09:54 编辑
[localvideo]93bc847a912615a6b43e4e6f84d36d96[/localvideo]
[localvideo]7a6b5f8f35d0c6a5ca9bee7c989f1e33[/localvideo]
[localvideo]7642a4dfc3c90ebd896721a5ef889ef7[/localvideo]
[localvideo]b1fd0680f30d9cb81902e1013c3f7de3[/localvideo]
[localvideo]1d2db7abe8ec4a9c682fc262d0a00c66[/localvideo]
[localvideo]8334c00593ae137d3abccd92f705fb1e[/localvideo]
情绪来源:LM35 Temperatures sensor,LDR module,Moisture sensor和触碰植物。
彩色LCD生动地展现情绪(60帧动图):
Thirsty:每当土壤湿度对植物来说太低时。
Hot:温度过高时。
Freeze:温度太低时。
Sleepy:光线第的时候。
Savory:给植物浇水(土壤湿度快速升高)。
Happy:白天且环境适宜植物生长,或者人触碰植物叶片时。
这里视频不知道怎么,上传多个可能不太行,具体动画可见【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统-EEWORLD大学堂,表情动画在视频末尾。
-
发表了主题帖:
Pyrhon获取小米蓝牙温湿度计中的数据信息
本帖最后由 许大锤 于 2024-1-12 09:53 编辑
我的温湿度计是秒秒蓝牙温湿度计(MHO-C401),和小米是一样的。
1. 环境配置
首先,确保您的树莓派的操作系统(如Raspberry Pi OS)是最新的,并且蓝牙功能是启用的。安装必要的蓝牙相关工具和库:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
2. 安装Python库
使用Python来编写脚本。首先,安装Python及必要的库,如bluepy,这是一个Python模块,用于与蓝牙LE设备通信。
sudo apt-get install python3-pip
pip3 install bluepy
3. 扫描蓝牙设备
编写一个简单的Python脚本来扫描周围的蓝牙设备,以找到秒秒蓝牙温湿度计的MAC地址。下面是一个基本的示例:
from bluepy.btle import Scanner
scanner = Scanner()
devices = scanner.scan(10.0) # 扫描10秒
for dev in devices:
print("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))
for (adtype, desc, value) in dev.getScanData():
print(" %s = %s" % (desc, value))
结果:
sudo python3 blue.py
Device 61:ad:7b:8c:03:bd (random), RSSI=-70 dB
Flags = 1a
Manufacturer = 4c000c0e083c5c0762c09c6fc77e15aa223010064b1d62288c18
Device 6d:e0:8f:a6:ac:59 (random), RSSI=-69 dB
Flags = 1a
Manufacturer = 4c0009081302c0a800051b58
Device 63:c6:21:60:56:2c (random), RSSI=-77 dB
Flags = 1a
Manufacturer = 4c000c0e083c5c0762c09c6fc77e15aa223010064b1d62288c18
Device 7a:93:04:3d:5e:cf (random), RSSI=-75 dB
Flags = 1a
Tx Power = 11
Manufacturer = 4c001006471d1cc1f568
Device 79:c9:33:67:86:46 (random), RSSI=-76 dB
Flags = 1a
Manufacturer = 4c0010050318b52fab
Device a4:c1:38:6c:9c:96 (public), RSSI=-85 dB
Flags = 06
16b Service Data = 95fe30588703a7969c6c38c1a408
Complete Local Name = MHO-C401
Device e1:3b:d1:16:0e:e2 (random), RSSI=-68 dB
Manufacturer = 4c0012020002
Device c6:a0:73:ab:c1:ae (random), RSSI=-76 dB
Manufacturer = 4c0012020001
Device 04:e2:29:b3:4a:e7 (public), RSSI=-98 dB
Flags = 06
0x1c = 00
Manufacturer = 290910000004e229b34ae60100e903
这里“a4:c1:38:6c:9c:96”就是我的“秒秒测蓝牙温湿度计”
4. 连接和读取数据
找到秒秒蓝牙温湿度计的MAC地址后,您需要编写代码来连接设备并读取数据。这可能需要一些尝试和错误,因为您需要知道正确的服务和特性UUID来读取数据。这些信息可能在设备的文档中或者需要通过一些实验来确定。
这里提供一个基本的框架,但请注意,您可能需要调整服务和特性的UUID:
from bluepy.btle import Peripheral
try:
p = Peripheral("a4:c1:38:6c:9c:96", "public")
# 您可能需要根据实际情况更改服务和特性的UUID
services = p.getServices()
for service in services:
print(service)
# 假设您找到了正确的服务和特性
# characteristic = p.getCharacteristics(uuid='特性的UUID')[0]
# if characteristic.supportsRead():
# while True:
# data = characteristic.read()
# print(data)
# time.sleep(1)
finally:
p.disconnect()
结果:
Service <uuid=Generic Access handleStart=1 handleEnd=7>
Service <uuid=Generic Attribute handleStart=8 handleEnd=11>
Service <uuid=Device Information handleStart=12 handleEnd=24>
Service <uuid=Battery Service handleStart=25 handleEnd=28>
Service <uuid=00010203-0405-0607-0809-0a0b0c0d1912 handleStart=29 handleEnd=32>
Service <uuid=ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6 handleStart=33 handleEnd=78>
Service <uuid=fe95 handleStart=79 handleEnd=98>
Service <uuid=00000100-0065-6c62-2e74-6f696d2e696d handleStart=99 handleEnd=107>
这些输出显示了您连接的蓝牙设备提供的服务列表。每个服务由一个UUID(Universally Unique Identifier)标识,而且每个服务都有一个起始和结束句柄。这些服务可能包括设备信息、电池服务和其他特定于设备的服务。
以下是您列出的一些服务的可能含义:
Generic Access (UUID: Generic Access): 这是标准的蓝牙服务,用于提供设备的基本信息,例如名称和可见性。
Generic Attribute (UUID: Generic Attribute): 这个服务负责管理设备上的服务和特性的发现。
Device Information (UUID: Device Information): 这个服务通常包含设备的制造商名称、型号、序列号等信息。
Battery Service (UUID: Battery Service): 提供有关设备电池状态的信息,如电量百分比。
其他服务 (UUID: 特定值): 这些服务可能是特定于设备的,例如用于传输特定数据(例如温湿度数据)的自定义服务。特别是UUID为ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6的服务可能是与您的秒秒蓝牙温湿度计相关的关键服务。
为了获取温湿度数据,您需要进一步探索与UUID ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6 对应的服务。这个服务下可能有特定的特性(Characteristics),这些特性存储了温度和湿度的实际数据。
接下来,您可以使用 getCharacteristics() 方法来列出此服务下的所有特性,并尝试读取这些特性来查找包含温湿度数据的特性。代码示例可能如下:
service_uuid = "ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"
svc = p.getServiceByUUID(service_uuid)
characteristics = svc.getCharacteristics()
for char in characteristics:
print("Characteristic %s" % char)
print(" - UUID: %s" % char.uuid)
print(" - Handle: %s" % char.getHandle())
print(" - Properties: %s" % char.propertiesToString())
# 尝试读取特性
if char.supportsRead():
try:
value = char.read()
print(" - Value: %s" % value)
except Exception as e:
print("Error reading characteristic: %s" % str(e))
这个脚本将遍历指定服务下的所有特性,并尝试读取它们的值。您需要根据实际情况解析这些值来获取温度和湿度数据。请注意,这可能需要一些试验和错误,因为需要确定哪个特性包含了您需要的数据。
Characteristic Characteristic <ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 35
- Properties: READ WRITE
Characteristic Characteristic <ebe0ccb9-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccb9-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 38
- Properties: READ
Characteristic Characteristic <ebe0ccba-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccba-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 41
- Properties: READ WRITE
Characteristic Characteristic <ebe0ccbb-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccbb-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 44
- Properties: READ
Characteristic Characteristic <ebe0ccbc-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccbc-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 47
- Properties: NOTIFY
Characteristic Characteristic <ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 51
- Properties: READ WRITE
Characteristic Characteristic <ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 54
- Properties: READ NOTIFY
Characteristic Characteristic <ebe0ccc4-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccc4-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 58
- Properties: READ
Characteristic Characteristic <ebe0ccc8-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccc8-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 61
- Properties: WRITE
Characteristic Characteristic <ebe0ccd1-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccd1-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 64
- Properties: WRITE
Characteristic Characteristic <ebe0ccd4-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccd4-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 67
- Properties: WRITE
Characteristic Characteristic <ebe0ccd7-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccd7-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 70
- Properties: READ WRITE
Characteristic Characteristic <ebe0ccd8-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccd8-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 73
- Properties: WRITE
Characteristic Characteristic <ebe0ccd9-7a0a-4b0c-8a1a-6ff2997da3a6>
- UUID: ebe0ccd9-7a0a-4b0c-8a1a-6ff2997da3a6
- Handle: 76
- Properties: WRITE NOTIFY
每个特性都有一个唯一的UUID、句柄(Handle)以及一组属性(如 READ, WRITE, NOTIFY 等)。
现在,需要确定哪个特性包含温度和湿度数据。基于这些特性的属性,我们可以进行一些推断:
READ 属性的特性可用于读取数据。对于温湿度计来说,温度和湿度数据很可能是可以读取的。
NOTIFY 属性的特性可能用于实时更新数据。当温度或湿度发生变化时,设备可能会通过这些特性发送通知。
WRITE 属性的特性可能用于更改设备的设置或配置。
要找到包含温湿度数据的特性,您可以尝试读取那些具有 READ 属性的特性。例如:
characteristics = svc.getCharacteristics()
for char in characteristics:
if "READ NOTIFY" in char.propertiesToString():
try:
value = char.read()
print(f"Characteristic {char.uuid} Value: {value}")
except Exception as e:
print(f"Error reading characteristic {char.uuid}: {e}")
利用BLE助手进行分析,尝试有“NOTIFY,READ”不同的通知,分析结果。
接收到的数据 52 09 1F 89 0A 注意大小端 数据转为10进制 09 52->2386->即23.86摄氏度 1f->31->湿度31% 0A 89->26.97->电池电压26.97 mv
----------- 数据来源
UUID:ebe0ccc1-7a0a-4b0c-8a1a-6ff-2997da3a6 Properties:READ NOTIFY
import time
from bluepy import btle
from dataclasses import dataclass
mac = "a4:c1:38:6c:9c:96"
@dataclass
class Result:
temperature: float
humidity: int
voltage: float
battery: int = 0
class Measure(btle.DefaultDelegate):
def __init__(self, params):
btle.DefaultDelegate.__init__(self)
self.temperature = None
def handleNotification(self, cHandle, data):
try:
result = Result(0, 0, 0, 0)
temp = int.from_bytes(data[0:2], byteorder='little', signed=True) / 100
humidity = int.from_bytes(data[2:3], byteorder='little')
voltage = int.from_bytes(data[3:5], byteorder='little') / 1000
battery = round((voltage - 2) / (3.261 - 2) * 100, 2)
result.temperature = temp
result.humidity = humidity
result.voltage = voltage
result.battery = battery
print(result)
self.temperature = result.temperature
except Exception as e:
print(e)
class Connect:
def __init__(self):
self.measure = Measure("mijia")
def connect(self):
self.measure.temperature = None
p = btle.Peripheral(mac)
p.writeCharacteristic(0x0038, b'\x01\x00', True)
p.writeCharacteristic(0x0046, b'\xf4\x01\x00', True)
self.measure = Measure("mijia")
p.withDelegate(self.measure)
return p
def getTemperature(self):
return self.measure.temperature
if __name__ == '__main__':
while True:
p = Connect().connect()
time.sleep(1)
if p.waitForNotifications(3000):
p.disconnect()
-
发表了日志:
Pyrhon获取小米蓝牙温湿度计中的数据信息
-
上传了资料:
【DigiKey“智造万物,快乐不停”创意大赛】植物情绪监测与交互系统 代码及相关文件