鼠标传感器改造成扫描器,谁能根据描述给我给一个教程

2020-01-22 12:01发布

原帖在http://www.bidouille.org/hack/mousecam


光电鼠标拍摄

OK,所以最后决定让我的手在Arduino平台上,看到所有的嗡嗡声是真的。我必须说,我留下深刻的印象。这是迄今为止我所见过的大多数开发人员友好的开发平台。它的主要优点:

这很简单。硬件是非常简单的,并使用标准的,通常可用的组件。的软件IDE是基本的,但功能:编辑器窗口,状态窗口,集成了串行终端。就是这样。
这是相当强大的。Arduino的diecimilla,我用基于ATmega168微控制器时钟频率为16MHz。
它是基于开放源码硬件和软件(如果你省略了商标争议商标的Arduino)。电路板设计是公开的。这导致了创造的几个变种和的克隆(Freeduino)的平台的普及做出了贡献。
电源,固件更新和串行通信通过一个单一的USB电缆。
它的可扩展性。Arduino板的主要之上,可堆叠的“盾牌”的概念是天才:)作为一个事实上,一个小的原型盾的第一件事是我做了这个平台。
所以,前一段时间,我遇到了这个伟大的光电鼠标黑客雪碧。我决定,这将是巨大的做我的第一个Arduino的项目(超越“Blinky LED”的例子,那是。)

第一步,剥离的无线鼠标便宜的台风无线鼠标/键盘组合。



ADNS-2051针        Arduino的脚
1 SCLK        数字2
16 SDIO        数字3
15 PD        数字4
13 VDD        +5 V
12 GND        GND



#define SCLK 2
#define SDIO 3
#define PD 4

#define REG_PRODUCT_ID 0x00
#define REG_REVISION_ID 0x01
#define REG_MOTION 0x02
#define REG_DELTA_X 0x03
#define REG_DELTA_Y 0x04
#define REG_SQUAL 0x05
#define REG_AVERAGE_PIXEL 0x06
#define REG_MAXIMUM_PIXEL 0x07
#define REG_CONFIG_BITS 0x0A
#define REG_DATA_OUT_LOWER 0x0C
#define REG_DATA_OUT_UPPER 0x0D
#define REG_SHUTTER_LOWER 0x0E
#define REG_SHUTTER_UPPER 0x0F
#define REG_FRAME_PERIOD_LOWER 0x10
#define REG_FRAME_PERIOD_UPPER 0x11

int dumpWidth = 256; // Number of pixels to read for each frame.
byte frame[256];

void setup() {
  Serial.begin(115200);

  reset();
  byte productId = readRegister(REG_PRODUCT_ID);
  byte revisionId = readRegister(REG_REVISION_ID);
  Serial.print("Found productId ");
  Serial.print(productId, HEX);
  Serial.print(", rev. ");
  Serial.print(revisionId, HEX);
  Serial.println(productId == 0x02 ? " OK." : " Unknown productID. Carry on.");

  byte config = readRegister(REG_CONFIG_BITS);
  config |= B00000001; // Don't sleep (LED always powered on).
  writeRegister(REG_CONFIG_BITS, config);
}

void loop() {
  // Allows to set the dump window by sending the number of lines to read via the serial port.
  if(Serial.available() > 0) {
    dumpWidth = 16 * Serial.read();
    dumpWidth = constrain(dumpWidth, 0, 256);
  }

  readRegister(REG_MOTION); // Freezes DX and DY until they are read or MOTION is read again.
  char dx = readRegister(REG_DELTA_X);
  char dy = readRegister(REG_DELTA_Y);
  Serial.print("DELTA:");
  Serial.print(dx, DEC);
  Serial.print(" ");
  Serial.println(dy, DEC);

  if( dumpWidth > 0 )
    dumpFrame();
}

void dumpFrame() {
  byte config = readRegister(REG_CONFIG_BITS);
  config |= B00001000; // PixDump
  writeRegister(REG_CONFIG_BITS, config);

  int count = 0;
  do {
    byte data = readRegister(REG_DATA_OUT_LOWER);
    if( (data & 0x80) == 0 ) { // Data is valid
      frame[count++] = data;
    }
  }
  while (count != dumpWidth);

  config = readRegister(REG_CONFIG_BITS);
  config &= B11110111;
  writeRegister(REG_CONFIG_BITS, config);

  Serial.print("FRAME:");
  for(int i = 0; i < dumpWidth; i++) {
    byte pix = frame;
    if( pix < 0x10 )
      Serial.print("0");
    Serial.print(pix, HEX);
  }
  Serial.println();
}

