精华内容
下载资源
问答
  • PC机与下位机通讯时通过设置奇偶校验位来标识数据帧和地址,可是用Cserialport类来实现时候发送一串数据,包括地址和数据,当切换奇偶校验位时弹出错误;WARING:WaitCommEvent() failed with the following error:...

                   PC机与下位机通讯时通过设置奇偶校验位来标识数据帧和地址,可是用Cserialport类来实现的时候发送一串数据,包括地址和数据,当切换奇偶校验位时弹出错误;WARING:WaitCommEvent() failed with the following error:句柄无效

    展开全文
  • DIZ485与其它同类产品相比的特点是可以识别下位机的地址、下位机可以主动发送带地址的数据。DIZ485是世界上最小的带地址的串口转换器。 2、硬件安装 波仕DIZ485地址串口转换器的外形为DB-9/DB-9转接盒大小,如图...
  •  RS-232一变四地址扩展转换器(型号:DIZ4232)用于将一个上位机RS-232或者RS-485口扩展成四个带地址的下位机RS-232串行口。DIZ42324个下位机RS-232口各带地址,由上位机发送地址指令来分别选通。下位机RS-232...
  •  RS-232一变四地址扩展转换器(型号:DIZ4232)用于将一个上位机RS-232或者RS-485口扩展成四个带地址的下位机RS-232串行口。DIZ42324个下位机RS-232口各带地址,由上位机发送地址指令来分别选通。下位机RS-232...
  • 上位机获得下位机地址后,就知道那些地址的下位机已启动并根据请求把相应预置温度发给下位机,此后每隔一定时间逐一询问已启动的下位机测定温度信息,获得温度值后存入数据库并实时显示当前各路传感器测定温度,...
  • PLC学习神器提供RS485接口,可支持无协议RS指令、无协议RS2指令、Modbus通讯功能,可通过设置通讯格式改变通讯协议,RS485对应通讯格式地址是D8400; 本案例以RS485接口与温湿度变送器通讯,通讯格式如下一温湿度...

    PLC学习神器提供RS485接口,可支持无协议RS指令、无协议RS2指令、Modbus通讯功能,可通过设置通讯格式改变通讯协议,RS485对应的通讯格式地址是D8400;

    本案例以RS485接口与温湿度变送器通讯,通讯格式如下

    一温湿度变送器的说明书介绍

    1.1主要技术参数

    ff3e89790aef462f5c6071655581cb7b.png

    1.2 通讯协议

     1、所有通讯回路都应遵照主/从方式。依照主从方式,数据可以在一个主站和多个子站之间传递。

    任何一次通讯都不能从子站开始。

     2、信息传输方式为异步方式,字节格式为起始位1位,数据位8位,停止位1位,无校验。

     3、符合MODUBS RTU 协议标准。

     4、默认波特率为9600,地址为1。

    主站发送

    75a40c3aa6ec4c8b10ba00b83176a340.png

    返回:

    f94f87fbc9218115c261e8ecc151a2ba.png

    内部报文信息:

    9a7afd17424ed7c883dd18c162bfb498.png

    1.3通讯命令举例1

     读取温度湿度:01 03 00 00 00 02 C4 0B (地址为1,读温度湿度值)

     返回:01 03 04 00 B8 03 3F 3A F6 (对应温度:18.4℃,湿度83.1%)

     读取地址:FF 03 00 64 00 01 D0 0B

     写地址:01 06 00 64 00 02 49 D4 (已知原地址为01,改成02)

    FF 06 00 64 00 02 5C 0A (未知原地址,改成02)

    1.4通讯命令举例2

     读取温度湿度数据:

     上位机发送:01 04 00 00 00 02 71 CB (温湿度地址为1,寄存器起始地址为0,读2个字节)

     下位机返回:01 04 04,温度H,温度L,湿度H,湿度L,CRCH,CRCL。

     只读温度数据:

     上位机发送:01 04 00 00 0 001 31 CA(温湿度地址为1,寄存器起始地址为0,读1个字节)

     下位机返回:01 04 02,温度H,温度L,CRCH,CRCL。

     只读湿度数据:

     上位机发送:01 04 00 01 0 001 60 0A(温湿度地址为1,寄存器起始地址为1,读1个字节)

    下位机返回:01 04 02,湿度H,湿度L,CRCH,CRCL。

     设置地址:

     上位机发送:01 06 00 64 00 02 49 D4(温湿度原地址1改为2)

     下位机返回:01 06 00 64,地址H,地址L, CRCH,CRCL。

    22a51ce9a87ce25059b5fb12e5f6fae5.png

    PLC学习的RS485通讯口与温湿度变送器的接线:

    1.485-与B-连接,485+与A+连接;

    2.温湿度变送器,需要接上直流DC5V-DC24的电源;

    二通讯参数与通讯格式解读

    2.1通讯参数设定

    设定为无顺序通讯协议,数据长度为8位,无校验,停止位为1位,传送速度为9600,类型为RS-485,格式为无CR,LF

    997bf22ae8cd07d83bfde0ff0761a829.png

    2.2通讯格式设定

    8c21005ea16ef1345462f837eacd8d80.png

    设定通讯参数和通讯格式,任意选一种就好了。如果通讯参数和通讯格式同时设置,默认会使用通讯参数里的内容。

    3b455a54d4760fab92f759ef52237688.png

    三使用无协议RS2指令通讯程序案例

    83142638e1dcc3ac2fe3141a459fa2d3.png
    6ffbfc874f7d86ef2aee126002734c7e.png
    6ffbfc874f7d86ef2aee126002734c7e.png

    D8400与三菱公司出的FX3U一样是我们学习神器RS485口通讯格式的特殊寄存器,通讯格式按照前面的表格进行设定,案例里的D8400设置的是H881(数据长度为8位,无校验,停止位为1位,波特率是9600,无报头和报尾,无顺序协议)

    注意:当使用通讯格式时,需要设定D8409(RS超时设定),否则会有报警现象

    程序解读:

    1. RS-485通讯参数

     1.1将通讯格式D8400设置为H881(数据长度为8位,无校验,停止位为1位,波特率是9600,无报头和报尾,无顺序协议)

     1.2将通讯超时D8409设置为K10(10*10ms=100ms=0.1s)

     1.3 [RS2 D300 D330 D400 K10 K1],发送数据的起始元件为D300,发送数据的个数为D330,接收数据的起始元件为D400,接收数据的个数为K10,使用通道1进行通讯

    2. 读取温度和湿度数据

     2.1每一秒时钟接通一次M480

     2.2发送数据格式01 04 00 00 00 02 71 CB (读取温湿度地址为1,寄存器起始地址为0,读取2个数据,校验码71CB)

     2.3 D330为发送的字节数8个

     2.4 M8402是发送请求的特殊继电器,想发送数据需置位M8402就可以了,PLC发送完数据会自动复位M8402;

    3. 温度和湿度数据接收

     M8403是接收数据特殊继电器,接收完数据后必须复位。

     接收数据时,先清零D500-D509的数据,再把接收到的数据D400-D409传送至D500-D509里

    4. 接收的数据处理

     4.1.位组合传送;将D501的数据传送至M200-M215里;将D502的数据传送至M216-M231里;将D503的数据传送至M232-M267里()

     4.2位组合拆分;将M208-M223的数据传送D800里;将M224-M239的数据传送D801里

     4.3高低字节互换;将D800里数据高低字节互换;将D801里数据高低字节互换

    PLC学习神器作为Modbus主站,与温湿度变送器通讯

    2d6f323f2c7022eed1a6e7803e4a5e2d.png

    D8401是设置Modbus主站或者从站的特殊寄存器,设为H1就是Modbus主站,这个案例是作为主站功能使用,所以我们要把D8401设置为H1。

    D8400是PLC学习神器RS485口通讯格式的特殊寄存器,通讯格式按照前面的表格进行设定,案例里的D8400设置的是H81(数据长度为8位,无校验,停止位为1位,波特率是9600,无报头和报尾)

    程序用1秒时钟M8013实时触发Modbus RTU专用指令ADPRW发送数据,对ADRW指令不熟悉的可以参考FX3U通讯手册Modbus通讯篇。

    发送数据格式(从站地址为1,读取功能码03,寄存器起始地址为0,读取2个数据,接收数据寄存器为D900和D90)

    想学习PLC编程,了解更多自动化专业资料的可以加我微信:huiyi_1105709461

    f48bfc3b65fcd5385a03c1745a16238f.png
    展开全文
  • 串口地址转换实现

    2020-10-18 14:45:33
    通信时由上位机先发送某个下位机的地址,位于同一个网络中的所有下位机都同时读取这个地址的值,然后与自己的地址进行比较,如果地址相同则接收后面的数据,如果地址不同则不读取后面的数据。某些情况下,下
  • 串行通信参数可以通过写入相关寄存器来更新波特率,奇偶校验地址。如果写入任何一个寄存器,传感器将重置并引导新参数。 基于RS485电容式土壤湿度和温度传感器如何解读读数? 水分值是相对。意思是,更多...
  • 传感器进行周期性测量(默认情况每500ms一次),通过写入Modbus寄存器之一可以更新测量...串行通信参数可以通过写入相关寄存器来更新波特率,奇偶校验地址。如果写入任何一个寄存器,传感器将重置并引导新参数。
  • 2路RS-232对1路RS-485/232智能共享器(型号:HUB2215Z)用于两个RS-232上位机共同控制一个RS-485或RS-232下位机的通信连接。HUB2215Z使传统的RS-232口实现二对一多机通信。HUB2215Z已经有2个上位机插座(DB-9针座和...
  • 上位机和下位机通过RS232串口或者单片机TTL电平串口,I2C通讯接口,RS485进行通讯连接,可以在不改变原来系统功能基础上,只需在人机界面软件HMImaker建立人机交互接口所需通讯变量地址链接,“0”编程、"0"代码...
  • java串口通讯-实现rs485半双工轮询

    千次阅读 2018-06-07 12:03:18
    准备工作:要与串口通信首先要在项目添加RXTXcomm.jar包(放在项目中lib目录,并添加到build Path中)(win64下载地址:http://pan.baidu.com/s/1o6zLmTc);另外,还需要将解压后rxtxParallel.dll和...

     通讯方式: 485半双工轮询方式, 由主机(PC机)对仪表进行轮询访问,仪表接收到数据后根据协议返回命令;

    准备工作:

    要与串口通信首先要在项目添加RXTXcomm.jar包(放在项目中的lib目录下,并添加到build Path中)(win64位下载地址:http://pan.baidu.com/s/1o6zLmTc);另外,还需要将解压后的rxtxParallel.dll和rxtxSerial.dll两个文件放在%JAVA_HOME%/jre/bin目录和windows/System32下,这样该包才能被正常的加载和调用。

    程序代码如下:

    //包括向数据库读写数据库,发送的命令都是根据协议拼接

    //没有main方法是因为要在启动服务时启动,可以自己添加main方法,比较简单,如果不会可以提出来

    package com.elel.weigher.common;


    import java.io.*;
    import java.net.DatagramPacket;
    import java.text.ParseException;
    import java.util.*;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import com.alibaba.fastjson.JSONArray;
    import com.cloud.sys.exception.BusinessException;
    import com.elel.weigher.controller.FillDateAdd;
    import gnu.io.*;


    //@Component
    public class PortComm extends Thread implements SerialPortEventListener { // SerialPortEventListener
    // 监听器,独立开辟一个线程监听串口数据
    static CommPortIdentifier portId; // 串口通信管理类
    static Enumeration<?> portList; // 有效连接上的端口的枚举
    InputStream inputStream; // 从串口来的输入流
    static OutputStream outputStream;// 向串口输出的流
    static SerialPort serialPort; // 串口的引用
    byte[] readBuffer = new byte[1024];
    String trueString = "";
    int tid = 0;


    // 堵塞队列用来存放读到的数据
    private BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();


    @Override
    /**
    * SerialPort EventListene 的方法,持续监听端口上是否有数据流
    */
    public void serialEvent(SerialPortEvent event) {


    switch (event.getEventType()) {
    case SerialPortEvent.BI: /* Break interrupt,通讯中断 */
    case SerialPortEvent.OE: /* Overrun error,溢位错误 */
    case SerialPortEvent.FE: /* Framing error,传帧错误 */
    case SerialPortEvent.PE: /* Parity error,校验错误 */
    case SerialPortEvent.CD: /* Carrier detect,载波检测 */
    case SerialPortEvent.CTS: /* Clear to send,清除发送 */
    case SerialPortEvent.DSR: /* Data set ready,数据设备就绪 */
    case SerialPortEvent.RI: /* Ring indicator,响铃指示 */
    case SerialPortEvent.OUTPUT_BUFFER_EMPTY: /*
    * Output buffer is
    * empty,输出缓冲区清空
    */
    break;
    case SerialPortEvent.DATA_AVAILABLE: // 当有可用数据时读取数据 /*Data available at
    // the serial
    // port,端口有可用数据。读到缓冲数组,输出到终端*/


    int numBytes = -1;
    try {


    while (inputStream.available() > 0) {
    numBytes = inputStream.read(readBuffer);
    }
    if (numBytes > 0) {


    DatagramPacket packet = new DatagramPacket(readBuffer, numBytes);
    readBuffer = packet.getData();


    // 将字节数组转换为16进制字符串
    String hexString = HexConvert.BinaryToHexString(readBuffer);


    // 截取真实的目标字符转
    trueString = trueString + hexString.substring(0, numBytes * 3);
    System.out.println("---真实的trueString----::" + trueString);


    int i = trueString.indexOf("FF FF FF FF");
    System.out.println("i等于:::::::" + i);


    if (i != -1) {
    // 去掉字符串空格
    String ss = trueString.replaceAll("\\s*", "");
    System.out.println("ss:" + ss);


    // 截取CRC校验码
    String crc1 = ss.substring(ss.length() - 12, ss.length() - 8);
    System.out.println("crc1:" + crc1);


    // 需要校验的字符串
    String ss1 = ss.substring(0, ss.length() - 12);


    // 开始字符串校验
    byte[] sbuf = CRC16M.getSendBuf(ss1);
    String crc2 = CRC16M.getBufHexStr(sbuf).substring(CRC16M.getBufHexStr(sbuf).length() - 4,
    CRC16M.getBufHexStr(sbuf).length());


    System.out.println("crc2:" + crc2);


    // 接收的校验码和生成的校验码作验证,一样则为我们需要的数据
    if (crc1.equals(crc2)) {
    System.out.println(trueString + "是我们需要的");


    handelMessage(ss);
    }


    trueString = "";
    }


    } else {
    msgQueue.add("额------没有读到数据");
    }


    } catch (IOException e) {
    e.printStackTrace();
    }
    break;
    }


    }


    public void handelMessage(String ts) {


    String cw = ts.substring(2, 6);
    System.out.println("cw:" + cw);


    // OD01是设备常态时返回的命令;OCO1是上位机发送OC命令后开始灌装返回的命令;O3O1是灌装完成后上位机发03命令后,设备返回的命令;
    if ("0D01".equals(cw) || "0C01".equals(cw) || "0301".equals(cw) || "0D00".equals(cw)) {


    try {
    String id1 = ts.substring(0, 2); // 获取设备id;


    String sd1 = id1 + "0D";
    // 开始校验并获取16进制及校验码字符串
    byte[] cbuf1 = CRC16M.getSendBuf(sd1);
    String crcsd1 = CRC16M.getBufHexStr(cbuf1).substring(CRC16M.getBufHexStr(cbuf1).length() - 4,
    CRC16M.getBufHexStr(cbuf1).length());


    // 将16进制字符串转换成0x00类型字节
    byte j[] = HexConvert.hexStringToBytes(id1);
    byte k[] = HexConvert.hexStringToBytes(crcsd1);


    byte[] send = new byte[8];
    System.arraycopy(j, 0, send, 0, 1);
    send[1] = (byte) 0x0D;
    System.arraycopy(k, 0, send, 2, 2);
    send[4] = (byte) 0xFF;
    send[5] = (byte) 0xFF;
    send[6] = (byte) 0xFF;
    send[7] = (byte) 0xFF;


    outputStream.write(send);
    outputStream.flush();
    } catch (IOException e) {
    e.printStackTrace();
    }


    }


    // 0D0B命令是电子秤上放上重物并按下启动按钮,设备返回的命令
    if ("0D0B".equals(cw)) {
    tid = 0;
    try {
    // List<TaskInfo> list = FillDateAdd.select(ts);
    JSONArray list = (JSONArray) FillDateAdd.select(ts);
    if (list.size() > 0) {
    tid = (int) list.getJSONObject(0).get("tid");
    String xsh = (String) list.getJSONObject(0).get("tno"); // 销售号
    Integer no = Integer.parseInt(xsh);
    String aa = HexAndInt.IntToHex(no);


    int high = (int) list.getJSONObject(0).get("high") / 10; // 上限
    String hh = HexAndInt.IntToHex(high);


    int low = (int) list.getJSONObject(0).get("low") / 10; // 下限
    String ll = HexAndInt.IntToHex(low);


    String sno = HexAndInt.padLeft(aa, 8); // 转换成8位的16进制销售号
    String target = ts.substring(32, 38); // 目标值直接从0B命令里获取
    String hi = HexAndInt.padLeft(hh, 6); // 转换成6位的16进制上限
    String lo = HexAndInt.padLeft(ll, 6); // 转换成6位的16进制下限


    String id2 = ts.substring(0, 2); // 获取id;


    String cc = id2 + "0C01" + sno + target + "00002d" + lo + hi + "000000"; // 拼接成需要交验的16进制字符串


    // 开始校验并获取16进制及校验码字符串
    byte[] cbuf = CRC16M.getSendBuf(cc);


    String crc = CRC16M.getBufHexStr(cbuf).substring(CRC16M.getBufHexStr(cbuf).length() - 4,
    CRC16M.getBufHexStr(cbuf).length());


    // 将16进制字符串转换成0x00类型字节
    byte s[] = HexConvert.hexStringToBytes(sno);
    byte t[] = HexConvert.hexStringToBytes(target);
    byte h[] = HexConvert.hexStringToBytes(hi);
    byte l[] = HexConvert.hexStringToBytes(lo);
    byte y[] = HexConvert.hexStringToBytes(id2);
    byte c[] = HexConvert.hexStringToBytes(crc);


    byte[] send = new byte[28];
    System.arraycopy(y, 0, send, 0, 1);
    send[1] = (byte) 0x0C;
    send[2] = (byte) 0x01;
    System.arraycopy(s, 0, send, 3, 4); // 插入销售号字节
    System.arraycopy(t, 0, send, 7, 3); // 插入目标值字节
    send[10] = (byte) 0x00;
    send[11] = (byte) 0x00;
    send[12] = (byte) 0x2d;
    System.arraycopy(l, 0, send, 13, 3); // 插入下限字节
    System.arraycopy(h, 0, send, 16, 3); // 插入上限字节
    send[19] = (byte) 0x00;
    send[20] = (byte) 0x00;
    send[21] = (byte) 0x00;
    System.arraycopy(c, 0, send, 22, 2); // 插入校验码字节
    send[24] = (byte) 0xFF;
    send[25] = (byte) 0xFF;
    send[26] = (byte) 0xFF;
    send[27] = (byte) 0xFF;


    outputStream.write(send);
    outputStream.flush();


    FillDateAdd.update(tid); // 更新灌装状态为1(灌装中)
    } else {
    System.out.println("该客户下没有当前规格的任务单!");
    }


    } catch (IOException | ParseException e) {
    e.printStackTrace();
    }


    }


    // 0D03命令是灌装完成后设备返回的命令
    if ("0D03".equals(cw)) {


    try {


    FillDateAdd.upp(ts); // 更新灌装状态为2(灌装完)
    FillDateAdd.add(ts); // 插入灌装数据


    String id3 = ts.substring(0, 2);


    String sd3 = id3 + "0301";


    // 开始校验并获取16进制及校验码字符串
    byte[] cbufsd3 = CRC16M.getSendBuf(sd3);
    String crcsd3 = CRC16M.getBufHexStr(cbufsd3).substring(CRC16M.getBufHexStr(cbufsd3).length() - 4,
    CRC16M.getBufHexStr(cbufsd3).length());


    // 将16进制字符串转换成0x00类型字节
    byte m[] = HexConvert.hexStringToBytes(id3);
    byte n[] = HexConvert.hexStringToBytes(crcsd3);


    byte[] send = new byte[9];
    System.arraycopy(m, 0, send, 0, 1);
    send[1] = (byte) 0x03;
    send[2] = (byte) 0x01;
    System.arraycopy(n, 0, send, 3, 2);
    send[5] = (byte) 0xFF;
    send[6] = (byte) 0xFF;
    send[7] = (byte) 0xFF;
    send[8] = (byte) 0xFF;


    outputStream.write(send);
    outputStream.flush();
    } catch (IOException | ParseException e) {
    e.printStackTrace();
    }


    }


    }


    /**

    * 通过程序打开串口,设置监听器以及相关的参数

    * @return 返回1 表示端口打开成功,返回 0表示端口打开失败
    * @throws ParseException
    */
    public int startComPort() {
    // 通过串口通信管理类获得当前连接上的串口列表
    portList = CommPortIdentifier.getPortIdentifiers();


    while (portList.hasMoreElements()) {


    // 获取相应串口对象
    portId = (CommPortIdentifier) portList.nextElement();


    /*
    * System.out.println("设备类型:--->" + portId.getPortType());
    * System.out.println("设备名称:---->" + portId.getName());
    */


    // 判断端口类型是否为串口
    if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
    // 判断如果串口存在,就打开该串口
    if (portId.getName().equals("COM1")) {


    try {


    // 打开串口,延迟为2毫秒
    serialPort = (SerialPort) portId.open(portId.getName(), 2000);


    System.out.println("-----SerialPort----::::" + serialPort);


    } catch (PortInUseException e) {
    e.printStackTrace();
    return 0;
    }
    // 设置当前串口的输入输出流
    try {
    inputStream = serialPort.getInputStream();
    outputStream = serialPort.getOutputStream();
    } catch (IOException e) {
    e.printStackTrace();
    return 0;
    }
    // 给当前串口添加一个监听器
    try {
    serialPort.addEventListener(this);
    } catch (TooManyListenersException e) {
    e.printStackTrace();
    return 0;
    }
    // 设置监听器生效,即:当有数据时通知
    serialPort.notifyOnDataAvailable(true);


    // 设置串口的一些读写参数
    try {
    // 比特率、数据位、停止位、奇偶校验位
    serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
    SerialPort.PARITY_NONE);
    } catch (UnsupportedCommOperationException e) {
    e.printStackTrace();


    }


    return 1;
    }


    }
    }
    return 0;
    }


    @Override
    // @Scheduled(initialDelay = 5000, fixedDelay = 2000)
    public void run() {
    try {


    System.out.println("--------------任务处理线程运行了--------------");


    while (true) {


    // 如果堵塞队列中存在数据就将其输出
    if (msgQueue.size() > 0) {
    System.out.println(msgQueue.take());
    }


    JSONArray list = (JSONArray) FillDateAdd.selectDevice(); //查找所有记录在数据库中的设备


    long time = 150 * list.size() + 1;
    Thread.sleep(time);


    try {


    if (list.size() > 0) {

                            //对查到的设备进行轮询,并根据查询到的地址发送命令
    for (int i = 0; i < list.size(); i++) {

    Thread.sleep(150);


    int idt = (int) list.getJSONObject(i).get("daddress");
    String tt = HexAndInt.IntToHex(idt);
    String td = HexAndInt.padLeft(tt, 2); // 转换成1位的16进制销售号


    String td1 = td + "0D";


    System.out.println("--------轮询到设备--------::::" + idt);


    // 开始校验并获取16进制及校验码字符串
    byte[] cbuftd1 = CRC16M.getSendBuf(td1);
    String crctd1 = CRC16M.getBufHexStr(cbuftd1).substring(
    CRC16M.getBufHexStr(cbuftd1).length() - 4, CRC16M.getBufHexStr(cbuftd1).length());


    // 将16进制字符串转换成0x00类型字节
    byte ts[] = HexConvert.hexStringToBytes(td);
    byte tc[] = HexConvert.hexStringToBytes(crctd1);


    byte[] send = new byte[8];
    System.arraycopy(ts, 0, send, 0, 1);
    send[1] = (byte) 0x0D;
    System.arraycopy(tc, 0, send, 2, 2);
    send[4] = (byte) 0xFF;
    send[5] = (byte) 0xFF;
    send[6] = (byte) 0xFF;
    send[7] = (byte) 0xFF;


    outputStream.write(send);
    outputStream.flush();
    }
    } else {
    System.out.println("没有查询到设备!");
    }


    } catch (IOException e) {
    e.printStackTrace();
    }


    }


    } catch (InterruptedException | BusinessException e) {
    e.printStackTrace();
    }
    }

    }

    //以下是程序启动时,启动线程,包括service服务注入

    package com.elel.weigher.common;


    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.stereotype.Component;


    import com.dlh.un.context.SpringContextHolder;
    import com.elel.weigher.Feign.weigher.service.IFillDataService;


    @Component
    public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> {
    public void onApplicationEvent(ContextRefreshedEvent event) {
    System.out.println("-----parent-----:"+event.getApplicationContext().getParent().getParent());
    if (event.getApplicationContext().getParent().getParent() == null) {
    System.out.println(">>>>>>22222222222222");
    PortComm cRead = new PortComm();
    int i = cRead.startComPort();
    if (i == 1) {
    // 启动线程来处理收到的数据
    cRead.start();
    } else {
    // return;
    System.out.println("------------" + i);
    cRead.start();
    }
    }


    }


    @SuppressWarnings("unused")
    private void scheduler() {
    // ProxyConfiguration config =
    // SpringContextHolder.getBean(ProxyConfiguration.class);


    IFillDataService config = SpringContextHolder.getBean(IFillDataService.class);


    // TODO
    }


    }




    参考下面文章:

    https://blog.csdn.net/update_java/article/details/46898937




    展开全文
  • BLU232RS-232/485串口有2个用处:1、在传输模式作为蓝牙转换出来串口,2、在设置模式用于对BLU232产品进行设置。注意BLU232有DB-9孔和DB-9针RS-232口,它们实质上是同一个口,仅仅是为了方便用户使用。...
  • 在遥测、遥控领域中,常常使用工业PC机与单片机组成多机系统完成测控任务。...在进行数据传输时,一般先由上位机发出地址帧对指定的下位机寻址,在得到确认以后向选中的下位机发送命令和参数,或者...

    在遥测、遥控领域中,常常使用工业PC机与单片机组成的多机系统完成测控任务。PC机因其丰富的软硬件资源和友好的人机界面而被用作上位机,而单片机则因其优越的性价比和灵活的功能配置而被用作下位机。上位机和下位机之间通过串行数据总线(如CAN总线、RS485总线等)连接,具体结构如图1所示。在进行数据传输时,一般先由上位机发出地址帧对指定的下位机寻址,在得到确认以后向选中的下位机发送命令和参数,或者接收该下位机采集的数据。但在多机系统中,进行数据通信遇到的一个首要问题是如何区分总线的地址信息和其它的数据信息,这也是各类通信协议和通信规约中的一项重要内容。由于目前所使用的通信协议和通信规约比较复杂,因此在一个简单的主从式多机系统中,往往由开发人员自行定义一些简单的通信协议来解决上述问题。本文介绍一种基于编/解码器的通信方案,较好地解决了多机系统中作为上位机的工控机对各下位机的寻址问题。

    acccbb033b9f82d2a9cf0901610c4cad.png

    1 编/解码芯片UM3758-108A

    专用编/解码芯片UM3758-108A属大规模CMOS器件,其引脚排列如图2所示:A0~A9为三态编码地址输入;D0~D7为二态锁存式编码数据输入或输出;OSC引脚外接振荡电阻和电容,其值决定发送频率;VSS为电源地;T/R为编码发送与编码收选择引脚,接高电平时为编码发送,接低电平时为接收编码;IN为编码脉冲输入引脚(接收解码时);TX/RX外接驱动电路,为编码发送输出端,该引脚也可作为争码接收正确标志显示(RX输出低电平);VDD为电源正端(3~12V)。

    4fc25599f425cdcdb78f22211a68a167.png

    单片UM3758-108A芯片是一个完整的接口电路,集编码发送和解码输出于一身。当T/R端接高电平时,地址码A0~A9和数据码 D0~D7构成一个18位的数据帧,从TX/RX端循环不断地串行发送出去;当T/R端接低电平时,编码脉冲由IN端输入,如果接收的地址码连续两次与本地地址码一致,接收数据将按位传送到输出锁存器中,由D0~D7引脚输出。同时TX/RX引脚输出低电平,表示接收正确。

    2 UM3758-108A在多机通信中的具体应用

    使用编/解码器实现PC机与单片机的通信时,需要在PC机和单片机上分别配置编/解码器,以便完成数据信息的发送和接收。由于上位机不仅承担与下位机的通信任务,还要进行数据处理,并以表格或各种图形方式显示出来。如果让上位机直接控制编/解码芯片,通过并行口进行数据收发,在通信量较大的情况下,势必会占用上位机的大部分工作时间,导致整机性能下降。因此在通信量较大的情况下,应在上位机端设计一个智能I/O扩展卡,该卡可插到上位机底板的扩展槽上。为了上位机和扩屏卡之间达到更快的信息交换速度,可以采用共享存储器方式进行数据交换。传统的共用存储器硬件设计比较复杂,应用范围较小。本文采用Maxim公司生产的双端口存储器DS1609,大大简化了共用存储器硬件电路设计。如图3所示,DS1609为256字节双端口RAM,属大规模 CMOS器件;具有两个独立的端口,各自拥有一套相应的数据/地址复用总线和控制总线;控制信号只有读、写和片选,尤其适合于和Intel公司的CPU相连;硬件电路设计非常简单。该器件允许两个端口独立地对存储器单元进行存取操作,且由于存储器内部特殊的单元电路设计,端口双方同时对同一个单元进行读操作时无需促裁逻辑;但当端以方同时对同一单元进行读/写或写/写操作时,仍会发生竞争。解决读/写冲突的一个简单办法是执行冗余的读周期,也可使用“邮箱”传送状态信息方式进行软件仲裁,这种方法需给每个端口分配一个字节,用以写入状态信息,以告知对本端正在进行的操作。对于写/写冲突,可给双方分配固定的单元空间,另外,再给每一组数据分配校验和字节,以确保正确的数据交换。图3中DS1609一侧与89C51 CPU相连,另一侧通过三态缓冲器与扩展总线相连。

    3bd0b88997714ade3510e6d9556cb7d4.png

    图4为PC机与80C51单片机使用编/解码器实现通信的示意图。UM3758-108A的A0~A9是地址输入端,每位可有三种状态:高电平、低电平、开路。利用其不同的组合可产生3 10种不同的编码。二态时也有2 10种不同的编码。智能扩展卡需不断寻址各个下位机,所以利用锁存器将数据输出给编/解码器的地址端,以此可灵活地寻址各个下位机。为了简化起见,图4中省去了一个锁存器,将A8、A9直接悬空。

    2b278e3af81024e23c6e9aad0fd038fd.png

    UM3758-108A片内具有数据锁存能力,无需加锁存器,但需加双向缓冲器以收发数据。下位机端的编码地址用微型开关SW设置,也可用锁存器输出编码地址;但这样做需在下位机工作前,将编码地址由面板输入,和其它需要设定的参数一起保存在存储器(如 EEPROM)中,然后再由锁存器输出。后者增加了下位机地址编码的灵活性,但也加重了编程负担。图4中,智能I/O扩展卡用74LS273作为扩展接口,以锁存要寻址的下位机地址,用74LS245收发数据。为发送数据选择端:为低电平时,接口处于接收状态;为高电平时,处于发送状态。因此,初始化时,上、下位机的两个接口均应置成接收状态。每个接口的TX/RX端除了作为发送端外,还作为该接口接收正确与否的状态指示端。如果接收正确,该接口输出低电平;否则,为高电平。此端口可作为向CPU发出中断请求的信号。为此,发送数据时,应先关闭接收中断,发送完毕,再打开接收中断。

    该通信为半双工方式,且只能由上位机发起,下位机不主动申请通信。当处于轮询状态时,上位机根据下位机的编码地址,向下位机发送呼叫帧。每台下位机都由编/解码器接收并判断,但只有地址相符的下位机才发生中断接收数据,并建立和上位机的联系,以此接收上位机的命令和参数,或将采集的数据上传。由于这种通信方式无差错控制,因此应根据传输速率,精确定时,保证每个发送周期相同的编码信号连续发送3次,以提高通信的可靠性。

    使用编/解码器实现PC机与单片机的通信,波特率设置为2400baud,通信距离可达5km以上;不仅可用于数据采集系统、LED屏幕显示系统等有线通信方式,也可采用红外(IR)、超声波(US)等用于无线通信方式,以此可突破地理因素的局限。这种通信方式不仅传输距离远、抗干扰性通强、可靠性高、成本低,而且连接简单、使用方便;通信过程仅仅是读写I/O口的简单操作,编程简单,易于实现。

    结语

    本文提出了一种适用于PC机与多单片机之间的串行通信实现方法。该方法采用UM3758-108A编/解码芯片实现双工传输,采用DS1609 芯片实现智能卡和上位机的批量数据交换,实现了数据传输与数据处理功能的分离,使它们各司其职,保证了系统的实时性,也有效解决了上位机对下位机的寻址问题。另外,该方式有很宽的适用范围,具有一定的应用价值。

    责任编辑:gt

    打开APP阅读更多精彩内容

    声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉

    展开全文
  • 因为工作原因,一直做上位机我现在什么都干,从去年冬天开始就偶尔鼓捣鼓捣下位机,我这边用都是西门子1200,哈哈,做为小白我拿着说明书,连问带蒙,终于把通讯变频器搞定了,很开心。当然,从事这方面工作...
  • 在进行数据传输时,一般先由上位机发出地址帧对指定的下位机寻址,在得到确认以后向选中的下位机发送命令和参数,或者接收该下位机采集数据。但在多机系统中,进行数据通信遇到一个首要问题是如何区分总线的地址...
  • 该编/解码器通信方案,软好地解决了多机系统中作为上位机的工控机对各下位机的寻址问题。 关键词:编/解码器 双口RAM PC 串行通信 UM3758-108在遥测、遥控领域中,常常使用工业PC机与单片机组成的多机系统完成测控...
  • 介绍工业串口液晶显示触摸屏与...支持各种通讯协议,比如单片机协议,modbus协议,西门子PLC协议,三菱PLC协议,台达PLC通讯协议等,支持各种组态控件,关联通讯变量地址即可与下位机通信,10分钟内完成人机界面设计。
  • 该方法通过设置LabVIEW串口配置中奇偶校验为0校验和1校验,与RS485总线模式下的数据帧和地址帧匹配,实现基于LabVIEW通信。该方法采用基于LabVIEW双总线设计方案,利用双总线通信线路切换实现了通信系统...
  •  实例206 从桌面右角显示Popup窗口提醒 276 实例207 设置可执行文件生成图标 278 第10章 MDI窗体和继承窗体 279 10.1 MDI窗体使用 280  实例208 设置窗体为父窗体 280  实例209 使子窗体最大化...
  • 200为例,具体讲一下利用Comway软件无线串口软件实现组态王与PLC远程通信,通信原理图如下:PLC及DTU配置1、西门子PLC S7-200 RS-485 串口设置为MODBUS 从模式,如图所示,Modbus设备地址为1,串口波特率为...
  • 200为例,具体讲一下利用Comway软件无线串口软件实现组态王与PLC远程通信,通信原理图如下:PLC及DTU配置1、西门子PLC S7-200 RS-485 串口设置为MODBUS 从模式,如图所示,Modbus设备地址为1,串口波特率为...
  • 4232A 已经有 4 个下位机的硬件地址,无需修改下位机的软件。准RS-232 串行口只有 TXD(发送)、RXD(接收)、GND(信号地)三个信号。4232A 适用于一台 PC 机与多台 PC 机、单片机或仪表之间的通信。二、安装及性能...
  • Modbus学习☞1

    2020-03-19 14:34:23
    诞生原因: 对于离散量来说,PLC输入输出是有限,通过Modbus可以不添加硬件情况进行电气控制 对于模拟量控制来说,举个例子,通过电信号来...概念复杂:起始,停止,波特率,从机地址 基于485的modbus...
  • 进入编程模式后,键盘按【*02】+【OK】,这时主机会自动查找安装在总线上的总线模块,键盘上【模块】字符的数值在不断变化,六数值中中间两为模块的485地址,可以在登记过程中查看,【00】和【63】为主机模块...
  • 实例232 获取文件夹下的所有文件夹及文件名称 321 第7章 操作系统与Windows相关程序 324 7.1 启动相关 325 实例233 进入Windows系统前发出警告 325 实例234 实现注销、关闭和重启计算机 326 7.2 获得...
  • 串口服务器

    2020-05-30 23:01:12
    首先设置本IP地址与串口服务器地址在同一网段串口设备连接在串口服务器“COM1”,所用通信模式为“波特率:19200,校验:None,数据8,停止1”,串口工作在RS485模式。设置串口服务器在该串口工作模式...
  • Modbus学习笔记

    2017-11-23 10:42:07
    1、Modbus是一种通讯协议,区别于DIY通讯接口,Modbus接口是公布且标准,用户主要定义具体寄存器功能即可。...4、下位机返回数据由【地址码】【功能码】【数据长度】【数据】【校验码】组成。 5、校验
  • 举例 传输模块地址为13603292541时,首先末尾补0变成12数字的地址136032925410,最终填入0x13 0x60 0x32 0x92 0x54 0x10 2.1.7 目的地址长度 用途 数据帧接收方传输模块地址长度,即SIM卡号数字位数 格式 ...
  • 二 安装及性能 SWT2232G有2个DB-9孔上位机RS-232口和2个DB-9针的下位机RS-232口,并且不分方向,RS-232口也不分地址。SWT2232G无需供电。SWT2232G支持最高通信速率保证19.2Kbps以上。由于SWT2232G特有波仕零延时...

空空如也

空空如也

1 2 3 4 5 6
收藏数 103
精华内容 41
关键字:

下位机的485地址