51单片机简单Ping的实现
0 8 16 31 0 8 16 31
---------------------------- ---------------------------
| 寿命 | 协议 | 首部校验和 | | 源站IP地址 |
---------------------------- ---------------------------
| 源站IP地址 | | 目的站IP地址 |
---------------------------- ---------------------------
| 目的站IP地址 | | 零 | 协议 | UDP/TCP长度 |
---------------------------- ---------------------------
| 数据 | | UDP/TCP包数据 |
---------------------------- ---------------------------
IP包格式(局部) UDP、TCP伪首部+数据格式
图5 IP包格式(局部)和UDP、TCP伪首部格式对比图
伪代码清单:
PingRequest(IP地址) //Ping请求
{
//申请小号内存
pICMP=OSMemGet();
//填写以太网帧
目的MAC地址=ping命令传入的IP地址解析后得到的物理地址
源MAC地址=本节点MAC地址
类型=0x0800 //IP包
//填写IP帧
版本号首部长度=0x45
服务类型=0
总长度=60
标识符=GlobalID++ //全局变量16位GlobalID加1
标志分片偏移量=0x0000
寿命=0x80
协议=0x0001 //icmp
首部校验和=0x0000
源IP地址=本节点IP地址
目的IP地址=ping命令传入的IP地址
首部校验和=CheckSum(IP首部和长度) //计算IP包首部校验和
//填写ICMP帧
类型=8 //8 请求 0 应答
代码=0
校验和=0x0
标识符=0x0300
序号=GlobalID
校验和=CheckSum(ICMP首部和长度) //计算ICMP包首部校验和
//将ICMP包登记在PingBuf中
for(i=0;iMaxLenPingBuf;i++){
if(PingBuf[i].status==0){
PingBuf[i].times=0x8; //测试8次
PingBuf[i].ip=ping命令传入的IP地址;
PingBuf[i].memhandle=内存句柄;
PingBuf[i].status=4; //第一次准备发(用于同步1秒时钟)
break;
}
}
if(i==MaxLenPingBuf) 释放内存;
}
PingAnswer(*输入包缓冲区首址pBUF) //Ping应答
{
//改写以太网帧
目的MAC地址=源MAC地址
源MAC地址=本节点MAC地址
//改写IP帧
寿命=寿命-1
目的IP地址=源IP地址
源IP地址=本节点IP地址
首部校验和=0x0000
首部校验和=CheckSum(IP首部和长度) //计算IP包首部校验和
//改写ICMP帧
类型=0 //8 请求 0 应答
校验和=0x0
校验和=CheckSum(ICMP首部和长度) //计算ICMP包首部校验和
//直接发送ICMP包至TxQFIFO缓存
OSQSend(QID,*pBUF);
}
PingEcho(*输入包缓冲区首址pBUF) //收到应答后回显
{
//打印ping响应,因为51定时器较慢,time参数省略(time是本机与对方主机往返一次所用时间)。
PrintStr("\tReply from IP=");
PrintStr(输入包之源IP地址);
PrintStr(": bytes=32");
PrintStr(" TTL=");
PrintByte(输入包之TTL);
PrintStr("");
//处理PingBuf的记录
for(i=0;iMaxLenPingBuf;i++){
if(PingBuf[i].status==1){
if(PingBuf[i].ip==pBUF.ipframe.ip){
PingBuf[i].status=2; //已发出且应答
break;
}
}
}
}
PingCycle() //定时操作,放在1秒循环任务中
{
for(;;){
taskDelay(1秒);
for(i=0;iMaxLenPingBuf;i++){
switch(PingBuf[i].status)
case 0: //空闲
break;
{
case 1: //已发出但无应答
//打印超时信息
PrintStr("\tRequest timed out.(");
PrintStr(PingBuf[i].ip);
PrintStr(")");
case 2: //已发出且应答
//状态变迁
PingBuf[i].times=PingBuf[i].times-1;
if(PingBuf[i].times==0)
PingBuf[i].status=0;
else{
case 4: //第一次准备发(用于同步1秒时钟)
//查ARP缓存
if(ARP缓存有对应项){
//直接发送ICMP包至TxQFIFO缓存
OSQSend(QID,*pBUF);
PingBuf[i].status=1; //已发出但无应答
}
else PingBuf[i].status=3; //等ARP
}
break;
}
case 3: //等ARP
{
//查ARP缓存
if(ARP缓存有对应项){
//直接发送ICMP包至TxQFIFO缓存
OSQSend(QID,*pBUF);
}
PingBuf[i].status=1; //已发出但无应答
}
default: //其他状态,错误
PingBuf[i].status=0;
}
}
}
void PingCommand(WORDTABLE *WordTable)//PING命令处理
{
if(WordTable->Num==1)
PrintStr("Please input IP address!");
else{
if(IPadrToHEX(WordTable->wt[1].Str,ping_ip_address)==0){
PrintStr("IP address error!");return;
}
else
PingRequest(ping_ip_address);
}
}
INT16U CheckSum(INT16U *buf,INT16U length) //校验和计算
{
INT16U len;
INT32U sum;
len=length>>1;
for(sum=0;len>0;len--)
sum+=*buf++;
if(length1)
sum+=(*buf0xFF00);
sum=(sum>>16)+(sum0xFFFF);
sum+=(sum>>16);
return(~sum);
}
union ip_address_type{ //ip地址数据结构
unsigned long dwords;
unsigned int words[2];
unsigned char bytes[4];
};
- 关于RTX51 TINY的分析与探讨(05-30)
- 浅析8051模块化编程技巧(05-28)
- 基于DSP和单片机通信的液晶显示设计方案(07-20)
- 锁相环控制及初始化简析(08-27)
- 基于MSP430自动胀管控制器的研究(09-07)
- 嵌入式C实现延时程序的不同变量的区别(03-01)