硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2342|回复: 6
收起左侧

[RL-TCPnet教程] 【RL-TCPnet网络教程】第40章 RL-TCPnet之TFTP客户端

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2017-12-29 15:24:25 | 显示全部楼层 |阅读模式
第40章      RL-TCPnet之TFTP客户端

      本章节为大家讲解RL-TCPnet的TFTP客户端应用,学习本章节前,务必要优先学习第38章的TFTP基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的效果。
      本章教程含STM32F407开发板和STM32F429开发板。
40.1 初学者重要提示
40.2 TFTP函数
40.3 TFTP配置说明(Net_Config.c)
40.4 TFTP调试说明(Net_Debug.c)
40.5 TFTP服务器端软件和板子的操作步骤
40.6实验例程说明(RTX)
40.7 总结



40.1  初学者重要提示

1、学习本章节前,务必保证已经学习了第38章的基础知识。
2、本章配套的例子是将开发板作为TFTP客户端,使用开发板上面的SD卡作为客户端的存储介质。所以测试本章节的例子,务必要准备一个SD卡。
3、由于配套例子的文件系统是采用的RL-FlashFS,此文件系统的文件名仅支持ASCII字符,不支持中文,特别注意!
4、具体电脑端TFTP服务器的创建方法和板子的操作步骤在本章的40.5小节有详细说明。做本章节配套的实验,必须要看!
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 15:33:42 | 显示全部楼层
40.2  TFTP函数
      使用如下11个函数可以实现RL-TCPnet的TFTP:
(1)tftp_accept_host
(2)tftp_fclose
(3)tftp_fopen
(4)tftp_fread
(5)tftp_fwrite
(6)tftpc_fclose
(7)tftpc_fopen
(8)tftpc_fread
(9)tftpc_fwrite
(10)tftpc_get
(11)tftpc_put
关于这11个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件:
40.1.png
                              
这里我们重点的说以下6个函数,因为本章节配套的例子使用的是这6个函数:
(1)tftpc_fclose
(2)tftpc_fopen
(3)tftpc_fread
(4)tftpc_fwrite
(5)tftpc_get
(6)tftpc_put
关于这些函数注意以下三点:
1、TFTP的所有函数都不支持重入,也就是不支持多任务调用。
2、以tftp_开头的函数是用于TFTP服务器的。
3、以tftpc_开头的函数是用于TFTP客户端的。

40.2.1   函数tftpc_fopen
函数原型:
  1. void* tftpc_fopen (
  2.     U8* fname,     /* 文件名地址 */
  3. U8* mode );    /* 操作模式 */
复制代码
函数描述:
函数tftpc_fopen用于打开本地文件(TFTP客户端的文件)。此函数在MDK安装目录中的TFTPC_uif.c文件里面,属于底层接口函数,用户要在此函数里面添加具体的操作。
1、第1个参数是文件名地址。
2、第2个参数是操作模式,可以是读操作或者写操作,具体支持的形参类型如下:
40.2.png
3、返回值,打开文件成功的话,返回指向此文件的指针变量,否则返回NULL。
使用这个函数要注意以下问题:
1.     此接口函数是用于TFTP客户端的。
使用举例:
  1. void *tftpc_fopen (U8 *fname, U8 *mode) {
  2.   /* 打开文件,如果返回NULL,表示打开失败  */
  3.   return (fopen ((char *)fname, (char *)mode));
  4. }
复制代码

40.2.2   函数tftpc_fclose
函数原型:
  1. void tftpc_fclose (
  2. FILE* file );    /* 文件句柄地址 */
复制代码
函数描述:
函数tftpc_fclose用于关闭文件。此函数在MDK安装目录中的TFTPC_uif.c文件里面,属于底层接口函数,用户要在此函数里面添加具体的操作。
1、第1个参数是要关闭的文件句柄地址。
使用这个函数要注意以下问题:
1.     此接口函数是用于TFTP客户端的。
使用举例:
  1. void tftpc_fclose (void *file) {
  2.    /* 关闭文件 */
  3.   fclose (file);
  4. }
复制代码

40.2.3   函数tftpc_fread
函数原型:
  1. U16 tftpc_fread (
  2.     FILE* file,     /* 文件句柄地址 */
  3.     U8*   buf,      /* 数据缓冲地址 */
  4.     U16   len );    /* 要读取的字节数 */
复制代码
函数描述:
函数tftpc_fread用于从文件中读出len个字节数据。此函数在MDK安装目录中的TFTPC_uif.c文件里面,属于底层接口函数,用户要在此函数里面添加具体的操作。
1、第1个参数是要读取数据的文件句柄地址。
2、第2个参数是数据缓冲地址,用于存储读取出来的数据。
3、第3个参数是要读取出来的数据大小,单位字节。
4、返回值,返回从文件中实际读出的字节数。
使用这个函数要注意以下问题:
1.     设置读取函数时,必须设置指定大小的字节数。如果实际读出的字节数小于len,将停止读取并关闭TFTP会话,这种情况一般都是文件已经读取完毕。
2.     此接口函数是用于TFTP客户端的。
使用举例:
  1. U16 tftpc_fread (void *file, U8 *buf, U16 len) {
  2. /* 读取len字节到buf中,返回值是实际读取的字节数,返回数值小于len的话,表示文件已经读取完毕,
  3. 文件将被关闭 */
  4.   return (fread (buf, 1, len, file));
  5. }
复制代码

40.2.4   函数tftpc_fwrite
函数原型:
  1. U16 tftpc_fwrite (
  2.     FILE* file,     /* 文件句柄地址 */
  3.     U8*   buf,      /* 数据缓冲地址 */
  4.     U16   len );    /* 要写入的字节数 */
复制代码
函数描述:
函数tftpc_fwrite用于往文件中写入len个字节数据。此函数在MDK安装目录中的TFTPC_uif.c文件里面,属于底层接口函数,用户要在此函数里面添加具体的操作。
1、第1个参数是要写入数据的文件句柄地址。
2、第2个参数是数据缓冲地址,存储了要写入的数据。
3、第3个参数是要写入的数据大小,单位字节。
4、返回值,返回实际写入文件的字节数。
使用这个函数要注意以下问题:
1.     设置写函数时,必须设置指定大小的字节数。如果实际写入的字节数小于len,TFTP客户端将停止写入,终止数据传输并关闭TFTP会话,这种情况一般是写操作出错了。
2.     此接口函数是用于TFTP客户端的。
使用举例:
  1. U16 tftpc_fwrite (void *file, U8 *buf, U16 len) {
  2.   /* 将buf中的len字节写入到文件中,如果返回数值(实际写入的字节数)不等于len,数据传输将终止 */
  3.   return (fwrite (buf, 1, len, file));
  4. }
