Arduino之坑(四)——TCP通信

0.参考连接

https://blog.youkuaiyun.com/dpjcn1990/article/details/92830087

1.mac地址和ip地址

MAC地址是物理地址,IP地址是逻辑地址。MAC地址是不可改变的,IP地址是可以更改的。MAC地址具有唯一性,每个硬件出厂时候的MAC地址是固定的;IP地址不具备唯一性,因此,很多应用软件是围绕MAC地址开发的。二层基于MAC地址转发数据帧,三层基于IP地址转发报文。二层交换机基于MAC地址表转发数据,路由器基于路由表(IP地址)转发数据。MAC地址是Ethernet网卡上带的地址,长度为48位,IP地址目前主流是32位长。IP地址和MAC地址通过ARP协议联系到一起。IP地址的分配是基于网络拓扑,MAC地址的分配是基于制造商。MAC地址的长度为48位(6个字节),通常表示为12个16进制数,每2个16进制数之间用冒号隔开,如:00:50:29:5A:8H:1E就是一个MAC地址。IP地址为32位,由用点分隔开的4个8八位组构成,如192.168.0.1就是一个IP地址,这种写法叫点分十进制格式。

2.HTTP

http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使得开发和部署是那么的直截了当。

HTTP是基于客户/服务器模式,且面向连接的。典型的HTTP事务处理有如下的过程:

(1)客户与服务器建立连接;

(2)客户向服务器提出请求;

(3)服务器接受请求,并根据请求返回相应的文件作为应答;

(4)客户与服务器关闭连接。

HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。这就大大减轻了服务器记忆负担,从而保持较快的响应速度。HTTP是一种面向对象的协议。允许传送任意类型的数据对象。它通过数据类型和长度来标识所传送的数据内容和大小,并允许对数据进行压缩传送。当用户在一个HTML文档中定义了一个超文本链后,浏览器将通过TCP/IP协议与指定的服务器建立连接。

HTTP报文由从客户机到服务器的请求和从服务器到客户机的响应构成。请求报文格式如下:请求行 - 通用信息头 - 请求头 - 实体头 - 报文主体,请求行以方法字段开始,后面分别是 URL 字段和 HTTP 协议版本字段,并以 CRLF 结尾。SP 是分隔符。除了在最后的 CRLF 序列中 CF 和 LF 是必需的之外,其他都可以不要。有关通用信息头,请求头和实体头方面的具体内容可以参照相关文件。应答报文格式如下:状态行 - 通用信息头 - 响应头 - 实体头 - 报文主体,状态码元由3位数字组成,表示请求是否被理解或被满足。原因分析是对原文的状态码作简短的描述,状态码用来支持自动操作,而原因分析用来供用户使用。客户机无需用来检查或显示语法。有关通用信息头,响应头和实体头方面的具体内容可以参照相关文件。

3.IP和DNS

DNS地址其实也是ip地址。所有在Internet 上的设备都有ip地址而NDS地址就是DNS服务器ip地址。所有访问域名网站的主机都需要指DNS服务器地址,让DNS服务器解析域名

4.DHCP

DHCP(动态主机配置协议)是一个局域网的网络协议。指的是由服务器控制一段lP地址范围,客户机登录服务器时就可以自动获得服务器分配的lP地址和子网掩码。默认情况下,DHCP作为Windows Server的一个服务组件不会被系统自动安装,还需要管理员手动安装并进行必要的配置。

5.Test Demo

#include <SPI.h> 
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] =  { 192, 168, 0, 15 };
EthernetServer server(80);

void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  EthernetClient client = server.available();
  if (client)
  {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    while (client.connected()) 
    {
      if (client.available()) 
      {
        char c = client.read();
        // if we've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so we can send a reply
        if (c == '\n' && current_line_is_blank) 
        {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
         
          // output the value of each analog input pin
          client.print("welcome to tinyos");
          client.println("");
          client.print("//*************************************");
          client.println("");
          client.print("www.tinyos.net.cn");
          client.println("");
          client.print("//*************************************");
          client.println("");
          for (int i = 0; i < 6; i++)
          {
            client.print("analog input ");
            client.print(i);
            client.print(" is ");
            client.print(analogRead(i));
            client.println("");
          }
          break;
        }
        
        if (c == '\n')
        {
          // we're starting a new line
          current_line_is_blank = true;
        } 
        
        else if (c != '\r')
        {
          // we've gotten a character on the current line
          current_line_is_blank = false;
        }
      }
    }
    
    client.stop();
  }
}

首先把这段代码烧录进插好的板子里面,若此时硬件已经通了,则板子上的PWR、LINK、100M、FULLD四个LED灯会亮,然后进入控制面板,在网络适配器面板中为出现的端口分配ip地址,下面是我用的IP地址:

然后在cmd命令行里面输入ping 192.168.0.15

最后访问http://192.168.0.15看最终结果

6.下位机建立服务器端

网口配置如下图:

(1)首先,我们应该给下位机分配一个MAC地址和IP地址,并定义服务器端口号。

(2)其次,在setup函数中,应该调用begin函数启动Ethernet和EthernetServer

(3)最后,在loop函数中,先建立监听socket,接收到客户端链接,当监听到后则等待连接,对缓冲区进行判断,如果缓冲区有数据,则从串口和网口同时发送出来。

(4)当断开连接后,则利用stop停止通讯socket

