[Cortex-M0技术交流] 新手学习笔记4——SPI+ENC28J60(通过网页控制LED)

[复制链接]
 楼主| jxc827 发表于 2012-7-6 21:41 | 显示全部楼层 |阅读模式
本帖最后由 jxc827 于 2012-7-6 22:47 编辑

使用NUC120的SPI1口连接ENC28J60,实现网页控制LED的亮灭。
连线方式:CS——GPA13;  RST——GPA12;

工程直接利用网站上的例程进行修改,在此对作者表示感谢。

废话不多说,贴上部分程序:
hw_config.c
  1. #include "includes.h" //包含所需的头文件

  2. /*************************************************************************************
  3. ** Function name: Set_System
  4. ** Descriptions: 封装一些初始化模块
  5. ** input parameters: count
  6. ** output parameters: 无
  7. ** Returned value: 无
  8. *************************************************************************************/
  9. void Set_System(void)
  10. {
  11. RCC_Configuration(); //配置系统时钟

  12. GPIO_Configuration(); //配置GPIO

  13. SPI_Configuration(); //配置SPI1
  14. }
  15. /*************************************************************************************
  16. ** Function name: RCC_Configuration
  17. ** Descriptions: 系统时钟设置,使用PLL输出50M
  18. ** input parameters: none
  19. ** output parameters: none
  20. ** Returned value: none
  21. *************************************************************************************/
  22. void RCC_Configuration(void)
  23. {
  24. int32_t tmp;
  25. UNLOCKREG();
  26. DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1); // 使能外部12M时钟源
  27. DrvSYS_SelectPLLSource(E_SYS_EXTERNAL_12M); //选择外部12M时钟源PLL
  28. DrvSYS_SetPLLMode(0); //PLL 正常模式
  29. tmp = DrvSYS_GetPLLContent(E_SYS_EXTERNAL_12M, 50000000); //设置PLL输出50M
  30. DrvSYS_SetPLLContent(tmp);
  31. DrvSYS_SelectHCLKSource(2); //0:12M;1:32K;2LL;
  32. tmp = DrvSYS_GetHCLKFreq(); //回读HCLK时钟频率
  33. LOCKREG();
  34. }
  35. /*************************************************************************************
  36. ** Function name: GPIO_Configuration
  37. ** Descriptions: GPIO配置
  38. ** input parameters: none
  39. ** output parameters: none
  40. ** Returned value: none
  41. *************************************************************************************/
  42. void GPIO_Configuration()
  43. {
  44. DrvGPIO_Open( E_GPA, 13, E_IO_OUTPUT ); // SPI片选
  45. DrvGPIO_Open( E_GPA, 12, E_IO_OUTPUT ); // SPI复位
  46. DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT ); // LED灯控制

  47. }

  48. /*************************************************************************************
  49. ** Function name: SPI_Configuration
  50. ** Descriptions: SPI配置
  51. ** input parameters: none
  52. ** output parameters: none
  53. ** Returned value: none
  54. *************************************************************************************/
  55. void SPI_Configuration()
  56. {
  57. uint32_t tmp;
  58. DrvSPI_Open(eDRVSPI_PORT1, eDRVSPI_MASTER, eDRVSPI_TYPE1, 8,FALSE);
  59. DrvSPI_SetEndian(eDRVSPI_PORT1, eDRVSPI_MSB_FIRST); //配置SPI1传输比特的顺序:优先发送/接收MSB
  60. DrvSPI_DisableAutoSS(eDRVSPI_PORT1); //禁止自动片选功能
  61. DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT1, eDRVSPI_ACTIVE_LOW_FALLING); //设定从选择线的激活级别:低电平或者下降沿
  62. DrvSPI_Set2BitTransferMode(eDRVSPI_PORT1, FALSE); //禁止2比特串行数据I/O 模式
  63. DrvSPI_SetClockFreq(eDRVSPI_PORT1, 8000000, 0); //设置SPI的时钟频率为8MHz
  64. tmp = DrvSPI_GetClock1Freq(eDRVSPI_PORT1);

  65. DISABLE_SPI_CS; //输出高电平
  66. }

  67. /*************************************************************************************
  68. ** Function name: delay_ms
  69. ** Descriptions: 1ms(晶振为12MHZ)延时子程序
  70. ** input parameters: count
  71. ** output parameters: 无
  72. ** Returned value: 无
  73. *************************************************************************************/
  74. void delay_ms(uint32_t count)
  75. {
  76. uint32_t i,j;
  77. for(i=count;i>0;i--)
  78. for(j=2395;j>0;j--);
  79. }

  80. /*************************************************************************************
  81. ** Function name: SPInet_ReadWrite
  82. ** Descriptions: SPI读写数据函数
  83. ** input parameters: 写入数据
  84. ** output parameters: 无
  85. ** Returned value: 读出数据
  86. *************************************************************************************/
  87. uint8_t SPInet_ReadWrite(uint8_t writedat)
  88. {
  89. uint32_t au32SourceData;
  90. uint32_t au32DestinationData;

  91. au32SourceData = writedat;
  92. DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);
  93. while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {} //等待SPI端口空闲

  94. DrvSPI_DumpRxRegister(eDRVSPI_PORT1, &au32DestinationData, 1);

  95. return (au32DestinationData);
  96. }
