打印
[Cortex-M0技术交流]

新手学习笔记4——SPI+ENC28J60(通过网页控制LED)

[复制链接]
8478|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jxc827|  楼主 | 2012-7-6 21:41 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 jxc827 于 2012-7-6 22:47 编辑

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

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

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

/*************************************************************************************
** Function name: Set_System
** Descriptions: 封装一些初始化模块
** input parameters: count
** output parameters: 无
** Returned value: 无
*************************************************************************************/
void Set_System(void)
{
RCC_Configuration(); //配置系统时钟

GPIO_Configuration(); //配置GPIO

SPI_Configuration(); //配置SPI1
}
/*************************************************************************************
** Function name: RCC_Configuration
** Descriptions: 系统时钟设置,使用PLL输出50M
** input parameters: none
** output parameters: none
** Returned value: none
*************************************************************************************/
void RCC_Configuration(void)
{
int32_t tmp;
UNLOCKREG();
DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1); // 使能外部12M时钟源
DrvSYS_SelectPLLSource(E_SYS_EXTERNAL_12M); //选择外部12M时钟源PLL
DrvSYS_SetPLLMode(0); //PLL 正常模式
tmp = DrvSYS_GetPLLContent(E_SYS_EXTERNAL_12M, 50000000); //设置PLL输出50M
DrvSYS_SetPLLContent(tmp);
DrvSYS_SelectHCLKSource(2); //0:12M;1:32K;2LL;
tmp = DrvSYS_GetHCLKFreq(); //回读HCLK时钟频率
LOCKREG();
}
/*************************************************************************************
** Function name: GPIO_Configuration
** Descriptions: GPIO配置
** input parameters: none
** output parameters: none
** Returned value: none
*************************************************************************************/
void GPIO_Configuration()
{
DrvGPIO_Open( E_GPA, 13, E_IO_OUTPUT ); // SPI片选
DrvGPIO_Open( E_GPA, 12, E_IO_OUTPUT ); // SPI复位
DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT ); // LED灯控制

}

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

DISABLE_SPI_CS; //输出高电平
}

/*************************************************************************************
** Function name: delay_ms
** Descriptions: 1ms(晶振为12MHZ)延时子程序
** input parameters: count
** output parameters: 无
** Returned value: 无
*************************************************************************************/
void delay_ms(uint32_t count)
{
uint32_t i,j;
for(i=count;i>0;i--)
for(j=2395;j>0;j--);
}

