/* ********************************************************************************************************* * 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 RS485_EN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_2); //#define RS485_DIS() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_2); // 读取超时计数 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 // 泄露报警控制器读取寄存器个数 const uint8_t FLOW_ID = 4; // 流量计通信地址 #ifndef _SMARC_FLOWMETER_ #define FLOW_CMD 3 // 流量计读取命令 #define FLOW_ADDR 0 // 流量计起始寄存器地址 #define FLOW_LEN 15 // 流量计读取寄存器个数 #else #define FLOW_CMD 3 // 流量计读取命令 #define FLOW_ADDR 4068 // 流量计起始寄存器地址 #define FLOW_LEN 12 // 流量计读取寄存器个数 #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; }; 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 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; 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)提供,用于对读出的真空值进行修正 // 本函数只适用于规管量程为-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(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); } #ifndef _SMARC_FLOWMETER_ 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); } #else 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); } #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); // 等待中断处理 }