复制代码

40.2.5   函数tftpc_get
函数原型:
  1. BOOL tftpc_get (
  2.     U8*   ipadr,                   /* 远程TFTP服务器的IP地址 */
  3.     U16   port,                    /* 远程TFTP服务器的端口号 */
  4.     const char *src,               /* 远程TFTP服务器上的文件名 */
  5.     const char *dst,               /* 保存到本地的文件名 */
  6.     void (*cbfunc)(U8 event) );    /* 回调函数 */
复制代码
函数描述:
函数tftpc_get用于启动RL-TCPnet系统上的TFTP客户端,将文件从远程TFTP服务器下载到本地系统。 这样TFTP客户端就可以通过连接到UDP端口号为port(本函数的第2个形参)的TFTP服务器来启动TFTP会话。如果第2个参数的端口号填0,系统将使用TFTP服务器的标准端口号69进行连接。
1、第1个参数填TFTP服务器的IP地址。
2、第2个参数填TFTP服务器的端口号。
3、第3个参数是TFTP服务器上的文件名,即TFTP客户端要下载的文件名。
4、第4个参数是TFTP客户端上新建文件的文件名,用于存储从TFTP客户端下载的文件。如果这个参数填NULL,那么此文件在TFTP服务器上的文件名是什么,下载后还是什么。
5、第5个参数填此函数的回调函数,当TFTP会话即将结束时,会调用这个函数。此回调函数只有一个形参,形参类型如下:
40.3.png
6、返回值,返回__TRUE表示TFTP客户端启动成功(注意,仅仅是客户端启动成功,并不是文件传输已经完成),返回__FALSE表示启动失败。
使用这个函数要注意以下问题:
1.     标准TFTP的端口号是用的UDP端口69。
2.     用户是通过此函数启动RL-TCPnet的TFTP客户端下载TFTP服务器上的文件。
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *                              宏定义,远程FTP服务器的IP和端口
  4. *********************************************************************************************************
  5. */
  6. /* 要访问的远程FTP服务器IP配置 */
  7. #define IP1            192
  8. #define IP2            168
  9. #define IP3            1
  10. #define IP4            4

  11. #define PORT_NUM       69  /* FTP服务器,默认端口号是69,无需改动 */


  12. /*
  13. *********************************************************************************************************
  14. *                                         变量
  15. *********************************************************************************************************
  16. */
  17. uint8_t ServerIP[4] = {IP1, IP2, IP3, IP4};


  18. /*
  19. *********************************************************************************************************
  20. *    函 数 名: ftpc_notify
  21. *    功能说明: 函数tftpc_put和tftpc_get的回调函数。
  22. *    形    参: event  事件类型
  23. *    返 回 值: 无
  24. *********************************************************************************************************
  25. */
  26. static void tftpc_notify (U8 event)
  27. {
  28.      switch (event)
  29.      {
  30.           /* 文件传输成功 */
  31.          case TFTPC_EVT_SUCCESS:
  32.               printf_debug ("File successfully transferred.\r\n");
  33.               break;
  34.         
  35.           /* TFTP服务器响应超时,因此TFTP客户端终止操作 */
  36.          case TFTPC_EVT_TIMEOUT:
  37.               printf_debug ("TFTP Server timeout.\r\n");
  38.               break;
  39.    
  40.          /* 访问的是禁止操作的文件 */
  41.           case TFTPC_EVT_NOACCESS:
  42.               printf_debug ("File access on TFTP server is not allowed for a specified file.\r\n");
  43.               break;

  44.           /* 在TFTP服务器上找不到要访问的文件 */
  45.          case TFTPC_EVT_NOTFOUND:
  46.               printf_debug ("Requested file is not found on TFTP server.\r\n");
  47.               break;

  48.          /* TFTP服务器的存储器空间已经满,无法再进行文件传输 */
  49.          case TFTPC_EVT_DISKFULL:
  50.               printf_debug ("The TFTP server has run out of disk space.\r\n");
  51.               break;
  52.         
  53.           /* 文件传输过程中,TFTP服务器遇到一个错误 */
  54.          case TFTPC_EVT_ERROR:
  55.               printf_debug ("The TFTP server has encountered an error during file transfer process.\r\n");
  56.               break;
  57.         
  58.           /* 其它未定义 */
  59.          default:
  60.               printf_debug ("No Defined.\n");
  61.               break;
  62.      }
  63. }

  64. /*
  65. *********************************************************************************************************
  66. *    函 数 名: TCPnetTest
  67. *    功能说明: TCPent测试函数。
  68. *    形    参: 无
  69. *    返 回 值: 无
  70. *********************************************************************************************************
  71. */
  72. void TCPnetTest(void)
  73. {
  74.      OS_RESULT xResult;
  75.    
  76.      while (1)
  77.      {
  78.          os_evt_wait_or(0x0007, 0xFFFF);
  79.         
  80.          xResult = os_evt_get ();
  81.          switch (xResult)
  82.          {
  83.               /* 接收到K2键按下,从TFTP服务器下载文件server.pdf,并重命名为client.pdf  */
  84.               case KEY2_BIT1:      
  85.                    if (tftpc_get (ServerIP, PORT_NUM, "server.pdf", "client.pdf", tftpc_notify) == __FALSE)
  86.                    {
  87.                        printf_debug("File transfer not started, TFTP Client not ready.\n");
  88.                    }
  89.                    else
  90.                    {
  91.                        printf_debug("File transfer started.\n");
  92.                    }                 
  93.                    break;
  94.                   
  95.             
  96.                /* 其他的键值不处理 */
  97.               default:                    
  98.                    break;
  99.          }
  100.             
  101.          while (main_TcpNet() == __TRUE);
  102.      }
  103. }
复制代码

40.2.6   函数ftpc_put
函数原型:
  1. BOOL tftpc_put (
  2.     U8*   ipadr,                   /* 远程TFTP服务器的IP地址. */
  3.     U16   port,                    /* 远程TFTP服务器的IP地址. */
  4.     const char *src,               /* 本地要上传文件的文件名 */
  5.     const char *dst,               /* 远程TFTP服务器上文件的文件名 */
  6.     void (*cbfunc)(U8 event) );    /* 回调函数 */
