/* * ACS37800.c * * * Created on: Jun 23, 2023 * Author: IMT */ #include "main.h" #include "stdio.h" #include #include "i2c.h" //#include "udp_echoserver.h" #include "usart.h" #include "LRU_Power_ONOFF.h" #include "lwip/pbuf.h" #include "lwip/udp.h" #include "lwip/tcp.h" #include #include #include "ACS37800.h" #include "LRU_Power_ONOFF.h" #include "udpServerRAW.h" #define TEST_ACS37800 0 #define LIMIT_Volt 30.0 uint8_t UDP_TX_Alive_Buffer[4] = {0x60,0x01,0x03,0x04}; uint8_t UDP_TX_Buffer[6] = {0,}; uint8_t UDP_TX_Voltage_Current_Status[255] = {0,}; uint8_t UDP_RX_Buffer[26] = {0,}; uint8_t CheckSUM = 0; float Volt[127] = {0.0,}; float Amps[127] = {0.0,}; float Watts[127] = {0.0,}; uint8_t ACS37800_ID[127] = {0,}; uint8_t error = 0; //Volatile Registers const uint8_t ACS37800_REGISTER_VOLATILE_20 = 0x20; const uint8_t ACS37800_REGISTER_VOLATILE_21 = 0x21; const uint8_t ACS37800_REGISTER_VOLATILE_22 = 0x22; const uint8_t ACS37800_REGISTER_VOLATILE_25 = 0x25; const uint8_t ACS37800_REGISTER_VOLATILE_26 = 0x26; const uint8_t ACS37800_REGISTER_VOLATILE_27 = 0x27; const uint8_t ACS37800_REGISTER_VOLATILE_28 = 0x28; const uint8_t ACS37800_REGISTER_VOLATILE_29 = 0x29; const uint8_t ACS37800_REGISTER_VOLATILE_2A = 0x2A; const uint8_t ACS37800_REGISTER_VOLATILE_2C = 0x2C; const uint8_t ACS37800_REGISTER_VOLATILE_2D = 0x2D; const uint8_t ACS37800_REGISTER_VOLATILE_2F = 0x2F; const uint8_t ACS37800_REGISTER_VOLATILE_30 = 0x30; //EEPROM Registers const uint8_t ACS37800_REGISTER_EEPROM_0B = 0x0B; const uint8_t ACS37800_REGISTER_EEPROM_0C = 0x0C; const uint8_t ACS37800_REGISTER_EEPROM_0D = 0x0D; const uint8_t ACS37800_REGISTER_EEPROM_0E = 0x0E; const uint8_t ACS37800_REGISTER_EEPROM_0F = 0x0F; //The value of the sense resistor for voltage measurement in Ohms float _senseResistance = ACS37800_DEFAULT_SENSE_RES; //The value of the divider resistance for voltage measurement in Ohms float _dividerResistance = ACS37800_DEFAULT_DIVIDER_RES; //The ACS37800's current sensing range float _currentSensingRange = ACS37800_DEFAULT_CURRENT_RANGE; //The ACS37800's coarse current gain - needed by the current calculations float _currentCoarseGain; //Extract the vcodes. Convert to voltage in Volts. union { int16_t Signed; uint16_t unSigned; } signedUnsigned; // Avoid any ambiguity when casting to signed int // The default I2C Address is 0x60 when DIO_0 and DIO_1 are 0V on start-up const uint8_t ACS37800_DEFAULT_I2C_ADDRESS = 0x60; //Customer Access Code - stored in volatile register 0x2F uint32_t ACS37800_CUSTOMER_ACCESS_CODE = 0x4F70656E; /* * * */ uint8_t Write_ACS37800_I2C(uint32_t* TX, uint8_t Dev_ADD, uint8_t MEM_ADD) // 0906 Test 전 { uint8_t TX_data[4] = {0,}; // memcpy(TX_data,TX,sizeof(uint32_t)); uint32_t data = *TX; TX_data[0] = data & 0xFF; TX_data[1] = (data >> 8) & 0xFF; TX_data[2] = (data >> 16) & 0xFF; TX_data[3] = (data >> 24) & 0xFF; HAL_StatusTypeDef status; do { status = HAL_I2C_Mem_Write(&hi2c1, Dev_ADD, MEM_ADD, I2C_MEMADD_SIZE_16BIT, &TX_data[0], 32,HAL_MAX_DELAY); } while (status == HAL_BUSY); if (status != HAL_OK) { // 전송 실패 처리 return HAL_ERROR; } return error; } /* * * */ uint8_t Read_ACS37800_I2C(uint32_t* RX, uint8_t Dev_ADD, uint8_t MEM_ADD) { uint8_t RX_data[4] = {0}; error = 0; // I2C 통신으로 데이터 읽기 HAL_I2C_Mem_Read(&hi2c1,(uint16_t)Dev_ADD, (uint16_t)MEM_ADD, (uint16_t)I2C_MEMADD_SIZE_16BIT, RX_data, (uint16_t)sizeof(RX_data), (uint32_t)HAL_MAX_DELAY); error = HAL_I2C_GetState(&hi2c1); // 오류 처리 while (error != HAL_OK) { // 오류 처리를 수행하거나 필요한 조치를 취합니다. // 오류 메시지를 출력하거나 로깅하는 등의 작업이 가능합니다. return error; } // 읽은 데이터를 리틀 엔디안에서 32비트로 변환하여 RX에 저장 *RX = (uint32_t)RX_data[0] | ((uint32_t)RX_data[1] << 8) | ((uint32_t)RX_data[2] << 16) | ((uint32_t)RX_data[3] << 24); return ACS37800_SUCCESS; } /* * * */ uint8_t Set_ACS37800_address(uint8_t Dev_ADD, uint8_t New_Dev_ADD) { error = 0; error = Write_ACS37800_I2C(&ACS37800_CUSTOMER_ACCESS_CODE,Dev_ADD,ACS37800_REGISTER_VOLATILE_2F); // Set the customer access code if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("setI2Caddress: writeRegister (2F) returned: %d\r\n",error); #endif return (error); // Bail } ACS37800_REGISTER_0F_t store; error = Read_ACS37800_I2C(&store.data.all,Dev_ADD,ACS37800_REGISTER_EEPROM_0F); if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("setI2Caddress: readRegister (0F) returned: %d\r\n",error); #endif return (error); // Bail } store.data.bits.i2c_slv_addr = New_Dev_ADD & 0x7F; //Update the address store.data.bits.i2c_dis_slv_addr = 1; //Disable setting the address via the DIO pins error = Write_ACS37800_I2C(&store.data.all,Dev_ADD, ACS37800_REGISTER_EEPROM_0F); // Write register 0F if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("setI2Caddress: writeRegister (0F) returned: %d\r\n",error); #endif return (error); // Bail } // delay(100); // Allow time for the shadow/eeprom memory to be updated - otherwise the next readRegister will return zero... // Verify that the address was written correctly error = Read_ACS37800_I2C(&store.data.all,Dev_ADD,ACS37800_REGISTER_EEPROM_0F); if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("setI2Caddress: readRegister (0F) returned: %d\r\n",error); #endif return (error); // Bail } if ((store.data.bits.i2c_slv_addr == New_Dev_ADD) && (store.data.bits.ECC == ACS37800_EEPROM_ECC_NO_ERROR)) { return (ACS37800_SUCCESS); } else { #if TEST_ACS37800 printf("setI2Caddress: i2c_slv_addr is 0x%04X \r\n",store.data.bits.i2c_slv_addr); printf("setI2Caddress: ECC is %d\r\n",store.data.bits.ECC); #endif return (ACS37800_ERR_REGISTER_READ_MODIFY_WRITE_FAILURE); } return (error); } /* * * */ // Read volatile registers 0x2A and 0x2C. Return the vInst (Volts), iInst (Amps) and pInst (VAR). //Dataseat P36 uint8_t Read_ACS37800_Instantaneous(uint8_t Dev_ADD, float *vInst, float *iInst, float *pInst) { error = 0; float volts = 0; float resistorMultiplier = 0; float amps = 0; float power = 0; ACS37800_REGISTER_2A_t store; // Read register 2A error = Read_ACS37800_I2C(&store.data.all,Dev_ADD,ACS37800_REGISTER_VOLATILE_2A); if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("readInstantaneous: readRegister (2A) returned: 0x%04X \r\n", error); #endif return (error); // Bail } //Extract vcodes as signed int //vcodes as actually int16_t but is stored in a uint32_t as a 16-bit bitfield signedUnsigned.unSigned = store.data.bits.vcodes; volts = (float)signedUnsigned.Signed; #if TEST_ACS37800 printf("readInstantaneous: vcodes: 0x%04X \r\n", signedUnsigned.unSigned); printf("readInstantaneous: volts (LSB, before correction) is %.2f \r\n", volts); #endif // Datasheet says "Voltage Channel ADC Sensitivity: 110 LSB/mV" volts /= 27500.0; //Convert from codes to the fraction of ADC Full Scale volts *= 250; //Convert to mV (Differential Input Range is +/- 250mV) volts /= 1000; //Convert to Volts //Correct for the voltage divider: (RISO1 + RISO2 + RSENSE) / RSENSE //Or: (RISO1 + RISO2 + RISO3 + RISO4 + RSENSE) / RSENSE // P20 resistorMultiplier = (_dividerResistance + _senseResistance) / _senseResistance; volts *= resistorMultiplier; #if TEST_ACS37800 printf("readInstantaneous: volts (V, after correction) is %.2f \r\n", volts); #endif *vInst = volts; /////////////////////////////////////Current/////////////////////////////////////// signedUnsigned.unSigned = store.data.bits.icodes; //Extract icodes as signed int amps = (float)signedUnsigned.Signed; #if TEST_ACS37800 printf("readRMS: irms: 0x%04X \r\n", signedUnsigned.unSigned); printf("readRMS: amps (LSB, before correction) is%.2f \r\n", amps); #endif amps /= 27500.0; //Convert from codes to the fraction of ADC Full Scale amps *= _currentSensingRange; //Convert to Amps #if TEST_ACS37800 printf("readInstantaneous: amps (A, after correction) is %.2f \r\n", amps); #endif *iInst = amps; /////////////////////////////////////Power/////////////////////////////////////// ACS37800_REGISTER_2C_t pstore; error = Read_ACS37800_I2C(&pstore.data.all,Dev_ADD, ACS37800_REGISTER_VOLATILE_2C); // Read register 2C if (error != ACS37800_SUCCESS) { #if TEST_ACS37800 printf("readInstantaneous: readRegister (2C) returned: %d \r\n", error); #endif return (error); // Bail } //Extract pinstant as signed int. Convert to W //pinstant as actually int16_t but is stored in a uint32_t as a 16-bit bitfield signedUnsigned.unSigned = pstore.data.bits.pinstant; power = (float)signedUnsigned.Signed; #if TEST_ACS37800 printf("readInstantaneous: readRegister (2C) returned: %d \r\n", error); #endif float LSBpermW = 3.08; // LSB per mW LSBpermW *= 30.0 / _currentSensingRange; // Correct for sensor version power /= LSBpermW; //Convert from codes to mW //Correct for the voltage divider: (RISO1 + RISO2 + RSENSE) / RSENSE //Or: (RISO1 + RISO2 + RISO3 + RISO4 + RSENSE) / RSENSE power *= resistorMultiplier; power /= 1000; // Convert from mW to W *pInst = power; return(error); } //Change the value of the sense resistor (Ohms) void Set_ACS37800_SenseRes(float newRes) { _senseResistance = newRes; } //Change the value of the sense resistor (Ohms) void Set_ACS37800_DividerRes(float newRes) { _dividerResistance = newRes; } //Change the current-sensing range (Amps) //ACS37800KMACTR-030B3-I2C is a 30.0 Amp part - as used on the SparkFun Qwiic Power Meter //ACS37800KMACTR-090B3-I2C is a 90.0 Amp part void Set_ACS37800_CurrentRange(float newCurrent) { _currentSensingRange = newCurrent; } void Set_ACS37800_VoltCurrent_Buffer(void) { for(int ID = 0; ID < 31; ID++ ) { Read_ACS37800_Instantaneous(ID,&Volt[ID], &Amps[ID] ,&Watts[ID]); // 전류 전압 측정 memcpy(&UDP_TX_Voltage_Current_Status[(ID*8)+5],&Volt[ID],4); memcpy(&UDP_TX_Voltage_Current_Status[(ID*8)+9],&Amps[ID],4); } } void SEND_ACS37800_VoltCurrent_STATUS(uint8_t* Volt_Current_Status) { // struct pbuf *TIME_txBuf = NULL; // struct udp_pcb *upcb = NULL ; UDP_TX_Voltage_Current_Status[0] = TX_STX; UDP_TX_Voltage_Current_Status[1] = TX_Main_CMD; UDP_TX_Voltage_Current_Status[2] = Sub_Response_VoltCurrent; UDP_TX_Voltage_Current_Status[3] = 0x00; UDP_TX_Voltage_Current_Status[4] = Sub_Response_VoltCurrent_LEN; UDP_TX_Voltage_Current_Status[254] = TX_calculateChecksum(UDP_TX_Voltage_Current_Status, 255); /* copy data to pbuf */ // pbuf_take(TIME_txBuf, UDP_TX_Voltage_Current_Status, 9); // udp_send(upcb, TIME_txBuf); // udp_send_data(UDP_TX_Voltage_Current_Status,255); } /* * 50ms */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // struct pbuf *TIME_txBuf = NULL; // struct udp_pcb *upcb = NULL ; if(htim->Instance==TIM6) //50ms { #if 0 SEND_ACS37800_VoltCurrent_STATUS(ACS37800_ID[ID] , Volt[ID] , Amps[ID]); // 전압 전류 현 상태 전송 if(Volt[ID] >= LIMIT_Volt) //41 30V 이상일경우 { //Relay Turn OFF if(ID <= 16) { GPIOE->ODR &= ~(0x01 << ID); // SW_GATE_01 ~ 16 UDP_TX_Buffer[3] = Switch_Status_01; UDP_TX_Buffer[4] = GPIOE->ODR & 0x00FF; UDP_TX_Buffer[5] = (GPIOE->ODR & 0xFF00) >> 8; /* copy data to pbuf */ pbuf_take(TIME_txBuf, UDP_TX_Buffer, 6); /* Tell the client that we have accepted it */ udp_send(upcb, TIME_txBuf); } else if(ID > 16 || ID <= 32) { GPIOF->ODR &= ~(0x01 << (ID-16)); // SW_GATE_17 ~ 32 UDP_TX_Buffer[3] = Switch_Status_02; UDP_TX_Buffer[4] = GPIOE->ODR & 0x00FF; UDP_TX_Buffer[5] = (GPIOE->ODR & 0xFF00) >> 8; /* copy data to pbuf */ pbuf_take(TIME_txBuf, UDP_TX_Buffer, 6); /* Tell the client that we have accepted it */ udp_send(upcb, TIME_txBuf); } else if(ID > 32 || ID <= 41) { GPIOG->ODR &= ~(0x01 << (ID-32)); // SW_GATE_33 ~ 41 UDP_TX_Buffer[3] = Switch_Status_03; UDP_TX_Buffer[4] = GPIOE->ODR & 0x00FF; UDP_TX_Buffer[5] = (GPIOE->ODR & 0xFF00) >> 8; /* copy data to pbuf */ pbuf_take(TIME_txBuf, UDP_TX_Buffer, 6); /* Tell the client that we have accepted it */ udp_send(upcb, TIME_txBuf); } else ; } else ; printf("%d_ Volt: %.2f,Amps: %.2f, Watts : %.2f\r\n",ID,Volt, Amps, Watts ); #endif } else if(htim->Instance==TIM13) /*01 Second*/ { printf(".\r\n"); } else ; } void userDelay(uint32_t milsecond) { uint32_t one_ms = 11429; for(uint64_t i=0; i