ENC28J60.C
  1. #include "includes.h"

  2. static u8 Enc28j60Bank;
  3. static u16 NextPacketPtr;


  4. u8 enc28j60ReadOp(u8 op, u8 address)
  5. {
  6. u8 dat = 0;

  7. ENC28J60_CSL();

  8. dat = op | (address & ADDR_MASK);
  9. SPInet_ReadWrite(dat);
  10. dat = SPInet_ReadWrite(0x00);
  11. // do dummy read if needed (for mac and mii, see datasheet page 29)
  12. if (address & 0x80)
  13. {
  14. dat = SPInet_ReadWrite(0x00);
  15. }
  16. // release CS
  17. ENC28J60_CSH();
  18. return dat;
  19. }

  20. void enc28j60WriteOp(u8 op, u8 address, u8 data)
  21. {
  22. u8 dat = 0;

  23. ENC28J60_CSL();
  24. // issue write command
  25. dat = op | (address & ADDR_MASK);
  26. SPInet_ReadWrite(dat);
  27. // write data
  28. dat = data;
  29. SPInet_ReadWrite(dat);
  30. ENC28J60_CSH();
  31. }

  32. void enc28j60ReadBuffer(u16 len, u8* data)
  33. {
  34. ENC28J60_CSL();
  35. // issue read command
  36. SPInet_ReadWrite(ENC28J60_READ_BUF_MEM);
  37. while (len--)
  38. {
  39. *data++ = (u8) SPInet_ReadWrite(0);
  40. }
  41. *data = '\0';
  42. ENC28J60_CSH();
  43. }

  44. void enc28j60WriteBuffer(u16 len, u8* data)
  45. {
  46. ENC28J60_CSL();
  47. // issue write command
  48. SPInet_ReadWrite(ENC28J60_WRITE_BUF_MEM);

  49. while (len--)
  50. {
  51. SPInet_ReadWrite(*data++);
  52. }
  53. ENC28J60_CSH();
  54. }

  55. void enc28j60SetBank(u8 address)
  56. {
  57. // set the bank (if needed)
  58. if ((address & BANK_MASK) != Enc28j60Bank)
  59. {
  60. // set the bank
  61. enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
  62. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
  63. Enc28j60Bank = (address & BANK_MASK);
  64. }
  65. }

  66. u8 enc28j60Read(u8 address)
  67. {
  68. // set the bank
  69. enc28j60SetBank(address);
  70. // do the read
  71. return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
  72. }

  73. void enc28j60Write(u8 address, u8 data)
  74. {
  75. // set the bank
  76. enc28j60SetBank(address);
  77. // do the write
  78. enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
  79. }

  80. void enc28j60PhyWrite(u8 address, u16 data)
  81. {
  82. // set the PHY register address
  83. enc28j60Write(MIREGADR, address);
  84. // write the PHY data
  85. enc28j60Write(MIWRL, data & 0x00ff);
  86. enc28j60Write(MIWRH, data >> 8);
  87. // wait until the PHY write completes
  88. while (enc28j60Read(MISTAT) & MISTAT_BUSY)
  89. {
  90. }
  91. }

  92. void enc28j60clkout(u8 clk)
  93. {
  94. enc28j60Write(ECOCON, clk & 0x7);
  95. }

  96. void enc28j60Init(u8 * macaddr)
  97. {
  98. unsigned char tmp=0;
  99. unsigned long i;

  100. ENC28J60_RSTL();
  101. delay_ms(1000);
  102. ENC28J60_RSTH();
  103. delay_ms(1000); //必须延迟一段时间

  104. // perform system reset
  105. enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);

  106. // Del_1ms(250);
  107. // check CLKRDY bit to see if reset is complete
  108. // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
  109. //while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
  110. // do bank 0 stuff
  111. // initialize receive buffer
  112. // 16-bit transfers, must write low byte first
  113. // set receive buffer start address
  114. NextPacketPtr = RXSTART_INIT;
  115. // Rx start
  116. enc28j60Write(ERXSTL, RXSTART_INIT & 0xFF);
  117. enc28j60Write(ERXSTH, RXSTART_INIT >> 8);
  118. // set receive pointer address
  119. enc28j60Write(ERXRDPTL, RXSTART_INIT & 0xFF);
  120. enc28j60Write(ERXRDPTH, RXSTART_INIT >> 8);
  121. // RX end
  122. enc28j60Write(ERXNDL, RXSTOP_INIT & 0xFF);
  123. enc28j60Write(ERXNDH, RXSTOP_INIT >> 8);
  124. // TX start
  125. enc28j60Write(ETXSTL, TXSTART_INIT & 0xFF);
  126. enc28j60Write(ETXSTH, TXSTART_INIT >> 8);
  127. // TX end
  128. enc28j60Write(ETXNDL, TXSTOP_INIT & 0xFF);
  129. enc28j60Write(ETXNDH, TXSTOP_INIT >> 8);
  130. // do bank 1 stuff, packet filter:
  131. // For broadcast packets we allow only ARP packtets
  132. // All other packets should be unicast only for our mac (MAADR)
  133. //
  134. // The pattern to match on is therefore
  135. // Type ETH.DST
  136. // ARP BROADCAST
  137. // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
  138. // in binary these poitions are:11 0000 0011 1111
  139. // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
  140. enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);
  141. enc28j60Write(EPMM0, 0x3f);
  142. enc28j60Write(EPMM1, 0x30);
  143. enc28j60Write(EPMCSL, 0xf9);
  144. enc28j60Write(EPMCSH, 0xf7);
  145. //
  146. //
  147. // do bank 2 stuff
  148. // enable MAC receive
  149. enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
  150. // bring MAC out of reset
  151. enc28j60Write(MACON2, 0x00);
  152. // enable automatic padding to 60bytes and CRC operations
  153. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
  154. // set inter-frame gap (non-back-to-back)
  155. enc28j60Write(MAIPGL, 0x12);
  156. enc28j60Write(MAIPGH, 0x0C);
  157. // set inter-frame gap (back-to-back)
  158. enc28j60Write(MABBIPG, 0x12);
  159. // Set the maximum packet size which the controller will accept
  160. // Do not send packets longer than MAX_FRAMELEN:
  161. enc28j60Write(MAMXFLL, MAX_FRAMELEN & 0xFF);
  162. enc28j60Write(MAMXFLH, MAX_FRAMELEN >> 8);
  163. // do bank 3 stuff
  164. // write MAC address
  165. // NOTE: MAC address in ENC28J60 is byte-backward
  166. enc28j60Write(MAADR5, macaddr[0]);
  167. enc28j60Write(MAADR4, macaddr[1]);
  168. enc28j60Write(MAADR3, macaddr[2]);
  169. enc28j60Write(MAADR2, macaddr[3]);
  170. enc28j60Write(MAADR1, macaddr[4]);
  171. enc28j60Write(MAADR0, macaddr[5]);

  172. // printf("MAADR5 = 0x%x\r\n", enc28j60Read(MAADR5));
  173. // printf("MAADR4 = 0x%x\r\n", enc28j60Read(MAADR4));
  174. // printf("MAADR3 = 0x%x\r\n", enc28j60Read(MAADR3));
  175. // printf("MAADR2 = 0x%x\r\n", enc28j60Read(MAADR2));
  176. // printf("MAADR1 = 0x%x\r\n", enc28j60Read(MAADR1));
  177. // printf("MAADR0 = 0x%x\r\n", enc28j60Read(MAADR0));

  178. enc28j60PhyWrite(PHCON1, PHCON1_PDPXMD);

  179. // no loopback of transmitted frames
  180. enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS); // switch to bank 0
  181. enc28j60SetBank(ECON1);
  182. // enable interrutps
  183. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);

  184. // enable packet reception
  185. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);

  186. }

  187. // read the revision of the chip:
  188. u8 enc28j60getrev(void)
  189. {
  190. return(enc28j60Read(EREVID));
  191. }

  192. void enc28j60PacketSend(u16 len, u8* packet)
  193. {
  194. // Set the write pointer to start of transmit buffer area
  195. enc28j60Write(EWRPTL, TXSTART_INIT & 0xFF);
  196. enc28j60Write(EWRPTH, TXSTART_INIT >> 8);

  197. // Set the TXND pointer to correspond to the packet size given
  198. enc28j60Write(ETXNDL, (TXSTART_INIT + len) & 0xFF);
  199. enc28j60Write(ETXNDH, (TXSTART_INIT + len) >> 8);

  200. // write per-packet control byte (0x00 means use macon3 settings)
  201. enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);

  202. // copy the packet into the transmit buffer
  203. enc28j60WriteBuffer(len, packet);

  204. // send the contents of the transmit buffer onto the network
  205. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);

  206. // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
  207. if ((enc28j60Read(EIR) & EIR_TXERIF))
  208. {
  209. enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
  210. }
  211. }

  212. /*-----------------------------------------------------------------
  213. Gets a packet from the network receive buffer, if one is available.
  214. The packet will by headed by an ethernet header.
  215. maxlen The maximum acceptable length of a retrieved packet.
  216. packet Pointer where packet data should be stored.
  217. Returns: Packet length in bytes if a packet was retrieved, zero otherwise.
  218. -------------------------------------------------------------------*/
  219. u16 enc28j60PacketReceive(u16 maxlen, u8* packet)
  220. {
  221. u16 rxstat;
  222. u16 len;

  223. // check if a packet has been received and buffered
  224. //if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
  225. // The above does not work. See Rev. B4 Silicon Errata point 6.
  226. if (enc28j60Read(EPKTCNT) == 0)
  227. {
  228. return(0);
  229. }

  230. // Set the read pointer to the start of the received packet
  231. enc28j60Write(ERDPTL, (NextPacketPtr));
  232. enc28j60Write(ERDPTH, (NextPacketPtr) >> 8);

  233. // read the next packet pointer
  234. NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  235. NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;

  236. // read the packet length (see datasheet page 43)
  237. len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  238. len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;

  239. len -= 4; //remove the CRC count
  240. // read the receive status (see datasheet page 43)
  241. rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  242. rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
  243. // limit retrieve length
  244. if (len > maxlen - 1)
  245. {
  246. len = maxlen - 1;
  247. }

  248. // check CRC and symbol errors (see datasheet page 44, table 7-3):
  249. // The ERXFCON.CRCEN is set by default. Normally we should not
  250. // need to check this.
  251. if ((rxstat & 0x80) == 0)
  252. {
  253. // invalid
  254. len = 0;
  255. }
  256. else
  257. {
  258. // copy the packet from the receive buffer
  259. enc28j60ReadBuffer(len, packet);
  260. }
  261. // Move the RX read pointer to the start of the next received packet
  262. // This frees the memory we just read out
  263. enc28j60Write(ERXRDPTL, (NextPacketPtr));
  264. enc28j60Write(ERXRDPTH, (NextPacketPtr) >> 8);

  265. // decrement the packet counter indicate we are done with this packet
  266. enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
  267. return(len);
  268. }