复制代码
函数描述:
函数tftpc_put用于启动RL-TCPnet系统上的TFTP客户端,将本地文件上传到TFTP服务器。 这样TFTP客户端就可以通过连接到UDP端口号为port(本函数的第2个形参)的TFTP服务器来启动TFTP会话。如果第2个参数的端口号填0,系统将使用TFTP服务器的标准端口号69进行连接。
1、第1个参数填TFTP服务器的IP地址。
2、第2个参数填TFTP服务器的端口号。
3、第3个参数是TFTP客户端上的文件名,此文件是要被上传到TFTP服务器。
4、第4个参数是TFTP服务器上新建文件的文件名,用于存储从TFTP客户端上传的文件。如果这个参数填NULL,那么此文件在TFTP客户端上文件名是什么,上传到TFTP服务器后还是什么。
5、第5个参数填此函数的回调函数,当TFTP会话即将结束时,会调用这个函数。此回调函数只有一个形参,形参类型如下:
40.4.png
6、返回值,返回__TRUE表示TFTP客户端启动成功(注意,仅仅是客户端启动成功,并不是文件传输已经完成),返回__FALSE表示启动失败。
使用这个函数要注意以下问题:
1.     标准TFTP的端口号是用的UDP端口69。
2.     用户是通过此函数启动RL-TCPnet的TFTP客户端上传本地文件到TFTP服务器。
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *                              宏定义,远程FTP服务器的IP和端口
  4. *********************************************************************************************************
  5. */
  6. /* 要访问的远程FTP服务器IP配置 */
  7. #define IP1            192
  8. #define IP2            168
  9. #define IP3            1
  10. #define IP4            4

  11. #define PORT_NUM       69  /* FTP服务器,默认端口号是69,无需改动 */


  12. /*
  13. *********************************************************************************************************
  14. *                                         变量
  15. *********************************************************************************************************
  16. */
  17. uint8_t ServerIP[4] = {IP1, IP2, IP3, IP4};


  18. /*
  19. *********************************************************************************************************
  20. *    函 数 名: ftpc_notify
  21. *    功能说明: 函数tftpc_put和tftpc_get的回调函数。
  22. *    形    参: event  事件类型
  23. *    返 回 值: 无
  24. *********************************************************************************************************
  25. */
  26. static void tftpc_notify (U8 event)
  27. {
  28.      switch (event)
  29.      {
  30.           /* 文件传输成功 */
  31.          case TFTPC_EVT_SUCCESS:
  32.               printf_debug ("File successfully transferred.\r\n");
  33.               break;
  34.         
  35.           /* TFTP服务器响应超时,因此TFTP客户端终止操作 */
  36.          case TFTPC_EVT_TIMEOUT:
  37.               printf_debug ("TFTP Server timeout.\r\n");
  38.               break;
  39.    
  40.          /* 访问的是禁止操作的文件 */
  41.           case TFTPC_EVT_NOACCESS:
  42.               printf_debug ("File access on TFTP server is not allowed for a specified file.\r\n");
  43.               break;

  44.           /* 在TFTP服务器上找不到要访问的文件 */
  45.          case TFTPC_EVT_NOTFOUND:
  46.               printf_debug ("Requested file is not found on TFTP server.\r\n");
  47.               break;

  48.          /* TFTP服务器的存储器空间已经满,无法再进行文件传输 */
  49.          case TFTPC_EVT_DISKFULL:
  50.               printf_debug ("The TFTP server has run out of disk space.\r\n");
  51.               break;
  52.         
  53.           /* 文件传输过程中,TFTP服务器遇到一个错误 */
  54.          case TFTPC_EVT_ERROR:
  55.               printf_debug ("The TFTP server has encountered an error during file transfer process.\r\n");
  56.               break;
  57.         
  58.           /* 其它未定义 */
  59.          default:
  60.               printf_debug ("No Defined.\n");
  61.               break;
  62.      }
  63. }

  64. /*
  65. *********************************************************************************************************
  66. *    函 数 名: TCPnetTest
  67. *    功能说明: TCPent测试函数。
  68. *    形    参: 无
  69. *    返 回 值: 无
  70. *********************************************************************************************************
  71. */
  72. void TCPnetTest(void)
  73. {
  74.      OS_RESULT xResult;
  75.    
  76.      while (1)
  77.      {
  78.          os_evt_wait_or(0x0007, 0xFFFF);
  79.         
  80.          xResult = os_evt_get ();
  81.          switch (xResult)
  82.          {                 
  83.               /* 接收到K3键按下,K2按键按下后下载的client.pdf文件上传到TFTP服务器 */
  84.               case KEY3_BIT2:   
  85.                    if (tftpc_put (ServerIP, PORT_NUM, "client.pdf", NULL, tftpc_notify) == __FALSE)
  86.                    {
  87.                        printf("File transfer not started, TFTP Client not ready.\n");
  88.                    }
  89.                    else
  90.                    {
  91.                        printf_debug("File transfer started.\n");
  92.                    }
  93.                    break;
  94.             
  95.                /* 其他的键值不处理 */
  96.               default:                    
  97.                    break;
  98.          }
  99.             
  100.          while (main_TcpNet() == __TRUE);
  101.      }
  102. }
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 15:50:53 | 显示全部楼层
本帖最后由 席萌0209 于 2017-12-29 15:52 编辑

40.3 TFTP配置说明(Net_Config.c)
      (本章节配套例子的配置与本小节的说明相同)
      RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:
40.5.png
                              
RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。
40.6.png
System Definitions
(1)Local Host Name
      局域网域名。
      这里起名为armfly,使用局域网域名限制为15个字符。
(2)Memory Pool size
      参数范围1536-262144字节。
      内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。
(3)Tick Timer interval
      可取10,20,25,40,50,100,200,单位ms。
      系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。
40.7.png
Ethernet Network Interface
      以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP
(1)MAC Address
      局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。
(2)IP Address
      IP地址。
(3)Subnet mask
      子网掩码。
(4)Default Gateway
      默认网关。
40.8.png
Ethernet Network Interface
      以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。
(1)NetBIOS Name Service
      NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。
(2)Dynaminc Host Configuration
      即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。
40.9.png
UDP Sockets
UDP Sockets配置,打上对勾就使能了此项功能
(1)Number of UDP Sockets
      用于配置可创建的UDP Sockets数量,这里配置了5个。
      范围1 – 20。
40.10.png
TCP Sockets
TCP Sockets配置,打上对勾就使能了此项功能
(1)Number of TCP Sockets
      用于配置可创建的TCP Sockets数量。
(2)Number of Retries
      范围0-20。
      用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。
(3)Retry Timeout in seconds
      范围1-10,单位秒。
      重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。
(4)Default Connect Timeout in seconds
      范围1-600,单位秒。
      用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。
