我在 Mac 上使用 FTDI 芯片做了大量工作,所以我可以在这里提供一些见解。我使用了他们的 USB 串行转换器的单通道和双通道变体,它们的行为方式都相同。
FTDI 有他们的虚拟 COM 端口驱动程序,它在您的系统上创建一个串行 COM 端口,代表连接到他们的芯片的串行连接,以及他们的 D2XX 直接通信库。您将要使用后者,可以从他们的网站上为各种平台下载。
适用于 Mac 的 D2XX 库采用独立的 .dylib(最新的是 libftd2xx.1.2.2.dylib)或他们最近开始发布的新静态库。该软件包中还包含您需要的相应头文件(ftd2xx.h 和 WinTypes.h)。
在您的 Xcode 项目中,添加 .dylib 作为要链接的框架,并将 ftd2xx.h、WinTypes.h 和 ftd2xx.cfg 文件添加到您的项目中。在 Copy Bundled Frameworks 构建阶段,确保 libftd2xx.1.2.2.dylib 和 ftd2xx.cfg 存在于该阶段。您可能还需要调整此库所需的相对路径,以使其在您的应用程序包中运行,因此您可能需要在命令行中对其运行以下命令:
install_name_tool -id @executable_path/../Frameworks/libftd2xx.1.2.2.dylib libftd2xx.1.2.2.dylib
正确配置项目后,您将需要导入 FTDI 标头:
#import "ftd2xx.h"
并开始连接到您的串行设备。您在问题中链接到的示例有一个可下载的 C++ 示例,显示了它们如何与设备通信。您可以带入几乎所有使用的 C 代码并将其放置在您的 Objective-C 应用程序中。他们只是看起来使用标准的 FTDI D2XX 命令,可下载的 D2XX 程序员指南中详细描述了这些命令。
这是我从我的一个应用程序中提取的一些代码,用于连接到这些设备之一:
DWORD numDevs = 0;
// Grab the number of attached devices
ftdiPortStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
if (ftdiPortStatus != FT_OK)
{
NSLog(@"Electronics error: Unable to list devices");
return;
}
// Find the device number of the electronics
for (int currentDevice = 0; currentDevice < numDevs; currentDevice++)
{
char Buffer[64];
ftdiPortStatus = FT_ListDevices((PVOID)currentDevice,Buffer,FT_LIST_BY_INDEX|FT_OPEN_BY_DESCRIPTION);
NSString *portDescription = [NSString stringWithCString:Buffer encoding:NSASCIIStringEncoding];
if ( ([portDescription isEqualToString:@"FT232R USB UART"]) && (usbRelayPointer != NULL))
{
// Open the communication with the USB device
ftdiPortStatus = FT_OpenEx("FT232R USB UART",FT_OPEN_BY_DESCRIPTION,usbRelayPointer);
if (ftdiPortStatus != FT_OK)
{
NSLog(@"Electronics error: Can't open USB relay device: %d", (int)ftdiPortStatus);
return;
}
//Turn off bit bang mode
ftdiPortStatus = FT_SetBitMode(*usbRelayPointer, 0x00,0);
if (ftdiPortStatus != FT_OK)
{
NSLog(@"Electronics error: Can't set bit bang mode");
return;
}
// Reset the device
ftdiPortStatus = FT_ResetDevice(*usbRelayPointer);
// Purge transmit and receive buffers
ftdiPortStatus = FT_Purge(*usbRelayPointer, FT_PURGE_RX | FT_PURGE_TX);
// Set the baud rate
ftdiPortStatus = FT_SetBaudRate(*usbRelayPointer, 9600);
// 1 s timeouts on read / write
ftdiPortStatus = FT_SetTimeouts(*usbRelayPointer, 1000, 1000);
// Set to communicate at 8N1
ftdiPortStatus = FT_SetDataCharacteristics(*usbRelayPointer, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); // 8N1
// Disable hardware / software flow control
ftdiPortStatus = FT_SetFlowControl(*usbRelayPointer, FT_FLOW_NONE, 0, 0);
// Set the latency of the receive buffer way down (2 ms) to facilitate speedy transmission
ftdiPortStatus = FT_SetLatencyTimer(*usbRelayPointer,2);
if (ftdiPortStatus != FT_OK)
{
NSLog(@"Electronics error: Can't set latency timer");
return;
}
}
}
断开连接相当简单:
ftdiPortStatus = FT_Close(*electronicsPointer);
*electronicsPointer = 0;
if (ftdiPortStatus != FT_OK)
{
return;
}
写入串行设备非常容易:
__block DWORD bytesWrittenOrRead;
unsigned char * dataBuffer = (unsigned char *)[command bytes];
//[command getBytes:dataBuffer];
runOnMainQueueWithoutDeadlocking(^{
ftdiPortStatus = FT_Write(electronicsCommPort, dataBuffer, (DWORD)[command length], &bytesWrittenOrRead);
});
if((bytesWrittenOrRead < [command length]) || (ftdiPortStatus != FT_OK))
{
NSLog(@"Bytes written: %d, should be:%d, error: %d", bytesWrittenOrRead, (unsigned int)[command length], ftdiPortStatus);
return NO;
}
(command
是一个 NSData 实例,runOnMainQueueWithoutDeadlocking()
只是我用来保证在主队列上执行块的便利功能)。
您可以使用以下内容从串行接口读取原始字节:
NSData *response = nil;
DWORD numberOfCharactersToRead = size;
__block DWORD bytesWrittenOrRead;
__block unsigned char *serialCommunicationBuffer = malloc(numberOfCharactersToRead);
runOnMainQueueWithoutDeadlocking(^{
ftdiPortStatus = FT_Read(electronicsCommPort, serialCommunicationBuffer, (DWORD)numberOfCharactersToRead, &bytesWrittenOrRead);
});
if ((bytesWrittenOrRead < numberOfCharactersToRead) || (ftdiPortStatus != FT_OK))
{
free(serialCommunicationBuffer);
return nil;
}
response = [[NSData alloc] initWithBytes:serialCommunicationBuffer length:numberOfCharactersToRead];
free(serialCommunicationBuffer);
在上面的末尾,response
将是一个 NSData 实例,其中包含您从端口读取的字节。
此外,我建议您始终从主线程访问 FTDI 设备。尽管他们说他们支持多线程访问,但我发现任何类型的非主线程访问(甚至保证来自单个线程的独占访问)都会导致 Mac 上的间歇性崩溃。
除了我上面描述的情况之外,您可以查阅 D2XX 编程指南以了解 FTDI 在其 C 库中提供的其他功能。同样,您应该只需要从设备制造商提供给您的示例中转移适当的代码。