main.c
  1. /*---------------------------------------------------------------------------------------------------------*/
  2. /* */
  3. /* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved. */
  4. /* */
  5. /*---------------------------------------------------------------------------------------------------------*/
  6. #include "includes.h" //包含所需的头文件
  7. /*************************************************************************************
  8. ** Function name: main
  9. ** Descriptions: 默认IP地址: 192. 168. 1.100
  10. ** input parameters: 无
  11. ** output parameters: 无
  12. ** Returned value: 无
  13. *************************************************************************************/
  14. int main (void)
  15. {
  16. unsigned char tmp = 0;
  17. Set_System(); //系统初始化

  18. simple_server(); //简单网页服务器
  19. }

现场图片:

电脑截图:


添加上工程文件:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
john_lee 发表于 2012-7-6 21:57 | 显示全部楼层
这个必须穿裤子
 楼主| jxc827 发表于 2012-7-6 22:06 | 显示全部楼层
第一次穿裤子,受宠若惊啊!
abin0415 发表于 2012-7-7 22:09 | 显示全部楼层
这个必须顶
xyz549040622 发表于 2012-7-8 07:30 | 显示全部楼层
这个厉害,记住,我要试试
neo_bright 发表于 2012-7-8 23:47 | 显示全部楼层
thanks
kyzb001 发表于 2012-7-9 08:42 | 显示全部楼层
难道传来传去就这一个 工程?
 楼主| jxc827 发表于 2012-7-12 12:35 | 显示全部楼层