void reset() {
  pinMode(SCLK, OUTPUT);
  pinMode(SDIO, INPUT);
  pinMode(PD, OUTPUT);
  digitalWrite(SCLK, LOW);
  digitalWrite(PD, HIGH);
  delayMicroseconds(1);
  digitalWrite(PD, LOW);
}

byte readRegister(byte address) {
  pinMode (SDIO, OUTPUT);

  for (byte i=128; i >0 ; i >>= 1) {
    digitalWrite (SCLK, LOW);
    digitalWrite (SDIO, (address & i) != 0 ? HIGH : LOW);
    digitalWrite (SCLK, HIGH);
  }

  pinMode (SDIO, INPUT);

  delayMicroseconds(100); // tHOLD = 100us min.

  byte res = 0;
  for (byte i=128; i >0 ; i >>= 1) {
    digitalWrite (SCLK, LOW);
    digitalWrite (SCLK, HIGH);
    if( digitalRead (SDIO) == HIGH )
      res |= i;
  }

  return res;
}

void writeRegister(byte address, byte data) {
  address |= 0x80; // MSB indicates write mode.
  pinMode (SDIO, OUTPUT);

  for (byte i = 128; i > 0 ; i >>= 1) {
    digitalWrite (SCLK, LOW);
    digitalWrite (SDIO, (address & i) != 0 ? HIGH : LOW);
    digitalWrite (SCLK, HIGH);
  }

  for (byte i = 128; i > 0 ; i >>= 1) {
    digitalWrite (SCLK, LOW);
    digitalWrite (SDIO, (data & i) != 0 ? HIGH : LOW);
    digitalWrite (SCLK, HIGH);
  }

  delayMicroseconds(100); // tSWW, tSWR = 100us min.
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
18条回答
Argee
1楼-- · 2020-01-23 06:24
这是个比较好玩儿的过程,其实你也可以用单点的图像和成理解(允许我这么说吧,我说事总是很拗口,表达能力不好)
相当于鼠标还是正常工作,不过在光学部件的输出,并联了另外一个采样器——Arduino。
鼠标的移动,被java程序捕获,你就得到了XY,而光学输出,被Arduino采样,并解析数据桢,就可以在那个点画个16x16的小图,你的鼠标不停移动,就完成了扫描。如果图片很大,你想象下,用个反射的光对管,粘在鼠标上,移动的同时,采样光对管的输出,你也可以画个图出来。调个焦,光斑足够小,移动足够慢,也许,画出来的图不必他差:1个点,就不存在扭动的偏差了。
供你参考。
669911
2楼-- · 2020-01-23 10:09
 精彩回答 2  元偷偷看……
QQ798533792
3楼-- · 2020-01-23 15:25
好高级呀 学习啦
Friendz
4楼-- · 2020-01-23 17:01
光电鼠标的芯片,本身就是个高帧率的摄像芯片,有些芯片能查到说明书。 不过楼主的问题答不上来。
Argee
5楼-- · 2020-01-23 19:37
本帖最后由 Argee 于 2013-2-18 04:03 编辑

好吧,我来详细解释一下,可能不对,欢迎指正。
1,鼠标
从软件和硬件上,鼠标被复用了。它既是扫描(XY移动)的驱动器,也是图像采集采集器。
2,Arduino
它只完成图像采集后的传输,(编辑增加),说传输,不如说是截获,因为正常的鼠标功能,鼠标不需要把小图像传回PC,只告诉PC关于移动的信息。

软件结构是这样的,无论是Java还是什么语言,比如用最简单的excel VBA好了,如果他同时可以和Arduino接口的话(dll调用或者什么),整个过程和你写一个画图板程序没什么两样。
1,找到一个容器控件,能响应windows mouse move消息,通常一个对话窗,或者图片控件
2,添加响应windows mouse move的消息响应函数,此时的windows消息参数本身就包括我们需要绘图的中心点XY(当然你也可以认为是左上点,只要全局算法一致就行)
3,从Arduino读回像素点,然后把1维的线性数据,排成方阵,这个程序,就用逐点画就好了,不用建立内部的小16x16图片
4,检查下一个mouse move和当前的关系,比如,你X,Y都在8像素以外才开始画这也是循环操作的标准。(这句写得不好,不用看了)

一个个人观点,这个方案比较讨巧,用了无线鼠标,看上去,好像鼠标不工作了,其实,他没有破坏原有的鼠标功能,你用一个有线鼠标,也同样能完成。不过,你看到拖了2个数据线,你会觉得设计的没那么棒。
Argee
6楼-- · 2020-01-23 20:24
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)


Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    Dim hdc As Long, i As Single
   
    hdc = GetDC(FindWindow(vbNullString, Me.Caption))
    If Button > 0 Then
        Ellipse hdc, X, Y, X + 1, Y + 1
    End If
End Sub

一周热门 更多>