/*************************************************************************************
** Function name: SPInet_ReadWrite
** Descriptions: SPI读写数据函数
** input parameters: 写入数据
** output parameters: 无
** Returned value: 读出数据
*************************************************************************************/
uint8_t SPInet_ReadWrite(uint8_t writedat)
{
uint32_t au32SourceData;
uint32_t au32DestinationData;

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

DrvSPI_DumpRxRegister(eDRVSPI_PORT1, &au32DestinationData, 1);

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

static u8 Enc28j60Bank;
static u16 NextPacketPtr;


u8 enc28j60ReadOp(u8 op, u8 address)
{
u8 dat = 0;

ENC28J60_CSL();

dat = op | (address & ADDR_MASK);
SPInet_ReadWrite(dat);
dat = SPInet_ReadWrite(0x00);
// do dummy read if needed (for mac and mii, see datasheet page 29)
if (address & 0x80)
{
dat = SPInet_ReadWrite(0x00);
}
// release CS
ENC28J60_CSH();
return dat;
}

void enc28j60WriteOp(u8 op, u8 address, u8 data)
{
u8 dat = 0;

ENC28J60_CSL();
// issue write command
dat = op | (address & ADDR_MASK);
SPInet_ReadWrite(dat);
// write data
dat = data;
SPInet_ReadWrite(dat);
ENC28J60_CSH();
}

void enc28j60ReadBuffer(u16 len, u8* data)
{
ENC28J60_CSL();
// issue read command
SPInet_ReadWrite(ENC28J60_READ_BUF_MEM);
while (len--)
{
*data++ = (u8) SPInet_ReadWrite(0);
}
*data = '\0';
ENC28J60_CSH();
}

void enc28j60WriteBuffer(u16 len, u8* data)
{
ENC28J60_CSL();
// issue write command
SPInet_ReadWrite(ENC28J60_WRITE_BUF_MEM);

while (len--)
{
SPInet_ReadWrite(*data++);
}
ENC28J60_CSH();
}

void enc28j60SetBank(u8 address)
{
// set the bank (if needed)
if ((address & BANK_MASK) != Enc28j60Bank)
{
// set the bank
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
Enc28j60Bank = (address & BANK_MASK);
}
}

u8 enc28j60Read(u8 address)
{
// set the bank
enc28j60SetBank(address);
// do the read
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}

void enc28j60Write(u8 address, u8 data)
{
// set the bank
enc28j60SetBank(address);
// do the write
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}

void enc28j60PhyWrite(u8 address, u16 data)
{
// set the PHY register address
enc28j60Write(MIREGADR, address);
// write the PHY data
enc28j60Write(MIWRL, data & 0x00ff);
enc28j60Write(MIWRH, data >> 8);
// wait until the PHY write completes
while (enc28j60Read(MISTAT) & MISTAT_BUSY)
{
}
}

void enc28j60clkout(u8 clk)
{
enc28j60Write(ECOCON, clk & 0x7);
}

void enc28j60Init(u8 * macaddr)
{
unsigned char tmp=0;
unsigned long i;

ENC28J60_RSTL();
delay_ms(1000);
ENC28J60_RSTH();
delay_ms(1000); //必须延迟一段时间

// perform system reset
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);

// Del_1ms(250);
// check CLKRDY bit to see if reset is complete
// The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
//while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
// do bank 0 stuff
// initialize receive buffer
// 16-bit transfers, must write low byte first
// set receive buffer start address
NextPacketPtr = RXSTART_INIT;
// Rx start
enc28j60Write(ERXSTL, RXSTART_INIT & 0xFF);
enc28j60Write(ERXSTH, RXSTART_INIT >> 8);
// set receive pointer address
enc28j60Write(ERXRDPTL, RXSTART_INIT & 0xFF);
enc28j60Write(ERXRDPTH, RXSTART_INIT >> 8);
// RX end
enc28j60Write(ERXNDL, RXSTOP_INIT & 0xFF);
enc28j60Write(ERXNDH, RXSTOP_INIT >> 8);
// TX start
enc28j60Write(ETXSTL, TXSTART_INIT & 0xFF);
enc28j60Write(ETXSTH, TXSTART_INIT >> 8);
// TX end
enc28j60Write(ETXNDL, TXSTOP_INIT & 0xFF);
enc28j60Write(ETXNDH, TXSTOP_INIT >> 8);
// do bank 1 stuff, packet filter:
// For broadcast packets we allow only ARP packtets
// All other packets should be unicast only for our mac (MAADR)
//
// The pattern to match on is therefore
// Type ETH.DST
// ARP BROADCAST
// 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
// in binary these poitions are:11 0000 0011 1111
// This is hex 303F->EPMM0=0x3f,EPMM1=0x30
enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);
enc28j60Write(EPMM0, 0x3f);
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
//
//
// do bank 2 stuff
// enable MAC receive
enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
// bring MAC out of reset
enc28j60Write(MACON2, 0x00);
// enable automatic padding to 60bytes and CRC operations
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
// set inter-frame gap (non-back-to-back)
enc28j60Write(MAIPGL, 0x12);
enc28j60Write(MAIPGH, 0x0C);
// set inter-frame gap (back-to-back)
enc28j60Write(MABBIPG, 0x12);
// Set the maximum packet size which the controller will accept
// Do not send packets longer than MAX_FRAMELEN:
enc28j60Write(MAMXFLL, MAX_FRAMELEN & 0xFF);
enc28j60Write(MAMXFLH, MAX_FRAMELEN >> 8);
// do bank 3 stuff
// write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
enc28j60Write(MAADR5, macaddr[0]);
enc28j60Write(MAADR4, macaddr[1]);
enc28j60Write(MAADR3, macaddr[2]);
enc28j60Write(MAADR2, macaddr[3]);
enc28j60Write(MAADR1, macaddr[4]);
enc28j60Write(MAADR0, macaddr[5]);

