买了个能转的显示器当副屏, 然后因为买的太便宜, 没有带旋转感应的(不知道别的有没有).
然后觉得好像不大方便, 就想着写一个脚本, 能够一键切换屏幕旋转状态.
最后配合 MultiMonitorTool 的加载配置文件功能实现了一键切换布局.
我找到了内心的平静.
直到我发现, 这实在是太蠢了.
我每次都要找到脚本在哪, 再双击他切换布局.
于是我找了一个右键菜单编辑器, 把这个脚本放进了桌面的右键菜单里.
然后在桌面右键点击两次就能切换旋转状态.
我找到了内心的平静.
直到我发现, 这实在是太蠢了.
为什么不能直接根据实际状态旋转呢?
(x
DIY 这样一个东西, 大约需要 30 来块钱.
我买了一块已经焊好 USB 的 CH341A 和一块 MMA8452Q 模块, 某宝大约二十拿下.
然后再买了一些很长的杜邦线(因为要把 CH341 藏到桌子下面), 这样一共就花了三十多.
把 CH341 调成 3.3v 输出和 I2C 模式, 接上 MMA8452 的 4 根 I2C 针脚.
然后用装上 CH341 的 I2C 模式驱动:驱动
从里面找到CH341DLL.DLL
, 之后要用.
使用测试工具验证连接是否正确, 驱动是否安装成功: CH341 测试工具
找到压缩包内的CH341PAR\VC\CH341PAR.EXE
, 然后再把之前从驱动压缩包里翻出来的CH341DLL.DLL
放在一起.
运行CH341PAR.EXE
, 切换到 EEPROM 配置.
按照文档说明, 只接四根线的话, MMA8452 的设备地址应该是0x1c
: MMA8452 文档
然后在0x0d
上能够读取的 MMA8452 的 WHO_AM_I 信息: 0x2a
到这里硬件部分算是连接成功了.
然后编写代码轮询传感器, 获取屏幕旋转状态并通过 MultiMonitorTool 自动切换布局.
MultiMonitorTool
从刚刚的 CH341 测试工具包里可以找到CH341DLL.h
和CH341DLL.lib
代码仅供参考, 我一个写 JS 的, 写出来的玩意能跑就行.
#include <windows.h>
#include <stdio.h>
#include <signal.h>
#include "CH341DLL.H"
#define DEVICE_ADDR 0x1c // MMA8452 设备地址
#define DEVICE_ID 0 // CH341 设备编号
#define getbit(x, y) ((x) >> (y)&1)
// 检查设备状态并自动初始化重连
int CheckDevice(int DeviceId) {
UCHAR read = 0;
// 尝试读取 MMA8452 的 WHO_AM_I 信息
if (!CH341ReadI2C(DeviceId, DEVICE_ADDR, 0x0d, &read)) {
// 如果读不到, 尝试重新打开 CH341, 并再次尝试读取 WHO_AM_I 信息
CH341CloseDevice(DeviceId);
if (CH341OpenDevice(DeviceId) == INVALID_HANDLE_VALUE || !CH341ReadI2C(DeviceId, DEVICE_ADDR, 0x0d, &read)) {
printf("Failed to open device #%d.\n", DeviceId);
return 0;
} else {
printf("Opened device #%d.\n", DeviceId);
}
}
// 根据读到的 WHO_AM_I 信息检查模块是否为 MMA8452, 如果没连接模块应该读到 0xFF
if (read != 0x2a) {
puts("Invalid device WHO_AM_I response.");
return 0;
}
// 读取模块状态
if (!CH341ReadI2C(DeviceId, DEVICE_ADDR, 0x2a, &read)) {
printf("Device #%d closed unexpected.\n", DeviceId);
return 0;
}
// 如果模块没有被启用
if (read != 0x01) {
if(
!CH341WriteI2C(DeviceId, DEVICE_ADDR, 0x2a, 0b00000000) // 禁用模块(必须禁用掉模块才能调整模块设置)
|| !CH341WriteI2C(DeviceId, DEVICE_ADDR, 0x11, 0b11000000) // 启用旋转方向检测
|| !CH341WriteI2C(DeviceId, DEVICE_ADDR, 0x2a, 0b00000001) // 启用模块
|| (!CH341ReadI2C(DeviceId, DEVICE_ADDR, 0x2a, &read) || read != 0x01) // 检查模块是否被正确启用
) {
printf("Failed to initialize device #%d.\n", DeviceId);
return 0;
} else {
printf("Device #%d initialized successfully.\n", DeviceId);
}
}
return 1;
}
int main() {
UCHAR mBuffer = 0;
UCHAR Last = 255;
UCHAR Curr = 255;
if (LoadLibrary("CH341DLL.DLL") == NULL) {
puts("Cannot load required Dynamic Library CH341DLL.DLL.");
return -1;
}
while (1) {
Sleep(1000);
if (!CheckDevice(DEVICE_ID)) {
continue;
}
// 读取模块旋转状态
if (!CH341ReadI2C(0, DEVICE_ADDR, 0x10, &mBuffer) || mBuffer == 0xff) {
puts("Device disconnected unexpected.");
continue;
}
// 取出数据
// 我的显示器只能旋转 90 度, 于是偷懒只取出了表示横屏还是竖屏的数据位
// 如果有需要, 可以根据文档取得更多数据
// 此数据第 2 位表示横屏竖屏
// 第 1 位表示旋转方向
// 这两位结合可以判断屏幕的四向旋转
// 具体请参考 MMA8452 文档对于 0x10 数据的解释
Curr = getbit(mBuffer, 2);
if (Curr != Last) {
if (Curr == 0) {
system("MultiMonitorTool.exe /LoadConfig landscape.cfg"); // 用 MMT 加载预先写好的显示器布局配置文件
} else {
system("MultiMonitorTool.exe /LoadConfig portrait.cfg");
}
}
Last = Curr;
}
}
代码必须使用 VC 去编译, 因为 CH341DLL.dll 就是用的 VC, mingw 弄半天发现跑不起来就是这个操蛋原因.
把编译出来的东西跟 MultiMonitorTool 还有 CH341DLL.dll 放在一起, 就能使用了.
编译的成品有需要可以分享出来, 但是写了这么久还是有点懒了, 晚点再传吧.
把模块粘在显示器背后, 再把这个轮询程序放到后台, 非常完美. 纯 C 编写的工具占用也非常小, 挂后台 0.3M 的内存占用, 基本不吃米.
1
Kawa OP 这玩意属于是玩具的性质, 集成度不高, 不是很耐操, 裸板裸线 USB 接口也没固定, 但是可以用.
插到机箱后面之类的地方八百年碰不着, 损坏是不大可能, 但是得考虑粘在显示器背后的模块不掉下来. 关于轮询的问题, 我在群里聊这个的时候, 群友说轮询属实不大优雅, MMA8452 提供了两个可编程中断啥的... 没怎么听懂也不大理解, 感觉像是事件监听之类的吧, 但是毕竟 1s 一次的轮询也吃不了多少米, 我做的这个玩意对功耗要求不是很严格, 轮询问题也不大.png |
2
hs0000t 2022-04-29 00:52:38 +08:00 via Android
真不错,之前也想过要不要做个类似的工作,后来把转屏打包成了个快捷键就结束了,没有到定制硬件的程度
顺便建议不要学某 up 主的风格说话,容易招来不必要的麻烦 |
3
snoopyhai 2022-04-29 08:58:28 +08:00
非技术党, 纯幻想.
显示器从横向转到纵向是不是需要人手去掰? 那把你外置的感应器换成一个按钮. 每次掰完显示器顺手按一下, 是不是可以解决轮询问题? |
4
Cheons 2022-04-29 10:13:43 +08:00 via Android
伪需求,屏幕懒得动。直接上两个屏幕
|
6
Kawa OP |
7
snoopyhai 2022-04-29 12:26:33 +08:00 1
|
8
dongpengfei1 2022-05-03 13:53:15 +08:00
改用霍尔检测,被动接收,这个比重力感应稳定多了
|
9
Kawa OP @dongpengfei1 霍尔只能检测两个方向吧, 利用重力传感器能检查四向, 不过我这个需求里只需要两个方向, 用霍尔也不是不行.
用霍尔的话, 对于塑料件是不是需要装配额外的装置去触发传感器呢? 经过我连续四天的使用, 我没有感觉到重力传感器有什么不精确的地方, 用起来还是很舒服的. 在成本相近的情况下, 我觉得符合直觉 安装方便的重力传感器确实更好. |