[嵌入式开发模块]用于单线程的W5500控制驱动模块

左手的ㄟ右手 2022-05-14 11:25 625阅读 0赞

前言

上一篇中介绍了W5500的官方库中常用的函数的使用。通过这些函数,我们已经可以构建一个正常的TCP/IP应用了。但是上一篇中是一个个函数的讲,虽然是按照使用顺序,难免还是有些混乱。这一篇中,我直接给出了完整的程序框架和自己写的驱动模块,算是把上一篇中讲的整个给串了遍。

另:

  1. 这个模块使用的全是非阻塞调用,而且只用到了TCP和UDP,所以实际上官方库的代码中有很多都是可以裁剪掉的。我已经尝试过了裁剪并且可以正常运行,所以你会看到里头有两行include是”XXXX_lite.h”,但是已经注释掉而改成官方原版的库,毕竟目标肯定要完全兼容官方库的嘛。
  2. 模块只负责主要逻辑,不负责注册spi驱动函数等给官方库,需要用户自己注册。
  3. 官方库真要拿来做产品其实还有很多问题,主要是里头有很多无限循环等待,万一通讯出了一点问题可能程序就永远卡死了。所以实际还要对官方库进行修改,不能有无限循环。

模块代码

W5500Ctr.h

  1. /*
  2. *******************************************************************************************
  3. *
  4. *
  5. * W5500 CONTROLLER FOR SINGLE THREAD
  6. * W5500控制器(单线程)
  7. *
  8. * File : W5500Ctr.h
  9. * By : Lin Shijun(http://blog.csdn.net/lin_strong)
  10. * Date: 2018/09/05
  11. * version: V1.1
  12. * History: 2018/06/01 the prototype of W5500Ctr
  13. * 2018/09/05 V1.1 so many modifications.
  14. * NOTE(s): This module is intended to provide a framework to use W5500 on a single thread
  15. * with offical standard io library, which means all interact with W5500 should be
  16. * processed in on thread.
  17. code example
  18. #include <stdio.h>
  19. #include "SPI.h"
  20. #include "W5500Ctr.h"
  21. ......
  22. // for print debug message of this module.
  23. void prinf(const char *str){
  24. printf(str);
  25. }
  26. // implement delay function for module
  27. void Delayms(unsigned int n){
  28. ...
  29. }
  30. // implement callback function for io library
  31. uint8_t spi_readbyte(void) {...}
  32. void spi_writebyte(uint8_t wb) {...}
  33. void spi_readburst(uint8_t* pBuf, uint16_t len) {...}
  34. void spi_writeburst(uint8_t* pBuf, uint16_t len) {...}
  35. void cs_select(void) {...}
  36. void cs_deselect(void) {...}
  37. // callback function of this module when TCP connected
  38. void onTCPConnected(uint8_t sn){
  39. ...
  40. }
  41. // callback function of this module when TCP/UDP get any data
  42. void onGetData(uint8_t sn){
  43. static uint8_t databuf[DATABUF_SIZE];
  44. uint8_t last_ip[4];
  45. uint16_t last_port;
  46. int32_t len;
  47. if(sn == TCPS_SOCKETNUM || sn == TCPC_SOCKETNUM){
  48. // receive and process all the received data
  49. while((len = recv(sn,databuf,DATABUF_SIZE)) > 0){
  50. ...
  51. //send(sn,databuf,(uint16_t)len); // if send back
  52. }
  53. }
  54. if(sn == UDP_SOCKETNUM){
  55. // receive and process all the received data
  56. while((len = recvfrom(sn,databuf,DATABUF_SIZE,last_ip,&last_port)) > 0){
  57. ...
  58. //sendto(sn,databuf,(uint16_t)len,last_ip,last_port); // if send back
  59. }
  60. }
  61. }
  62. void main(void){
  63. // init flag for W5500
  64. unsigned char needInit;
  65. // call init functions
  66. ...
  67. // register functions to the io library
  68. reg_wizchip_spi_cbfunc(spi_readbyte,spi_writebyte);
  69. reg_wizchip_spiburst_cbfunc(spi_readburst,spi_writeburst);
  70. reg_wizchip_cs_cbfunc(cs_select,cs_deselect);
  71. // register functions to this module
  72. onConnected = onTCPConnected;
  73. onDataReceived = onGetData;
  74. // init at first time
  75. needInit = TRUE;
  76. while(1){
  77. if(needInit){
  78. while(!W5500_Init(NULL,NULL)); // init the W5500 by default configuration
  79. needInit = FALSE;
  80. // Delayms(3000);
  81. }
  82. // drive TCP Server socket
  83. if(Socket_Tick_TCPS(TCPS_SOCKETNUM,TCPS_LPORT) == SOCKETSTATE_UNKNOWN ||
  84. // drive UDP socket
  85. Socket_Tick_UDP(UDP_SOCKETNUM,UDP_LPORT) == SOCKETSTATE_UNKNOWN ||
  86. // drive TCP Client socket
  87. Socket_Tick_TCPC(TCPC_SOCKETNUM,TCPC_LPORT,TCPC_RIP,TCPC_RPORT) == SOCKETSTATE_UNKNOWN){
  88. // if any error, try to initial W5500 again.
  89. needInit = TRUE;
  90. }else{
  91. // some other process if need.
  92. }
  93. }
  94. }
  95. *********************************************************************************************
  96. */
  97. #ifndef W5500CTR_LITE_H
  98. #define W5500CTR_LITE_H
  99. #ifdef SOCKET_GLOBAL
  100. #define SOCKET_EXT
  101. #else
  102. #define SOCKET_EXT extern
  103. #endif
  104. /*
  105. ********************************************************************************************
  106. * MISCELLANEOUS
  107. ********************************************************************************************
  108. */
  109. #ifndef FALSE
  110. #define FALSE 0
  111. #endif
  112. #ifndef TRUE
  113. #define TRUE 1
  114. #endif
  115. /*
  116. *******************************************************************************************
  117. * DEBUG CONFIGURATION 调试配置
  118. *******************************************************************************************
  119. */
  120. //#define NDEBUG // comment it when is debugging
  121. // user should give the interface to print error message
  122. // prototype: void errmsg_print(char* msg);
  123. extern void prinf(const char *str);
  124. #ifdef NDEBUG
  125. #define errmsg_print(msg)
  126. #define m_assert(cond,errMsg)
  127. #else
  128. #define errmsg_print(msg) prinf(msg)
  129. #define m_assert(cond,errMsg) \
  130. if(!(cond)){ errmsg_print(errMsg); while(1);};
  131. #endif
  132. /*
  133. *******************************************************************************************
  134. * INCLUDES
  135. *******************************************************************************************
  136. */
  137. //#include "wizchip_conf_lite.h"
  138. //#include "socket_lite.h"
  139. #include "wizchip_conf.h"
  140. #include "socket.h"
  141. /*
  142. *******************************************************************************************
  143. * CONFIGURATION 配置
  144. *******************************************************************************************
  145. */
  146. // Network default configuration
  147. #define NETCFG_DEFAULT_STATIC_IP_EN TRUE // TRUE: 使用静态IP,否则使用动态分配的IP
  148. #define NETCFG_DEFAULT_LOCAL_IP 192,168,2,135// 本地IP地址,只在NETCFG_STATIC_IP_EN为TRUE时有用
  149. // 格式: XXX,XXX,XXX,XXX
  150. #define NETCFG_DEFAULT_SUBNET_MASK 255,255,255,0// 子网掩码,只在NETCFG_STATIC_IP_EN为TRUE时有用
  151. // 格式: XXX,XXX,XXX,XXX
  152. #define NETCFG_DEFAULT_GATEWAY 192,168,2,1 // 网关地址,只在NETCFG_STATIC_IP_EN为TRUE时有用
  153. // 格式: XXX,XXX,XXX,XXX
  154. #define NETCFG_DEFAULT_DNS_IP 0,0,0,0 // DNS服务器地址,只在NETCFG_STATIC_IP_EN为FALSE时有用
  155. // 格式: XXX,XXX,XXX,XXX
  156. #define NETCFG_DEFAULT_LOCAL_MAC 0x0c,0x29,0xab,0x7c,0x00,0x32 // 本地MAC地址,必填
  157. #define NETCFG_DEFAULT_RETRY_CNT 8 // 超时重传次数(默认8)
  158. #define NETCFG_DEFAULT_RETRY_TIME 2000 // 重试时间(单位:100us,默认2000即200ms)
  159. /*
  160. *******************************************************************************************
  161. * CONSTANT
  162. *******************************************************************************************
  163. */
  164. #define SOCKETSTATE_UNKNOWN 0 // if unknown or illegal state found, it's suggested
  165. // that reset the W5500
  166. // 发现未知或非法状态,建议重置W5500
  167. #define SOCKETSTATE_CLOSED 1 // if socket closed. The driver func is trying to init
  168. // the socket to the attempted protocol.
  169. // socket关闭状态。驱动函数正试图初始化socket端口为
  170. // 对应协议
  171. #define SOCKETSTATE_NORMAL 2 // if socket is in normal state.
  172. // 一切正常
  173. #define SOCKETSTATE_LINKED 3 // if tcp socket has connected with remote port.
  174. // tcp链接已建立
  175. /*
  176. *******************************************************************************************
  177. * EVENTS
  178. *******************************************************************************************
  179. */
  180. typedef void (* SOCKET_EVENT)(uint8_t sn);
  181. // 有端口收到数据时触发,用户需要自己到对应端口取数据进行处理,sn为触发这个事件的端口号
  182. SOCKET_EXT SOCKET_EVENT onDataReceived;
  183. // 当socket建立连接时触发,建议如果没有东西发的话也立刻随便发个字符回去,这样才能触发自动心跳检测
  184. // sn为触发这个事件的端口号
  185. SOCKET_EXT SOCKET_EVENT onConnected;
  186. /*
  187. *******************************************************************************************
  188. * FUNCTION PROTOTYPES 函数原型
  189. *******************************************************************************************
  190. */
  191. // 延迟函数,要求用户在某处实现,n为要延迟多少ms
  192. extern void Delayms(unsigned int n);
  193. // 初始化W5500为指定网络配置
  194. // 返回 TRUE表示成功,FALSE表示失败,在这个成功之后其他操作才有效
  195. // arguments : pNetInfo 指定网络地址配置,NULL使用默认配置
  196. // pNetTo 指定网络重传配置
  197. // return : TRUE if success
  198. // FALSE if fail
  199. uint8_t W5500_Init(wiz_NetInfo const* pNetInfo,wiz_NetTimeout const *pNetTo);
  200. // 获取默认网络参数
  201. // arguments : pNetInfo 返回默认网络地址配置,NULL则不返回
  202. // pNetTo 返回默认网络重传配置, NULL则不返回
  203. // return : void
  204. void getDefaultNetCfg(wiz_NetInfo* pNetInfo,wiz_NetTimeout* pNetTo);
  205. // TCP服务器驱动函数,需要不时调用这个函数以驱动套接字正常运作
  206. // arguments : sn 驱动的套接字号
  207. // lPort 绑定的本地端口
  208. // return : SOCKETSTATE_UNKNOWN 未知状态,建议重置W5500
  209. // SOCKETSTATE_CLOSED socket关闭,重新打开失败
  210. // SOCKETSTATE_NORMAL 一切正常
  211. // SOCKETSTATE_LINKED TCP链接已建立
  212. unsigned char Socket_Tick_TCPS(uint8_t sn,uint16_t lPort);
  213. // TCP客户端驱动函数,需要不时调用这个函数以驱动套接字正常运作
  214. // arguments : sn 驱动的套接字号
  215. // lPort 绑定的本地端口
  216. // dIP 要连接的目标IP
  217. // dPort 要连接的目标端口
  218. // return : SOCKETSTATE_UNKNOWN 未知状态,建议重置W5500
  219. // SOCKETSTATE_CLOSED socket关闭,重新打开失败
  220. // SOCKETSTATE_NORMAL 一切正常
  221. // SOCKETSTATE_LINKED TCP链接已建立
  222. unsigned char Socket_Tick_TCPC(uint8_t sn,uint16_t lPort,uint8_t dIP[4],uint16_t dPort);
  223. // UDP驱动函数,需要不时调用这个函数以驱动套接字正常运作
  224. // arguments : sn 驱动的套接字号
  225. // lPort 绑定的本地端口
  226. // return : SOCKETSTATE_UNKNOWN 未知状态,建议重置W5500
  227. // SOCKETSTATE_CLOSED socket关闭,重新打开失败
  228. // SOCKETSTATE_NORMAL UDP端口已打开
  229. unsigned char Socket_Tick_UDP(uint8_t sn,uint16_t lPort);
  230. #endif

