主题中讨论的其他器件: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 板示例。
非常感谢!