主题中讨论的其他器件:TM4C123、 ENERGIA、 CC2650
工具/软件:Code Composer Studio
大家好、
我正在尝试将数据从 TM4C123保存到 USB Pendrive。 我需要记录来自非公路用车的7个输入:
- 4个制动盘温度(NTC 传感器)
- CVT 温度(PT100)
- 发动机转速(由包含555计时器的电路产生的脉冲)
- 速度(利用电感式传感器)
尚未开始尝试记录这些数据、我需要更好地了解如何先将数据放入 USB 记忆棒。 因此、我将使用 由 krithik 提供的代码 、可在此处找到该代码:
https://github.com/krithik/tiva-usb-host-msc
我修改了代码以将数据放入我的待定驱动器中(我使用连接到 GND 和5V 引脚的外部电源、因此不进行调试)。 下面是一个工作示例:
#include #include #include #include #include ///---------------------- // TivaWare 头文件 //--------------- include "inc/hw_memblumap.h" #include "inc/hw_types.h" #include "driverlib/rom.h" #include "driverlib/fpu.h" #include "driverlib/driverlib.h" #include "driverlib/driverlib.h"#include "driverlib/sub.us.h"#include "driverlib/srusb.usb.包含 "driverlib"#include "driverlib/srus.us.usb/tms"#include" #include"#driverlib.us.us.us.us.us.usb/tick#include "#include" #include "#include "driverlib"#include "driverlib.us.us.us.us.us.us.lib"#include"#include "driverlib"#include "driverlib.us.us.us.us.us.us.us.us.usb/trigg"#include"#include "#include "#include "driverb/us.us.us.us.us.lib"#include "driverb/us.us.us. 静态 FIL g_sFileObject; // 定义保存路径的缓冲区的大小,或 来自 USB 磁盘的临时//数据。 分配了两个具有此大小的缓冲区。 //缓冲区大小必须足够大,以容纳预期的 int32_test //完整路径名,包括文件名和后缀空字符。 //// ***************** #define PATH_BUF_SIZE 80 //********* // //定义呼叫以检查连接的设备是否 就绪的次数//。 //// ***************** #define USBMSC_DRIVE_RETRY 4 //************* // //此缓冲区保存到当前工作目录的完整路径。 //最初它是根("/")。 //// ***************** 静态 char g_cCwdBuf[path_BUF_size]="/"; //********* // //下面是 FatFs 使用的数据结构。 //// ***************** 静态 FATFS g_sFatFs; 静态 DIR g_sDirObject; 静态 FILINFO g_sFileInfo; //********* // //保持 FRESULT 数字代码、 //和字符串表示之间映射的结构。 从 FatFs // FAT 文件系统驱动程序返回 FRESULT 代码。 //// ***************** typedef 结构 { FRESULT 结果; char * pcResultStr; } tFresultString; //************* // //一个宏,可以轻松地将结果代码添加到表中。 //// ***************** #define FRESULT_Entry (f) {(f)、(#f)} //********* // //保存数字 FRESULT 代码与 //它的名称作为字符串之间映射的表。 这用于查找错误代码和 //提供人类可读的字符串。 //// ***************** tFresultString g_sFresultStrings[]= { FRESULT_Entry (FR_OK)、 FRESULT_Entry (FR_DISK_ERR)、 FRESULT_Entry (FR_INT_ERR)、 FRESULT_Entry (FR_NOT_READY)、 FRESULT_Entry (FR_NO_FILE)、 FRESULT_Entry (FR_NO_PATH)、 FRESULT_Entry (FR_INVALID_NAME)、 FRESULT_Entry (FR_DENIED)、 FRESULT_Entry (FR_Exists)、 FRESULT_Entry (FR_INVALID_object)、 FRESULT_Entry (FR_WRITE_PROTECTED)、 FRESULT_Entry (FR_INVALID_DRIVE)、 FRESULT_Entry (FR_NOT_ENABLED)、 FRESULT_Entry (FR_NO_filesystem)、 FRESULT_Entry (FR_mkfs_aborted)、 FRESULT_Entry (FR_TIMEOUT)、 FRESULT_Entry (FR_LOCKED)、 FRESULT_Entry (FR_INT_ENSBY_CORE)、 FRESULT_Entry (FR_TO_MUSE_OPEN 文件)、 FRESULT_Entry (FR_INVALID_PARAMETER)、 }; //********* // //保存结果代码数的宏。 //// ***************** #define NUM_FRESULT_CODES (sizeof (g_sFresultStrings)/ sizeof (tFresultString)) //********* // // ChangeToDirectory()返回的错误原因。 //// ***************** #define NAME_TOW_LON_ERROR 1 #define opendir_error 2 //********* // //每秒的 SysTick 节拍数。 //// ***************** #define TICKS_PER_second 100 #define MS_PER_SysTick (1000 / TICKS_PER_second) //********* // //系统时钟节拍计数器,用于简单定时。 //// ***************** 静态 uint32_t g_ui32SysTickCount; //************* // //保持系统的全局标志。 //// ***************** 静态 uint32_t g_ui32Flags = 0; //********* // //存储文件名。 //// ***************** #define NUM_LIST_STRINS 48 const char * g_ppcDirListStrings[NUM_LIST_STRINTS]; //********* // //存储当前目录中的文件名。 文件名 //存储为目录的"(D) filename.ext"格式或 文件的"(F) filename.ext"//格式。 //// ***************** #define MAX_FILENAME_STRING_LEN (4 + 8 + 1 + 3 + 1) char g_pcFilename[NUM_LIST_STRING][MAX_FILENAME_STRIN_LEN]; //********* // //存储显示在 //显示底部状态框中的字符串。 //// ************* #define NUM_STATUS_STRINS 6 #define MAX_STATUS_STRIN_LEN (36 + 1) char g_pcStatus[NUM_STATUS_STRINS][MAX_STATUS_STRIN_LEN]; //********* // //标志表示已连接某些 USB 设备。 //// ***************** #define flags_device_present 0x00000001 //********* // //保持应用程序的当前状态。 //// ***************** volatile enum { // //不存在设备。 // State_no_device、 // //正在枚举大容量存储设备。 // State_device_enum、 // //大容量存储设备就绪。 // State_DEVICE_READY、 // //连接了不受支持的设备。 // State_unknown_device、 // //已连接大容量存储设备,但未能随时报告。 // State_Timeout_device、 // //发生电源故障。 // State_Power_FAULT } g_Estate; //********* // //主机控制器内存池的大小(以字节为单位)。 //// ***************** #define HCD_MEMORY_SIZE 128 //************* // //提供给主机控制器驱动程序的内存池。 //// ***************** uint8_t g_pHCPool [hcd_memory_size]; //********* // // MSC 驱动程序的实例数据。 //// ***************** tUSBHMSCInstance * g_psMSCInstance = 0; //********* // //声明 USB 事件驱动程序接口。 //// ***************** Declate_event_driver (g_sUSBEventDriver、0、0、USBHCEDents); //*************** // //包含应用程序中使用的所有主机驱动程序的全局变量。 //在本例中,仅加载 MSC 类。 //// ***************** 静态 tUSBHostClassDriver const * const g_ppHostClassDriver[]= { &g_sUSBHostMSCClassDriver、 &g_sUSBEventDriver }; //********* // //此全局变量保存 g_ppHostClassDrivers //列表中的类驱动程序数。 //// ***************** 静态常量 uint32_t g_ui32NumHostClassDrivers = sizeof (g_ppHostClassDrivers)/ sizeof (tUSBHostClassDriver *); //********* // // uDMA 控制器使用的控制表。 此表必须与 1024字节边界对齐//。 在此应用中、UDMA 仅用于 USB、 //因此只需要前6个通道。 //// ***************** #if defined (ewarm) #pragma DATA_alignment=1024 tDMAControlTable g_psDMAControlTable[6]; #Elif Defined (CCS) #pragma DATA_align (g_psDMAControlTable、1024) tDMAControlTable g_psDMAControlTable[6]; #else tDMAControlTable_aligned (g_pDMAControlTable、1024) tDMAControlTable_h (_dMAControlTable_h) (_dMA_h)(_dMA_dMAControlTable_h)(_h)(_h)(h)(h)(h)__g_g // //定义一对用于保存路径信息的缓冲区。 //缓冲区大小必须足够大,以容纳预期的最长 //完整路径名,包括文件名和尾随的空字符。 //初始路径设置为根"/"。 //// ***************** #define PATH_BUF_SIZE 80 //********* // //定义可在任何目录级别显示的最大文件数。 //这用于为保存文件信息分配空间。 //定义子目录的最大深度,也用于为 目录结构分配空间//。 //定义允许为文件存储的最大字符数 //名称。 //// ***************** #define MAX_FILES _PER_MENU 64 #define MAX_SUBDIR_DEPTH 32 //--------------- //原型 ///---------------- void hardware_init (void); static bool FileInit (void); void SysTickHandler (void); static const char * StringFromFresult(FRESULT fresult); static void MSCCallback (tUSBHMSCInstance * ps32Instance,Uprint32_t ui32Event,void * pvData); static---------(static/--/--/--/--/--/--) // main()//----------------- void main (void) { uint32_t ui32DriveTimeout、ui32SysClock; // //将主系统时钟设置为以50MHz 的频率从 PLL 运行 //处理器时钟的计算方法为(PLL/2)/4 ->(400/2)/4 = 50 //注:对于 USB 操作,它至少应为20MHz // SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz); //habilita TIMER0 SysCtlPeripheralDisable (SYSCTL_Periph_TIMER0); SysCtlPeripheralReset (SYSCTL_Periph_TIMER0); SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); while (!SysCtlPeripheralReady (SYSCTL_Periph_TIMER0)); //configura o TIMER0 como periódico TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE); //define o TIMER0 para zerar a cada cada 1 TimerLoadSet (TIMER0_BASE、TIMER_A、SysCtlClockGet ()-1); //desabilitya e limpa interrupções pendentes IntDisable (INT_TIMER0A); TimerIntDisable (TIMER0_BASE、TIMER_TINA_TIMEOUT); IntPendClear (INT_TIMER0A); TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); //定义原始的 ao 中断使其具有均衡性 IntPrioritySet (INT_TIMER0A、0x20); //configura interrupt para Gerar após o timeout (após zerar a configurem) TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); //恢复操作系统中断 IntEnable (INT_TIMER0A); //mant é m num loop enquanto interrupt não é rabilitado while (!IntIsEnabled (INT_TIMER0A)); // //获取系统时钟速率 // 50 MHz // ui32SysClock = SysCtlClockGet (); //启用 USB0 // // PB0 --- USB ID --> GND (硬件) // PB1 --- USB VBUS // PD4 --- USB D+ // PD5 --- USB D- // SysCtlPeripheralEnable (SYSCTL_Periph_USB0); SysCtlUSBPLLEnable(); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB); GPIOPinTypeUSBAnalog (GPIO_PORTB_BASE、GPIO_PIN_0 | GPIO_PIN_1); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD); GPIOPinTypeUSBAnalog (GPIO_PORTD_BASE、GPIO_PIN_4 | GPIO_PIN_5); // //仅为主机模式初始化 USB 堆栈。 // USBStackModeSet (0、eUSBModeForceHost、0); // //注册主机类驱动程序。 // USBHCDRegisterDrivers (0、g_ppHostClassDrivers、g_ui32NumHostClassDrivers); // //为100Hz 中断配置 SysTick。 // SysTick 周期= 5000000 / 100 -> 500000 // SysTickPeriodSet (SysCtlClockGet ()/ ticks_per_second); SysTickEnable(); SysTickIntEnable(); // //启用 uDMA 控制器并设置控制表基址。 // USB 库使用 uDMA 控制器。 // SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); uDMAEnable(); uDMAControlBaseSet (g_psDMAControlTable); //初始化 UART0 (通过调试 USB 端口呈现到控制台) // RX -- PA0 // TX -- PA1 //注:使用 UARTstdio 实用程序 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); UARTClockSourceSet (UART0_BASE、(UART_CLOCK_SYSTEM)); UARTStdioConfig (0、115200、SysCtlClockGet ()); IntEnable (INT_UART0); UARTIntEnable (UART0_BASE、UART_INT_RX | UART_INT_RT); //启用所有中断。 IntMasterEnable(); UARTprintf ("硬件已初始化\r\n"); // //最初等待设备连接。 // g_Estate = State_no_device; // //打开海量存储类驱动程序的实例。 // G_psMSCInstance = USBHMSCDriveOpen (0、MSCCallback); // //初始化驱动器超时。 // ui32DriveTimeout = USBMSC_DRIVE_RETRY; // //初始化 USB 控制器以进行主机操作。 // USBHCDInit (0、g_pHCPool、HCD_MEMORY_SIZE); // //初始化 FAT 文件系统。 // FileInit(); UARTprintf ("FAT 文件系统模块已初始化\r\n); //habilita ambos TIMERA e TIMERB TimerEnable (TIMER0_BASE、TIMER_A); char sings[16]; snprintf (some,sizeof(some),"some,\r\n"); // //输入一个(几乎)无限循环来读取和处理命令 //用户。 // while (1) { // //调用 USB 堆栈使其保持运行。 // USBHCDMain(); switch (g_Estate) { 实例 State_device_enum: { // //如果大容量存储设备速度慢,请在该设备上轻松操作 //连接后启动。 // if (USBHMSCDriveReady (g_psMSCInstance)!= 0) { // //在尝试检查是否为之前等待大约500ms //设备已就绪。 // // 1个机器循环需要(1/50*10^6)秒 // SysCtlDelay 使用3个机器周期,因此它将是3*(1/50*10^6)秒 //总延迟->(3个机器周期所需的时间)*计数值 // //因此,[(3/50*10^6)*(50*10^6/(3*2)]=1/2秒 // // SysCtlDelay (ui32SysClock /(3 * 2)); // //减少重试计数。 // ui32DriveTimeout --; // //如果超时被按下,则转至 // State_Timeout_device 状态。 // if (ui32DriveTimeout = 0) { g_Estate = State_Timeout_device; } 中断; } UARTprintf ("USB 大容量存储设备就绪\r\n"); deviceispresent = true; // //到达此处意味着设备已准备就绪。 //将 CWD 重置为根目录。 // G_cCwdBuf[0]='/'; G_cCwdBuf[1]= 0; // //使用找到的文件和目录填充列表框。 // if (!printFileStructure()) { // //如果没有报告错误,我们就可以了 // MSC 操作。 // g_Estate = State_device_ready; } // //设置设备存在标志。 // G_ui32Flags = flags_device_present; 中断; } // //如果没有设备,则只需等待一个。 // 案例 State_no_device: { if (g_ui32Flags = flags_device_present) { // //清除设备存在标志。 // G_ui32Flags &&~flags_device_present; } 中断; } // //连接了未知设备。 // 案例 State_UNKNOWN_DEVICE: { // //如果这是新设备,则更改状态。 // if ((g_ui32Flags & flags_device_present)=0) { //指示存在未知设备。 UARTprintf ("未知设备已连接\r\n); } // //设置设备存在标志。 // G_ui32Flags = flags_device_present; 中断; } // //连接的大容量存储设备未准备好报告。 // 案例 State_Timeout_device: { // //如果这是第一次处于此状态,则打印 A //消息。 // if ((g_ui32Flags & flags_device_present)=0) { //指示尝试连接时的超时 UARTprintf ("未知设备\r\n"); } // //设置设备存在标志。 // G_ui32Flags = flags_device_present; 中断; } // //某些情况导致了电源故障。 // 案例 State_Power_FAULT: { 中断; } 默认值: { 中断; } } if (设备存在) { UINT bw; if (f_open (&g_sFileObject、"123.txt"、fa_write | fa_open_always)== FR_OK) { f_lseek (&g_sFileObject、g_sFileObject.fsize); f_write (&G) sFileObject、sound、sizeof (sone)、&bw); f_close (&g_sFileObject); } } } //********* // //初始化文件系统模块。 // //\param 无。 // //此函数初始化第三方 FAT 实现。 // //返回成功时返回\e true,失败时返回\e false。 //// ***************** 静态 bool 文件初始化(void){ // //使用逻辑磁盘0装入文件系统。 // if (f_mount (0、&g_sFatfs)!= FR_OK) { return (false); } return (true); } //********* // //这是该 SysTick 中断的处理程序。 它只是增加 一个用于计时的//计数器。 //// ***************** void SysTickHandler (void){ // //更新我们的 tick 计数器。 // G_ui32SysTickCount++; } //********* // //此函数返回错误代码//的字符串表示 ,该错误代码是从函数调用返回到 FatFs 的。 它可用于 //打印人类可读的错误消息。 //// ***************** static const char * StringFromFresult (FRESULT fresult){ uint32_t ui32Idx; // //输入循环以搜索错误代码表以查找匹配项 //错误代码。 // 对于(ui32Idx = 0;ui32Idx < NUM_FRESULT_CODES;ui32Idx++) { // //如果找到匹配项,则返回的字符串名称 //错误代码。 // if (g_sFresultStrings[ui32Idx].fresult=fresults) { return (g_sFresultStrings[ui32Idx].pcResultStr); } } // //此时未找到匹配的代码,因此返回 a //指示未知错误的字符串。 // return ("未知 ERR"); } //********* // //这是 MSC 驱动程序的回调。 // //\param ui32Instance 是 与驱动程序进行通信时所需的驱动程序实例//。 //\param ui32event 是驱动程序定义的事件之一。 //\param pvData 是传递到寄存器初始调用 中的数据的指针//回调。 // //此函数处理 MSC 驱动程序的回调事件。 当前处理的唯一事件//是 MSC_EVENT_OPEN 和 MSC_EVENT_CLOSE。 这使 //主例程能够知道何时检测到 MSC 设备并 枚举//以及何时从系统中删除 MSC 设备。 // //返回无 // ////********* 静态空 MSCCallback (tUSBHMSCInstance * ps32Instance、uint32_t ui32Event、void * pvData){ // //确定事件。 // switch (ui32event) { // //设备驱动程序已成功枚举 MSC 时调用 //器件。 // 案例 MSC_EVENT_OPEN: { // //继续到枚举状态。 // g_Estate = State_device_enum; 中断; } // //由于错误或而卸载设备驱动程序时调用 //设备不再存在。 // 案例 MSC_EVENT_CLOSE: { // //返回到“无设备”状态并等待新连接。 // g_Estate = State_no_device; // //重新初始化文件系统。 // FileInit(); 中断; } 默认值: { 中断; } } //********* // //这是来自主机堆栈的通用回调。 // //// pvData 实际上是 tEventInfo 结构的指针。 // //将调用此函数,以便在发生与 大容量存储设备相关的 USB 事件之外的//时通知应用程序。 此时 //此选项用于检测插入和删除的不受支持的设备。 //它还用于在发生电源故障时通知应用程序。 // 将 g_USBGenericEventDriver 包含在//主机控制器驱动程序数组中时,需要此函 数,该数将传递到// USBHCDRegisterDrivers()函数。 //// ***************** void USBHCEDEvents (void *pvData){ tEventInfo *pEventInfo; // //将此指针投射到其实际类型。 // pEventInfo =(tEventInfo *) pvData; // //处理每种事件 // switch (pEventInfo->ui32Event) { // //已连接未知设备。 // 案例 USB_EVENT_UNKNOWN_Connected: { // //检测到未知设备。 // g_Estate = State_unknown_device; 中断; } // //已拔下未知设备。 // 案例 USB_EVENT_DISCONNECTED: { // //已删除未知设备。 // g_Estate = State_no_device; 中断; } // //检测到总线电源故障。 // 案例 USB_EVENT_POWER_FAULT: { // //不能通电表示没有设备。 // G_ARRAT = State_Power_FAULT; 中断; } 默认值: { 中断; } } //********* //在 UART 上打印文件结构。 // 静态 int printFileStructure (void){ uint32_t ui32ItemCount; FRESULT 结果; // //打开当前目录进行访问。 // fresult = f_opendir (&g_sDirObject、g_cCwdBuf); // //检查错误,如果有问题,则返回。 // if (fresult!= FR_OK) { // //确保报告错误。 // UARTprintf ("USB 盘出错:\r\n"); UARTprintf ((char *) StringFromFresult (fresult)); UARTprintf ("\r\n"); return (fresult); } ui32ItemCount = 0; // //输入循环以枚举所有目录条目。 // for (;;) { // //从目录中读取条目。 // fresult = f_readdir (&g_sDirObject、&g_sFileInfo); // //检查错误,如果有问题,则返回。 // if (fresult!= FR_OK) { UARTprintf ("USB 盘出错:\r\n"); UARTprintf ((char *) StringFromFresult (fresult)); UARTprintf ("\r\n"); return (fresult); } // //如果文件名为空,则这是的结尾 //列表。 // if (!g_sFileInfo.fname[0]) { 中断; } // //在控制台上添加信息 // if (ui32ItemCount < NUM_LIST_STRES) { usnprintf (g_pcFilename[ui32ItemCount]、MAX_FILENAME_STRING_LEN、 "(%c)%s"、(g_sFileInfo.fattrib 和 am_DIR)? 'D':'F'、 g_sFileInfo.fname); UARTprintf (g_pcFilames[ui32ItemCount]); UARTprintf ("\r\n"); } // //移动到我们用于填充的项目数组中的下一个条目 //列表框。 // ui32ItemCount++; } // //将其添加到这里,返回时没有错误。 // return (0); } void Timer0IntHandler (void) { TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); }
现在、我遇到了很多问题。
- 如果我尝试向 USB pendrive outside main()函数(例如,计时器 ISR)写入任何内容,则 pendrive 会闪烁,表示正在忙,但没有数据写入。
- 如果我写入一个长字符串、如"12345678910111213141516171819820212223224252627282930\r\n"、它会写入垃圾、如下所示:
- 如果我用一个 char[25]编写"sings,\r"、它的写入方式如下:
- 如果我使用 snprintf (soming、sizeof (soming)、"%.4F\r\n"、floatnum)编写浮点、它不会写入任何内容。 它写了"s往"、但在将字符串更改为浮点后、它停止写入:
我需要生成该输出:
有什么帮助吗? 通过 USB 进行日志记录似乎是在 Tiva 上最困难的事情...
是的、我多次验证了 QS 记录器示例。 很难理解、因为有一百万个东西一起运行、我想知道为什么没有一个 EK 板示例。
非常感谢!