前一段时间是针对专门的问题,发了一些帖子,这次在从最基本简单的入手,让我们一起逐步地深入吧。
1.首先我们可以在桌面上创建一个文件夹,my_proj。
2.把StellarisWare下的一些文件夹复制到my_proj下,其中progjects文件夹用来保存我们要创建的工程,这样我们以后要用到的文件都包含在下图中的文件夹中了,不至于太多无关的文件浪费时间。
3.在projects文件夹下创建enet_udp文件夹,我们将一步步地完成一个简单的基于的UDP客户端地例子。
4.在enet_udp文件夹中创建工程enet_udp.uvproj。并配置工程,具体的配置,可以参考StellarisWare的例程。
5.创建enet_udp.c文件,并添加到工程中。然后添加最重要的两个文件到工程中,driverlib和lwiplib.c
6.此时编译一下,会发现有很多头文件找不到。不用急,我们可以根据提示的错误添加相应的头文件路径。我比较喜欢使用下面的方法,简单。编译,出错,添加路径,再编译,再出错,再添加。当然多手动添加几次,就会对lwip文件结构有一个整体的认识,以后就会很快了。最后别忘了添加当前目录。
7.最后别忘了复制一个lwipopts.h到工程当前文件夹下,它是配置lwip协议栈最重要的文件。然后配置启动文件。
8.开始编写主程序enet_udp.c中的内容。这里对网上的进行了某些地方的修改,但这只是最基本的发送,以后在这个基础上逐步地去深入。
9.添加常见的头文件
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "inc/hw_sysctl.h"
#include "driverlib/ethernet.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "utils/lwiplib.h"
#define My_Mac_ID {0X00,0x14,0x97,0x0F,0x1D,0xE3} //存储以太网控制器的物理地址,即MAC地址
#define MY_IP_ID {192,168,0,100} //以太网通信的IP地址
#define IP_MARK_ID {255,255,255,0} //255.255.255.0,子网掩码
#define MY_GATEWAY_ID {192,168,0,1} //以太网通信的网关地址
static const unsigned char pucMACAddress[]=My_Mac_ID;
static const unsigned char IPAddress[] = MY_IP_ID;
static const unsigned char NetMaskAddr[] = IP_MARK_ID;
static const unsigned char GwWayAddr[] = MY_GATEWAY_ID;
const static unsigned char UDPData[]="LwIP UDP客户端在Luminary微控制器上的测试\r\n";
#define SYSTICKHZ 100
#define SYSTICKMS (1000 / SYSTICKHZ)
#define SYSTICKUS (1000000 / SYSTICKHZ)
#define SYSTICKNS (1000000000 / SYSTICKHZ)
void
SysTickIntHandler(void)
{
lwIPTimer(SYSTICKMS);
}
int
main(void)
{
struct ip_addr ulIPAddr,ulNetMask,ulGWAddr;
struct udp_pcb *Pcb1;
struct ip_addr ipaddr1;
struct pbuf *p;
if(REVISION_IS_A2)
{
SysCtlLDOSet(SYSCTL_LDO_2_75V);
}
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_8MHZ);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3);
SysTickPeriodSet(SysCtlClockGet() / SYSTICKHZ);
SysTickEnable();
SysTickIntEnable();
IntMasterEnable();
IP4_ADDR(&ulIPAddr,IPAddress[3],IPAddress[2],IPAddress[1],IPAddress[0]);
IP4_ADDR(&ulNetMask,NetMaskAddr[3],NetMaskAddr[2],NetMaskAddr[1],NetMaskAddr[0]);
IP4_ADDR(&ulGWAddr,GwWayAddr[3],GwWayAddr[2],GwWayAddr[1],GwWayAddr[0]);
lwIPInit(pucMACAddress,ulIPAddr.addr, ulNetMask.addr, ulGWAddr.addr, IPADDR_USE_STATIC);
p = pbuf_alloc(PBUF_RAW,sizeof(UDPData),PBUF_RAM);
p->payload=(void *)UDPData;
IP4_ADDR(&ipaddr1,192,168,0,127); //这里是PC机的IP地址。
Pcb1 = udp_new();
udp_bind(Pcb1,IP_ADDR_ANY,1025); /* 绑定到本地IP地址,设端口为1025,客户端一般为偶数。*/
udp_connect(Pcb1,&ipaddr1,1025); /* 连接PC机上的1025号端口,其实服务器的端口一般为奇数。*/
while(1)
{
udp_send(Pcb1,p);
SysCtlDelay(SysCtlClockGet()/3);
}
}
[ 本帖最后由 academic 于 2011-4-10 12:29 编辑 ]
上面的程序是最简单的使用lwIP来循环发送UDP数据报,下面对它进行完善后,使它具有接收UDP数据报的功能,并在需要的时候来发送UDP数据包的一个简单例子,并顺便学习几个重要的字符串处理函数的使用。
#include <string.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "inc/hw_sysctl.h"
#include "driverlib/ethernet.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "utils/lwiplib.h"
#include "utils/ustdlib.h"
#define My_Mac_ID {0X00,0x14,0x97,0x0F,0x1D,0xE3} //存储以太网控制器的物理地址,即MAC地址
#define MY_IP_ID {192,168,0,100} //以太网通信的IP地址
#define IP_MARK_ID {255,255,255,0} //255.255.255.0,子网掩码
#define MY_GATEWAY_ID {192,168,0,1} //以太网通信的网关地址
static const unsigned char pucMACAddress[]=My_Mac_ID;
static const unsigned char IPAddress[] = MY_IP_ID;
static const unsigned char NetMaskAddr[] = IP_MARK_ID;
static const unsigned char GwWayAddr[] = MY_GATEWAY_ID;
//const static unsigned char UDPData[]="LwIP UDP客户端在Luminary微控制器上的测试\r\n";
#define SYSTICKHZ 100
#define SYSTICKMS (1000 / SYSTICKHZ)
#define SYSTICKUS (1000000 / SYSTICKHZ)
#define SYSTICKNS (1000000000 / SYSTICKHZ)
static struct udp_pcb *g_psPCB = NULL;
void
SysTickIntHandler(void)
{
lwIPTimer(SYSTICKMS);
}
static void
APP_recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port)
{
char *pcData = p->payload;
struct pbuf *p_out;
static char pcBuf[100];
unsigned long ulIPAddr;
unsigned char pucMACAddr[6];
ulIPAddr = lwIPLocalIPAddrGet();
if(ulIPAddr == 0)
{
return;
}
lwIPLocalMACGet(pucMACAddr);
usprintf(pcBuf,"\r\nTHE TARGET IP IS:%d.%d.%d.%d AND THE MAC IS:%02X%02X%02X%02X%02X%02X", ((ulIPAddr >> 0) & 0xFF),
((ulIPAddr >> 8) & 0xFF), ((ulIPAddr >> 16) & 0xFF),
((ulIPAddr >> 24) & 0xFF),
pucMACAddr[0],
pucMACAddr[1], pucMACAddr[2], pucMACAddr[3],
pucMACAddr[4], pucMACAddr[5]);
//说明是外设控制
p_out = pbuf_alloc(PBUF_TRANSPORT, strlen(pcBuf), PBUF_RAM);
if(p_out != NULL)
{
memcpy(p_out->payload,pcBuf, strlen(pcBuf));
udp_send(g_psPCB, p_out);
pbuf_free(p_out);
}
if(strncmp(pcData, "CONTROL LED ON", 14) == 0)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_PIN_0);
pbuf_free(p);
return;
}
if(ustrstr(pcData, "OFF") != NULL)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0, 0);
pbuf_free(p);
return;
}
pbuf_free(p);
return;
}
void
io_init(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0, 0);
}
int
main(void)
{
struct ip_addr ulIPAddr,ulNetMask,ulGWAddr;
struct udp_pcb *Pcb1;
struct ip_addr ipaddr1;
// struct pbuf *p;
if(REVISION_IS_A2)
{
SysCtlLDOSet(SYSCTL_LDO_2_75V);
}
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_8MHZ);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3);
io_init();
SysTickPeriodSet(SysCtlClockGet() / SYSTICKHZ);
SysTickEnable();
SysTickIntEnable();
IntMasterEnable();
IP4_ADDR(&ulIPAddr,IPAddress[3],IPAddress[2],IPAddress[1],IPAddress[0]);
IP4_ADDR(&ulNetMask,NetMaskAddr[3],NetMaskAddr[2],NetMaskAddr[1],NetMaskAddr[0]);
IP4_ADDR(&ulGWAddr,GwWayAddr[3],GwWayAddr[2],GwWayAddr[1],GwWayAddr[0]);
lwIPInit(pucMACAddress,ulIPAddr.addr, ulNetMask.addr, ulGWAddr.addr, IPADDR_USE_STATIC);
// p = pbuf_alloc(PBUF_RAW,sizeof(UDPData),PBUF_RAM);
// p->payload=(void *)UDPData;
IP4_ADDR(&ipaddr1,192,168,0,127);
g_psPCB=Pcb1 = udp_new();
udp_recv(Pcb1, APP_recv_udp, NULL);
udp_bind(Pcb1,IP_ADDR_ANY,1025); /* 绑定本地IP地址 */
udp_connect(Pcb1,&ipaddr1,1025); /* 连接远程主机 */
while(1)
{
// udp_send(Pcb1,p);
// SysCtlDelay(SysCtlClockGet()/3);
}
}
当在TCP&UDPdebug中发送:CONTROL LED ON时,会点亮开发板上的LED。并返回开发板的IP地址和MAC地址。
当我们发送的字符中含有:OFF时,就会关闭LED。
我这么做,是为了把几个重要的字符串处理函数都包括进来。其中它们基本上都在utils/ustdlib.c中,还有个别在string.h中引用。简单介绍下:
usprintf:是对标准的sprintf的改写,主要作用就是格式化打印字符串。
strncmp:C标准库中的字符串比较函数。
用 法: int strncmp(char *str1, char *str2, int maxlen);
说明:比较字符串str1和str2的大小,如果str1小于str2,返回值就<0,反之如果str1大于str2,返回值就>0,如果str1等于str2,返回值就=0,maxlen指的是str1与str2的比较的字符数。此函数功能即比较字符串str1和str2的前maxlen个字符。
ustrstr:也是对C库函数中的原来改写的,作用是在一个字符串中寻找另一个字符串。
在发送一个UDP数据报的时候,我们就分配一个合适大小的pbuf,但发送完了之后,记得释放它,否则发送的数据多了,会把RAM耗尽的,这就是为什么有的朋友会发现数据发送一段时间后,就自动停止发送了,内存用完了,能不停止吗?
[ 本帖最后由 academic 于 2010-12-2 17:53 编辑 ]
在GPIO.c里边。这个测试工具有很多地方可以下载。
目标IP:就是我们数据要发送到的IP地址,这里一般情况下都是我们的开发板的IP地址。开发板的IP地址,常见的有静态方式,在程序中指定,DHCP分配的动态的,可能需要我们借助locator.c和finder来发现,或者用程序显示到OLED上。上面这个简单的程序中我采用的是静态IP地址,不难在上面找到它。当然你可以更改的。
目标端口:就是填写我们要把UDP或TCP数据报发送到的端口。一般是一些知名端口,或者自己在开发板程序里边指定的。
类型:UDP,TCP,UDP组播。前两个根据程序采用的哪种传输协议来选择,后一种我也不太清楚,反正我还没有通过它受到过组播的UDP,望高手指点啊。
基本就是这么个意思啊。
[ 本帖最后由 academic 于 2010-12-2 18:03 编辑 ]引用: 原帖由 academic 于 2010-12-4 19:00 发表 最近坛子有点冷清啊,我还是要坚持下去,努力实现当初申请板子时的目标,分享也是对我个人的一种鞭策,加深了对知识的理解,还能帮助到一些人,何乐而不为呢?