C开发的智能电表读数程序可用485和计算机读取电量并存最近在搞一个C开发的智能电表读数程序主要是通过485接口和计算机通信读取电量并存到数据库里。说实话这玩意儿一开始还挺让人头疼的毕竟涉及到硬件通信和数据处理搞不好就各种bug满天飞。不过经过一番折腾总算搞定了今天就来聊聊这个过程。首先485通信这块儿C里用到了libmodbus这个库。这个库挺方便的封装了底层的通信细节直接调用API就能搞定。先来看一下初始化485通信的代码#include modbus/modbus.h modbus_t *ctx; ctx modbus_new_rtu(/dev/ttyUSB0, 9600, N, 8, 1); if (ctx NULL) { fprintf(stderr, Unable to create the libmodbus context\n); return -1; } if (modbus_connect(ctx) -1) { fprintf(stderr, Connection failed: %s\n, modbus_strerror(errno)); modbus_free(ctx); return -1; }这段代码主要是初始化一个modbust对象指定了串口设备、波特率、校验位等参数。如果初始化失败程序就直接退出了。modbusconnect函数用来建立连接失败的话也会退出并释放资源。接下来就是读取电表数据的部分了。电表的数据一般存储在寄存器里通过读取寄存器来获取电量信息。我们假设电量的寄存器地址是0x0001数据类型是16位无符号整数。代码如下uint16_t tab_reg[1]; int rc modbus_read_registers(ctx, 0x0001, 1, tab_reg); if (rc -1) { fprintf(stderr, Failed to read registers: %s\n, modbus_strerror(errno)); modbus_close(ctx); modbus_free(ctx); return -1; } uint16_t power tab_reg[0]; printf(Current power: %d kWh\n, power);modbusreadregisters函数用来读取寄存器数据参数分别是上下文、寄存器地址、读取数量和存储数据的数组。如果读取失败程序会打印错误信息并退出。成功的话数据会存储在tab_reg数组中我们取出第一个元素就是当前的电量值。C开发的智能电表读数程序可用485和计算机读取电量并存读取到电量后下一步就是存到数据库里了。这里我用的是SQLite因为它轻量级不需要额外的数据库服务器。先来看一下数据库的初始化代码#include sqlite3.h sqlite3 *db; char *err_msg 0; int rc sqlite3_open(power.db, db); if (rc ! SQLITE_OK) { fprintf(stderr, Cannot open database: %s\n, sqlite3_errmsg(db)); sqlite3_close(db); return -1; } char *sql CREATE TABLE IF NOT EXISTS PowerLog (id INTEGER PRIMARY KEY AUTOINCREMENT, power INTEGER, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);; rc sqlite3_exec(db, sql, 0, 0, err_msg); if (rc ! SQLITE_OK) { fprintf(stderr, SQL error: %s\n, err_msg); sqlite3_free(err_msg); sqlite3_close(db); return -1; }这段代码打开了一个SQLite数据库文件power.db如果文件不存在会自动创建。然后执行了一个SQL语句创建了一个PowerLog表用来存储电量数据。表中有三个字段id是自增主键power是电量值timestamp是记录时间默认是当前时间。最后一步就是把读取到的电量存到数据库里char sql_insert[100]; sprintf(sql_insert, INSERT INTO PowerLog (power) VALUES (%d);, power); rc sqlite3_exec(db, sql_insert, 0, 0, err_msg); if (rc ! SQLITE_OK) { fprintf(stderr, SQL error: %s\n, err_msg); sqlite3_free(err_msg); } sqlite3_close(db);这里用sprintf动态生成了一条SQL插入语句把电量值插入到PowerLog表中。如果插入失败程序会打印错误信息。最后别忘了关闭数据库连接。整个过程就是这样了从485通信到读取数据再到存储到数据库虽然步骤不少但每个环节都还算清晰。当然实际项目中可能会遇到更多问题比如通信不稳定、数据格式复杂等等这就需要根据具体情况来调整了。不过掌握了这些基本操作后续的优化和扩展就会容易很多。