新手请谅解。
KFYSX 发表于 2012-7-17 17:53 | 显示全部楼层
怎么回事?
在浏览器中输入:http://192.168.1.100/
显示:
http://192.168.1.100/
在浏览器中输入:http://192.168.1.100/888/1
显示:
[url=http://192.168.1.100/888http://192.168.1.100/888]http://192.168.1.100/888http://192.168.1.100/888[/url]
KFYSX 发表于 2012-7-17 17:54 | 显示全部楼层
怎么回事?
在浏览器中输入:http://192.168.1.100/

显示:
http://192.168.1.100/

在浏览器中输入:http://192.168.1.100/888/1

显示:
http://192.168.1.100/888http://192.168.1.100/888
myfish 发表于 2012-9-2 20:32 | 显示全部楼层
学习学习~~~~
lwslws201 发表于 2012-9-10 19:57 | 显示全部楼层
这个是野火的历程修改过来的!
rejoice818 发表于 2012-9-12 13:11 | 显示全部楼层
smartmcu也有相关例程,还配套上下位机的源码。
lu0718 发表于 2012-9-12 20:24 | 显示全部楼层
顶LZ
夏末一直很在乎 发表于 2013-7-23 15:06 | 显示全部楼层
学习学习
cgd 发表于 2013-7-23 16:16 | 显示全部楼层
ilee123 发表于 2013-8-14 21:57 | 显示全部楼层
回贴才是乖孩子
chengshaobin 发表于 2016-5-27 18:32 | 显示全部楼层
你好,有些问题想咨询一下您 方便的话加个企鹅吧?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

53

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部