鼠标宏系列之二-光电鼠标设计案例

我们会从一个真实的鼠标设计案例开始,来看看一个真实的光电鼠标是什么样子的,在文章的最后我会将鼠标项目打包上传到资源部分。

这个方案主要使用了adns2620芯片,这个芯片是光电传感器的集成芯片,方案中也有PCB图以及对应的程序代码,PCB结构之类的和本系列无关,就不去一一赘述了,我们主要看代码部分。

fireware代码如下:

/* 自动捕获鼠标坐标 */
static void getMouseMovement(void)
{
	reportBuffer.dx = -read(DELTA_X_REG);
	reportBuffer.dy = read(DELTA_Y_REG);
}

/* ------------------------------------------------------------------------- */

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
    usbRequest_t    *rq = (void *)data;

    // 以下请求从未使用过。但由于它们是规范,我们在这个例子中实现了它们。

    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)
    {    
        // 类请求类型
        DBG1(0x50, &rq->bRequest, 1);   
        // 调试输出: 打印请求 
        if(rq->bRequest == USBRQ_HID_GET_REPORT)
        {   
            // wValue:ReportType(高字节),ReportID(低字节)
            usbMsgPtr = (void *)&reportBuffer;
            return sizeof(reportBuffer);
        }
        else if(rq->bRequest == USBRQ_HID_GET_IDLE)
        {
            usbMsgPtr = &idleRate;
            return 1;
        }    
        else if(rq->bRequest == USBRQ_HID_SET_IDLE)
        {
            idleRate = rq->wValue.bytes[1];
        }
    }
    else
    {
        // 未实现特定于供应商的请求 未实现请求,就不向主机返回任何数据
    }
    return 0;   
}

/* ------------------------------------------------------------------------- */

/* ------------------- ADNS2610 Functions ---------------------------------- */
//Function Description: 从ADNS2610读取指定地址的字节    
//Inputs:  ADNS2610要写入的寄存器地址
//Outputs: None
//Return:  从ADNS2610读取的字节
//usage: value = read(CONFIGURATION_REG);
char read(char address)
{
    char value=0;
	sbi(ADNS_DIR, ADNS_SDIO);	// 确保SDIO引脚设置为输出。
    sbi(ADNS_PORT, ADNS_SCL);   // 确保时钟引脚拉高。
    address &= 0x7F;            // 请确保地址字节的最高位为“0”以指示读取。
 
	int address_bit=0;
    // 发送地址到 ADNS2610
    for(address_bit=7; address_bit >=0; address_bit--)
    {
        cbi(ADNS_PORT, ADNS_SCL);  // 拉低时钟引脚
        sbi(ADNS_DIR, ADNS_SDIO);  // 确保SDIO引脚设置为输出
        
        // 如果当前位为1,则设置SDIO引脚。否则,清除SDIO引脚
        if(address & (1<= 0; value_bit--)
    {
        cbi(ADNS_PORT, ADNS_SCL);     // 拉低 clock 引脚
        _delay_us(1);                 // 允许ADNS2610配置SDIO引脚
        sbi(ADNS_PORT, ADNS_SCL);     // 上拉 clock 引脚
        _delay_us(1);
        // 如果SDIO引脚为高电平,则在value变量中设置当前位。如果为低,则保留默认值位(0)。
        //if(sdio.read())value|=(1<=0; address_bit--)
    {
        cbi(ADNS_PORT, ADNS_SCL);  // 拉低 clock 引脚
        
        // 提供一个小延迟(仅用于第一次迭代,以确保ADNS2610放弃
        
        _delay_us(1); 

        // 如果我们在“读取”命令之后执行此写入,则控制SDIO。
        
        // 如果当前位为1,则设置SDIO引脚。如果没有,清除SDIO引脚
        if(address & (1<= 0; value_bit--)
    {
        cbi(ADNS_PORT, ADNS_SCL);  // 拉低 clock 引脚
        // 如果当前位为1,则设置SDIO引脚。否则,清除SDIO引脚
        if(value & (1< 250 ms */
        wdt_reset();
        _delay_ms(1);
    }
    usbDeviceConnect();
    sei();
    DBG1(0x01, 0, 0);       /* debug output: main loop starts */
    for(;;){                /* 主循环 */
        DBG1(0x02, 0, 0);   /* debug output: main loop iterates */
        wdt_reset();
        usbPoll();
        if(usbInterruptIsReady())
        {
            // 在每次轮询中断端点后调用
            //advanceCircleByFixedAngle();
			getMouseMovement();
            DBG1(0x03, 0, 0);   /* debug output: interrupt report prepared */
            usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
        }
    }
}

/* ------------------------------------------------------------------------- */

这部分主要是对一些芯片上的引脚的操作。

可以看一下Auduino库:

// 从ADNS2620传感器读取寄存器。将结果返回给调用函数。
// Example: value = mouse.read(CONFIGURATION_REG);
char ADNS2620::read(char address)
{
    char value=0;
	pinMode(_sda, OUTPUT);     // 确保SDIO引脚设置为输出。
    digitalWrite(_scl, HIGH);  // 确保时钟引脚为高。
    address &= 0x7F;           // 请确保地址字节的最高位为“0”以指示读取。
 
    //Send the Address to the ADNS2620
    for(int address_bit=7; address_bit >=0; address_bit--)
    {
        digitalWrite(_scl, LOW); 
        pinMode(_sda, OUTPUT); 
        
        if(address & (1<= 0; value_bit--)
    {
        digitalWrite(_scl, LOW);   
        delayMicroseconds(10);     
        digitalWrite(_scl, HIGH);  
        delayMicroseconds(10);

		if(digitalRead(_sda))value |= (1<

我们对比FW程序和Auduino库,会发现几乎一致,实际上就是这么修改的,在读写的时候,会根据引脚的状态来设置value。

不过我估计很多人看了这个还是一头雾水,所以下一个文档会从最上层的开发方式来再做一个鼠标键盘输入器,读者可以体会两者之间的差距。

 

 

你可能感兴趣的:(游戏辅助,鼠标键盘的实现,c++,计算机外设)