AVR-C:可以成功检测到USB连接,不是USB断开连接
AVR-C: USB connection can be detected successfully, not an USB disconnect
它在 ATMega32U4 MCU 上工作正常,但是......当电池供电时,它无法检测到与 USB 的断开连接。它可以检测到重新连接 (false),然后是 true 状态,但不会断开连接。
例如:
bool TEnjoyPad::isUSBConnected()
{
#if defined(UDADDR) && defined(_BV) && defined(ADDEN)
//setDelay( 1000 );
Serial1.println( "--------" );
Serial1.println( UDADDR & _BV(ADDEN), HEX );
//Serial1.println( UDADDR, HEX ); // 97 or 98 hex
//Serial1.println( _BV(ADDEN), HEX );
return (UDADDR & _BV(ADDEN));
#else
return false;
#endif
}
当你看行时:
Serial1.println( UDADDR & _BV(ADDEN), HEX );
它打印:
Connected: 0x80 (function result = true)
Not connected: 0x00 (function result = false)
它可以检测从未连接到已连接但未连接到未连接(断开连接)的变化。
有没有简单的解决方法?
编辑 2017 年 13 月 13 日:
只需弄清楚这一点即可,但并非总是如此。在这里找到它:
http://forum.arduino.cc/index.php?topic=28567.0
UDINT寄存器,连接时报告16十进制(0x10十六进制)
上述第一个版本函数的修改版本:
bool TEnjoyPad::isUSBConnected()
{
#if defined(UDADDR) && defined(_BV) && defined(ADDEN) && defined(UDINT) && defined(USBCON)
return ( (UDADDR & _BV(ADDEN)) && (UDINT) );
#else
return false;
#endif
}
但只有在满足以下条件时才有效:
- Device is connected to computer, phone etc
- Device is disconnected from computer, phone etc
例如,如果您使用 USB 电池组,它会报告 true,并且对于某些电池组,断开连接时状态仍然为 true。总线混乱?当您再次连接到计算机时,phone 等它报告 false 然后报告 true,当断开连接时它报告 false(它应该)。
有什么想法吗?与建设USB数据线有关?
在示例中,他们使用了这一行。当我添加它时,它对我没有影响:
USBCON = USBCON | B00010000;
编辑 2017 年 14 月 14 日:
感谢@ralph htp,请参阅下面我发布的答案,也许它也可以帮助其他人。
资料sheet第261、279页说有VBUSTI
USB插拔中断。 LUFA 堆栈 中有一个实现(EVENT_USB_Host_DeviceUnattached()
如果在主机模式下,EVENT_USB_Device_Disconnect()
如果在设备模式下)
编辑
仅在 USB 设备模式下有效:
如果你想检测像电池块这样的纯电压源是连接还是分离,你可以使用 VBUS
(电压总线)焊盘。它的状态可以在VBUS
位/标志的USBSTA
(USB状态)中访问,这是在第268页的数据sheet中。
为此捕获 VBUSTI
中断,每当中断发生时检查 USBSTA
寄存器中的 VBUS
位/标志。如果 VBUS
高 (1) 电池已连接(VBUS
焊盘上的电压 > 1.4 V,数据 sheet 第 265 页)如果电池电量低则未连接电池(VBUS 上的电压焊盘 < 1.4 V )
最后,它完美运行,感谢“@ralf htp”。他是对的 USBSTA
寄存器在连接到 USB 时变为 1
,在未连接时变为 0
。您必须 include pins_arduino.h
否则寄存器是未知的。因此,这使得检测 USB 电源状态变得非常容易。
但是,当你想知道USB总线的状态,数据线是否连接,连接是否建立时,就有点复杂了。当 MCU 需要作为 USB HID 设备运行时,您需要知道建立 USB 连接。
我不知道这是一个错误还是 USB 的工作方式,即使设备断开连接或连接到 USB 电池组,MCU 也会保留 USB 设备的地址。一些寄存器甚至在 'invalid' 状态下保持它们的值。
但是,当建立连接时,地址会发生变化。所以可以判断是真的连接了,连接成功了,MCU被USB主机识别了。
在我的以下代码中我可以检测到:
- 已连接外置USB电源;
- 建立数据连接,是否识别设备;
- 结合这些东西,很容易弄清楚它是如何供电的 and/or 连接。
现在您可以决定设备功能是否可用,或者向用户报告设备的状态。
我的更新代码如下所示:
// enjoypad.h
#include <pins_arduino.h> // Required to access some register defines
..........
..........
..........
// Via pins_arduino.h => defined in avr/iom32u4.h
#ifdef USBSTA
#define TEP_USB_VBUS_CONNECTED (USBSTA == 3)
#define TEP_USB_VBUS_DISCONNECTED (USBSTA == 2)
#endif
#ifdef UDADDR
#define TEP_USB_ADDRESS (isOnUSBPower()?UDADDR:0)
#endif
#if defined(ADDEN) && defined(UDINT)
#define TEP_USB_ADDRESS_ESTABLISHED (_BV(ADDEN)== 0x80 && UDINT > 0 )
#endif
..........
..........
..........
// enjoypad.cpp
uint8_t TEnjoyPad::getUSBaddress()
{
#ifdef TEP_USB_ADDRESS
return TEP_USB_ADDRESS;
#else
return 0;
#endif
}
bool TEnjoyPad::isOnUSBPower()
{
#ifdef TEP_USB_VBUS_CONNECTED
return TEP_USB_VBUS_CONNECTED;
#else
return false;
#endif
}
bool TEnjoyPad::isUSBDataEstablished()
{
#ifdef TEP_USB_ADDRESS_ESTABLISHED
static uint8_t iLastAddress = 0;
static uint8_t bUSBDataEstablished = false;
// The address changes from 0 to something (byte) or increases
// with one each time you plugin the device, when this is an USB host.
// If the VBUS not connected, it returns always 0 (zero)
uint8_t iAddress = getUSBaddress();
if( iAddress > 0 )
{
//Serial1.println( _BV(ADDEN), HEX );
//Serial1.println( UDINT, HEX );
if( TEP_USB_ADDRESS_ESTABLISHED )
{
//Serial1.println( iAddress );
// Need update? On USB Battery for example, address stays the same
// so it never perform an update and never reports there is a
// data connection established.
if( iAddress != iLastAddress )
{
bUSBDataEstablished = true;
iLastAddress = iAddress;
}
}
}
else { bUSBDataEstablished = false; }
return bUSBDataEstablished;
#else
return false;
#endif
}
bool TEnjoyPad::isOnUSBPowerBattery() // Or something else providing power
{ return ( isOnUSBPower() && !isUSBDataEstablished() ); }
bool TEnjoyPad::isOnBatteryPower()
{ return !isOnUSBPower(); }
实际代码 :-) :
它在 ATMega32U4 MCU 上工作正常,但是......当电池供电时,它无法检测到与 USB 的断开连接。它可以检测到重新连接 (false),然后是 true 状态,但不会断开连接。
例如:
bool TEnjoyPad::isUSBConnected()
{
#if defined(UDADDR) && defined(_BV) && defined(ADDEN)
//setDelay( 1000 );
Serial1.println( "--------" );
Serial1.println( UDADDR & _BV(ADDEN), HEX );
//Serial1.println( UDADDR, HEX ); // 97 or 98 hex
//Serial1.println( _BV(ADDEN), HEX );
return (UDADDR & _BV(ADDEN));
#else
return false;
#endif
}
当你看行时:
Serial1.println( UDADDR & _BV(ADDEN), HEX );
它打印:
Connected: 0x80 (function result = true)
Not connected: 0x00 (function result = false)
它可以检测从未连接到已连接但未连接到未连接(断开连接)的变化。
有没有简单的解决方法?
编辑 2017 年 13 月 13 日:
只需弄清楚这一点即可,但并非总是如此。在这里找到它: http://forum.arduino.cc/index.php?topic=28567.0
UDINT寄存器,连接时报告16十进制(0x10十六进制)
上述第一个版本函数的修改版本:
bool TEnjoyPad::isUSBConnected()
{
#if defined(UDADDR) && defined(_BV) && defined(ADDEN) && defined(UDINT) && defined(USBCON)
return ( (UDADDR & _BV(ADDEN)) && (UDINT) );
#else
return false;
#endif
}
但只有在满足以下条件时才有效:
- Device is connected to computer, phone etc
- Device is disconnected from computer, phone etc
例如,如果您使用 USB 电池组,它会报告 true,并且对于某些电池组,断开连接时状态仍然为 true。总线混乱?当您再次连接到计算机时,phone 等它报告 false 然后报告 true,当断开连接时它报告 false(它应该)。
有什么想法吗?与建设USB数据线有关?
在示例中,他们使用了这一行。当我添加它时,它对我没有影响:
USBCON = USBCON | B00010000;
编辑 2017 年 14 月 14 日:
感谢@ralph htp,请参阅下面我发布的答案,也许它也可以帮助其他人。
资料sheet第261、279页说有VBUSTI
USB插拔中断。 LUFA 堆栈 中有一个实现(EVENT_USB_Host_DeviceUnattached()
如果在主机模式下,EVENT_USB_Device_Disconnect()
如果在设备模式下)
编辑
仅在 USB 设备模式下有效:
如果你想检测像电池块这样的纯电压源是连接还是分离,你可以使用 VBUS
(电压总线)焊盘。它的状态可以在VBUS
位/标志的USBSTA
(USB状态)中访问,这是在第268页的数据sheet中。
为此捕获 VBUSTI
中断,每当中断发生时检查 USBSTA
寄存器中的 VBUS
位/标志。如果 VBUS
高 (1) 电池已连接(VBUS
焊盘上的电压 > 1.4 V,数据 sheet 第 265 页)如果电池电量低则未连接电池(VBUS 上的电压焊盘 < 1.4 V )
最后,它完美运行,感谢“@ralf htp”。他是对的 USBSTA
寄存器在连接到 USB 时变为 1
,在未连接时变为 0
。您必须 include pins_arduino.h
否则寄存器是未知的。因此,这使得检测 USB 电源状态变得非常容易。
但是,当你想知道USB总线的状态,数据线是否连接,连接是否建立时,就有点复杂了。当 MCU 需要作为 USB HID 设备运行时,您需要知道建立 USB 连接。
我不知道这是一个错误还是 USB 的工作方式,即使设备断开连接或连接到 USB 电池组,MCU 也会保留 USB 设备的地址。一些寄存器甚至在 'invalid' 状态下保持它们的值。
但是,当建立连接时,地址会发生变化。所以可以判断是真的连接了,连接成功了,MCU被USB主机识别了。
在我的以下代码中我可以检测到:
- 已连接外置USB电源;
- 建立数据连接,是否识别设备;
- 结合这些东西,很容易弄清楚它是如何供电的 and/or 连接。
现在您可以决定设备功能是否可用,或者向用户报告设备的状态。
我的更新代码如下所示:
// enjoypad.h
#include <pins_arduino.h> // Required to access some register defines
..........
..........
..........
// Via pins_arduino.h => defined in avr/iom32u4.h
#ifdef USBSTA
#define TEP_USB_VBUS_CONNECTED (USBSTA == 3)
#define TEP_USB_VBUS_DISCONNECTED (USBSTA == 2)
#endif
#ifdef UDADDR
#define TEP_USB_ADDRESS (isOnUSBPower()?UDADDR:0)
#endif
#if defined(ADDEN) && defined(UDINT)
#define TEP_USB_ADDRESS_ESTABLISHED (_BV(ADDEN)== 0x80 && UDINT > 0 )
#endif
..........
..........
..........
// enjoypad.cpp
uint8_t TEnjoyPad::getUSBaddress()
{
#ifdef TEP_USB_ADDRESS
return TEP_USB_ADDRESS;
#else
return 0;
#endif
}
bool TEnjoyPad::isOnUSBPower()
{
#ifdef TEP_USB_VBUS_CONNECTED
return TEP_USB_VBUS_CONNECTED;
#else
return false;
#endif
}
bool TEnjoyPad::isUSBDataEstablished()
{
#ifdef TEP_USB_ADDRESS_ESTABLISHED
static uint8_t iLastAddress = 0;
static uint8_t bUSBDataEstablished = false;
// The address changes from 0 to something (byte) or increases
// with one each time you plugin the device, when this is an USB host.
// If the VBUS not connected, it returns always 0 (zero)
uint8_t iAddress = getUSBaddress();
if( iAddress > 0 )
{
//Serial1.println( _BV(ADDEN), HEX );
//Serial1.println( UDINT, HEX );
if( TEP_USB_ADDRESS_ESTABLISHED )
{
//Serial1.println( iAddress );
// Need update? On USB Battery for example, address stays the same
// so it never perform an update and never reports there is a
// data connection established.
if( iAddress != iLastAddress )
{
bUSBDataEstablished = true;
iLastAddress = iAddress;
}
}
}
else { bUSBDataEstablished = false; }
return bUSBDataEstablished;
#else
return false;
#endif
}
bool TEnjoyPad::isOnUSBPowerBattery() // Or something else providing power
{ return ( isOnUSBPower() && !isUSBDataEstablished() ); }
bool TEnjoyPad::isOnBatteryPower()
{ return !isOnUSBPower(); }
实际代码 :-) :