/* ********************************************************************************************************* * 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]; }