最近老板有个项目,其中要做一个Zigbee的无线接入点,即将ZigBee无线传感网络中的数据通过TCP/IP协议传输到以太网上。传统的这种无线接入点即网关都是上位机加下位机模式做成的,即主控芯片(如ARM)加无线模块(如cc2530),ARM与cc2530通过UARST通信,cc2530建立WSN网络,ARM与PC机通过TCP/IP通信,考虑到此系统的成本以及其中的数据传输量不大,就不用ARM,直接将cc2530做成网关,这就需要将TCP/IP协议栈移植到cc2530上,同时与ZigBee协议栈能很好的协同运行。
因为cc2530的FLASH有256K,Z-stack占用了大部分,所以要用TCP/IP,只能移植一个轻量型网络协议栈,现在比较流行的就是Adam Dunkels写的lwIP和uIP,还有Micrium的uc/IP,lwip和uc/ip所占空间较大,移植较为麻烦,所以就用uip。uip是一种免费可的极小的TCP/IP协议栈,主要实现了ARP,ICMP,TCP,UDP协议,在8位或16位单片机上用的较多,对rom和ram要求很少。
在网上看了一些uip移植到51或STM32的文章,同时也花了两天时间看了uip的实现源码,如果不熟悉TCP/IP协议的话读起来还是很吃力,所以先看看TCP/IP,建议看TCP/IP协议详解——卷一。看完之后大概知道移植过程了。
移植之前先要写网络芯片驱动程序,我用的是enc28j60,独立控制的SPI接口,因为cc2530的spi接口用来下载调试了,另一个spi被串口复用了,所以只用用GPIO模拟SPI。
写驱动程序之前认真读了enc28j60的datasheet,在网上也找到了相关的驱动程序,可以稍加修改拿来用。下面贴出spi程序和enc28j60的程序。
#include "spi.h"
void WriteByte(u8_t dat)
{
u8_t i;
for(i=0;i<8;i++)
{
SCKN = 0;
asm("nop");
if(dat&0x80)
{
SIN = 1;
}
else
SIN = 0;
dat <<= 1;
asm("nop");
SCKN = 1;
asm("nop");
}
SCKN=0; //空闲状态为低电平
}
u8_t ReadByte(void)
{
u8_t i,dat;
SCKN=0;
dat1=0;
for(i=0;i<8;i++)
{
SCKN=1;
dat1 <<=1;
dat1 |= SON;
SCKN=0;
}
return dat;
}
spi.h文件定义了与enc28j60spi接口的GPIO,
#ifndef SPI_H
#define SPI_H
#include <ioCC2530.h>
#define SON P0_5 // MISO
#define SIN P0_6 // MOSI
#define SCKN P0_7 // SCK
#define CSN P1_3 // 28J60-- CS
#define RESET P1_2 // Reset
void WriteByte(u8_t dat);
u8_t ReadByte(void);
#endif
enc28j60.c文件:
#include "enc28j60.h"
#include "spi.h"
#define MIN(a,b) (a) < (b) ? (a) : (b)
XDATA u8_t Enc28j60Bank;
XDATA u16_t NextPacketPtr;
void delay_100ns()
{
asm("nop");
asm("nop");
asm("nop");
}
void delay_ms(int t1)
{
int i;
while(t1--)
{
for(i=10;i;--i)
{
delay_100ns();
}
}
}
//*******************************************************************************************
//
// Function : enc28j60ReadOp
// Description :
//
//*******************************************************************************************
u8_t enc28j60ReadOp(u8_t op, u8_t address)