(5)Maximum Segment Size
      范围536-1460,单位字节。
      MSS定义了TCP数据包能够传输的最大数据分段。
(6)Receive Window Size
      范围536-65535,单位字节。
      TCP接收窗口大小。
40.11.png
TFTP Client
TFTP 配置,打上对勾就使能了此项功能
(1)Block Size
      每次传输的块大小,可以选择128,256,512,1024和1428,单位字节。
(2)Number of Retries
      TFTP客户端放弃发送前,可以尝试的发送次数,超过这个次数还没有发送成功,将放弃发送。
      范围1-10次。
(3)Retry Timeout
      如果这段时间内数据帧未被确认,TFTP客户端将重新发送数据。
      可以选择的重传溢出时间有200ms,500ms,1sec,2sec,5sec和10sec。

40.4 TFTP调试说明(Net_Debug.c)
      (重要说明,RL-TCPnet的调试是通过串口打印出来的)
      RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:
40.12.png
Print Time Stamp
      勾选了此选项的话,打印消息时,前面会附带时间信息。
其它所有的选项
      默认情况下,所有的调试选项都关闭了,每个选项有三个调试级别可选择,这里我们以TFTP Client
Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Fulldebug三个调试级别可供选择,每个调试选项里面都是这三个级别。
40.13.png
      Off:表示关闭此选项的调试功能。
      Errorsonly:表示仅在此选项出错时,将其错误打印出来。
      Fulldebug:表示此选项的全功能调试。
      具体测试,我们这里就不做了,大家可以按照第11章讲解的调试方法进行测试

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 15:59:58 | 显示全部楼层
本帖最后由 席萌0209 于 2017-12-29 16:01 编辑

40.5 TFTP服务器端软件和板子的操作步骤
      本章节的测试稍麻烦些,需要大家配置工程,并且在电脑端建立一个TFTP服务器,而开发板是作为客户端,并且采用SD卡作为存储介质(测试前要准备好一个SD卡插到开发板上面),所以大家测试本章节配套的例子前,务必将这里的操作步骤全部看完才可以做测试!
       另外有一点特别注意,我们使用的是RL-FlashFS文件系统,此文件系统的文件名仅支持ASCII字符,不支持中文,对于中文名的文件夹或者文件是无法操作的,因此,电脑端创建TFTP服务器的时候,使用的文件名也不要有中文。

40.5.1 获取电脑的IP地址
      获取电脑IP地址的方法很多,可以在网上邻居获取,也可以通过输入命令ipconfig获取:
(1)WIN+R组合键打开“运行”窗口,输入cmd。
40.14.png
(2)弹出的命令窗口中,输入ipconfig。
40.15.png
(3)输入ipconfig后,回车。
40.16.png
获得电脑的IP地址是192.168.1.4。

40.5.2 在程序中配置要访问的TFTP服务器IP地址和端口
      根据刚获得的IP地址,需要大家配置程序中app_tcpnet_lib.c文件开头的宏定义:
  1. /*
  2. *********************************************************************************************************
  3. *                              宏定义,远程TFTP服务器的IP和端口
  4. *********************************************************************************************************
  5. */
  6. /* 要访问的远程FTP服务器IP配置 */
  7. #define IP1            192
  8. #define IP2            168
  9. #define IP3            1
  10. #define IP4            4

  11. #define PORT_NUM       69  /* TFTP服务器,默认端口号是69,无需改动 */
复制代码

40.5.3 TFTP服务器软件安装和设置
第1步:下载TFTP服务器软件。
TFTP软件推荐采用TFTPD32,客户端和服务器都支持,分32bit和64bit两个版本,大家根据自己电脑系统选择相应版本进行安装,另外推荐绿色版,无需安装,使用起来简单省事。下载地址:http://bbs.armfly.com/read.php?tid=32486
第2步:下载绿色版后,解压出来就可以使用,打开软件的效果如下(我的系统是WIN764bit,所以使用的是64位版本):
40.17.png
第3步:关闭不需要的功能,仅留下TFTP Server(不是必须的,仅剩下服务器功能,看着简洁些)。
首先点击settings:
40.18.png
在弹出的窗口里面仅选择TFTP Server:
40.19.png
设置后,点击OK按键,弹出如下窗口,继续点击OK:
40.20.png
经过这么设置后,就仅剩下TFTP服务器功能了,为了使得设置的功能起作用,务必关闭软件,然后重新打开。
40.21.png
设置完毕后,就可以测试文件的上传和下载功能了。

40.5.4 开发板下载TFTP服务器上的文件
第1步:准备一个测试文件:
简单的在电脑桌面上创建一个文件夹,起名为good(任何其它地方均可,但建议不要有中文,防止测试不成功)
40.22.png
为了方便查看上传和下载文件的效果,找一个稍大些的文件放到此文件夹,这里将我们之前做的FreeRTOS教程放到这个新建的文件夹里面(已经将这个文件放在了本章节配套例子的Doc文件夹),起名为server.pdf,务必且只能设置成此名字,因为我们的程序中是配置成访问此文件。
40.23.png
仅放这一个文件即可。
第2步:配置文件访问路径:
现在需要将good文件夹路径添加到TFTP服务器软件上。
40.24.png
第3步:选择电脑端用于通信的网口IP:
40.25.png
设置完毕后就可以测试开发板下载TFTP服务器上的server.pdf文件了,首先需要用户先将SD卡插到开发板上,因为文件server.pdf是下载到开发板中的SD里面,然后下载本章节配套的程序,程序下载后,串口调试助手会打印网络初始化过程(波特率115200,数据位8,奇偶校验位无,停止位1):
40.26.png
上面的6条信息都打印出来后,就可以按下K2按键了,之后就可以看到开发板从TFTP服务器下载文件的进度,速度有1MB/S左右。
40.27.png
下载完毕后,大家可以查看SD卡中是否有一个client.pdf文件(程序中将下载的server.pdf文件重命名成client.pdf),然后查看此文件是否可以正常打开并浏览,如果正常的话,说明下载成功,否则下载失败。并且下载成功后,串口调试助手会打印如下信息:
40.28.png

40.5.5 开发板上传文件到TFTP服务器
      为了方便测试,我们这里直接将40.5.4小节中下载到开发板SD卡中的client.pdf文件上传到电脑端。上传后的名字不换,还叫client.pdf。对于TFTP服务器软件,还继续用之前设置好的,这里什么都不用修改,用户仅需按下开发板上的K3按键,之后就可以看到如下上传进度,速度1MB/S左右。