// printf("MAADR5 = 0x%x\r\n", enc28j60Read(MAADR5));
// printf("MAADR4 = 0x%x\r\n", enc28j60Read(MAADR4));
// printf("MAADR3 = 0x%x\r\n", enc28j60Read(MAADR3));
// printf("MAADR2 = 0x%x\r\n", enc28j60Read(MAADR2));
// printf("MAADR1 = 0x%x\r\n", enc28j60Read(MAADR1));
// printf("MAADR0 = 0x%x\r\n", enc28j60Read(MAADR0));

enc28j60PhyWrite(PHCON1, PHCON1_PDPXMD);

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

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

}

// read the revision of the chip:
u8 enc28j60getrev(void)
{
return(enc28j60Read(EREVID));
}

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

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

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

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

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

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

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

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

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

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

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

len -= 4; //remove the CRC count
// read the receive status (see datasheet page 43)
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
// limit retrieve length
if (len > maxlen - 1)
{
len = maxlen - 1;
}

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

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



main.c
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
#include "includes.h" //包含所需的头文件
/*************************************************************************************
** Function name: main
** Descriptions: 默认IP地址: 192. 168. 1.100
** input parameters: 无
** output parameters: 无
** Returned value: 无
*************************************************************************************/
int main (void)
{
unsigned char tmp = 0;
Set_System(); //系统初始化

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

现场图片:

电脑截图:


添加上工程文件:
SPI_ENC28J60.rar (668.2 KB)

相关帖子

沙发
john_lee| | 2012-7-6 21:57 | 只看该作者
这个必须穿裤子

使用特权

评论回复
板凳
jxc827|  楼主 | 2012-7-6 22:06 | 只看该作者
第一次穿裤子,受宠若惊啊!

使用特权

评论回复
地板
abin0415| | 2012-7-7 22:09 | 只看该作者
这个必须顶

使用特权

评论回复
5
xyz549040622| | 2012-7-8 07:30 | 只看该作者
这个厉害,记住,我要试试

使用特权

评论回复
6
neo_bright| | 2012-7-8 23:47 | 只看该作者
thanks

使用特权

评论回复
7
kyzb001| | 2012-7-9 08:42 | 只看该作者
难道传来传去就这一个 工程?

使用特权

评论回复
8
jxc827|  楼主 | 2012-7-12 12:35 | 只看该作者
新手请谅解。

使用特权

评论回复
9
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]

使用特权

评论回复
10
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

使用特权

评论回复
11
myfish| | 2012-9-2 20:32 | 只看该作者
学习学习~~~~

使用特权

评论回复
12
lwslws201| | 2012-9-10 19:57 | 只看该作者
这个是野火的历程修改过来的!

使用特权

评论回复
13
rejoice818| | 2012-9-12 13:11 | 只看该作者
smartmcu也有相关例程,还配套上下位机的源码。

使用特权

评论回复
14
lu0718| | 2012-9-12 20:24 | 只看该作者
顶LZ

使用特权

评论回复
15
夏末一直很在乎| | 2013-7-23 15:06 | 只看该作者
学习学习

使用特权

评论回复
16
cgd| | 2013-7-23 16:16 | 只看该作者

使用特权

评论回复
17
ilee123| | 2013-8-14 21:57 | 只看该作者
回贴才是乖孩子

使用特权

评论回复
18
chengshaobin| | 2016-5-27 18:32 | 只看该作者
你好,有些问题想咨询一下您 方便的话加个企鹅吧?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

53

帖子

1

粉丝