#include <SPI.h> 
#include <Ethernet.h>//以太网头文件
//#include <SoftwareSerial.h>//串口头文件
#include <Servo.h>//舵机头文件

void(*resetFunc) (void) = 0; //重新复位Arduino的函数  

//全局变量
Servo pumb;//气体泵对象
Servo Solenoid;//电磁阀对象
int incomedate = 0;//接收数据
int times = 200;//循环次数

//定义各个电机相关引脚
#define EN        8       //步进电机使能端,低电平有效
#define X_DIR     5       //X轴 步进电机方向控制
#define Y_DIR     6       //y轴 步进电机方向控制
//#define Z_DIR     7       //z轴 步进电机方向控制
#define X_STP     2       //x轴 步进控制
#define Y_STP     3       //y轴 步进控制
//#define Z_STP     4       //z轴 步进控制

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//给下位机分配一个MAC
byte ip[] =  { 192, 168, 0, 15 };//设置服务器的IP地址
EthernetServer server(80);//设置服务器的端口号

void Servo_init()//初始化气体泵控制函数
{
  pumb.attach(4);//气体泵接pin4引脚——SpinEnable
  Solenoid.attach(7);//电磁阀接pin7引脚——SpinDir

  pumb.write(0);
  Solenoid.write(0);
}

void open_pumb()//打开气体泵
{
    pumb.write(180);   
    Solenoid.write(0); 
}


void close_pumb()//释放物体函数或关闭气体泵
{
    pumb.write(0);   
    Solenoid.write(180);
    delay(10000);
}

void motor_Init()//电机初始化函数
{
  pinMode(X_DIR, OUTPUT);
  pinMode(X_STP, OUTPUT);
  pinMode(Y_DIR, OUTPUT);
  pinMode(Y_STP, OUTPUT);  
  //pinMode(Z_DIR, OUTPUT);
 // pinMode(Z_STP, OUTPUT);
  pinMode(EN, OUTPUT);
  digitalWrite(EN, LOW);
}

void step(boolean dir,byte EnablePin,byte stepperPin,int steps)//步进电机控制函数
{
  digitalWrite(EnablePin, dir);
  delay(50);
 
  for (int i = 0; i < steps; i++) 
  {
    digitalWrite(stepperPin, HIGH);
    delayMicroseconds(800);  
    digitalWrite(stepperPin, LOW);
    delayMicroseconds(800);  
  }  
}

void setup()//单片机初始化函数
{
  Servo_init();
  motor_Init();
  Ethernet.begin(mac, ip);//初始化以太网的设置
  server.begin();//启动服务器
}

void loop()//单片机循环函数
{
  EthernetClient client = server.available();//建立监听socket
  if (client)//如果建立socket通讯
  {
   // boolean current_line_is_blank = true;
    while (client.connected()) //等待客户端连接
    {
      if (client.available()) //如果客户端有数据发送过来
      {
        incomedate = client.read();
        
        if (incomedate == 'O')//打开气体泵字符
        {
          client.print('O');
          open_pumb();
        }

        else if(incomedate == 'C')//关闭字体泵字符
        {
          client.print('C');
          close_pumb();
        }

        else if(incomedate == 'R')
        {
            client.print(times);
            client.print('R');
          
            for(int i = 0;i<times;i++)
            {
               step(true, X_DIR, X_STP, 400);//气体泵右移
               delay(100);
            }
        }

        else if(incomedate == 'L')
        {
           client.print(times);
           client.print('L');
          
            for(int i = 0;i<times;i++)
            {
               step(false, X_DIR, X_STP, 400);//气体泵左移
               delay(100);
            }
         }

        else if(incomedate == 'U')
        {
            client.print(times);
            client.print('U');
           
            for(int i = 0;i<times;i++)
            {
                 step(true, Y_DIR, Y_STP, 400);//气体泵上移
                 delay(100);
            }
        }

        else if(incomedate == 'D')
        {
            client.print(times);
            client.print('D');
            
            for(int i = 0;i<times;i++)
            {
                step(false, Y_DIR, Y_STP, 400);//气体泵下移
                delay(100);
            }
         }
      }
    }
    
    client.stop();
  }
}

7.下位机建立客户端(没通)

(1)首先,我们应该给下位机分配一个MAC地址,也就是6个十六进制的。

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

(2)然后,指定服务器的IP地址或者DNS域名

IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

(3)下来分配自己的IP地址和DNS的IP,设置在DHCP分配失败时使用的静态IP地址,即MAC地址失败的话,则访问静态IP地址

IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);

(4)实例化EthernetClient类

(5)进入setup函数,启动以太网和进行链接

void setup() 
{
     if (Ethernet.begin(mac) == 0)//无法使用DHCP配置以太网
     {
        if (Ethernet.hardwareStatus() == EthernetNoHardware) //检查是否存在以太网硬件 
        {
            //什么都不做,没有以太网硬件就没有意义
        }

        
         if (Ethernet.linkStatus() == LinkOFF)//以太网电缆未连接
         {
              //什么都不做,没有以太网硬件就没有意义
         }

          Ethernet.begin(mac, ip, myDns);//尝试使用IP地址而不是DHCP进行配置:
     }

    //给以太网屏蔽一秒钟来初始化
    delay(1000);
    
    if (client.connect(server, 8080)) 
    {
        client.print();//输出内容告诉链接成功了
    }    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值