40.29.png
上传完毕后,为了验证下载是否成功,需要大家查看之前创建的good文件夹中client.pdf文件是否可以正常打开并浏览,如果没有问题,说明上传成功,否则失败。
40.30.png
并且上传成功后,串口调试助手会打印如下信息:
40.31.png
至此,TFTP客户端的文件上传和下载功能就都测试完毕了。

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 16:58:46 | 显示全部楼层
40.6 实验例程说明(RTX)
40.6.1 STM32F407开发板实验
配套例子:
      V5-1060_RL-TCPnet实验_TFTP客户端(RTX)
实验目的:
      1.     学习RL-TCPnet的TFTP客户端实现。
实验内容:
      1.      强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。
      2.      TFTP客户端的存储器是采用的SD卡,所以测试本例子前务必准备好一个SD卡并插上。
      3.      文件系统是采用的RL-FlashFS,此文件系统的文件名仅支持ASCII字符,不支持中文,特别注意!
      4.      远程TFTP服务器的IP地址和端口号是在文件app_tcpnet_lib.c开头的宏定义设置。
      5.      测试本例子,需要在电脑端先建立TFTP服务器,具体建立方法和本例子的测试步骤在本实例配套教程里面有详细讲解,必看!!
      6.      K2按键按下,将TFTP服务器上的server.pdf文件下载到开发板的SD卡中,重命名为client.pdf。
      7.      K3按键按下,将K2按键按下后下载的client.pdf文件上传回TFTP服务器。所以务必要优先测试K2按键的文件下载功能。
实验操作:
      详见本章节40.5小节。
配置向导文件设置(Net_Config.c):
      详见本章节40.3小节。
调试文件设置(Net_Debug.c):
      详见本章节40.4小节。
RTX配置:
      RTX配置向导详情如下:
40.32.png
                              
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任务调试信息:
40.33.png
程序设计:
任务栈大小分配:
      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类型数据运算会出问题。
系统栈大小分配:
40.34.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,              /* 任务函数 */
  16.                        5,                         /* 任务优先级 */
  17.                        &AppTaskStartStk,          /* 任务栈 */
  18.                        sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

硬件外设初始化
     硬件外设的初始化是在 bsp.c 文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。

  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

  18.      bsp_InitDWT();     /* 初始化DWT */
  19.      bsp_InitUart();    /* 初始化串口 */
  20.      bsp_InitKey();    /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  21.      bsp_InitLed();    /* 初始LED指示灯端口 */

  22.      MountSD();        /* 挂载SD卡 */
  23. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25.    
  26.     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */
  27.                                            4,                         /* 任务优先级 */
  28.                                            &AppTaskTCPMainStk,         /* 任务栈 */
  29.                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
  30. }
复制代码

五个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t ucKeyCode;

  13.     while(1)
  14.     {
  15.          ucKeyCode = bsp_GetKey();
  16.         
  17.          if (ucKeyCode != KEY_NONE)
  18.          {
  19.               switch (ucKeyCode)
  20.               {
  21.                    /* K1键按下 */
  22.                    case KEY_DOWN_K1:
  23.                        printf("K1键按下\r\n");        
  24.                        break;  

  25.                    /* K2键按下,直接发送事件标志给任务AppTaskTCPMain,设置bit1 */
  26.                    case KEY_DOWN_K2:
  27.                        printf("K2键按下,直接发送事件标志给任务AppTaskTCPMain,bit1被设置\r\n");
  28.                        os_evt_set (KEY2_BIT1, HandleTaskTCPMain);
  29.                        break;
  30.                   
  31.                    /* K3键按下,直接发送事件标志给任务AppTaskTCPMain,设置bit2 */
  32.                    case KEY_DOWN_K3:
  33.                        printf("K3键按下,直接发送事件标志给任务AppTaskTCPMain,bit2被设置\r\n");
  34.                        os_evt_set (KEY3_BIT2, HandleTaskTCPMain);
  35.                        break;
  36.                                     
  37.                    /* 其他的键值不处理 */
  38.                    default:                    
  39.                        break;
  40.               }
  41.          }
  42.         
  43.          os_dly_wait(20);
  44.      }
  45. }

  46. /*
  47. *********************************************************************************************************
  48. *    函 数 名: AppTaskLED
  49. *    功能说明: LED闪烁。
  50. *    形    参: 无
  51. *    返 回 值: 无
  52. *   优 先 级: 2
  53. *********************************************************************************************************
  54. */
  55. __task void AppTaskLED(void)
  56. {
  57.      const uint16_t usFrequency = 500; /* 延迟周期 */
  58.    
  59.      /* 设置延迟周期 */
  60.      os_itv_set(usFrequency);
  61.    
  62.     while(1)
  63.     {
  64.          bsp_LedToggle(2);

  65.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  66.          os_itv_wait();
  67.     }
  68. }

  69. /*
  70. *********************************************************************************************************
  71. *    函 数 名: AppTaskMsgPro
  72. *    功能说明: 按键检测
  73. *    形    参: 无
  74. *    返 回 值: 无
  75. *   优 先 级: 3
  76. *********************************************************************************************************
  77. */
  78. __task void AppTaskMsgPro(void)
  79. {
  80.     while(1)
  81.     {
  82.          bsp_KeyScan();
  83.          os_dly_wait(10);
  84.     }
  85. }

  86. /*
  87. *********************************************************************************************************
  88. *    函 数 名: AppTaskTCPMain
  89. *    功能说明: RL-TCPnet测试任务
  90. *    形    参: 无
  91. *    返 回 值: 无
  92. *   优 先 级: 4
  93. *********************************************************************************************************
  94. */
  95. __task void AppTaskTCPMain(void)
  96. {
  97.      while (1)
  98.      {
  99.          TCPnetTest();
  100.      }
  101. }

  102. /*
  103. *********************************************************************************************************
  104. *    函 数 名: AppTaskStart
  105. *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
  106. *    形    参: 无
  107. *    返 回 值: 无
  108. *   优 先 级: 5
  109. *********************************************************************************************************
  110. */
  111. __task void AppTaskStart(void)
  112. {
  113.      /* 初始化RL-TCPnet */
  114.      init_TcpNet ();
  115.    
  116.      /* 创建任务 */
  117.      AppTaskCreate();
  118.    
  119.      os_itv_set (100);
  120.    
  121.     while(1)
  122.     {
  123.          os_itv_wait ();
  124.         
  125.          /* RL-TCPnet时间基准更新函数 */
  126.          timer_tick ();
  127.          os_evt_set(0x0001, HandleTaskTCPMain);
  128.     }
  129. }
复制代码