W5500Ctr.c

  1. /*
  2. *******************************************************************************************
  3. *
  4. *
  5. * W5500 CONTROLLER FOR SINGLE THREAD
  6. * W5500控制器(单线程)
  7. *
  8. * File : W5500Ctr.c
  9. * By : Lin Shijun(http://blog.csdn.net/lin_strong)
  10. * Date: 2018/09/05
  11. * version: V1.1
  12. * History:
  13. *
  14. * NOTE(s):
  15. *********************************************************************************************
  16. */
  17. #define SOCKET_GLOBAL
  18. #include "W5500Ctr.h"
  19. #undef SOCKET_GLOBAL
  20. #include <stddef.h>
  21. #include <stdio.h>
  22. /*
  23. *******************************************************************************************
  24. * LOCAL VARIABLE
  25. *******************************************************************************************
  26. */
  27. // 默认网络参数
  28. static const wiz_NetInfo _dfNetInfo = {
  29. {NETCFG_DEFAULT_LOCAL_MAC}, // MAC
  30. {NETCFG_DEFAULT_LOCAL_IP}, // IP address
  31. {NETCFG_DEFAULT_SUBNET_MASK}, // Subnet Mask
  32. {NETCFG_DEFAULT_GATEWAY}, // GateWay IP Address
  33. {NETCFG_DEFAULT_DNS_IP}, // DNS server IP Address
  34. #if(NETCFG_DEFAULT_STATIC_IP_EN == TRUE)
  35. NETINFO_STATIC // net type
  36. #else
  37. NETINFO_DHCP
  38. #endif
  39. };
  40. static const wiz_NetTimeout _dfNetTo={
  41. NETCFG_DEFAULT_RETRY_CNT,
  42. NETCFG_DEFAULT_RETRY_TIME
  43. };
  44. /*
  45. *******************************************************************************************
  46. * LOCAL FUNCTION DECLARE
  47. *******************************************************************************************
  48. */
  49. static void _ISRHander(uint8_t sn);
  50. /*
  51. *********************************************************************************************************
  52. * initialize the W5500 chip
  53. *
  54. * Description : initialize/reset the W5500 chip by given configuration.
  55. *
  56. * Arguments : pNetInfo pointer to the net address configuration, if NULL, use default.
  57. * pNetTo pointer to the net timeout configuration, if NULL, use default.
  58. *
  59. * Return : TRUE if success.
  60. * FALSE if fail(configure fail).
  61. * Note(s) :
  62. *********************************************************************************************************
  63. */
  64. uint8_t W5500_Init(wiz_NetInfo const* pNetInfo,wiz_NetTimeout const *pNetTo){
  65. uint8_t ip_c[4];
  66. wiz_NetInfo conf;
  67. // 软重启
  68. // wizchip_sw_reset();
  69. setMR(MR_RST); // 对上面函数的简化
  70. // 延迟10ms
  71. Delayms(10);
  72. if(pNetInfo == NULL)
  73. pNetInfo = &_dfNetInfo;
  74. // 设置网络参数
  75. wizchip_setnetinfo((wiz_NetInfo *)pNetInfo);
  76. // 回读确认设置成功
  77. wizchip_getnetinfo(&conf);
  78. #ifndef NDEBUG
  79. {
  80. static char buf[400];
  81. prinf("=== W5500 NET CONF ===\r\n");
  82. (void)sprintf(buf,"MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n"
  83. "MASK:%3u.%3u.%3u.%3u\r\n"
  84. "GATE:%3u.%3u.%3u.%3u\r\n"
  85. "LIP :%3u.%3u.%3u.%3u\r\n"
  86. "地址类型 :静态IP\r\n",
  87. conf.mac[0],conf.mac[1],conf.mac[2],conf.mac[3],conf.mac[4],conf.mac[5],
  88. conf.sn[0],conf.sn[1],conf.sn[2],conf.sn[3],
  89. conf.gw[0],conf.gw[1],conf.gw[2],conf.gw[3],
  90. conf.ip[0],conf.ip[1],conf.ip[2],conf.ip[3]);
  91. prinf(buf);
  92. }
  93. #endif
  94. if(memcmp(&conf,pNetInfo,sizeof(wiz_NetInfo)) != 0)
  95. return FALSE;
  96. // 配置超时
  97. if(pNetTo == NULL)
  98. pNetTo = &_dfNetTo;
  99. if(pNetTo->retry_cnt != 8 || pNetTo->time_100us != 2000)
  100. wizchip_settimeout((wiz_NetTimeout *)pNetTo);
  101. return TRUE;
  102. //设置发送缓冲区和接收缓冲区的大小的方法,默认全部为2K,分别加起来不能超32K,仅供参考
  103. //uint8_t rxsize[8] = {2,2,2,2,2,2,2,2};
  104. //uint8_t txsize[8] = {2,2,2,2,2,2,2,2};
  105. //wizchip_init_size(txsize,rxsize);
  106. }
  107. /*
  108. *********************************************************************************************************
  109. * get default network configuration
  110. *
  111. * Description : get default network configuration.
  112. *
  113. * Arguments : pNetInfo pointer to the space to hold default NetInfo;
  114. * pNetTo pointer to the space to hold default NetTimeout
  115. *
  116. * Return :
  117. * Note(s) :
  118. *********************************************************************************************************
  119. */
  120. void getDefaultNetCfg(wiz_NetInfo* pNetInfo,wiz_NetTimeout* pNetTo){
  121. if(pNetInfo != NULL)
  122. (void)memcpy((void *)pNetInfo,(void *)&_dfNetInfo,sizeof(wiz_NetInfo));
  123. if(pNetTo != NULL)
  124. (void)memcpy((void *)pNetTo,(void *)&_dfNetTo,sizeof(wiz_NetTimeout));
  125. return;
  126. }
  127. /*
  128. *********************************************************************************************************
  129. * tick for tcp server socket
  130. *
  131. * Description : drive the tcp server socket.
  132. *
  133. * Arguments : sn Socket number
  134. * lPort Port number to be bined locally.
  135. *
  136. * Return : SOCKETSTATE_UNKNOWN if unknown state
  137. * SOCKETSTATE_CLOSED if socket closed and fail opening.
  138. * SOCKETSTATE_NORMAL if every thing is OK.
  139. * SOCKETSTATE_LINKED if linked.
  140. * Note(s) : if return SOCKETSTATE_UNKNOWN, it's recommended to reset the W5500.
  141. *********************************************************************************************************
  142. */
  143. char errStr1[] = "打开socket 时出现问题\r\n";
  144. char errStr2[] = "socket 开始监听\r\n";
  145. unsigned char Socket_Tick_TCPS(uint8_t sn,uint16_t lPort){
  146. register uint8_t ret = SOCKETSTATE_UNKNOWN;
  147. switch(getSn_SR(sn)){ // 获取socket的状态
  148. case SOCK_CLOSE_WAIT: // Socket处于等待关闭状态
  149. disconnect(sn);
  150. // 故意不break; 与其他状态整合
  151. case SOCK_CLOSED: // 重新Open套接字
  152. if(socket(sn,Sn_MR_TCP,lPort,SF_TCP_NODELAY | SF_IO_NONBLOCK) != sn){
  153. ret = SOCKETSTATE_CLOSED;
  154. #ifndef NDEBUG
  155. errStr1[10] = '0' + sn;
  156. errmsg_print(errStr1);
  157. #endif
  158. break;
  159. }
  160. // 故意不break; 与其他状态整合
  161. case SOCK_INIT: // Socket处于初始化完成(打开)状态
  162. setSn_KPALVTR(sn,2); // 设置心跳包自动发送间隔
  163. (void)listen(sn); // 监听刚刚打开的本地端口,等待客户端连接
  164. ret = SOCKETSTATE_NORMAL;
  165. #ifndef NDEBUG
  166. errStr2[6] = '0' + sn;
  167. errmsg_print(errStr2);
  168. #endif
  169. break;
  170. case SOCK_ESTABLISHED:
  171. ret = SOCKETSTATE_LINKED;
  172. break;
  173. case SOCK_LISTEN:
  174. case SOCK_SYNRECV:
  175. // disconnect-process
  176. case SOCK_TIME_WAIT:
  177. case SOCK_CLOSING:
  178. case SOCK_LAST_ACK:
  179. case SOCK_FIN_WAIT:
  180. ret = SOCKETSTATE_NORMAL;
  181. break;
  182. // 意外的状态返回异常,这种情况一般是通讯上有问题或者W5500没配置成功
  183. //default:
  184. //return SOCKETSTATE_UNKNOWN; // */(初始化值)
  185. }
  186. _ISRHander(sn);
  187. return ret;
  188. }
  189. /*
  190. *********************************************************************************************************
  191. * tick for tcp client socket
  192. *
  193. * Description : drive the tcp client socket.
  194. *
  195. * Arguments : sn Socket number
  196. * lPort Port number to be bined locally.
  197. * dIP the destination ip to connect
  198. * dPort the destination port to connect
  199. *
  200. * Return : SOCKETSTATE_UNKNOWN if unknown state
  201. * SOCKETSTATE_CLOSED if socket closed and fail opening.
  202. * SOCKETSTATE_NORMAL if every thing is OK.
  203. * SOCKETSTATE_LINKED if linked.
  204. * Note(s) : if return SOCKETSTATE_UNKNOWN, it's recommended to reset the W5500.
  205. *********************************************************************************************************
  206. */
  207. char errStr4[] = "socket 发起连接\r\n";
  208. unsigned char Socket_Tick_TCPC(uint8_t sn,uint16_t lPort,uint8_t dIP[4],uint16_t dPort){
  209. register uint8_t ret = SOCKETSTATE_UNKNOWN;
  210. switch(getSn_SR(sn)){ // 获取socket的状态
  211. case SOCK_CLOSE_WAIT: // Socket处于等待关闭状态
  212. disconnect(sn);
  213. // 故意不break; 与其他状态整合
  214. case SOCK_CLOSED: // 重新Open套接字
  215. if(socket(sn,Sn_MR_TCP,lPort,SF_TCP_NODELAY | SF_IO_NONBLOCK) != sn){
  216. ret = SOCKETSTATE_CLOSED;
  217. #ifndef NDEBUG
  218. errStr1[10] = '0' + sn;
  219. errmsg_print(errStr1);
  220. #endif
  221. break;
  222. }
  223. // 故意不break; 与其他状态整合
  224. case SOCK_INIT: // Socket处于初始化完成(打开)状态
  225. setSn_KPALVTR(sn,2); // 设置心跳包自动发送间隔
  226. (void)connect(sn,dIP,dPort); // 主动连接
  227. ret = SOCKETSTATE_NORMAL;
  228. #ifndef NDEBUG
  229. errStr4[6] = '0' + sn;
  230. errmsg_print(errStr4);
  231. #endif
  232. break;
  233. case SOCK_ESTABLISHED:
  234. ret = SOCKETSTATE_LINKED;
  235. break;
  236. // connect-process
  237. case SOCK_SYNSENT:
  238. // disconnect-process
  239. case SOCK_TIME_WAIT:
  240. case SOCK_CLOSING:
  241. case SOCK_LAST_ACK:
  242. case SOCK_FIN_WAIT:
  243. ret = SOCKETSTATE_NORMAL;
  244. break;
  245. // 意外的状态返回异常,这种情况一般是通讯上有问题或者W5500没配置成功
  246. //default:
  247. //return SOCKETSTATE_UNKNOWN; // */(初始化值)
  248. }
  249. _ISRHander(sn);
  250. return ret;
  251. }
  252. /*
  253. *********************************************************************************************************
  254. * tick for udp server socket
  255. *
  256. * Description : drive the udp socket.
  257. *
  258. * Arguments : sn Socket number
  259. * lPort Port number to be bined locally.
  260. *
  261. * Return : SOCKETSTATE_UNKNOWN if unknown state
  262. * SOCKETSTATE_CLOSED if socket closed and fail opening.
  263. * SOCKETSTATE_NORMAL if udp opend.
  264. * Note(s) : if return 1, it's recommended to reset the W5500.
  265. *********************************************************************************************************
  266. */
  267. char errStr3[] = "socket 打开UDP\r\n";
  268. unsigned char Socket_Tick_UDP(uint8_t sn,uint16_t lPort){
  269. register uint8_t ret = SOCKETSTATE_UNKNOWN;
  270. switch(getSn_SR(sn)){
  271. case SOCK_CLOSED:
  272. if(socket(sn,Sn_MR_UDP,lPort,SF_IO_NONBLOCK) != sn){
  273. ret = SOCKETSTATE_CLOSED;
  274. #ifndef NDEBUG
  275. errStr1[10] = '0' + sn;
  276. errmsg_print(errStr1);
  277. #endif
  278. break;
  279. };
  280. #ifndef NDEBUG
  281. errStr3[6] = '0' + sn;
  282. errmsg_print(errStr3);
  283. #endif
  284. case SOCK_UDP:
  285. ret = SOCKETSTATE_NORMAL;
  286. break;
  287. // 意外的状态返回异常
  288. //default:
  289. //return SOCKETSTATE_UNKNOWN; (初始化值)
  290. }
  291. _ISRHander(sn);
  292. return ret;
  293. }
  294. /*
  295. *******************************************************************************************
  296. * LOCAL FUNCTION
  297. *******************************************************************************************
  298. */
  299. static void _ISRHander(uint8_t sn){
  300. uint8_t ir;
  301. ir = getSn_IR(sn);
  302. if(ir & Sn_IR_CON){
  303. setSn_IR(sn, Sn_IR_CON); // Sn_IR的CON位置1,通知W5500连接已建立
  304. if(onConnected != NULL)
  305. onConnected(sn);
  306. }
  307. if(ir & Sn_IR_RECV){
  308. setSn_IR(sn, Sn_IR_RECV); // Sn_IR的RECV位置1,通知接收到了数据
  309. if(onDataReceived != NULL)
  310. onDataReceived(sn);
  311. }
  312. }

