1009 lines
27 KiB
C
1009 lines
27 KiB
C
/*
|
||
*********************************************************************************************************
|
||
* IAR Development Kits
|
||
* on the
|
||
*
|
||
* M451
|
||
*
|
||
* Filename : spi_adc.c
|
||
* Version : V1.00
|
||
* Programmer(s) : Qian Xianghong
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#include "includes.h"
|
||
|
||
// 默认为斯达易思的流量计
|
||
//
|
||
// 是否SMAR C的流量计
|
||
//#define _SMARC_FLOWMETER_
|
||
// 是否天信流量计(MODBUS/A4协议)
|
||
//#define _TIANCYA4_FLOWMETER_
|
||
|
||
// 定义中断处理的回到函数
|
||
typedef void (*RS485_Read_CallBack)(uint8_t c);
|
||
RS485_Read_CallBack RS485_Read = NULL;
|
||
|
||
#define RS485_EN PC7
|
||
|
||
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 // 泄露报警控制器读取寄存器个数
|
||
|
||
const uint8_t FLOW_ID = 4; // 流量计通信地址
|
||
#if defined(_SMARC_FLOWMETER_)
|
||
#define FLOW_CMD 3 // 流量计读取命令
|
||
#define FLOW_ADDR 4068 // 流量计起始寄存器地址
|
||
#define FLOW_LEN 12 // 流量计读取寄存器个数
|
||
#elif defined(_TIANCYA4_FLOWMETER_)
|
||
#define FLOW_CMD 3 // 流量计读取命令
|
||
#define FLOW_ADDR 0 // 流量计起始寄存器地址
|
||
#define FLOW_LEN 12 // 流量计读取寄存器个数
|
||
#else
|
||
#define FLOW_CMD 3 // 流量计读取命令
|
||
#define FLOW_ADDR 0 // 流量计起始寄存器地址
|
||
#define FLOW_LEN 15 // 流量计读取寄存器个数
|
||
#endif
|
||
|
||
#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;
|
||
|
||
// 天信流量计数据(Modbus/A4通信协议)
|
||
struct
|
||
{
|
||
double nM3; // 标况体积
|
||
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型接收
|
||
} flow_TancyA4;
|
||
};
|
||
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;
|
||
|
||
// 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 crc(RS_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;
|
||
|
||
// MODBUS的CRC算法
|
||
uint16_t MODBUS_RTU_CRC16(const uint8_t *puchMsg, uint16_t usDataLen)
|
||
{
|
||
uint16_t crc = 0xFFFF;
|
||
uint8_t i;
|
||
while (usDataLen--) // 传输消息缓冲区
|
||
{
|
||
crc ^= *puchMsg++;
|
||
for(i = 0; i < 8; i++)
|
||
{
|
||
if(crc & 0x0001)
|
||
{
|
||
crc >>= 1;
|
||
crc ^= 0xA001;
|
||
}
|
||
else
|
||
{
|
||
crc >>= 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 交换高低字节顺序
|
||
return ((crc & 0xFF) << 8) | ((crc >> 8) & 0xFF);
|
||
}
|
||
|
||
// 将十进制转换成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');
|
||
}
|
||
}
|
||
|
||
// 本函数由规管设计者(Zhang Jm)提供,用于对读出的真空值进行修正
|
||
// 本函数只适用于规管量程为-2(0.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(uint8_t c)
|
||
{
|
||
uint8_t i;
|
||
uint32_t reversed;
|
||
int32_t i_reversed;
|
||
float f;
|
||
uint8_t d_reversed[8];
|
||
double d;
|
||
|
||
/* 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;
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
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.11.03)
|
||
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));
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
#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");
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
#elif defined(_TIANCYA4_FLOWMETER_)
|
||
else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD
|
||
&& modbus.recv.header.len == sizeof(modbus.recv.flow_TancyA4)
|
||
&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_TancyA4) + 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");
|
||
|
||
// 标况体积总量: double型, 先颠倒顺序
|
||
memmove(d_reversed, &modbus.recv.flow_TancyA4.nM3, 8);
|
||
i = d_reversed[0];
|
||
d_reversed[0] = d_reversed[7];
|
||
d_reversed[7] = i;
|
||
i = d_reversed[1];
|
||
d_reversed[1] = d_reversed[6];
|
||
d_reversed[6] = i;
|
||
i = d_reversed[2];
|
||
d_reversed[2] = d_reversed[5];
|
||
d_reversed[5] = i;
|
||
i = d_reversed[3];
|
||
d_reversed[3] = d_reversed[4];
|
||
d_reversed[4] = i;
|
||
memmove(&d, &d_reversed, 8);
|
||
// 整数部分
|
||
reversed = (uint32_t) d;
|
||
dec2bcd(reversed, modbus_sample->flow.nM3, 5);
|
||
// 小数部分
|
||
reversed = (uint32_t) ((d - reversed) * 100);
|
||
dec2bcd(reversed, modbus_sample->flow.nM3 + 5, 1);
|
||
|
||
// 标况流量
|
||
reversed = ntohl(modbus.recv.flow_TancyA4.nM3_h);
|
||
memmove(&f, &reversed, 4);
|
||
reversed = f * 100;
|
||
dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
|
||
// 工况流量
|
||
reversed = ntohl(modbus.recv.flow_TancyA4.M3_h);
|
||
memmove(&f, &reversed, 4);
|
||
reversed = f * 100;
|
||
dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
|
||
// 温度
|
||
reversed = ntohl(modbus.recv.flow_TancyA4.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_TancyA4.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");
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
#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");
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
// 物理层校验
|
||
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(uint8_t c)
|
||
{
|
||
uint8_t *RS_ModuleData = (uint8_t *) &RS_TranFrame;
|
||
uint16_t i;
|
||
uint8_t frameOk, frameErr;
|
||
|
||
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((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;
|
||
}
|
||
}
|
||
|
||
NVIC_SetPendingIRQ(TMR1_IRQn);
|
||
}
|
||
}
|
||
|
||
// 继续寻找下一帧
|
||
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 SC0_IRQHandler(void)
|
||
{
|
||
uint8_t c;
|
||
|
||
// 接收中断
|
||
if(SCUART_GET_INT_FLAG(SC0, SC_ISR_RDA_IS_Msk) || SCUART_GET_INT_FLAG(SC0, SC_ISR_RTMR_IS_Msk)) /* Rx Ready or Time-out INT*/
|
||
{
|
||
c = SC0->RBR;
|
||
//printf("<%02X>", c);
|
||
if(RS485_Read != NULL)
|
||
RS485_Read(c);
|
||
}
|
||
// 错误中断
|
||
if(SCUART_GET_INT_FLAG(SC0, SC_ISR_TERR_IS_Msk))
|
||
{
|
||
SCUART_CLR_INT_FLAG(SC0, SC_ISR_TERR_IS_Msk);
|
||
}
|
||
}
|
||
|
||
void Sensor_Init()
|
||
{
|
||
/* Select SC UART module clock source as HXT and UART module clock divider as 1 */
|
||
CLK_SetModuleClock(SC0_MODULE, CLK_CLKSEL2_SC_S_HXT, CLK_SC0_CLK_DIVIDER(1));
|
||
|
||
/* Set PA.8 and PA.9 pin for SC UART mode */
|
||
SYS->PA_H_MFP &= ~(SYS_PA_H_MFP_PA8_MFP_Msk | SYS_PA_H_MFP_PA9_MFP_Msk);
|
||
SYS->PA_H_MFP |= (SYS_PA_H_MFP_PA8_MFP_SC0_CLK | SYS_PA_H_MFP_PA9_MFP_SC0_DAT);
|
||
GPIO_ENABLE_PULL_UP(PA, BIT9);
|
||
|
||
/* Enable SC UART module clock */
|
||
CLK_EnableModuleClock(SC0_MODULE);
|
||
|
||
SYS->PC_L_MFP &= ~SYS_PC_L_MFP_PC7_MFP_Msk;
|
||
SYS->PC_L_MFP |= SYS_PC_L_MFP_PC7_MFP_GPC7;
|
||
GPIO_SetMode(PC, 1 << 7, GPIO_PMD_OUTPUT);
|
||
RS485_EN = 0;
|
||
}
|
||
|
||
void Sensor_Open()
|
||
{
|
||
SCUART_Open(SC0, 9600);
|
||
SCUART_ENABLE_INT(SC0, (SC_IER_RDA_IE_Msk)); // | SC_IER_RTMR_IE_Msk));// | SC_IER_TERR_IE_Msk));
|
||
NVIC_SetPriority(SC0_IRQn, 1);
|
||
NVIC_EnableIRQ(SC0_IRQn);
|
||
}
|
||
|
||
static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
|
||
{
|
||
RS485_EN = 1;
|
||
delay_us(1);
|
||
/* Send data */
|
||
SCUART_Write(SC0, pu8TxBuf, u32WriteBytes);
|
||
delay_ms(6); // 至少5ms,保险起见6ms
|
||
RS485_EN = 0;
|
||
}
|
||
|
||
// 物理层发送
|
||
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)
|
||
{
|
||
// 设置中断回调函数
|
||
RS485_Read = Modbus_Read;
|
||
// 修改波特率
|
||
SCUART_Open(SC0, 9600);
|
||
|
||
// 默认读取失败
|
||
sample->vacuum[sensorIdx].staVacuum = VACUUM_STATUS_COMM_FAULT;
|
||
sample->vacuum[sensorIdx].lifeVacuum = 0;
|
||
sample->vacuum[sensorIdx].vacuum = 0;
|
||
sample->vacuum[sensorIdx].rateVacuum = 0;
|
||
|
||
/* Flush FIFO */
|
||
while(SCUART_GET_RX_EMPTY(SC0) == 0)
|
||
{
|
||
SCUART_READ(SC0);
|
||
}
|
||
|
||
// 初始化
|
||
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)
|
||
{
|
||
// 设置中断回调函数
|
||
RS485_Read = Modbus_Read;
|
||
// 修改波特率
|
||
SCUART_Open(SC0, 9600);
|
||
|
||
// 默认读取失败
|
||
memset(&sample->flow, 0, sizeof(sample->flow));
|
||
|
||
/* Flush FIFO */
|
||
while(SCUART_GET_RX_EMPTY(SC0) == 0)
|
||
{
|
||
SCUART_READ(SC0);
|
||
}
|
||
|
||
// 初始化
|
||
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_ReadLeak(data_sample_t *sample)
|
||
{
|
||
uint8_t reSample = 0;
|
||
|
||
#if 0
|
||
// 设置中断回调函数
|
||
RS485_Read = Modbus_Read;
|
||
// 修改波特率
|
||
SCUART_Open(SC0, 9600);
|
||
#else
|
||
// 设置中断回调函数
|
||
RS485_Read = RS_ParseFrame;
|
||
// 修改波特率
|
||
SCUART_Open(SC0, 19200);
|
||
#endif
|
||
|
||
// 默认读取失败
|
||
sample->leak.staLeak = LEAK_STATUS_COMM_FAULT;
|
||
sample->leak.concentrations = 0;
|
||
// 传感器类型
|
||
sample->leak.typeLeak = LEAK_TYPE_SWITCH | LEAK_TYPE_CURRENT | LEAK_TYPE_MODBUS;
|
||
|
||
/* Flush FIFO */
|
||
while(SCUART_GET_RX_EMPTY(SC0) == 0)
|
||
{
|
||
SCUART_READ(SC0);
|
||
}
|
||
|
||
// 初始化
|
||
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
|
||
|
||
// 等待中断处理
|
||
}
|
||
|
||
uint32_t Sensor_ReadDOL()
|
||
{
|
||
uint8_t buf[14];
|
||
uint8_t c, i;
|
||
uint8_t idx = 0;
|
||
int16_t fld;
|
||
uint32_t adc[20] = {-1};
|
||
uint8_t cnt = 0;
|
||
uint32_t tick = GetDelayTick(1000);
|
||
|
||
// 禁止中断
|
||
NVIC_DisableIRQ(UART0_IRQn);
|
||
// 将串口更改为19200bps
|
||
UART_Open(UART0, 19200);
|
||
|
||
while(!IsTickOut(tick))
|
||
{
|
||
if(UART_GET_INT_FLAG(UART0, UART_ISR_BUF_ERR_IS_Msk)) /* Buffer Error INT */
|
||
{
|
||
UART_ClearIntFlag(UART0, UART_ISR_BUF_ERR_IS_Msk);
|
||
}
|
||
if(UART_GET_INT_FLAG(UART0, UART_ISR_RLS_IS_Msk)) /* RLS INT */
|
||
{
|
||
UART_ClearIntFlag(UART0, UART_ISR_RLS_IS_Msk);
|
||
}
|
||
|
||
// 解析DOL传感器的TTL数据:每13个字节为一帧,以0x35开头。
|
||
// 由于不知道帧校验方式,所以将检测连续2个帧头(一头一尾)且第10个字节为0x81,作为合法帧的标准
|
||
if(UART_GET_INT_FLAG(UART0, UART_ISR_RDA_IS_Msk) || UART_GET_INT_FLAG(UART0, UART_ISR_RTO_IS_Msk))
|
||
{
|
||
c = UART0->RBR;
|
||
|
||
// 定位第1个帧头
|
||
if(idx == 0 && c != 0x35)
|
||
continue;
|
||
|
||
buf[idx++] = c;
|
||
|
||
// 检查第2个帧头,确保收到正确的一帧
|
||
if(idx == 14 && (buf[13] != 0x35 || buf[10] != 0x81))
|
||
{
|
||
// 查找有没有中间的帧头
|
||
for(i = 1; i < idx; i++)
|
||
{
|
||
if(buf[i] == 0x35)
|
||
break;
|
||
}
|
||
|
||
// 如果没有找到,则i等于idx,idx将变为0
|
||
idx -= i;
|
||
memmove(buf, buf + i, idx);
|
||
}
|
||
|
||
// 收到一帧
|
||
if(idx == 14)
|
||
{
|
||
// 取第2~3字节组成的有符号整数,除以系数27.3,即为英寸水柱的值
|
||
memmove(&fld, buf + 2, 2);
|
||
if(fld < 0)
|
||
adc[cnt] = 0;
|
||
else
|
||
adc[cnt] = fld;
|
||
|
||
// 收够20帧
|
||
if(++cnt == 20)
|
||
{
|
||
// 排序以后取中间10帧的平均值
|
||
sort(adc, cnt);
|
||
adc[0] = 0;
|
||
for(i = 5; i < 15; i++)
|
||
adc[0] += adc[i];
|
||
adc[0] /= 10;
|
||
break;
|
||
}
|
||
|
||
// 准备接收下一帧,将当前帧头用起来
|
||
idx = 0;
|
||
buf[idx++] = c;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 恢复中断
|
||
UART_Open(UART0, 115200ul);
|
||
NVIC_EnableIRQ(UART0_IRQn);
|
||
|
||
return adc[0];
|
||
}
|