MS-DTU/MS-DTU-V1/User/485_sensor.c

1150 lines
31 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
* IAR Development Kits
* on the
*
* M451
*
* Filename : spi_adc.c
* Version : V1.00
* Programmer(s) : Qian Xianghong
*********************************************************************************************************
*/
#include "includes.h"
// 是否SMARC的流量计
#define _SMARC_FLOWMETER_
// 是否热式流量计
//#define _THERMAL_FLOWMETER_
// 是否希尔思S401流量计
//#define _S401_FLOWMETER_
// 默认为斯达易思流量计
// 读取超时计数
volatile uint32_t modbus_outTick = 0;
const uint8_t VACUUM_ID[] = {1, 2}; // 真空计通信地址
#define VACUUM_CMD 4 // 真空计读取命令
#define VACUUM_ADDR 608 // 真空计起始寄存器地址
#define VACUUM_LEN 8 // 真空计读取寄存器个数
const uint8_t LEAK_ID = 3; // 泄露报警控制器通信地址
#define LEAK_CMD 3 // 泄露报警控制器读取命令
#define LEAK_ADDR 0x08 // 泄露报警控制器起始寄存器地址
#define LEAK_LEN 8 // 泄露报警控制器读取寄存器个数
#if defined(_SMARC_FLOWMETER_)
const uint8_t FLOW_ID = 1; // SMARC流量计通信地址
#define FLOW_CMD 3 // 流量计读取命令
#define FLOW_ADDR 4068 // 流量计起始寄存器地址
#define FLOW_LEN 12 // 流量计读取寄存器个数
#elif defined(_THERMAL_FLOWMETER_)
const uint8_t FLOW_ID = 4; // 热式流量计通信地址
#define FLOW_CMD 3 // 流量计读取命令
#define FLOW_ADDR 7 // 流量计起始寄存器地址
#define FLOW_LEN 6 // 流量计读取寄存器个数
#elif defined(_S401_FLOWMETER_)
const uint8_t FLOW_ID = 4; // S401流量计通信地址
#define FLOW_CMD 3 // 流量计读取命令
#define FLOW_ADDR 6 // 流量计起始寄存器地址
#define FLOW_LEN 4 // 流量计读取寄存器个数
#else
const uint8_t FLOW_ID = 4; // 斯达易思流量计通信地址
#define FLOW_CMD 3 // 流量计读取命令
#define FLOW_ADDR 0 // 流量计起始寄存器地址
#define FLOW_LEN 15 // 流量计读取寄存器个数
#endif
const uint8_t LEAK_O2_ID = 1; // O2浓度传感器通信地址
#define LEAK_O2_SOF 0xFF // O2浓度传感器起始符
#define LEAK_O2_CMD 0x86 // O2浓度传感器读取命令
#pragma pack(push, 1)
typedef struct
{
uint8_t id;
uint8_t cmd;
uint16_t addr;
uint16_t len;
uint16_t crc;
} modbus_send_t;
typedef struct
{
struct
{
uint8_t id;
uint8_t cmd;
uint8_t len;
} header;
union{
// 真空计数据
struct
{
uint16_t staVacuum; // 状态
uint16_t lifeVacuum; // 使用年限
uint32_t vacuum; // 真空度float型先用整形交换字节序
uint32_t rateVacuum; // 漏放气速率float型先用整形交换字节序
uint32_t tempr; // 温度float型先用整形交换字节序
} vacuum;
// 泄漏报警器数据
struct
{
unsigned unit : 4; // 气体单位
unsigned ratio : 4; // 数值单位
uint8_t type; // 气体类型
uint16_t A1; // A1报警值
uint16_t A2;
uint16_t A3;
uint16_t A4;
uint16_t range; // 量程
uint16_t concentrations; // 浓度
uint8_t staLeak; // 传感器状态
unsigned : 8;
} leak;
// 流量计数据
struct
{
uint32_t nM3_int; // 标况累积总量整数部分
uint16_t nM3_frac; // 标况累积总量小数部分放大10000倍
uint32_t M3_int; // 工况累积总量整数部分
uint16_t M3_frac; // 工况累积总量小数部分放大10000倍
uint32_t nM3_h; // 标况流量nM3/h放大100倍
uint32_t M3_h; // 工况流量M3/h放大100倍
int16_t tempr; // 温度放大10倍第一位正负位(即数值大于0x7FFF为负)
uint32_t pressure; // 压力(绝压KPa, 放大10倍)
uint16_t err1; // 异常标志位1
//温度错误标志位: 0x0003
//压力错误标志位: 0x0030
//电池电量低标志位: 0x0300
//工况流量超最大工况流量: 0x3000
//无异常0x0000
uint16_t err2; // 异常标志位2
//存储器异常标志位: 0x0003
//无异常0x0000
} flow;
// SMARC流量计数据
struct
{
uint32_t nM3_h; // 标况流量: float, 方便颠倒顺序用uint32_t型接收
uint32_t M3_h; // 工况流量: float, 方便颠倒顺序用uint32_t型接收
uint32_t tempr; // 温度: float, 方便颠倒顺序用uint32_t型接收
uint32_t pressure; // 压力: float, 方便颠倒顺序用uint32_t型接收
uint16_t warnFlag; // 报警标志
uint8_t nM3_BCD[6]; // 标况体积
} flow_SMARC;
// 热式流量计数据
struct
{
uint32_t nM3_h; // 标况流量: float, 方便颠倒顺序用uint32_t型接收
uint32_t nM3x100; // 累计流量100以上uint32_t
uint32_t nM3r100; // 累计流量100以下float, 方便颠倒顺序用uint32_t型接收
} flow_Thermal;
// S401流量计数据
struct
{
uint32_t nM3_h; // 流量: 分辨率0.1, uint32_t
uint32_t nM3; // 累积量分辨率1uint32_t
} flow_S401;
};
uint16_t crc; // 占位置
} modbus_recv_t;
typedef union
{
modbus_send_t send;
modbus_recv_t recv;
uint8_t buff[sizeof(modbus_recv_t)];
} modbus_comm_t;
// O2浓度传感器读取命令
typedef struct
{
uint8_t addr;
uint8_t cmd;
uint8_t reserved[5];
} leak_o2_send_t;
// O2浓度传感器返回结果
typedef struct
{
uint8_t cmd;
uint16_t concentrations; // 浓度
uint8_t reserved[4];
} leak_o2_recv_t;
// O2浓度传感器通信帧
typedef union
{
struct
{
uint8_t sof;
union
{
leak_o2_send_t send;
leak_o2_recv_t recv;
};
uint8_t cs;
};
uint8_t buff[9];
} leak_o2_comm_t;
// DYQ-7通信协议的泄露报警器、电容采集头、压力采集头等
#define RS_MIN_FRAME_LEN (15)
#define RS_MAX_FRAME_LEN (39)
#define RS_MIN_DATA_LEN (0)
#define RS_MAX_DATA_LEN (RS_MAX_FRAME_LEN - RS_MIN_FRAME_LEN)
#define RS_FRAME_SOF (0x1B) // 标识一个帧的开始
#define RS_DIR_M2S (0) // Master->Slave
#define RS_DIR_S2M (1) // Slave->Master
#define RS_PROTOCOL_VER_1 (1)
// 请求命令
#define RS_CMD_READ_DATA (5) // 读采集数据
// 处理结果
#define RS_RESULT_SUCC (0) // 处理成功
#define RS_RESULT_FAIL (-1) // 处理失败
// 通信协议版本
const uint8_t RS_PROTOCOL_VER = RS_PROTOCOL_VER_1;
// 485泄露报警器请求数据
typedef struct // size = RS_MAX_FRAME_LEN
{
uint8_t sof; // RS_FRMAE_SOF
uint8_t len; // bytes from sof to crcRS_MIN_FRAME_LEN~RS_MAX_FRAME_LEN
uint8_t destAddr;
uint8_t srcAddr;
uint8_t srcPSN[6];
uint8_t dir;
uint8_t protocol_ver; // RS_PROTOCOL
uint8_t cmd;
uint8_t data[RS_MAX_DATA_LEN];
uint16_t crc; // 占位置实际crc可能更靠前
} rs_frame_t;
// 485泄露报警器应答数据
typedef struct // size = 20
{
uint16_t adc; // 采集ADC值
float measureValue; // 采集值
uint8_t measureState; // 测量值状态
uint16_t levelHeight; // 液位高度
uint16_t volume; // 剩余液量
uint16_t volumeMax; // 有效容积
uint16_t quality; // 剩余重量
uint8_t warnState; // 报警状态
uint16_t envAdc; // 环境温度ADC
int16_t envTempr; // 环境温度
} rs_data_t;
#pragma pack(pop)
rs_frame_t RS_TranFrame;
modbus_comm_t modbus;
uint8_t modbus_idx = 0;
uint8_t vaccum_idx = 0;
data_sample_t *modbus_sample;
leak_o2_comm_t leakO2;
// 将十进制转换成BCD
void dec2bcd(uint32_t dec, uint8_t *bcd, uint8_t len)
{
char fmt[10], str[20];
uint8_t i;
// 生成格式串(如:%010u
sprintf(fmt, "%%0%du", len * 2);
// 将dec值转换成前面补0的字符串000000123456)
sprintf(str, fmt, dec);
// 转换
for(i = 0; i < strlen(str); i += 2)
{
bcd[i / 2] = ((str[i] - '0') << 4) | (str[i + 1] - '0');
}
}
// 计算O2浓度传感器校验和
uint8_t leak_o2_calcuCS(uint8_t *data, uint16_t len)
{
uint8_t cs = 0;
while(len--)
cs += *data++;
return (~cs) + 1;
}
// 初始化O2浓度通信帧
void leak_o2_init_frame(leak_o2_comm_t *frame)
{
memset(frame, 0, sizeof(leak_o2_comm_t));
frame->sof = LEAK_O2_SOF;
}
// 本函数由规管设计者Zhang Jm提供用于对读出的真空值进行修正
// 本函数只适用于规管量程为-20.01Pa)的情况
/**
* @brief Function of Fuzzy Processing.
* @param value: vacuun value.
* @retval None.
*/
float Mode1_Fuzzy_Process(float value)
{
static const float beta1 = -0.2539755;
static const float beta2 = 13.15659;
static const float theta = 0.011666666;
static const float eta = 0.9999999;
static const float kappa = 0.006666666;
float temp1, temp2, result, lower_t = 0.0101;
if((value < 0.09f) && (value > 0.04f))
{
temp1 = -beta1 * value;
temp2 = beta2 * pow(value, 2.0);
return(1 - exp(temp1 - temp2));
}
else if((value <= 0.04f) && (value > 0.005f))
{/*y = theta*x^eta/(kappa^eta+x^eta)*/
temp1 = pow(value, eta);
temp2 = pow(kappa, eta) + temp1;
result = theta * temp1 / temp2;
if(result < lower_t)
return(lower_t);
else
return(result);
}
else
return(value);
}
void Modbus_Read(USART_Handle *huart)
{
uint8_t i;
uint32_t reversed;
int32_t i_reversed;
float f;
uint8_t c = (uint8_t) huart->Instance->RDR;
/* Receive data */
if(modbus_idx < sizeof(modbus_recv_t))
{
modbus.buff[modbus_idx++] = c;
if(modbus.recv.header.id == LEAK_ID && modbus.recv.header.cmd == LEAK_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.leak)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.leak) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
/* Print the received data */
// printf("Received data:\n");
// for(i = 0; i < modbus_idx; i++)
// {
// printf("%02X ", modbus.buff[i]);
// }
// printf("\n");
// 探测器状态
modbus_sample->leak.staLeak = modbus.recv.leak.staLeak;
// 浓度
modbus_sample->leak.concentrations = ntohs(modbus.recv.leak.concentrations);
if(modbus.recv.leak.ratio == 1)
modbus_sample->leak.concentrations /= 10;
else if(modbus.recv.leak.ratio == 2)
modbus_sample->leak.concentrations /= 100;
else if(modbus.recv.leak.ratio == 3)
modbus_sample->leak.concentrations /= 1000;
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
else if(modbus.recv.header.id == VACUUM_ID[vaccum_idx] && modbus.recv.header.cmd == VACUUM_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.vacuum)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.vacuum) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
/* Print the received data */
printf("Received data:\n");
for(i = 0; i < modbus_idx; i++)
{
printf("%02X ", modbus.buff[i]);
}
printf("\n");
// 传感器状态
modbus_sample->vacuum[vaccum_idx].staVacuum = ntohs(modbus.recv.vacuum.staVacuum);
// 使用年限
modbus_sample->vacuum[vaccum_idx].lifeVacuum = ntohs(modbus.recv.vacuum.lifeVacuum);
// 真空度
reversed = ntohl(modbus.recv.vacuum.vacuum);
memmove(&modbus_sample->vacuum[vaccum_idx].vacuum, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].vacuum));
// 调用真空值修正函数2021.10.28
modbus_sample->vacuum[vaccum_idx].vacuum = Mode1_Fuzzy_Process(modbus_sample->vacuum[vaccum_idx].vacuum);
// 漏放气速率
reversed = ntohl(modbus.recv.vacuum.rateVacuum);
memmove(&modbus_sample->vacuum[vaccum_idx].rateVacuum, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].rateVacuum));
// 温度
reversed = ntohl(modbus.recv.vacuum.tempr);
memmove(&modbus_sample->vacuum[vaccum_idx].tempr, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].tempr));
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
#if defined(_SMARC_FLOWMETER_)
else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.flow_SMARC)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_SMARC) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
// /* Print the received data */
// printf("Received data:\n");
// for(i = 0; i < modbus_idx; i++)
// {
// printf("%02X ", modbus.buff[i]);
// }
// printf("\n");
// 标况体积总量
// 整数部分
reversed = 0;
for(i = 0; i < 9; i++)
{
reversed *= 10;
if(i % 2 == 0)
reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] >> 4);
else
reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] & 0x0F);
}
dec2bcd(reversed, modbus_sample->flow.nM3, 5);
// 小数部分
reversed = 0;
for(i = 9; i < 11; i++)
{
reversed *= 10;
if(i % 2 == 0)
reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] >> 4);
else
reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] & 0x0F);
}
dec2bcd(reversed, modbus_sample->flow.nM3 + 5, 1);
// 标况流量
reversed = ntohl(modbus.recv.flow_SMARC.nM3_h);
memmove(&f, &reversed, 4);
reversed = f * 100;
dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
// 工况流量
reversed = ntohl(modbus.recv.flow_SMARC.M3_h);
memmove(&f, &reversed, 4);
reversed = f * 100;
dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
// 温度
reversed = ntohl(modbus.recv.flow_SMARC.tempr);
memmove(&f, &reversed, 4);
i_reversed = f * 100;
if(i_reversed >= 0)
dec2bcd(i_reversed, modbus_sample->flow.tempr, 4);
else
{
dec2bcd(-i_reversed, modbus_sample->flow.tempr, 4);
modbus_sample->flow.tempr[0] = 0x80;
}
// 压力
reversed = ntohl(modbus.recv.flow_SMARC.pressure);
memmove(&f, &reversed, 4);
reversed = f * 100;
dec2bcd(reversed, modbus_sample->flow.pressure, 4);
/* Print the converted bcd data */
printf("Flowmeter BCD data:\n");
for(i = 0; i < sizeof(modbus_sample->flow); i++)
{
printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
}
printf("\n");
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
#elif defined(_THERMAL_FLOWMETER_)
else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.flow_Thermal)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_Thermal) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
// /* Print the received data */
// printf("Received data:\n");
// for(i = 0; i < modbus_idx; i++)
// {
// printf("%02X ", modbus.buff[i]);
// }
// printf("\n");
// 标况流量
reversed = ntohl(modbus.recv.flow_Thermal.nM3_h);
memmove(&f, &reversed, 4);
reversed = f * 100;
dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
// 工况流量(协议无,填标况流量)
dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
// 温度协议无填0
dec2bcd(0, modbus_sample->flow.tempr, 4);
// 压力协议无填0
dec2bcd(0, modbus_sample->flow.pressure, 4);
// 标况体积总量
// 100以上部分
reversed = ntohl(modbus.recv.flow_Thermal.nM3x100);
dec2bcd(reversed, modbus_sample->flow.nM3, 4);
// 100以下部分
reversed = ntohl(modbus.recv.flow_Thermal.nM3r100);
memmove(&f, &reversed, 4);
reversed = f * 100;
dec2bcd(reversed, modbus_sample->flow.nM3 + 4, 2);
/* Print the converted bcd data */
printf("Flowmeter BCD data:\n");
for(i = 0; i < sizeof(modbus_sample->flow); i++)
{
printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
}
printf("\n");
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
#elif defined(_S401_FLOWMETER_)
else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.flow_S401)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_S401) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
// /* Print the received data */
// printf("Received data:\n");
// for(i = 0; i < modbus_idx; i++)
// {
// printf("%02X ", modbus.buff[i]);
// }
// printf("\n");
// 流量
reversed = ntohl(modbus.recv.flow_S401.nM3_h) * 10; // x10->x100
dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
// 工况流量(协议无,填标况流量)
dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
// 温度协议无填0
dec2bcd(0, modbus_sample->flow.tempr, 4);
// 压力协议无填0
dec2bcd(0, modbus_sample->flow.pressure, 4);
// 累积量
reversed = ntohl(modbus.recv.flow_S401.nM3) * 100; // x1->x100
dec2bcd(reversed, modbus_sample->flow.nM3, 6);
/* Print the converted bcd data */
printf("Flowmeter BCD data:\n");
for(i = 0; i < sizeof(modbus_sample->flow); i++)
{
printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
}
printf("\n");
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
#else
else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD
&& modbus.recv.header.len == sizeof(modbus.recv.flow)
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow) + sizeof(modbus.recv.crc)
&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
{
// /* Print the received data */
// printf("Received data:\n");
// for(i = 0; i < modbus_idx; i++)
// {
// printf("%02X ", modbus.buff[i]);
// }
// printf("\n");
// 标况体积总量BCD码放大100倍
if((htons(modbus.recv.flow.err2) & 0x000F) == 0x0003) // 是否存储器错误?
dec2bcd(0, modbus_sample->flow.nM3, 6);
else
{
reversed = ntohl(modbus.recv.flow.nM3_int); // 整数部分
dec2bcd(reversed, modbus_sample->flow.nM3, 5);
reversed = ntohs(modbus.recv.flow.nM3_frac); // 小数部分
reversed /= 100; // 放大10000倍->放大100倍
dec2bcd(reversed, modbus_sample->flow.nM3 + 5, 1);
}
// 标况流量BCD码放大100倍
reversed = ntohl(modbus.recv.flow.nM3_h);
dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
// 工况流量BCD码放大100倍
reversed = ntohl(modbus.recv.flow.M3_h);
dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
// 温度BCD码放大100倍第一字节为符号 80H 为负00H 为正)
if((htons(modbus.recv.flow.err1) & 0x000F) == 0x0003) // 是否温度传感器错误?
i_reversed = 0;
else
{
i_reversed = ntohs(modbus.recv.flow.tempr);
i_reversed *= 10; // 放大10倍->放大100倍
}
if(i_reversed >= 0)
dec2bcd(i_reversed, modbus_sample->flow.tempr, 4);
else
{
dec2bcd(-i_reversed, modbus_sample->flow.tempr, 4);
modbus_sample->flow.tempr[0] = 0x80;
}
// 压力BCD码放大100倍
if((htons(modbus.recv.flow.err1) & 0x00F0) == 0x0030) // 是否压力传感器错误?
reversed = 0;
else
{
reversed = ntohl(modbus.recv.flow.pressure);
reversed *= 10; // 放大10倍->放大100倍
}
dec2bcd(reversed, modbus_sample->flow.pressure, 4);
/* Print the converted bcd data */
printf("Flowmeter BCD data:\n");
for(i = 0; i < sizeof(modbus_sample->flow); i++)
{
printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
}
printf("\n");
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
#endif
}
}
void LeakO2_Read(USART_Handle *huart)
{
uint8_t i;
uint8_t c = (uint8_t) huart->Instance->RDR;
uint16_t concentrations = 0;
/* Receive data */
if(modbus_idx < sizeof(leak_o2_comm_t))
{
leakO2.buff[modbus_idx++] = c;
if(modbus_idx == sizeof(leak_o2_comm_t)
&& leakO2.sof == LEAK_O2_SOF && leakO2.recv.cmd == LEAK_O2_CMD
&& leak_o2_calcuCS(leakO2.buff + 1, sizeof(leak_o2_comm_t) - 2) == leakO2.cs)
{
/* Print the received data */
printf("Received data:\n");
for(i = 0; i < modbus_idx; i++)
{
printf("%02X ", leakO2.buff[i]);
}
printf("\n");
#if 1
// 浓度: 分辨率0.1%
concentrations = ntohs(leakO2.recv.concentrations);
#else
// 测试报警输出
concentrations = 240;
#endif
// 浓度降到21.5%,重启泄露报警
if(concentrations <= 215)
Leak_Alarm_Enabled = 1;
// 报警阀值浓度达到23%
if(concentrations >= 230)
{
modbus_sample->leak.staLeak = LEAK_STATUS_A2_ALARM;
modbus_sample->leak.concentrations = 1;
}
else
{
modbus_sample->leak.staLeak = LEAK_STATUS_OK;
modbus_sample->leak.concentrations = 0;
}
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
}
}
// 物理层校验
uint8_t rs_phy_valid(rs_frame_t *frame)
{
if(frame->protocol_ver != RS_PROTOCOL_VER || frame->dir != RS_DIR_S2M)
{
// 物理层校验失败
return 0;
}
return 1;
}
// mac层校验
uint8_t rs_mac_valid(rs_frame_t *frame, uint8_t dir)
{
if(frame->destAddr != dcBuff.configBottle.addr)
{
// mac层校验失败
return 0;
}
return 1;
}
// 初始化帧
void rs_initial_frame(rs_frame_t *frame)
{
memset((uint8_t *) frame, 0, sizeof(rs_frame_t));
frame->len = RS_MIN_FRAME_LEN;
}
// 追加负载数据
uint8_t rs_append_data(rs_frame_t *frame, uint8_t *data, uint8_t len)
{
if(frame->len < RS_MIN_FRAME_LEN || frame->len + len > RS_MAX_FRAME_LEN)
return 0;
if(len > 0)
memmove(frame->data + (frame->len - RS_MIN_FRAME_LEN), data, len);
frame->len += len;
return 1;
}
// 重新寻找SOF
void RS_SearchSOF(uint8_t *buf, uint16_t fromPos, uint8_t *len)
{
uint8_t i;
for(i = fromPos; i < *len && buf[i] != RS_FRAME_SOF; i++)
{
}
*len -= i;
memmove(buf, buf + i, *len);
}
// 模块任务主体:处理射频接收数据
void RS_ParseFrame(USART_Handle *huart)
{
uint8_t *RS_ModuleData = (uint8_t *) &RS_TranFrame;
uint16_t i;
uint8_t frameOk, frameErr;
uint8_t c = (uint8_t) huart->Instance->RDR;
uint32_t mask;
rs_data_t *rsData = (rs_data_t *) (RS_TranFrame.data + sizeof(mask));
if(modbus_idx == 0 && c != RS_FRAME_SOF)
return;
RS_ModuleData[modbus_idx++] = c;
do
{
frameErr = (modbus_idx >= 2 &&
(RS_ModuleData[1] < RS_MIN_FRAME_LEN || RS_ModuleData[1] > RS_MAX_FRAME_LEN));
if(frameErr)
{
// 从1开始寻找SOF
RS_SearchSOF(RS_ModuleData, 1, &modbus_idx);
}
frameOk = (modbus_idx >= 2 && RS_ModuleData[1] >= RS_MIN_FRAME_LEN && RS_ModuleData[1] <= RS_MAX_FRAME_LEN
&& modbus_idx >= RS_ModuleData[1]);
if(frameOk)
{
if(MODBUS_RTU_CRC16(RS_ModuleData, RS_ModuleData[1]) == 0)
{
if(rs_phy_valid(&RS_TranFrame) && rs_mac_valid(&RS_TranFrame, RS_DIR_M2S))
{
// 收到一帧
printf("\r\nRS recv %d bytes:\r\n", RS_ModuleData[1]);
for(i = 0; i < RS_ModuleData[1]; i++)
printf(" %02X", RS_ModuleData[i]);
printf("\r\n");
// 处理这一帧
memmove(&mask, RS_TranFrame.data, 4);
mask = ntohl(mask);
if(RS_TranFrame.srcAddr == 0x51)
{
// 泄漏报警数据
if((mask & 0x61000000) == 0x61000000) // 检查数据掩码
{
modbus_sample->leak.typeLeak = LEAK_TYPE_MODBUS;
if(rsData->measureState > 1)
modbus_sample->leak.staLeak = LEAK_STATUS_FAULT;
else if(rsData->warnState == 4)
modbus_sample->leak.staLeak = LEAK_STATUS_A2_ALARM;
else
modbus_sample->leak.staLeak = LEAK_STATUS_OK;
if(rsData->warnState < 3)
modbus_sample->leak.concentrations = 0;
else
{
memmove(&mask, &rsData->measureValue, 4);
mask = ntohl(mask);
memmove(&rsData->measureValue, &mask, 4);
modbus_sample->leak.concentrations = rsData->measureValue / 1000;
}
}
}
else if(RS_TranFrame.srcAddr == 0x31)
{
// 差压/电容数据,在采集模块里计算
if((mask & 0xE0000000) == 0xE0000000) // 检查数据掩码
{
if(dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
{
// 电容测量:只要电容值,不管归一化状态
modbus_sample->staDPress.status = SENSOR_STATUS_NORMAL;
}
else
modbus_sample->staDPress.status = rsData->measureState;
modbus_sample->adDPress = ntohs(rsData->adc);
modbus_sample->diff = ntohf(rsData->measureValue);
if(dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
{
// 电容只保留1位小数
modbus_sample->diff = ((int16_t) (modbus_sample->diff * 10)) * 0.1;
}
}
}
else if(RS_TranFrame.srcAddr == 0x41)
{
// 压力数据,在采集模块里计算
if((mask & 0xE0000000) == 0xE0000000) // 检查数据掩码
{
modbus_sample->staPress.status = rsData->measureState;
modbus_sample->adPress = ntohs(rsData->adc);
modbus_sample->pressure = ntohf(rsData->measureValue);
}
}
// 退出超时等待
modbus_outTick = GetDelayTick(0);
}
// 继续寻找下一帧
modbus_idx -= RS_ModuleData[1];
memmove(RS_ModuleData, RS_ModuleData + RS_ModuleData[1], modbus_idx);
// 从0开始寻找SOF
RS_SearchSOF(RS_ModuleData, 0, &modbus_idx);
}
else
{
// 从1开始寻找SOF
RS_SearchSOF(RS_ModuleData, 1, &modbus_idx);
}
}
} while(frameOk || frameErr);
}
void Sensor_Init()
{
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
/**LPUART1 GPIO Configuration
PA2 ------> LPUART1_TX
PA3 ------> LPUART1_RX
PB1 ------> LPUART1_DE
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2|LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//RS485_DIS();
}
void Sensor_Open(uint32_t baudrate)
{
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(LPUART1_IRQn);
LPUART_InitStruct.BaudRate = baudrate;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_EnableDEMode(LPUART1);
LL_LPUART_SetDESignalPolarity(LPUART1, LL_LPUART_DE_POLARITY_HIGH);
LL_LPUART_SetDEAssertionTime(LPUART1, 0);
LL_LPUART_SetDEDeassertionTime(LPUART1, 0);
SET_BIT(LPUART1->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
LL_LPUART_Enable(LPUART1);
}
// 切换串口至Modubs通信模式
void Modbus_Open()
{
LL_LPUART_Disable(hlpuart1.Instance);
// 设置中断回调函数
hlpuart1.RxISR = Modbus_Read;
// 修改波特率
Sensor_Open(9600);
}
// 切换到O2浓度传感器通信模式
void LeakO2_Open()
{
LL_LPUART_Disable(hlpuart1.Instance);
// 设置中断回调函数
hlpuart1.RxISR = LeakO2_Read;
// 修改波特率
Sensor_Open(9600);
}
// 切换串口至DYQ-7通信模式
void Modbus_Close()
{
LL_LPUART_Disable(hlpuart1.Instance);
// 设置中断回调函数
hlpuart1.RxISR = RS_ParseFrame;
// 修改波特率
Sensor_Open(19200);
}
static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
//RS485_EN();
delay_us(1);
// 设置超时和结果
modbus_outTick = GetDelayTick(500);
UART_Transmit_IT(&hlpuart1, pu8TxBuf, u32WriteBytes);
delay_ms(9); // 至少8ms保险起见9ms
//RS485_DIS();
}
// 物理层发送
uint8_t rs_uart_send(rs_frame_t *frame, uint8_t destAddr, uint8_t dir)
{
uint16_t crc;
uint8_t i;
// 填写固定字段
frame->sof = RS_FRAME_SOF;
frame->destAddr = destAddr;
frame->srcAddr = dcBuff.configBottle.addr;
memmove(frame->srcPSN, dcBuff.configBottle.PSN, 6);
frame->dir = dir;
frame->protocol_ver = RS_PROTOCOL_VER;
crc = MODBUS_RTU_CRC16((uint8_t *) frame, frame->len - 2);
((uint8_t *) frame)[frame->len - 2] = crc >> 8;
((uint8_t *) frame)[frame->len - 1] = crc & 0xFF;
printf("\r\nRS send %d bytes:\r\n", frame->len);
for(i = 0; i < frame->len; i++)
printf(" %02X", ((uint8_t *) frame)[i]);
printf("\r\n");
RS485_SendDataByte((uint8_t *) frame, frame->len);
return 1;
}
// 读取真空计数据
void Sensor_ReadVacuum(uint8_t sensorIdx, data_sample_t *sample)
{
Modbus_Open();
// 默认读取失败
sample->vacuum[sensorIdx].staVacuum = VACUUM_STATUS_COMM_FAULT;
sample->vacuum[sensorIdx].lifeVacuum = 0;
sample->vacuum[sensorIdx].vacuum = 0;
sample->vacuum[sensorIdx].rateVacuum = 0;
// 初始化
modbus_sample = sample;
vaccum_idx = sensorIdx;
modbus_idx = 0;
// 发送
modbus.send.id = VACUUM_ID[sensorIdx];
modbus.send.cmd = VACUUM_CMD;
modbus.send.addr = htons(VACUUM_ADDR - 1);
modbus.send.len = htons(VACUUM_LEN);
modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
// 等待中断处理
}
// 读取流量计数据
void Sensor_ReadFlow(data_sample_t *sample)
{
Modbus_Open();
// 默认读取失败
memset(&sample->flow, 0, sizeof(sample->flow));
// 初始化
modbus_sample = sample;
modbus_idx = 0;
// 发送
modbus.send.id = FLOW_ID;
modbus.send.cmd = FLOW_CMD;
modbus.send.addr = htons(FLOW_ADDR);
modbus.send.len = htons(FLOW_LEN);
modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
// 等待中断处理
}
// 读取氧传感器数据
void Sensor_ReadLeakO2(data_sample_t *sample)
{
uint8_t reSample = 0;
LeakO2_Open();
// 默认读取失败
sample->leak.staLeak = LEAK_STATUS_COMM_FAULT;
sample->leak.concentrations = 0;
// 传感器类型
sample->leak.typeLeak = LEAK_TYPE_SWITCH | LEAK_TYPE_CURRENT | LEAK_TYPE_MODBUS;
// 初始化
modbus_sample = sample;
modbus_idx = 0;
// 发送
leak_o2_init_frame(&leakO2);
leakO2.send.addr = LEAK_O2_ID;
leakO2.send.cmd = LEAK_O2_CMD;
leakO2.cs = leak_o2_calcuCS(leakO2.buff + 1, sizeof(leak_o2_comm_t) - 2);
RS485_SendDataByte(leakO2.buff, sizeof(leak_o2_comm_t));
// 等待中断处理
}
// 读取泄漏报警数据
void Sensor_ReadLeak(data_sample_t *sample)
{
uint8_t reSample = 0;
Modbus_Close();
// 默认读取失败
sample->leak.staLeak = LEAK_STATUS_COMM_FAULT;
sample->leak.concentrations = 0;
// 传感器类型
sample->leak.typeLeak = LEAK_TYPE_SWITCH | LEAK_TYPE_CURRENT | LEAK_TYPE_MODBUS;
// 初始化
modbus_sample = sample;
modbus_idx = 0;
// 发送
#if 0
modbus.send.id = LEAK_ID;
modbus.send.cmd = LEAK_CMD;
modbus.send.addr = htons(LEAK_ADDR);
modbus.send.len = htons(LEAK_LEN);
modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
#else
rs_initial_frame(&RS_TranFrame);
RS_TranFrame.cmd = RS_CMD_READ_DATA;
rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
rs_uart_send(&RS_TranFrame, 0x50, RS_DIR_M2S);
#endif
// 等待中断处理
}
// 读取差压/电容数据
void Sensor_ReadDPress(data_sample_t *sample)
{
uint8_t reSample = 0;
Modbus_Close();
// 默认读取失败
sample->staDPress.status = SENSOR_STATUS_NOCONNECT;
sample->adDPress = 0;
sample->diff = 0;
// 初始化
modbus_sample = sample;
modbus_idx = 0;
// 发送
rs_initial_frame(&RS_TranFrame);
RS_TranFrame.cmd = RS_CMD_READ_DATA;
rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
rs_uart_send(&RS_TranFrame, 0x31, RS_DIR_M2S);
// 等待中断处理
}
// 读取压力数据
void Sensor_ReadPress(data_sample_t *sample)
{
uint8_t reSample = 0;
Modbus_Close();
// 默认读取失败
sample->staPress.status = SENSOR_STATUS_NOCONNECT;
sample->adPress = 0;
sample->pressure = 0;
// 初始化
modbus_sample = sample;
modbus_idx = 0;
// 发送
rs_initial_frame(&RS_TranFrame);
RS_TranFrame.cmd = RS_CMD_READ_DATA;
rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
rs_uart_send(&RS_TranFrame, 0x41, RS_DIR_M2S);
// 等待中断处理
}