任务:
编程实现采集传感器数据和控制硬件设备(传感器和硬件通过slave模拟)
1.传感器:2个,光线传感器、加速度传感器(x\y\z)
2. 硬件设备:2个,led灯、蜂鸣器
要求:
1. 多任务编程:多线程、多进程
2.循环1s采集一次数据,并将数据打印至终端
3.同时从终端输入指令控制硬件设备
// 0 1 :led灯打开
// 0 0:led灯关闭
// 1 1:蜂鸣器开
// 1 0 : 蜂鸣器关
编程流程:
1. 创建实例
modbus_new_tcp
2. 设置从机ID
modbus_set_slave
3. 和从机进行连接
modbus_connect
4. 寄存器进行操作
功能码对应函数
5. 关闭套接字
modbus_close
6. 释放实例
modbus_free
函数接口(很重要!)
modbus_t* modbus_new_tcp(const char *ip, int port)
功能:以TCP方式创建Modbus实例,并初始化
参数:
ip :ip地址
port:端口号
返回值:成功:Modbus实例
失败:NULL
int modbus_set_slave(modbus_t *ctx, int slave)
功能:设置从机ID
参数:
ctx :Modbus实例
slave:从机ID
返回值:成功:0
失败:-1
int modbus_connect(modbus_t *ctx)
功能:和从机(slave)建立连接
参数:
ctx:Modbus实例
返回值:成功:0
失败:-1
void modbus_free(modbus_t *ctx)
功能:释放Modbus实例
参数:ctx:Modbus实例
void modbus_close(modbus_t *ctx)
功能:关闭套接字
参数:ctx:Modbus实例
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
功能:读取线圈状态,可读取多个连续线圈的状态(对应功能码为0x01)
参数:
ctx :Modbus实例
addr :寄存器起始地址
nb :寄存器个数
dest :得到的状态值
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
功能:读取输入状态,可读取多个连续输入的状态(对应功能码为0x02)
参数:
ctx :Modbus实例
addr :寄存器起始地址
nb :寄存器个数
dest :得到的状态值
返回值:成功:返回nb的值
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
功能:读取保持寄存器的值,可读取多个连续保持寄存器的值(对应功能码为0x03)
参数:
ctx :Modbus实例
addr :寄存器起始地址
nb :寄存器个数
dest :得到的寄存器的值
返回值:成功:读到寄存器的个数
失败:-1
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
功能:读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04)
参数:
ctx :Modbus实例
addr :寄存器起始地址
nb :寄存器个数
dest :得到的寄存器的值
返回值:成功:读到寄存器的个数
失败:-1
int modbus_write_bit(modbus_t *ctx, int addr, int status);
功能:写入单个线圈的状态(对应功能码为0x05)
参数:
ctx :Modbus实例
addr :线圈地址
status:线圈状态
返回值:成功:0
失败:-1
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
功能:写入多个连续线圈的状态(对应功能码为15)
参数:
ctx :Modbus实例
addr :线圈地址
nb :线圈个数
src :多个线圈状态
返回值:成功:0
失败:-1
int modbus_write_register(modbus_t *ctx, int addr, int value);
功能: 写入单个寄存器(对应功能码为0x06)
参数:
ctx :Modbus实例
addr :寄存器地址
value :寄存器的值
返回值:成功:0
失败:-1
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
功能:写入多个连续寄存器(对应功能码为16)
参数:
ctx :Modbus实例
addr :寄存器地址
nb :寄存器的个数
src :多个寄存器的值
返回值:成功:0
失败:-1
运行代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <modbus.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
int sockfd;
uint16_t dest[64] = {};
int main()
{
modbus_t *ctx;
ctx = modbus_new_tcp("192.168.XX.XX", 502);
if (ctx == NULL)
{
perror("error\n");
return -1;
}
int a = modbus_set_slave(ctx, 1);
int b = modbus_connect(ctx);
pid_t pid = fork();
if (pid < 0)
{
perror("fork err");
return -1;
}
else if (pid == 0)
{
while (1)
{
modbus_read_registers(ctx, 0, 4, dest);
for (int i = 0; i < 4; i++)
{
if (i == 0)
{
printf("光传感器:");
printf("%#x\n", dest[i]);
}
else if (i == 1)
{
printf("加速度传感器x:%#x\n", dest[i]);
}
else if (i == 2)
{
printf("加速度传感器y:%#x\n", dest[i]);
}
else if (i == 3)
{
printf("加速度传感器z:%#x\n", dest[i]);
}
putchar(10);
}
sleep(5);
}
exit(0);
}
else
{
int a, b;
while (1)
{
scanf("%d", &a);
scanf("%d", &b);
if (a == 0 && b == 1)
{
printf("led灯打开\n");
}
else if (a == 0 && b == 0)
{
printf("led灯关闭\n");
}
else if (a == 1 && b == 1)
{
printf("蜂鸣器开\n");
}
else if (a == 1 && b == 0)
{
printf("蜂鸣器关\n");
}
modbus_write_bit(ctx, a, b);
}
wait(NULL);
// exit(0);
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
运行结果:
注意:在slave内设置上线圈与寄存器,连接上主机ip地址,同时在虚拟机内编译通过后执行时也连接主机ip地址就可以循环获取设备的数值和通过终端输入来设置线圈状态