RL-TCPnet功能测试
      这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,此文件主要实现开发板从TFTP服务器下载文件和上传文件到TFTP服务器以及网络主函数main_TcpNet的调用。
  1. #include "includes.h"



  2. /*
  3. *********************************************************************************************************
  4. *                                      用于本文件的调试
  5. *********************************************************************************************************
  6. */
  7. #if 1
  8.      #define printf_debug printf
  9. #else
  10.      #define printf_debug(...)
  11. #endif


  12. /*
  13. *********************************************************************************************************
  14. *                              宏定义,远程FTP服务器的IP和端口
  15. *********************************************************************************************************
  16. */
  17. /* 要访问的远程FTP服务器IP配置 */
  18. #define IP1            192
  19. #define IP2            168
  20. #define IP3            1
  21. #define IP4            4

  22. #define PORT_NUM       69  /* FTP服务器,默认端口号是69,无需改动 */


  23. /*
  24. *********************************************************************************************************
  25. *                                         变量
  26. *********************************************************************************************************
  27. */
  28. uint8_t ServerIP[4] = {IP1, IP2, IP3, IP4};


  29. /*
  30. *********************************************************************************************************
  31. *    函 数 名: ftpc_notify
  32. *    功能说明: 函数tftpc_put和tftpc_get的回调函数。
  33. *    形    参: event  事件类型
  34. *    返 回 值: 无
  35. *********************************************************************************************************
  36. */
  37. static void tftpc_notify (U8 event)
  38. {
  39.      switch (event)
  40.      {
  41.           /* 文件传输成功 */
  42.          case TFTPC_EVT_SUCCESS:
  43.               printf_debug ("File successfully transferred.\r\n");
  44.               break;
  45.         
  46.           /* TFTP服务器响应超时,因此TFTP客户端终止操作 */
  47.          case TFTPC_EVT_TIMEOUT:
  48.               printf_debug ("TFTP Server timeout.\r\n");
  49.               break;
  50.    
  51.          /* 访问的是禁止操作的文件 */
  52.           case TFTPC_EVT_NOACCESS:
  53.               printf_debug ("File access on TFTP server is not allowed for a specified file.\r\n");
  54.               break;

  55.           /* 在TFTP服务器上找不到要访问的文件 */
  56.          case TFTPC_EVT_NOTFOUND:
  57.               printf_debug ("Requested file is not found on TFTP server.\r\n");
  58.               break;

  59.          /* TFTP服务器的存储器空间已经满,无法再进行文件传输 */
  60.          case TFTPC_EVT_DISKFULL:
  61.               printf_debug ("The TFTP server has run out of disk space.\r\n");
  62.               break;
  63.         
  64.           /* 文件传输过程中,TFTP服务器遇到一个错误 */
  65.          case TFTPC_EVT_ERROR:
  66.               printf_debug ("The TFTP server has encountered an error during file transfer process.\r\n");
  67.               break;
  68.         
  69.           /* 其它未定义 */
  70.          default:
  71.               printf_debug ("No Defined.\n");
  72.               break;
  73.      }
  74. }

  75. /*
  76. *********************************************************************************************************
  77. *    函 数 名: TCPnetTest
  78. *    功能说明: TCPent测试函数。
  79. *    形    参: 无
  80. *    返 回 值: 无
  81. *********************************************************************************************************
  82. */
  83. void TCPnetTest(void)
  84. {
  85.      OS_RESULT xResult;
  86.    
  87.      while (1)
  88.      {
  89.          os_evt_wait_or(0x0007, 0xFFFF);
  90.         
  91.          xResult = os_evt_get ();
  92.          switch (xResult)
  93.          {
  94.               /* 接收到K2键按下,从TFTP服务器下载文件server.pdf,并重命名为client.pdf  */
  95.               case KEY2_BIT1:      
  96.                    if (tftpc_get (ServerIP, PORT_NUM, "server.pdf", "client.pdf", tftpc_notify) == __FALSE)
  97.                    {
  98.                        printf_debug("File transfer not started, TFTP Client not ready.\n");
  99.                    }
  100.                    else
  101.                    {
  102.                        printf_debug("File transfer started.\n");
  103.                    }                 
  104.                    break;
  105.                   
  106.               /* 接收到K3键按下,将K2按键按下后下载的client.pdf文件上传到TFTP服务器 */
  107.               case KEY3_BIT2:   
  108.                    if (tftpc_put (ServerIP, PORT_NUM, "client.pdf", NULL, tftpc_notify) == __FALSE)
  109.                    {
  110.                        printf("File transfer not started, TFTP Client not ready.\n");
  111.                    }
  112.                    else
  113.                    {
  114.                        printf_debug("File transfer started.\n");
  115.                    }
  116.                    break;
  117.             
  118.                /* 其他的键值不处理 */
  119.               default:                    
  120.                    break;
  121.          }
  122.             
  123.          while (main_TcpNet() == __TRUE);
  124.      }
  125. }
复制代码

TFTP用户接口文件的实现
      KEIL官网有提供TFTP的接口文件,名为TFTPC_uif.c文件。我们就是在这个文件上修改。具体修改后的代码如下:
  1. #include <stdio.h>
  2. #include <Net_Config.h>


  3. /*----------------------------------------------------------------------------
  4. * TFTP Client File Access Functions
  5. *---------------------------------------------------------------------------*/

  6. /*--------------------------- tftpc_fopen -----------------------------------*/

  7. void *tftpc_fopen (U8 *fname, U8 *mode) {
  8.   /* Open local file for reading or writing. */
  9.   return (fopen ((char *)fname, (char *)mode));
  10. }


  11. /*--------------------------- tftpc_fclose ----------------------------------*/

  12. void tftpc_fclose (void *file) {
  13.   /* Close a local file. */
  14.   fclose (file);
  15. }


  16. /*--------------------------- tftpc_read ------------------------------------*/

  17. U16 tftpc_fread (void *file, U8 *buf, U16 len) {
  18.   /* Read 'len' bytes from file to buffer 'buf'. Return number of bytes */
  19.   /* copied. The file will be closed, when the return value is < 'len'  */
  20.   return (fread (buf, 1, len, file));
  21. }


  22. /*--------------------------- tftpc_write -----------------------------------*/

  23. U16 tftpc_fwrite (void *file, U8 *buf, U16 len) {
  24.   /* Write data to file. Return number of bytes actually written. */
  25.   return (fwrite (buf, 1, len, file));
  26. }


  27. /*----------------------------------------------------------------------------
  28. * end of file
  29. *---------------------------------------------------------------------------*/
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 17:03:23 | 显示全部楼层
40.6.2 STM32F429开发板实验
配套例子:
      V6-1060_RL-TCPnet实验_TFTP客户端(RTX)