简单解释

注释已经注释的很清楚了,函数的用法也在上一篇讲的较清楚了,所以就不细说了。
先去.h文件的配置那里修改一下默认配置。然后到调试配置那里决定一下要不要输出调试信息。
如果需要输出调试信息的话还要实现下prinf函数(没看错,就是没有那个’t’)。
然后实现那个延迟函数,主要是为了裁剪下软重置过程,当然直接使用不裁剪的就可以不用延时函数了。
最后把两个事件给实现了,用于程序的一些业务逻辑。

基本照着下面的示例程序使用就没有问题了。

示例主程序

下面程序是基于MC9S12X的,如果用的其他MCU需要进行相应修改。
用到的两个驱动(SPI、SCI)已经发布在之前的文章中了。

  1. /*
  2. *******************************************************************************************
  3. * example program for W5500Ctr
  4. * This program demonstrate how to implement a TCP/IP application through W5500 by polling
  5. * method with W5500Ctr module.
  6. * You can use this demo as the start point of your application.
  7. * For the purpose of demonstration, I open one tcp client socket, one tcp server socket
  8. * and one udp socket; and all data received are just simply sended back. You can modify it
  9. * as your need.
  10. *********************************************************************************************
  11. */
  12. #include <hidef.h> /* common defines and macros */
  13. #include <stddef.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "derivative.h" /* derivative-specific definitions */
  17. #include "SPI.h"
  18. #include "SCI_def.h"
  19. #include "W5500Ctr.h"
  20. /*
  21. *******************************************************************************************
  22. * CONFIGURATION 配置
  23. *******************************************************************************************
  24. */
  25. #define BUS_CLOCK 32000000 //总线频率
  26. #define OSC_CLOCK 16000000 //晶振频率
  27. #define HOLD PTJ_PTJ0
  28. #define HOLD_dir DDRJ_DDRJ0
  29. #define CS_dir DDRS_DDRS7
  30. #define W5500_RST PTJ_PTJ0 //定义W5500的RST引脚
  31. #define W5500_SCS PTS_PTS7 //定义W5500的CS引脚
  32. #define RST_dir DDRJ_DDRJ0
  33. #define W5500_SPI SPI0 // 到SPI.h 中的SPI_USED进行设置
  34. #define TCPS_SOCKETNUM 0 // Socket number of tcp server
  35. #define TCPS_LPORT 4000 // local port of tcp server
  36. #define UDP_SOCKETNUM 1 // Socket number of udp server
  37. #define UDP_LPORT 6535 // local port of udp
  38. #define TCPC_SOCKETNUM 2 // Socket number of tcp client
  39. #define TCPC_LPORT 5555 // local port of tcp client
  40. #define TCPC_RIP 192,168,2,50 // remote ip of tcp client to connect
  41. #define TCPC_RPORT 3333 // remote port of tcp client to connect
  42. /*
  43. *******************************************************************************************
  44. * LOCAL FUNCTION DECLARATION
  45. *******************************************************************************************
  46. */
  47. static void PLL_Init(void);
  48. static void GPIO_Init(void);
  49. /*
  50. *******************************************************************************************
  51. * DEBUG FUNCTION
  52. *******************************************************************************************
  53. */
  54. // W5500Ctr调试用函数,通过在W5500Ctr.h的配置中uncomment
  55. // #define NDEBUG
  56. // 以取消输出调试信息
  57. void prinf(const char *str){
  58. while(*str){
  59. SCI_PutChar(SCI0,*str);
  60. str++;
  61. }
  62. }
  63. /*
  64. *******************************************************************************************
  65. * DELAY FUNCTION
  66. *******************************************************************************************
  67. */
  68. void Delayms(unsigned int n){
  69. unsigned int i,j;
  70. for(j=0;j<n;j++)
  71. for(i=0;i<6700;i++)
  72. ;
  73. }
  74. /*
  75. *******************************************************************************************
  76. * FUNCTIONS FOR LIBRARY
  77. *******************************************************************************************
  78. */
  79. uint8_t spi_readbyte(void) {
  80. return SPI_ExchangeChar(W5500_SPI,0xaa);}
  81. void spi_writebyte(uint8_t wb) {SPI_ExchangeChar(W5500_SPI,wb);}
  82. void spi_readburst(uint8_t* pBuf, uint16_t len) {
  83. for(;len > 0;len--, pBuf++){
  84. *pBuf = SPI_ExchangeChar(W5500_SPI,0xaa);
  85. }
  86. }
  87. void spi_writeburst(uint8_t* pBuf, uint16_t len) {
  88. for(;len > 0;len--, pBuf++){
  89. SPI_ExchangeChar(W5500_SPI,*pBuf);
  90. }
  91. }
  92. void cs_select(void) {W5500_SCS = 0;}
  93. void cs_deselect(void) {W5500_SCS = 1;}
  94. /*
  95. *******************************************************************************************
  96. * CALL BACK FUNCTIONS FOR LIBRARY
  97. *******************************************************************************************
  98. */
  99. // TCP一建立链接就会触发这个事件
  100. void onTCPConnected(uint8_t sn){
  101. // 建议立刻发送点任意数据,这样才能触发W5500自动的超时检测
  102. #define DATABUF_SIZE 400
  103. static uint8_t databuf[DATABUF_SIZE];
  104. #ifndef NDEBUG
  105. uint8_t ip[4];
  106. uint16_t port;
  107. // 记录连接的地址
  108. getSn_DIPR(sn,ip);
  109. port = getSn_DPORT(sn);
  110. sprintf(databuf,"=== Socket %u 连接建立 ===\r\n"
  111. "DIP : %3u.%3u.%3u.%3u\r\n"
  112. "DPort: %u\r\n",
  113. sn,ip[0],ip[1],ip[2],ip[3], port);
  114. prinf(databuf);
  115. #endif
  116. }
  117. // 每次收到数据时触发。
  118. void onGetData(uint8_t sn){
  119. #define DATABUF_SIZE 400
  120. static uint8_t databuf[DATABUF_SIZE];
  121. uint8_t last_ip[4]; // only for UDP
  122. uint16_t last_port; // only for UDP
  123. int32_t len;
  124. if(sn == TCPS_SOCKETNUM || sn == TCPC_SOCKETNUM){
  125. while((len = recv(sn,databuf,DATABUF_SIZE)) > 0){
  126. prinf("收到TCP数据:");
  127. send(sn,databuf,(uint16_t)len); // 回环发送
  128. databuf[len] = '\0';
  129. prinf(databuf); // 串口打印接收到的数据
  130. }
  131. }else if(sn == UDP_SOCKETNUM){
  132. while((len = recvfrom(sn,databuf,DATABUF_SIZE,last_ip,&last_port)) > 0){
  133. prinf("收到UDP数据:");
  134. sendto(sn,databuf,(uint16_t)len,last_ip,last_port); // 回环发送
  135. databuf[len] = '\0';
  136. prinf(databuf); // 串口打印接收到的数据
  137. }
  138. }
  139. }
  140. /*
  141. *******************************************************************************************
  142. * MAIN FUNCTION
  143. *******************************************************************************************
  144. */
  145. void main(void){
  146. unsigned char needInit;
  147. uint8_t tcp_rip[4] = {TCPC_RIP};
  148. GPIO_Init();
  149. PLL_Init();
  150. SCI_Init(SCI0);
  151. SCI_EnableTrans(SCI0);
  152. SCI_EnableRecv(SCI0);
  153. SPI_Init(SPI0);
  154. SPI_Enable(SPI0);
  155. // 注册驱动函数
  156. reg_wizchip_spi_cbfunc(spi_readbyte,spi_writebyte);
  157. reg_wizchip_spiburst_cbfunc(spi_readburst,spi_writeburst);
  158. reg_wizchip_cs_cbfunc(cs_select,cs_deselect);
  159. onConnected = onTCPConnected;
  160. onDataReceived = onGetData;
  161. needInit = TRUE;
  162. while(1){
  163. if(needInit){
  164. while(!W5500_Init(NULL,NULL)); // 用默认参数初始化,初始化失败则不断重试
  165. needInit = FALSE;
  166. Delayms(3000);
  167. }
  168. // 驱动 TCP Server 端口
  169. if(Socket_Tick_TCPS(TCPS_SOCKETNUM,TCPS_LPORT) == SOCKETSTATE_UNKNOWN ||
  170. // 驱动 UDP 端口
  171. Socket_Tick_UDP(UDP_SOCKETNUM,UDP_LPORT) == SOCKETSTATE_UNKNOWN ||
  172. // 驱动 TCP 端口
  173. Socket_Tick_TCPC(TCPC_SOCKETNUM,TCPC_LPORT,tcp_rip,TCPC_RPORT) == SOCKETSTATE_UNKNOWN){
  174. // 任一次tick发现有问题则需要重新初始化W5500
  175. needInit = TRUE;
  176. }
  177. }
  178. }
  179. /*
  180. *******************************************************************************************
  181. * LOCAL FUNCTION
  182. *******************************************************************************************
  183. */
  184. // 初始化锁相环
  185. void PLL_Init(void){
  186. CLKSEL &= 0x7f; //set OSCCLK as sysclk
  187. PLLCTL &= 0x8F; //DisaKble PLL circuit
  188. CRGINT &= 0xDF;
  189. #if(BUS_CLOCK == 40000000)
  190. SYNR = 0x44;
  191. #elif(BUS_CLOCK == 32000000)
  192. SYNR = 0x43;
  193. #elif(BUS_CLOCK == 24000000)
  194. SYNR = 0x42;
  195. #endif
  196. REFDV = 0x81; //PLLCLK=2×OSCCLK×(SYNR+1)/(REFDV+1)=64MHz ,fbus=32M
  197. PLLCTL =PLLCTL|0x70; //Enable PLL circuit
  198. asm NOP;
  199. asm NOP;
  200. while(!(CRGFLG&0x08)); //PLLCLK is Locked already
  201. CLKSEL |= 0x80; //set PLLCLK as sysclk
  202. }
  203. // 初始化IO口
  204. void GPIO_Init(void){
  205. HOLD_dir = 1;
  206. HOLD = 1;//复位引脚拉高
  207. CS_dir = 1;
  208. }

测试结果

70

发表评论

表情:
评论列表 (有 0 条评论,625人围观)

还没有评论,来说两句吧...

相关阅读