|
本帖最后由 muggle 于 2013-6-30 23:09 编辑
基于物联网的能源管理,筹备许久,终于动手了。过程之中,遇到很多困难,在朋友的帮助下顺利解决。
交流电量管理模块+Arduino Uno+W5100+485模块+2004LCD
程序参考:
https://sites.google.com/site/jp ... duino-modbus-master
http://www.geek-workshop.com/thread-544-1-1.html
测试链接:
https://cosm.com/feeds/97970
破烂的程序,还没有优化整理,先贴出来,接受批评
- /*
- History:
- 2013.01.16 First success with AC Meter Module & 485 MODUBUS
- modebus_zxy_testAC_20130116ethernetCOSM
- Modbus over serial line - RTU Master Arduino Sketch
-
- By Juan Pablo Zometa : [email][email protected][/email]
- [url]http://sites.google.com/site/jpmzometa/[/url]
-
- These functions implement functions 3 and 16 (read holding registers
- and preset multiple registers) of the Modbus RTU Protocol, to be used
- over the Arduino serial connection.
-
- This implementation DOES NOT fully comply with the Modbus specifications.
-
- This Arduino adaptation is derived from the work
- By P.Costigan email: [email][email protected][/email] [url]http://pcscada.com.au[/url]
-
- These library of functions are designed to enable a program send and
- receive data from a device that communicates using the Modbus protocol.
-
- Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- The functions included here have been derived from the
- Modicon Modbus Protocol Reference Guide
- which can be obtained from Schneider at [url]www.schneiderautomation.com.[/url]
-
- This code has its origins with
- [email][email protected][/email] ([url]http://www.pmcrae.freeserve.co.uk[/url])
- who wrote a small program to read 100 registers from a modbus slave.
-
- I have used his code as a catalist to produce this more functional set
- of functions. Thanks paul.
-
- */
- /* FIXME: not yet being used */
- unsigned long interframe_delay = 2; /* Modbus t3.5 = 2 ms */
- /*
- * preset_multiple_registers: Modbus function 16. Write the data from an
- * array into the holding registers of a slave.
- * INPUTS
- * slave: modbus slave id number
- * start_addr: address of the slave's first register (+1)
- * reg_count: number of consecutive registers to preset
- * data: array of words (ints) with the data to write into the slave
- * RETURNS: the number of bytes received as response on success, or
- * 0 if no bytes received (i.e. response timeout)
- * -1 to -4 (modbus exception code)
- * -5 for other errors (port error, etc.).
- */
- int preset_multiple_registers(int slave, int start_addr,
- int reg_count, int *data);
- /*
- * read_holding_registers: Modbus function 3. Read the holding registers
- * in a slave and put the data into an array
- * INPUTS
- * slave: modbus slave id number
- * start_addr: address of the slave's first register (+1)
- * count: number of consecutive registers to read
- * dest: array of words (ints) on which the read data is to be stored
- * dest_size: size of the array, which should be at least 'count'
- * RETURNS: the number of bytes received as response on success, or
- * 0 if no valid response received (i.e. response timeout, bad crc)
- * -1 to -4 (modbus exception code)
- * -5 for other errors (port error, etc.).
- */
- int read_holding_registers(int slave, int start_addr, int count,
- int *dest, int dest_size);
- // include the library code:
- #include <LiquidCrystal.h>
- // initialize the library with the numbers of the interface pins
- LiquidCrystal lcd( 8, 7, 6, 5, 3, 2);
- //Ethernet & COSM
- #include <ERxPachube.h>
- #include <SPI.h>
- #include <Ethernet.h>
- // Enter a MAC address and IP address for your controller below.
- // The IP address will be dependent on your local network:
- byte mac[] = {
- 0xDE, 0xAD, 0xBE, 0xEE, 0xFF, 0xED };
- IPAddress ip(192,168,2, 120);
- #define PACHUBE_API_KEY "xxxxxxxxxxxx" // your Cosm API key
- #define PACHUBE_FEED_ID "97970" // your Cosm feed ID
- ERxPachubeDataOut dataout(PACHUBE_API_KEY, PACHUBE_FEED_ID);
- void PrintDataStream(const ERxPachube& pachube);
- void setup()
- {
- const int baudrate = 4800;
- if (baudrate <= 19200)
- interframe_delay = (unsigned long)(3.5 * 11 / baudrate); /* Modbus t3.5 */
- Serial.begin(baudrate); /* format 8N1, DOES NOT comply with Modbus spec. */
- // set up the LCD's number of columns and rows:
- lcd.begin(20, 4);
- // Print a message to the LCD.
- lcd.setCursor(0, 0);
- lcd.print("AC 485 Module");
- delay(10000);
- // start the Ethernet connection and the server:
- Ethernet.begin(mac, ip);
- dataout.addData(0);
- dataout.addData(1);
- dataout.addData(2);
- dataout.addData(3);
- dataout.addData(4);
- dataout.addData(5);
- }
- /* example data */
- int retval;
- int data[10];
- int tt[30];
- void loop()
- {
- int i;
- /* example, this will write some data in the first 10 registers of slave 1 */
- // retval = preset_multiple_registers(1,1,10, data);
- // data[0] = retval;
- // data[1]++;
- // data[8]=0xdead;
- // data[9] = 0xbeaf;
- // delay(500);
- //int read_holding_registers(int slave, int start_addr, int count,int *dest, int dest_size);
- // retval = read_holding_registers(2,1, 1,tt,6);
- retval = read_holding_registers(1, 0x49, 6, tt, 1); // 1:5,2:7,3:9
- // delay(1000);
- // Serial.print("receve flag=");
- // Serial.println(retval);
- // print the number of return byte:
- lcd.setCursor(17, 0);
- lcd.print("R");
- lcd.print(retval);
- // print the number of seconds since reset:
- lcd.setCursor(0, 2);
- lcd.print(" ");
- lcd.setCursor(0, 3);
- lcd.print(" ");
- // lcd.println(tt[1];
- // for (i = 0; i < (retval-0); i++) {lcd.print(":"); lcd.print(tt[i]);} //only test
- // for (i = 0; i <retval; i++) {Serial.print("---"); Serial.println(tt[i]);} //only test
- int Voltage = tt[0]; Voltage = Voltage / 100;
- float Amp = tt[1]; Amp = Amp / 1000;
- int Watt = tt[2];
- //long y=x0*65536+x1;
- int Kwhh = tt[3];
- int Kwhl = tt[4];
- unsigned long kwhA = Kwhh *65536 + Kwhl;
- // unsigned long kwhA = Kwhh <<16 + Kwhl;
- float Kwh = kwhA; Kwh = Kwh / 3200;
- // double Kwh = kwhA / 3200; //Kwh = kwh / 32;
- // int Kwh = tt[4];
- float Pf = tt[5]; Pf = Pf / 1000;
- float C = tt[5]; C = C / 1000;
- lcd.setCursor(0, 1);
- lcd.print("V=");
- lcd.print(Voltage);
- lcd.setCursor(11, 1);
- lcd.print("A=");
- lcd.print(Amp);
- lcd.setCursor(0, 2);
- lcd.print("W=");
- lcd.print(Watt);
- lcd.setCursor(9, 2);
- lcd.print("Kwh=");
- lcd.print(Kwh);
- lcd.setCursor(0, 3);
- lcd.print("C=");
- lcd.print(C);
- lcd.setCursor(10, 3);
- lcd.print("Pf=");
- lcd.print(Pf);
- // print the number of seconds since reset:
- // lcd.setCursor(0, 3);
- // lcd.print(millis()/1000);
- dataout.updateData(0, Voltage);
- dataout.updateData(1, Amp);
- dataout.updateData(2, Watt);
- dataout.updateData(3, Kwh);
- dataout.updateData(4, Pf);
- dataout.updateData(5, C);
- int status = dataout.updatePachube();
- // Serial.print("sync status code <OK == 200> => ");
- // Serial.println(status);
- // PrintDataStream(dataout);
- delay(20000);
- }
- void PrintDataStream(const ERxPachube& pachube)
- {
- unsigned int count = pachube.countDatastreams();
- Serial.print("data count=> ");
- Serial.println(count);
- Serial.println("<id>,<value>");
- for(unsigned int i = 0; i < count; i++)
- {
- Serial.print(pachube.getIdByIndex(i));
- Serial.print(",");
- Serial.print(pachube.getValueByIndex(i));
- Serial.println();
- }
- }
- /****************************************************************************
- * BEGIN MODBUS RTU MASTER FUNCTIONS
- ****************************************************************************/
- //#define TIMEOUT 1000 /* 1 second */
- #define TIMEOUT 10000 /* 10 second */
- #define MAX_READ_REGS 125
- #define MAX_WRITE_REGS 125
- #define MAX_RESPONSE_LENGTH 256
- #define PRESET_QUERY_SIZE 256
- /* errors */
- #define PORT_ERROR -5
- /*
- CRC
-
- INPUTS:
- buf -> Array containing message to be sent to controller.
- start -> Start of loop in crc counter, usually 0.
- cnt -> Amount of bytes in message being sent to controller/
- OUTPUTS:
- temp -> Returns crc byte for message.
- COMMENTS:
- This routine calculates the crc high and low byte of a message.
- Note that this crc is only used for Modbus, not Modbus+ etc.
- ****************************************************************************/
- unsigned int crc(unsigned char *buf, int start, int cnt)
- {
- int i, j;
- unsigned temp, temp2, flag;
- temp = 0xFFFF;
- for (i = start; i < cnt; i++) {
- temp = temp ^ buf[i];
- for (j = 1; j <= 8; j++) {
- flag = temp & 0x0001;
- temp = temp >> 1;
- if (flag)
- temp = temp ^ 0xA001;
- }
- }
- /* Reverse byte order. */
- temp2 = temp >> 8;
- temp = (temp << 8) | temp2;
- temp &= 0xFFFF;
- return (temp);
- }
- /***********************************************************************
- *
- * The following functions construct the required query into
- * a modbus query packet.
- *
- ***********************************************************************/
- #define REQUEST_QUERY_SIZE 6 /* the following packets require */
- #define CHECKSUM_SIZE 2 /* 6 unsigned chars for the packet plus */
- /* 2 for the checksum. */
- void build_request_packet(int slave, int function, int start_addr,
- int count, unsigned char *packet)
- {
- packet[0] = slave;
- packet[1] = function;
- start_addr -= 1;
- packet[2] = start_addr >> 8;
- packet[3] = start_addr & 0x00ff;
- packet[4] = count >> 8;
- packet[5] = count & 0x00ff;
-
- //below test only
- // packet[0] =0x01;
- // packet[1] = 0x03;
- // packet[2] = 0;
- // packet[3] = 0x48;
- // packet[4] = 0;
- // packet[5] = 0x02;
- }
- /*************************************************************************
- *
- * modbus_query( packet, length)
- *
- * Function to add a checksum to the end of a packet.
- * Please note that the packet array must be at least 2 fields longer than
- * string_length.
- **************************************************************************/
- void modbus_query(unsigned char *packet, size_t string_length)
- {
- int temp_crc;
- temp_crc = crc(packet, 0, string_length);
- packet[string_length++] = temp_crc >> 8;
- packet[string_length++] = temp_crc & 0x00FF;
- packet[string_length] = 0;
- }
- /***********************************************************************
- *
- * send_query(query_string, query_length )
- *
- * Function to send a query out to a modbus slave.
- ************************************************************************/
- int send_query(unsigned char *query, size_t string_length)
- {
- int i;
- modbus_query(query, string_length);
- string_length += 2;
- for (i = 0; i < string_length; i++) {
- // Serial.print(query[i], HEX); //Orginal
- Serial.write(query[i]); //JingLi
-
- }
- /* without the following delay, the reading of the response might be wrong
- * apparently, */
- delay(200); /* FIXME: value to use? */
- return i; /* it does not mean that the write was succesful, though */
- }
- /***********************************************************************
- *
- * receive_response( array_for_data )
- *
- * Function to monitor for the reply from the modbus slave.
- * This function blocks for timeout seconds if there is no reply.
- *
- * Returns: Total number of characters received.
- ***********************************************************************/
- int receive_response(unsigned char *received_string)
- {
- int bytes_received = 0;
- int i = 0;
- /* wait for a response; this will block! */
- while(Serial.available() == 0) {
- delay(1);
- if (i++ > TIMEOUT)
- return bytes_received;
- }
- delay(200);
- /* FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? */
- while(Serial.available()) {
- received_string[bytes_received] = Serial.read();
- // Serial.print(bytes_received); //only test
- // Serial.print("-"); //only test
- // Serial.println(received_string[bytes_received]); //only test
- bytes_received++;
- if (bytes_received >= MAX_RESPONSE_LENGTH)
- return PORT_ERROR;
- }
- //Serial.print("bytes_received=");
- //Serial.println(bytes_received);
- return (bytes_received);
- }
- /*********************************************************************
- *
- * modbus_response( response_data_array, query_array )
- *
- * Function to the correct response is returned and that the checksum
- * is correct.
- *
- * Returns: string_length if OK
- * 0 if failed
- * Less than 0 for exception errors
- *
- * Note: All functions used for sending or receiving data via
- * modbus return these return values.
- *
- **********************************************************************/
- int modbus_response(unsigned char *data, unsigned char *query)
- {
- int response_length;
- int i;
- unsigned int crc_calc = 0;
- unsigned int crc_received = 0;
- unsigned char recv_crc_hi;
- unsigned char recv_crc_lo;
- do { // repeat if unexpected slave replied
- response_length = receive_response(data);
- } while ((response_length > 0) && (data[0] != query[0]));
- // for (i = 0; i <response_length; i++) { Serial.print(data[i]);Serial.print("---"); Serial.println(query[i]);} //only test
- if (response_length) {
- crc_calc = crc(data, 0, response_length - 2);
- recv_crc_hi = (unsigned) data[response_length - 2];
- recv_crc_lo = (unsigned) data[response_length - 1];
- crc_received = data[response_length - 2];
- crc_received = (unsigned) crc_received << 8;
- crc_received =
- crc_received | (unsigned) data[response_length - 1];
- /*********** check CRC of response ************/
- if (crc_calc != crc_received) {
- response_length = 0;
- // Serial.println("CRC erro"); //only test
- }
- /********** check for exception response *****/
- if (response_length && data[1] != query[1]) {
- response_length = 0 - data[2];
- }
- }
- return (response_length);
- }
- /************************************************************************
- *
- * read_reg_response
- *
- * reads the response data from a slave and puts the data into an
- * array.
- *
- ************************************************************************/
- int read_reg_response(int *dest, int dest_size, unsigned char *query)
- {
- unsigned char data[MAX_RESPONSE_LENGTH];
- int raw_response_length;
- int temp, i;
- raw_response_length = modbus_response(data, query);
- if (raw_response_length > 0)
- raw_response_length -= 2;
- if (raw_response_length > 0) {
- /* FIXME: data[2] * 2 ???!!! data[2] isn't already the byte count (number of registers * 2)?! */
- for (i = 0;
- i < (data[2] * 2) && i < (raw_response_length / 2);
- i++) {
- /* shift reg hi_byte to temp */
- temp = data[3 + i * 2] << 8;
- /* OR with lo_byte */
- temp = temp | data[4 + i * 2];
- dest[i] = temp;
- }
- }
- return (raw_response_length);
- }
- /***********************************************************************
- *
- * preset_response
- *
- * Gets the raw data from the input stream.
- *
- ***********************************************************************/
- int preset_response(unsigned char *query)
- {
- unsigned char data[MAX_RESPONSE_LENGTH];
- int raw_response_length;
- raw_response_length = modbus_response(data, query);
- return (raw_response_length);
- }
- /************************************************************************
- *
- * read_holding_registers
- *
- * Read the holding registers in a slave and put the data into
- * an array.
- *
- *************************************************************************/
- int read_holding_registers(int slave, int start_addr, int count,
- int *dest, int dest_size)
- {
- int function = 0x03; /* Function: Read Holding Registers */
- int ret;
- unsigned char packet[REQUEST_QUERY_SIZE + CHECKSUM_SIZE];
- if (count > MAX_READ_REGS) {
- count = MAX_READ_REGS;
- }
- build_request_packet(slave, function, start_addr, count, packet);
- if (send_query(packet, REQUEST_QUERY_SIZE) > -1) {
- ret = read_reg_response(dest, dest_size, packet);
- }
- else {
- ret = -1;
- }
- return (ret);
- }
- /************************************************************************
- *
- * preset_multiple_registers
- *
- * Write the data from an array into the holding registers of a
- * slave.
- *
- *************************************************************************/
- int preset_multiple_registers(int slave, int start_addr,
- int reg_count, int *data)
- {
- int function = 0x10; /* Function 16: Write Multiple Registers */
- int byte_count, i, packet_size = 6;
- int ret;
- unsigned char packet[PRESET_QUERY_SIZE];
- if (reg_count > MAX_WRITE_REGS) {
- reg_count = MAX_WRITE_REGS;
- }
- build_request_packet(slave, function, start_addr, reg_count, packet);
- byte_count = reg_count * 2;
- packet[6] = (unsigned char)byte_count;
- for (i = 0; i < reg_count; i++) {
- packet_size++;
- packet[packet_size] = data[i] >> 8;
- packet_size++;
- packet[packet_size] = data[i] & 0x00FF;
- }
- packet_size++;
- if (send_query(packet, packet_size) > -1) {
- ret = preset_response(packet);
- }
- else {
- ret = -1;
- }
- return (ret);
- }
复制代码
程序和硬件,慢慢整理以后,与大家分享。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|