实验目的:
      1.     学习RL-TCPnet的TFTP客户端实现。
实验内容:
      1.      强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。
      2.      TFTP客户端的存储器是采用的SD卡,所以测试本例子前务必准备好一个SD卡并插上。
      3.      文件系统是采用的RL-FlashFS,此文件系统的文件名仅支持ASCII字符,不支持中文,特别注意!
      4.      远程TFTP服务器的IP地址和端口号是在文件app_tcpnet_lib.c开头的宏定义设置。
      5.      测试本例子,需要在电脑端先建立TFTP服务器,具体建立方法和本例子的测试步骤在本实例配套教程里面有详细讲解,必看!!
      6.      K2按键按下,将TFTP服务器上的server.pdf文件下载到开发板的SD卡中,重命名为client.pdf。
      7.      K3按键按下,将K2按键按下后下载的client.pdf文件上传回TFTP服务器。所以务必要优先测试K2按键的文件下载功能。
实验操作:
      详见本章节40.5小节。
配置向导文件设置(Net_Config.c):
      详见本章节40.3小节。
调试文件设置(Net_Debug.c):
      详见本章节40.4小节。
RTX配置:
      RTX配置向导详情如下:
40.35.png
                              
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任务调试信息:
40.36.png
程序设计:
任务栈大小分配:
      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类型数据运算会出问题。
系统栈大小分配:
40.37.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,              /* 任务函数 */
  16.                        5,                         /* 任务优先级 */
  17.                        &AppTaskStartStk,          /* 任务栈 */
  18.                        sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

硬件外设初始化
      硬件外设的初始化是在 bsp.c 文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.           由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。

  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

  18.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */

  19.      bsp_InitDWT();      /* 初始化DWT */
  20.      bsp_InitUart();     /* 初始化串口 */
  21.      bsp_InitKey();     /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */

  22.      bsp_InitExtIO();    /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  23.      bsp_InitLed();      /* 初始LED指示灯端口 */

  24.      MountSD();          /* 挂载SD卡 */
  25. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25.    
  26.     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */
  27.                                            4,                         /* 任务优先级 */
  28.                                            &AppTaskTCPMainStk,         /* 任务栈 */
  29.                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
  30. }
复制代码

五个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t ucKeyCode;

  13.     while(1)
  14.     {
  15.           ucKeyCode = bsp_GetKey();
  16.         
  17.          if (ucKeyCode != KEY_NONE)
  18.          {
  19.               switch (ucKeyCode)
  20.               {
  21.                    /* K1键按下 */
  22.                    case KEY_DOWN_K1:
  23.                        printf("K1键按下\r\n");        
  24.                        break;  

  25.                    /* K2键按下,直接发送事件标志给任务AppTaskTCPMain,设置bit1 */
  26.                    case KEY_DOWN_K2:
  27.                        printf("K2键按下,直接发送事件标志给任务AppTaskTCPMain,bit1被设置\r\n");
  28.                        os_evt_set (KEY2_BIT1, HandleTaskTCPMain);
  29.                        break;
  30.                   
  31.                    /* K3键按下,直接发送事件标志给任务AppTaskTCPMain,设置bit2 */
  32.                    case KEY_DOWN_K3:
  33.                        printf("K3键按下,直接发送事件标志给任务AppTaskTCPMain,bit2被设置\r\n");
  34.                        os_evt_set (KEY3_BIT2, HandleTaskTCPMain);
  35.                        break;
  36.                                     
  37.                    /* 其他的键值不处理 */
  38.                    default:                    
  39.                        break;
  40.               }
  41.          }
  42.         
  43.          os_dly_wait(20);
  44.      }
  45. }

  46. /*
  47. *********************************************************************************************************
  48. *    函 数 名: AppTaskLED
  49. *    功能说明: LED闪烁。
  50. *    形    参: 无
  51. *    返 回 值: 无
  52. *   优 先 级: 2
  53. *********************************************************************************************************
  54. */
  55. __task void AppTaskLED(void)
  56. {
  57.      const uint16_t usFrequency = 500; /* 延迟周期 */
  58.    
  59.      /* 设置延迟周期 */
  60.      os_itv_set(usFrequency);
  61.    
  62.     while(1)
  63.     {
  64.          bsp_LedToggle(2);

  65.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  66.          os_itv_wait();
  67.     }
  68. }

  69. /*
  70. *********************************************************************************************************
  71. *    函 数 名: AppTaskMsgPro
  72. *    功能说明: 按键检测
  73. *    形    参: 无
  74. *    返 回 值: 无
  75. *   优 先 级: 3
  76. *********************************************************************************************************
  77. */
  78. __task void AppTaskMsgPro(void)
  79. {
  80.     while(1)
  81.     {
  82.          bsp_KeyScan();
  83.          os_dly_wait(10);
  84.     }
  85. }

  86. /*
  87. *********************************************************************************************************
  88. *    函 数 名: AppTaskTCPMain
  89. *    功能说明: RL-TCPnet测试任务
  90. *    形    参: 无
  91. *    返 回 值: 无
  92. *   优 先 级: 4
  93. *********************************************************************************************************
  94. */
  95. __task void AppTaskTCPMain(void)
  96. {
  97.      while (1)
  98.      {
  99.          TCPnetTest();
  100.      }
  101. }

  102. /*
  103. *********************************************************************************************************
  104. *    函 数 名: AppTaskStart
  105. *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
  106. *    形    参: 无
  107. *    返 回 值: 无
  108. *   优 先 级: 5
  109. *********************************************************************************************************
  110. */
  111. __task void AppTaskStart(void)
  112. {
  113.      /* 初始化RL-TCPnet */
  114.      init_TcpNet ();
  115.    
  116.      /* 创建任务 */
  117.      AppTaskCreate();
  118.    
  119.      os_itv_set (100);
  120.    
  121.     while(1)
  122.     {
  123.          os_itv_wait ();
  124.         
  125.          /* RL-TCPnet时间基准更新函数 */
  126.          timer_tick ();
  127.          os_evt_set(0x0001, HandleTaskTCPMain);
  128.     }
  129. }
复制代码

