37.6.2 STM32F429开发板实验 配套例子: V6-1054_RL-TCPnet实验_FTP客户端(RTX) 实验目的: 1. 学习RL-TCPnet的FTP客户端实现。 实验内容: 1. 强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。 2. FTP客户端的存储器是采用的SD卡,所以测试本例子前务必准备好一个SD卡并插上。 3. 文件系统是采用的RL-FlashFS,此文件系统的文件名仅支持ASCII字符,不支持中文,特别注意! 4. 远程FTP服务器的IP地址和端口号是在app_tcpnet_lib.c文件开头的宏定义设置。 5. 需要上传下载的文件、文件夹的创建和删除、文件夹浏览等配置是在FTPC_uif.c文件开头的宏定义设置。 6. 测试本例子,需要在电脑端先建立FTP服务器,具体建立方法和本例子的测试步骤在本实例配套教程里面有详细讲解,必看!! 7. K2按键按下,从FTP服务器下载文件到开发板的SD卡。 8. K3按键按下,将开发板SD卡里面的文件上传到FTP服务器。 9. 摇杆上键按下,浏览FTP服务器当前目录下的所有文件详情。 10. 摇杆左键按下,创建一个文件夹。 11. 摇杆右键按下,删除一个文件夹。 实验操作: 详见本章节37.5小节。 配置向导文件设置(Net_Config.c): 详见本章节37.3小节。 调试文件设置(Net_Debug.c): 详见本章节37.4小节。 RTX配置: RTX配置向导详情如下: Task Configuration (1)Number of concurrent running tasks 允许创建6个任务,实际创建了如下5个任务: AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁。 AppTaskMsgPro任务 :按键检测。 AppTaskTCPMain任务:RL-TCPnet测试任务。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。 (2)Number of tasks with user-provided stack 创建的5个任务都是采用自定义堆栈方式。 (3)Run in privileged mode 设置任务运行在非特权级模式。 RTX任务调试信息: 程序设计: 任务栈大小分配: staticuint64_t AppTaskUserIFStk[1024/8]; /* 任务栈 */ staticuint64_t AppTaskLEDStk[1024/8]; /* 任务栈 */ staticuint64_t AppTaskMsgProStk[1024/8]; /* 任务栈 */ staticuint64_t AppTaskTCPMainStk[4096/8]; /* 任务栈 */ staticuint64_t AppTaskStartStk[1024/8]; /* 任务栈 */ 将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。 系统栈大小分配: RTX初始化: - /*
- *********************************************************************************************************
- * 函 数 名: main
- * 功能说明: 标准c程序入口。
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- int main (void)
- {
- /* 初始化外设 */
- bsp_Init();
-
- /* 创建启动任务 */
- os_sys_init_user (AppTaskStart, /* 任务函数 */
- 5, /* 任务优先级 */
- &AppTaskStartStk, /* 任务栈 */
- sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
- while(1);
- }
复制代码
硬件外设初始化 硬件外设的初始化是在 bsp.c 文件实现: - /*
- *********************************************************************************************************
- * 函 数 名: bsp_Init
- * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void bsp_Init(void)
- {
- /*
- 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
- 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
-
- 系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
- */
- /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
-
- SystemCoreClockUpdate(); /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
-
- bsp_InitDWT(); /* 初始化DWT */
- bsp_InitUart(); /* 初始化串口 */
- bsp_InitKey(); /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
-
- bsp_InitExtIO(); /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
- bsp_InitLed(); /* 初始LED指示灯端口 */
-
- MountSD(); /* 挂载SD卡 */
- }
复制代码
RTX任务创建: - /*
- *********************************************************************************************************
- * 函 数 名: AppTaskCreate
- * 功能说明: 创建应用任务
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void AppTaskCreate (void)
- {
- HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */
- 1, /* 任务优先级 */
- &AppTaskUserIFStk, /* 任务栈 */
- sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
-
- HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */
- 2, /* 任务优先级 */
- &AppTaskLEDStk, /* 任务栈 */
- sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */
-
- HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */
- 3, /* 任务优先级 */
- &AppTaskMsgProStk, /* 任务栈 */
- sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
-
- HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain, /* 任务函数 */
- 4, /* 任务优先级 */
- &AppTaskTCPMainStk, /* 任务栈 */
- sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
- }
复制代码
五个RTX任务的实现:
RL-TCPnet功能测试 这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,此文件主要实现开发板发给FTP服务器的文件操作命令和网络主函数main_TcpNet的调用。 - #include "includes.h"
-
-
-
- /*
- *********************************************************************************************************
- * 用于本文件的调试
- *********************************************************************************************************
- */
- #if 1
- #define printf_debug printf
- #else
- #define printf_debug(...)
- #endif
-
-
- /*
- *********************************************************************************************************
- * 宏定义,远程FTP服务器的IP和端口
- *********************************************************************************************************
- */
- /* 要访问的远程FTP服务器IP配置 */
- #define IP1 192
- #define IP2 168
- #define IP3 1
- #define IP4 4
-
- #define PORT_NUM 21 /* FTP服务器,默认端口号是21,无需改动 */
-
-
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- uint8_t ServerIP[4] = {IP1, IP2, IP3, IP4};
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: ftpc_notify
- * 功能说明: 函数ftpc_connect的回调函数。
- * 形 参: event 事件类型
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void ftpc_notify (U8 event)
- {
- switch (event)
- {
- /* 文件操作成功 */
- case FTPC_EVT_SUCCESS:
- printf_debug ("Command successful\n");
- break;
-
- /* 失败,因为FTP服务器响应时间溢出,因此FTP客户端终止操作 */
- case FTPC_EVT_TIMEOUT:
- printf_debug ("Failed, timeout expired\n");
- break;
-
- /* 失败,FTP客户端登陆FTP服务器失败 */
- case FTPC_EVT_LOGINFAIL:
- printf ("Failed, username/password invalid\n");
- break;
-
- /* 失败,禁止操作此文件 */
- case FTPC_EVT_NOACCESS:
- printf_debug ("Failed, operation not allowed\n");
- break;
-
- /* 失败,在FTP服务器上找不到请求的文件 */
- case FTPC_EVT_NOTFOUND:
- printf_debug ("Failed, file or path not found\n");
- break;
-
- /* 失败,在FTP服务器上找不到工作目录路径 */
- case FTPC_EVT_NOPATH:
- printf ("Failed, working directory not found\n");
- break;
-
- /* 失败,文件打开或者写入出错,即FTP客户端操作SD卡或者其它存储介质出错 */
- case FTPC_EVT_ERRLOCAL:
- printf_debug ("Failed, local file open/write error\n");
- break;
-
- /* 失败,未指定的协议错误,或者说在文件操作过程中遇到错误 */
- case FTPC_EVT_ERROR:
- printf_debug ("Failed, unspecified protocol error\n");
- break;
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TCPnetTest
- * 功能说明: TCPent测试函数。
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TCPnetTest(void)
- {
- OS_RESULT xResult;
-
- while (1)
- {
- os_evt_wait_or(0x003F, 0xFFFF);
-
- xResult = os_evt_get ();
- switch (xResult)
- {
- /* 接收到K2键按下,发送FTPC_CMD_GET命令,表示从FTP服务器下载文件 */
- case KEY2_BIT1:
- if (ftpc_connect (ServerIP, PORT_NUM, FTPC_CMD_GET, ftpc_notify) == 0)
- {
- printf_debug("Connect failed, the client is busy.\n");
- }
- else
- {
- printf_debug("FTP client started.\n");
- }
- break;
-
- /* 接收到K3键按下,发送FTPC_CMD_PUT命令,表示向FTP服务器上传文件 */
- case KEY3_BIT2:
- if (ftpc_connect (ServerIP, PORT_NUM, FTPC_CMD_PUT, ftpc_notify) == 0)
- {
- printf_debug("Connect failed, the client is busy.\n");
- }
- else
- {
- printf_debug("FTP client started.\n");
- }
- break;
-
- /* 接收到摇杆上键按下,发送FTPC_CMD_LIST命令,表示列出当前目录下所有文件详细信息 */
- case JOY_U_BIT3:
- if (ftpc_connect (ServerIP, PORT_NUM, FTPC_CMD_LIST, ftpc_notify) == 0)
- {
- printf_debug("Connect failed, the client is busy.\n");
- }
- else
- {
- printf_debug("FTP client started.\n");
- }
- break;
-
- /* 接收到摇杆左键按下,发送FTPC_CMD_MKDIR命令,表示创建一个文件夹 */
- case JOY_L_BIT4:
- if (ftpc_connect (ServerIP, PORT_NUM, FTPC_CMD_MKDIR, ftpc_notify) == 0)
- {
- printf_debug("Connect failed, the client is busy.\n");
- }
- else
- {
- printf_debug("FTP client started.\n");
- }
- break;
-
- /* 接收到摇杆右键按下,发送FTPC_CMD_RMDIR命令,表示删除一个文件夹,文件夹为空的时候才可以删除 */
- case JOY_R_BIT5:
- if (ftpc_connect (ServerIP, PORT_NUM, FTPC_CMD_RMDIR, ftpc_notify) == 0)
- {
- printf_debug("Connect failed, the client is busy.\n");
- }
- else
- {
- printf_debug("FTP client started.\n");
- }
- break;
-
- /* 其他的键值不处理 */
- default:
- break;
- }
-
- while (main_TcpNet() == __TRUE);
- }
- }
复制代码
FTP用户接口文件的实现 KEIL官网有提供FTP的接口文件,名为FTPC_uif.c文件。我们就是在这个文件上修改。具体修改后的代码如下: - #include <Net_Config.h>
- #include <stdio.h>
-
- #define FTPC_USERNAME "armfly" /* 远程FTP服务器的账号 */
- #define FTPC_PASSWORD "123456" /* 远程FTP服务器的密码 */
- #define FTPC_PATH "" /* 要访问的子文件夹,FTP电脑端设置后是没有路径的,填空 */
- #define FTPC_FILENAME "server.pdf" /* 要访问的文件 */
- #define FTPC_NEWNAME "renamed.pdf" /* 使用这里定义的文件字重命名宏定义FTPC_FILENAME的文件名 */
- #define FTPC_DIRNAME "New_Folder" /* 创建名字为New_Folder的文件夹或者删除名字为New_Folder的文件夹 */
- #define FTPC_LISTNAME "*" /* 浏览宏定义FTPC_PATH路径下所有文件 */
-
- #define LOCAL_FILE "client.pdf" /* 开发板SD卡里面要上传的文件,或者从FTP服务器下载文件后,
- 文件会被设置成此名字 */
-
-
- /*----------------------------------------------------------------------------
- * FTP Client File Access and Data CallBack Functions
- *---------------------------------------------------------------------------*/
-
- /*--------------------------- ftpc_fopen ------------------------------------*/
-
- void *ftpc_fopen (U8 *mode) {
- /* Open local file for reading or writing. If the return value is NULL, */
- /* processing of FTP Client commands PUT, APPEND or GET is cancelled. */
- return (fopen (LOCAL_FILE, (char *)mode));
- }
-
-
- /*--------------------------- ftpc_fclose -----------------------------------*/
-
- void ftpc_fclose (void *file) {
- /* Close a local file. */
- fclose (file);
- }
-
-
- /*--------------------------- ftpc_fread ------------------------------------*/
-
- U16 ftpc_fread (void *file, U8 *buf, U16 len) {
- /* Read 'len' bytes from file to buffer 'buf'. Return number of bytes */
- /* copied. The file will be closed, when the return value is 0. */
- /* For optimal performance the return value should be 'len' */
- return (fread (buf, 1, len, file));
- }
-
-
- /*--------------------------- ftpc_fwrite -----------------------------------*/
-
- U16 ftpc_fwrite (void *file, U8 *buf, U16 len) {
- /* Write 'len' bytes from buffer 'buf' to a file. Data transfer will be */
- /* aborted, if the return value is not equal 'len'. */
- return (fwrite (buf, 1, len, file));
- }
-
-
- /*--------------------------- ftpc_cbfunc -----------------------------------*/
-
- U16 ftpc_cbfunc (U8 code, U8 *buf, U16 buflen) {
- /* This function is called by the FTP client to get parameters. It returns*/
- /* the number of bytes written to buffer 'buf'. This function should NEVER*/
- /* write more than 'buflen' bytes to this buffer. */
- /* Parameters: */
- /* code - function code with following values: */
- /* 0 = Username for FTP authentication */
- /* 1 = Password for FTP authentication */
- /* 2 = Working directory path for all commands */
- /* 3 = Filename for PUT, GET, APPEND, DELETE, RENAME command */
- /* 4 - New filename for RENAME command */
- /* 5 - Directory name for MKDIR, RMDIR command */
- /* 6 - File filter/mask for LIST command (wildcards allowed) */
- /* 7 = Received directory listing on LIST command */
- /* buf - transmit/receive buffer */
- /* buflen - length of this buffer */
- /* on transmit, it specifies size of 'buf' */
- /* on receive, specifies the number of bytes received */
- U32 i,len = 0;
-
- switch (code) {
- case 0:
- /* Enter Username for login. */
- len = str_copy (buf, FTPC_USERNAME);
- break;
-
- case 1:
- /* Enter Password for login. */
- len = str_copy (buf, FTPC_PASSWORD);
- break;
-
- case 2:
- /* Enter a working directory path. */
- len = str_copy (buf, FTPC_PATH);
- break;
-
- case 3:
- /* Enter a filename for file operations. */
- len = str_copy (buf, FTPC_FILENAME);
- break;
-
- case 4:
- /* Enter a new name for rename command. */
- len = str_copy (buf, FTPC_NEWNAME);
- break;
-
- case 5:
- /* Enter a directory name to create or remove. */
- len = str_copy (buf, FTPC_DIRNAME);
- break;
-
- case 6:
- /* Enter a file filter for list command. */
- len = str_copy (buf, FTPC_LISTNAME);
- break;
-
- case 7:
- /* Process received directory listing in raw format. */
- /* Function return value is don't care. */
- for (i = 0; i < buflen; i++) {
- putchar (buf[i]);
- }
- break;
- }
- return ((U16)len);
- }
-
-
- /*----------------------------------------------------------------------------
- * end of file
- *---------------------------------------------------------------------------*/
复制代码
|