/********************************************************************\ Name: weather_station.c Created by: Stefan Ritt Contents: Application specific (user) part of Midas Slow Control Bus protocol for Mu3e Weather Station \********************************************************************/ #include #include // for atof() #include #include #include "mscbemb.h" extern bit FREEZE_MODE; extern bit DEBUG_MODE; char code node_name[] = "WStation"; /* declare number of sub-addresses to framework */ unsigned char idata _n_sub_addr = 1; bit flush_flag; sbit SCK = P0^0; // Serial Clock (output) sbit MISO = P0^1; // Master In / Slave Out (input) sbit MOSI = P0^2; // Master Out / Slave In (output) sbit NCS_DAC = P0^3; // /CS DAC sbit NHV_ENABLE = P0^7; sbit NCS_ADC = P1^3; // /CS HV ADC // delay for opto-coupler in microseconds #define OPT_DELAY 1 // For mode 1, the first 8 channels are only T sensors, and the next 8 adc channels are reserved for standard sensor stations #define TSENSOR_MODE 1 /*---- Define variable parameters returned to CMD_GET_INFO command ----*/ /* data buffer (mirrored in EEPROM) */ struct { float adc[16]; } xdata user_data; #if TSENSOR_MODE == 1 MSCB_INFO_VAR code vars[] = { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T1", &user_data.adc[0], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T2", &user_data.adc[1], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T3", &user_data.adc[2], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T4", &user_data.adc[3], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T5", &user_data.adc[4], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T6", &user_data.adc[5], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T7", &user_data.adc[6], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T8", &user_data.adc[7], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P2T0", &user_data.adc[8], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P2T1", &user_data.adc[9], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P2RH", &user_data.adc[10], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P2O2", &user_data.adc[11], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P3T0", &user_data.adc[12], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P3T1", &user_data.adc[13], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P3RH", &user_data.adc[14], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P3O2", &user_data.adc[15], 0 }; #else MSCB_INFO_VAR code vars[] = { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T1", &user_data.adc[0], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P0T2", &user_data.adc[1], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P0RH", &user_data.adc[2], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P0O2", &user_data.adc[3], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T0", &user_data.adc[4], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P1T1", &user_data.adc[5], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P1RH", &user_data.adc[6], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P1O2", &user_data.adc[7], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P2T0", &user_data.adc[8], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P2T1", &user_data.adc[9], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P2RH", &user_data.adc[10], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P2O2", &user_data.adc[11], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P3T0", &user_data.adc[12], 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "P3T1", &user_data.adc[13], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P3RH", &user_data.adc[14], 4, UNIT_PERCENT, 0, 0, MSCBF_FLOAT, "P3O2", &user_data.adc[15], 0 }; #endif MSCB_INFO_VAR *variables = vars; /********************************************************************\ Application specific init and inout/output routines \********************************************************************/ void user_write(unsigned char index) reentrant; void write_gain(void); void set_hv(float value); /*---- User init function ------------------------------------------*/ extern SYS_INFO idata sys_info; void user_init(unsigned char init) { if (init); SFRPAGE = LEGACY_PAGE; P0MDOUT = 0x5D; // SCLK, MOSI, CS_DAC, DI, DE_RE push-pull P1MDOUT = 0xFF; } /*---- User write function -----------------------------------------*/ #pragma NOAREGS void user_write(unsigned char index) reentrant { if (index); } /*---- User read function ------------------------------------------*/ unsigned char user_read(unsigned char index) { if (index == 0); return 0; } /*---- User function called vid CMD_USER command -------------------*/ unsigned char user_func(unsigned char *data_in, unsigned char *data_out) { /* echo input data */ data_out[0] = data_in[0]; data_out[1] = data_in[1]; return 2; } /*---- ADC functions ------------------------------------------------*/ unsigned char read_adc() { static unsigned char channel = 0; unsigned char i, cmd, nc; long d; float f; static unsigned int last = 0; unsigned char overflow_flag = 0; // only measure once every 200 ms if (time() < last+20) return 0; last = time(); SCK = 0; MOSI = 1; NCS_ADC = 0; // chip select delay_us(OPT_DELAY); watchdog_refresh(1); if (MISO == 1) { // check /EOC NCS_ADC = 1; // remove chip select delay_us(OPT_DELAY); return 0; } nc = (channel + 1) % 16; cmd = 0xB0 | ((nc & 0x01) << 3) | (nc >> 1); MOSI = (cmd & 0x80) > 0 ? 1 : 0; cmd <<= 1; for (i=0,d=0 ; i<24 ; i++) { delay_us(OPT_DELAY); SCK = 1; d = (d << 1) | MISO; delay_us(OPT_DELAY); SCK = 0; MOSI = (cmd & 0x80) > 0 ? 1 : 0; cmd <<= 1; } SCK = 1; MOSI = 1; NCS_ADC = 1; // remove CS if ((d >> 20) == 0x03) { f = 1.25; overflow_flag = 1; } else if ((d >> 20) == 0x00) { f = -1.25; overflow_flag = 1; } else if ((d >> 21) == 0x01) { d = d & 0x000FFFFF; f = d; f = f / (1l<<20) * 1.25; } else { d = (d | 0xFFF00000); f = d; f = f / (1l<<20) * 1.25; } // convert to current in uA, 2k5 shunt f = f / 2500 * 1E6; // RH calibration // I at 0%: 969 uA , I at 100%: 57.6 uA #if TSENSOR_MODE == 1 if (channel % 4 == 0 || channel % 4 == 1 || channel < 8) { f = f - 273.2; // AD592 1uA / K if (f < -100) f = -100; } else if (channel %4 == 2) { f = 100 + (f - 57.6)*( (0.0 -100.0)/(969-57.6) ); // HIH-4010, if (f > 100) f = -100; } else { f = (f - 200) / 200 * 100; // O2-A2, 200-400 uA range if (f < 0 || f > 30) f = -100; } #else if (channel % 4 == 0 || channel % 4 == 1 ) { f = f - 273.2; // AD592 1uA / K if (f < -100) f = -100; } else if (channel %4 == 2) { f = 100 + (f - 57.6)*( (0.0 -100.0)/(969-57.6) ); // HIH-4010, if (f > 100) f = -100; } else { f = (f - 200) / 200 * 100; // O2-A2, 200-400 uA range if (f < 0) f = -100; } #endif // round to three digits f = floor(f * 1000 + 0.5) / 1000; // check overflow flag, and don't set sensible values if so if(overflow_flag==1) f=-101; // channels are in reverse order user_data.adc[channel] = f; // increment channel channel = (channel + 1) % 16; return 1; } /*---- User loop function ------------------------------------------*/ void user_loop(void) { read_adc(); }