RL-TCPnet功能测试
      这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,此文件主要实现开发板从TFTP服务器下载文件和上传文件到TFTP服务器以及网络主函数main_TcpNet的调用。
  1. #include "includes.h"



  2. /*
  3. *********************************************************************************************************
  4. *                                      用于本文件的调试
  5. *********************************************************************************************************
  6. */
  7. #if 1
  8.      #define printf_debug printf
  9. #else
  10.      #define printf_debug(...)
  11. #endif


  12. /*
  13. *********************************************************************************************************
  14. *                              宏定义,远程FTP服务器的IP和端口
  15. *********************************************************************************************************
  16. */
  17. /* 要访问的远程FTP服务器IP配置 */
  18. #define IP1            192
  19. #define IP2            168
  20. #define IP3            1
  21. #define IP4            4

  22. #define PORT_NUM       69  /* FTP服务器,默认端口号是69,无需改动 */


  23. /*
  24. *********************************************************************************************************
  25. *                                         变量
  26. *********************************************************************************************************
  27. */
  28. uint8_t ServerIP[4] = {IP1, IP2, IP3, IP4};


  29. /*
  30. *********************************************************************************************************
  31. *    函 数 名: ftpc_notify
  32. *    功能说明: 函数tftpc_put和tftpc_get的回调函数。
  33. *    形    参: event  事件类型
  34. *    返 回 值: 无
  35. *********************************************************************************************************
  36. */
  37. static void tftpc_notify (U8 event)
  38. {
  39.      switch (event)
  40.      {
  41.           /* 文件传输成功 */
  42.          case TFTPC_EVT_SUCCESS:
  43.               printf_debug ("File successfully transferred.\r\n");
  44.               break;
  45.         
  46.           /* TFTP服务器响应超时,因此TFTP客户端终止操作 */
  47.          case TFTPC_EVT_TIMEOUT:
  48.               printf_debug ("TFTP Server timeout.\r\n");
  49.               break;
  50.    
  51.          /* 访问的是禁止操作的文件 */
  52.           case TFTPC_EVT_NOACCESS:
  53.               printf_debug ("File access on TFTP server is not allowed for a specified file.\r\n");
  54.               break;

  55.           /* 在TFTP服务器上找不到要访问的文件 */
  56.          case TFTPC_EVT_NOTFOUND:
  57.               printf_debug ("Requested file is not found on TFTP server.\r\n");
  58.               break;

  59.          /* TFTP服务器的存储器空间已经满,无法再进行文件传输 */
  60.          case TFTPC_EVT_DISKFULL:
  61.               printf_debug ("The TFTP server has run out of disk space.\r\n");
  62.               break;
  63.         
  64.           /* 文件传输过程中,TFTP服务器遇到一个错误 */
  65.          case TFTPC_EVT_ERROR:
  66.               printf_debug ("The TFTP server has encountered an error during file transfer process.\r\n");
  67.               break;
  68.         
  69.           /* 其它未定义 */
  70.          default:
  71.               printf_debug ("No Defined.\n");
  72.               break;
  73.      }
  74. }

  75. /*
  76. *********************************************************************************************************
  77. *    函 数 名: TCPnetTest
  78. *    功能说明: TCPent测试函数。
  79. *    形    参: 无
  80. *    返 回 值: 无
  81. *********************************************************************************************************
  82. */
  83. void TCPnetTest(void)
  84. {
  85.      OS_RESULT xResult;
  86.    
  87.      while (1)
  88.      {
  89.          os_evt_wait_or(0x0007, 0xFFFF);
  90.         
  91.          xResult = os_evt_get ();
  92.          switch (xResult)
  93.          {
  94.               /* 接收到K2键按下,从TFTP服务器下载文件server.pdf,并重命名为client.pdf  */
  95.               case KEY2_BIT1:      
  96.                    if (tftpc_get (ServerIP, PORT_NUM, "server.pdf", "client.pdf", tftpc_notify) == __FALSE)
  97.                    {
  98.                        printf_debug("File transfer not started, TFTP Client not ready.\n");
  99.                    }
  100.                    else
  101.                    {
  102.                        printf_debug("File transfer started.\n");
  103.                    }                 
  104.                    break;
  105.                   
  106.               /* 接收到K3键按下,将K2按键按下后下载的client.pdf文件上传到TFTP服务器 */
  107.               case KEY3_BIT2:   
  108.                    if (tftpc_put (ServerIP, PORT_NUM, "client.pdf", NULL, tftpc_notify) == __FALSE)
  109.                    {
  110.                        printf("File transfer not started, TFTP Client not ready.\n");
  111.                    }
  112.                    else
  113.                    {
  114.                        printf_debug("File transfer started.\n");
  115.                    }
  116.                    break;
  117.             
  118.                /* 其他的键值不处理 */
  119.               default:                    
  120.                    break;
  121.          }
  122.             
  123.          while (main_TcpNet() == __TRUE);
  124.      }
  125. }
复制代码

TFTP用户接口文件的实现
      KEIL官网有提供TFTP的接口文件,名为TFTPC_uif.c文件。我们就是在这个文件上修改。具体修改后的代码如下:
  1. #include <stdio.h>
  2. #include <Net_Config.h>


  3. /*----------------------------------------------------------------------------
  4. * TFTP Client File Access Functions
  5. *---------------------------------------------------------------------------*/

  6. /*--------------------------- tftpc_fopen -----------------------------------*/

  7. void *tftpc_fopen (U8 *fname, U8 *mode) {
  8.   /* Open local file for reading or writing. */
  9.   return (fopen ((char *)fname, (char *)mode));
  10. }


  11. /*--------------------------- tftpc_fclose ----------------------------------*/

  12. void tftpc_fclose (void *file) {
  13.   /* Close a local file. */
  14.   fclose (file);
  15. }


  16. /*--------------------------- tftpc_read ------------------------------------*/

  17. U16 tftpc_fread (void *file, U8 *buf, U16 len) {
  18.   /* Read 'len' bytes from file to buffer 'buf'. Return number of bytes */
  19.   /* copied. The file will be closed, when the return value is < 'len'  */
  20.   return (fread (buf, 1, len, file));
  21. }


  22. /*--------------------------- tftpc_write -----------------------------------*/

  23. U16 tftpc_fwrite (void *file, U8 *buf, U16 len) {
  24.   /* Write data to file. Return number of bytes actually written. */
  25.   return (fwrite (buf, 1, len, file));
  26. }


  27. /*----------------------------------------------------------------------------
  28. * end of file
  29. *---------------------------------------------------------------------------*/
复制代码


努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-12-29 17:04:28 | 显示全部楼层
40.7  总结
      本章节就为大家讲解这么多,其中TFTP的测试稍麻烦些,希望大家实际动手操作一遍,并将其熟练掌握。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-11-1 07:27 , Processed in 0.405893 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表