一个特别简单的目的,就是让8266读取DDSU666的电表数据上传。
想偷懒用arduino里自带的modbus库文件用用(里面有例程可以抄),失败~~总是编译不过去~这个没定义那个没定义之类的~
大神们有什么好建议么?
也想过直接串口通讯,不过什么奇偶校验啊,CRC停止位啥的搞得很头大·~~,主要是懒~~~
离线
modbus很简单的一个协议,几行代码就搞定了,没不要去折腾库。
离线
欸,一点都偷不了懒么?~~~
离线
离线
果然可以,以前modbus代码都是自己撸的,发现这个libmodbus更简洁:
简书上面找到一个demo
RTU:
#include <modbus.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
modbus_t *ctx=NULL; // context
int addr=0; // address
int rc=0; // received
int nb = 3; // the number of bit
uint16_t *tab_rq_registers=NULL;
uint16_t *tab_rp_registers=NULL;
/* RTU */
ctx = modbus_new_rtu("/dev/ttySAC3",9600,'N',8,1);
modbus_set_debug(ctx, TRUE);
modbus_set_slave(ctx, 0x01); // 设置从机地址
// connect
if (-1 == modbus_connect(ctx))
{
fprintf(stderr, "Conncetion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
// 读取数据
uint16_t tab_reg[2]; // 存放要读的数据
int regs=modbus_read_registers(ctx,0,2,tab_reg);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
TCP:
/*
* The client of modbus tcp.
* test 2 register
*
* 2017-10-26
*/
#include <modbus.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
modbus_t *ctx=NULL; // context
int addr=0; // address
int rc=0; // received
int nb = 3; // the number of bit
uint16_t *tab_rq_registers=NULL;
uint16_t *tab_rp_registers=NULL;
/* TCP */
ctx = modbus_new_tcp("192.168.2.29", 1502);
modbus_set_debug(ctx, TRUE);
// connect
if (-1 == modbus_connect(ctx))
{
fprintf(stderr, "Conncetion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
/* Allocate and initialize the memory spaces. */
tab_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
memset(tab_rq_registers, 0, nb * sizeof(uint16_t));
tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
memset(tab_rp_registers, 0, nb * sizeof(uint16_t));
// write
tab_rq_registers[0] = 25;
tab_rq_registers[1] = 2;
tab_rq_registers[2] = 88;
rc = modbus_write_registers(ctx, addr, nb, tab_rq_registers);
if (rc != nb)
{
printf("ERROR modbus_write_bits single (%d)\n", rc);
printf("address = %d\n", addr);
}
// read
rc = modbus_read_registers(ctx, addr, nb, tab_rp_registers);
if (rc != nb)
{
printf("ERROR modbus_read_bits single (%d)\n", rc);
printf("address = %d\n", addr);
}
for (int i = 0; i < nb; ++i)
{
printf("%d%c", tab_rp_registers[i], (i==nb-1)?'\n':' ');
}
free(tab_rq_registers);
free(tab_rp_registers);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
离线
欸,一点都偷不了懒么?~~~
应该可以偷懒了:
Small Modbus slave, RTU (serial) for Arduino (arduino modbus从机):
https://github.com/stephane/modbusino
Simple Makefile to compile and upload Arduino sketches:
https://github.com/stephane/arduinoMakefile
离线
这个代码移植stm32要自己实现好多东西么
离线
离线
应该可以偷懒了:
Small Modbus slave, RTU (serial) for Arduino (arduino modbus从机):
https://github.com/stephane/modbusinoSimple Makefile to compile and upload Arduino sketches:
https://github.com/stephane/arduinoMakefile
这个更省事顺手!
离线
Simple Makefile to compile and upload Arduino sketches:
https://github.com/stephane/arduinoMakefile
“Windows users: sorry, please use a better OS.”
这哥们挺逗~
离线
这个 libmodbus 我在 NUC972 + Linux非常好用, 我把原来自己撸的代码替换了, 测试了两天, 已经小批量发货给客户了。
离线
这个 libmodbus 我在 NUC972 + Linux非常好用, 我把原来自己撸的代码替换了, 测试了两天, 已经小批量发货给客户了。
NUC972性价比是不是要好一些?
离线
NUC972性价比是不是要好一些?
要看和谁比,应用场景是什么。
300Mhz主频有点鸡肋,内置DRAM, 引脚超级多,UART也多。
离线
要看和谁比,应用场景是什么。
300Mhz主频有点鸡肋,内置DRAM, 引脚超级多,UART也多。
我学习下,我这UART用的多。
离线
我也是要读这个电表,真是太tmd坎坷了。
本来用的天问的asrpro模块,想着它带喇叭可以语音说话,我想做个当电流超多少时自动语音报警(因为家里是速热热水器,开起来最大到32A,我限制了水流到20A,家里总断路器才32A的,如果这时候烧水或是干啥容易超电流跳闸,我自己会注意,家人不太懂电这东西),结果他们的芯片有问题,偶校验2400波特率走modbus模块,发送数据是正常的,但收数据就是大概率误码,如果我读电量,电流电压功率,大概率电压能读出来,如果我只读电压,是一次正确一次误码。后来测试自收自发还误码,真狗,浪费了2天休息日的大好时光。然后图省事,试了试手里的arduino nano,和nodemcu8266,但都是只有一个串口,没法看调试信息,后来用nano那一个串口测试,和esp8266测试,都是用的arduino,也是不行,真狗,这两个模块用示波器测了下,原来是rx脚被板载USB串口芯片的tx拉高了,果断把nano上的ch340焊下来。果然好了,太tm坎坷了。
代码我是直接对AI提的编程需求,粘上就能用。问法如下。我的硬件是Arduino Nano。我需要使用串口以MODBUS RTU协议读取电表的电压 电流 功率 电量。电量的地址是0x0000,数据长度为2。电压的地址是0x0300,数据长度为1。电流的地址是0x0303,数据长度为1。功率的地址是0x0306,数据长度为1。modbus的读参量用03H号命令。电表的modbus地址为15。电量数据是高位在前,低位在后,若读出值为0012D687H(1234567),则电能计量值为 1234567×0.01=12345.67kWh。电能表中所测电压值固定为 1 位小数,数据格式为 XXX.X,单位为 V,若通讯读出,电压值为 0897H(2199),则电压的实际值为 219.9V;所测电流值固定为 2 位小数数据格式为 XXX.XX,单位 A,若通讯读出电流值为 0096H(150), 则电流的实际值为 1.50A。电能表的有功率值固定为 2 位小数,数据格式为 XXX.XX,单位为 kW, 若通讯读出有功功
率值为 0020H(32),则有功率的实际值为 0.32kW。 帮我写出对应功能的arduino程序。 调试信息不打印。注意,接电表的串口使用偶校验。当电流大于1A时,控制4脚输出高,低于1A时输出低。请不要使用modbus库,请使用代码实现modbus的发送及接收。
离线
ai代码如下
#include <Arduino.h>
#define SLAVE_ID 15
#define BAUDRATE 2400
#define TIMEOUT 1000
#define TX_ENABLE_PIN 4
// MODBUS function codes
#define READ_HOLDING_REGISTERS 0x03
// Registers addresses
#define ADDR_ENERGY 0x0000
#define ADDR_VOLTAGE 0x0300
#define ADDR_CURRENT 0x0303
#define ADDR_POWER 0x0306
// Registers lengths
#define LEN_ENERGY 2
#define LEN_VOLTAGE 1
#define LEN_CURRENT 1
#define LEN_POWER 1
void setup() {
Serial.begin(BAUDRATE, SERIAL_8E1); // 偶校验
pinMode(TX_ENABLE_PIN, OUTPUT);
}
void loop() {
float energy = readRegister(ADDR_ENERGY, LEN_ENERGY) * 0.01; // kWh
float voltage = readRegister(ADDR_VOLTAGE, LEN_VOLTAGE) * 0.1; // V
float current = readRegister(ADDR_CURRENT, LEN_CURRENT) * 0.01; // A
float power = readRegister(ADDR_POWER, LEN_POWER) * 0.01; // kW
if (current > 1.0) {
digitalWrite(TX_ENABLE_PIN, HIGH);
} else {
digitalWrite(TX_ENABLE_PIN, LOW);
}
// 延时一段时间后再次读取
delay(5000);
}
long readRegister(unsigned int addr, unsigned char len) {
unsigned char buf[8];
buf[0] = SLAVE_ID; // Slave Address
buf[1] = READ_HOLDING_REGISTERS; // Function Code
buf[2] = highByte(addr); // Starting Address High
buf[3] = lowByte(addr); // Starting Address Low
buf[4] = 0x00; // Number of Registers High
buf[5] = len; // Number of Registers Low
unsigned int crc = calculateCRC(buf, 6);
buf[6] = lowByte(crc); // CRC Low
buf[7] = highByte(crc); // CRC High
sendRequest(buf, 8);
delay(100);
if (Serial.available()) {
// Read the response
// TODO: Add code to parse the response
}
return 0; // Placeholder for actual value
}
void sendRequest(unsigned char *packet, unsigned char packetLength) {
digitalWrite(TX_ENABLE_PIN, HIGH);
for (unsigned char i = 0; i < packetLength; i++) {
Serial.write(packet[i]);
}
Serial.flush();
digitalWrite(TX_ENABLE_PIN, LOW);
}
unsigned int calculateCRC(unsigned char *buf, unsigned char len) {
unsigned int crc = 0xFFFF;
for (unsigned int pos = 0; pos < len; pos++) {
crc ^= (unsigned int)buf[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
最近编辑记录 迪卡 (2024-01-30 00:15:27)
离线
现在是不是python也可以了
离线