/** * @file MDC04_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2026 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief functions of MDC04 sensor for all embedded device * * @version * - 1_00_250101 > ATY * -# Initial version, support OneWire and I2C modes ******************************************************************************** */ #ifndef __MDC04_ATY_C #define __MDC04_ATY_C #include "MDC04_ATY.h" /******************************* For user *************************************/ /******************************************************************************/ /** * @brief Initialize MDC04 device * * @param dev device structure pointer * @return uint8_t status code * @note Initialize device and check presence */ uint8_t MDC04_Init(struct MDC04_ATY_Dev *dev) { __ATY_LOCK(dev); if (dev == NULL) { __ATY_UNLOCK(dev); return MDC04_STATUS_ERROR; } // Initialize device parameters dev->devicePresent = 0; dev->temperature = 0.0f; dev->rawTemperature = 0; dev->initialized = 1; // Set initialization flag dev->conversionTime = 750; // Default conversion time 750ms // Clear ROM code for (uint8_t i = 0; i < 8; i++) { dev->romCode[i] = 0; } // Set default I2C address if not set if (dev->mode == MDC04_MODE_I2C && dev->i2cAddress == 0) { dev->i2cAddress = MDC04_I2C_ADDR_DEFAULT; } // Check device presence uint8_t status = MDC04_Reset(dev); if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 Init: Mode=%d, Status=%d", dev->mode, status); } dev->lastStatus = status; __ATY_UNLOCK(dev); return status; } /** * @brief Reset MDC04 device * * @param dev device structure pointer * @return uint8_t status code * @note Reset device and check presence pulse */ uint8_t MDC04_Reset(struct MDC04_ATY_Dev *dev) { if (dev == NULL) return MDC04_STATUS_ERROR; if (dev->mode == MDC04_MODE_ONEWIRE) { // OneWire reset sequence if (dev->oneWireSetLow == NULL || dev->oneWireSetHigh == NULL || dev->oneWireRead == NULL || dev->delayUs == NULL) { return MDC04_STATUS_ERROR; } // Pull line low for reset pulse dev->oneWireSetLow(); dev->delayUs(MDC04_RESET_PULSE_TIME); // Release line and wait for presence pulse dev->oneWireSetHigh(); dev->delayUs(MDC04_PRESENCE_WAIT_TIME); // Check for presence pulse (line should be low) uint8_t presence = dev->oneWireRead(); dev->delayUs(MDC04_PRESENCE_PULSE_TIME); dev->devicePresent = (presence == 0) ? 1 : 0; if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 OneWire Reset: Presence=%d", dev->devicePresent); } return dev->devicePresent ? MDC04_STATUS_OK : MDC04_STATUS_NO_DEVICE; } else if (dev->mode == MDC04_MODE_I2C) { // I2C device detection if (dev->i2cStart == NULL || dev->i2cStop == NULL || dev->i2cWriteByte == NULL) { return MDC04_STATUS_ERROR; } uint8_t status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte(dev->i2cAddress << 1); // Write address dev->i2cStop(); dev->devicePresent = (status == 0) ? 1 : 0; if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 I2C Reset: Address=0x%02X, Present=%d", dev->i2cAddress, dev->devicePresent); } return dev->devicePresent ? MDC04_STATUS_OK : MDC04_STATUS_NO_DEVICE; } return MDC04_STATUS_ERROR; } /** * @brief Start temperature conversion * * @param dev device structure pointer * @return uint8_t status code * @note Start temperature conversion process */ uint8_t MDC04_StartConversion(struct MDC04_ATY_Dev *dev) { if (dev == NULL) { return MDC04_STATUS_ERROR; } // Auto-initialize if not initialized if (!dev->initialized) { uint8_t initStatus = MDC04_Init(dev); if (initStatus != MDC04_STATUS_OK) { return initStatus; } } if (!dev->devicePresent) { return MDC04_STATUS_NO_DEVICE; } __ATY_LOCK(dev); if (dev->mode == MDC04_MODE_ONEWIRE) { // Reset and skip ROM if (MDC04_Reset(dev) != MDC04_STATUS_OK) { __ATY_UNLOCK(dev); return MDC04_STATUS_NO_DEVICE; } MDC04_OneWire_WriteByte(dev, MDC04_CMD_SKIP_ROM); MDC04_OneWire_WriteByte(dev, MDC04_CMD_READ_TEMP); if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 OneWire: Conversion started"); } } else if (dev->mode == MDC04_MODE_I2C) { // I2C start conversion command uint8_t status = MDC04_I2C_WriteRegister(dev, 0x01, MDC04_CMD_READ_TEMP); if (status != MDC04_STATUS_OK) { __ATY_UNLOCK(dev); return status; } if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 I2C: Conversion started"); } } __ATY_UNLOCK(dev); return MDC04_STATUS_OK; } /** * @brief Read temperature from MDC04 * * @param dev device structure pointer * @return uint8_t status code * @note Read temperature data and convert to Celsius */ uint8_t MDC04_ReadTemperature(struct MDC04_ATY_Dev *dev) { if (dev == NULL) { return MDC04_STATUS_ERROR; } // Auto-initialize if not initialized if (!dev->initialized) { uint8_t initStatus = MDC04_Init(dev); if (initStatus != MDC04_STATUS_OK) { return initStatus; } } if (!dev->devicePresent) { return MDC04_STATUS_NO_DEVICE; } __ATY_LOCK(dev); uint8_t data[9]; uint8_t status = MDC04_STATUS_OK; if (dev->mode == MDC04_MODE_ONEWIRE) { // Reset and skip ROM if (MDC04_Reset(dev) != MDC04_STATUS_OK) { __ATY_UNLOCK(dev); return MDC04_STATUS_NO_DEVICE; } MDC04_OneWire_WriteByte(dev, MDC04_CMD_SKIP_ROM); MDC04_OneWire_WriteByte(dev, 0xBE); // Read scratchpad // Read 9 bytes of data for (uint8_t i = 0; i < 9; i++) { data[i] = MDC04_OneWire_ReadByte(dev); } // Verify CRC uint8_t crc = MDC04_OneWire_CRC8(data, 8); if (crc != data[8]) { status = MDC04_STATUS_CRC_ERROR; if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 OneWire: CRC Error, calc=0x%02X, recv=0x%02X", crc, data[8]); } } else { // Extract temperature data dev->rawTemperature = (data[1] << 8) | data[0]; dev->temperature = MDC04_ConvertRawToTemperature(dev->rawTemperature); if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 OneWire: Temp=%.2f°C, Raw=0x%04X", dev->temperature, dev->rawTemperature); } } } else if (dev->mode == MDC04_MODE_I2C) { // Read temperature registers uint8_t tempData[2]; status = MDC04_I2C_ReadMultiple(dev, 0x00, tempData, 2); if (status == MDC04_STATUS_OK) { dev->rawTemperature = (tempData[0] << 8) | tempData[1]; dev->temperature = MDC04_ConvertRawToTemperature(dev->rawTemperature); if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 I2C: Temp=%.2f°C, Raw=0x%04X", dev->temperature, dev->rawTemperature); } } } dev->lastStatus = status; __ATY_UNLOCK(dev); return status; } /** * @brief Read ROM code (OneWire mode only) * * @param dev device structure pointer * @return uint8_t status code * @note Read 64-bit ROM code from device */ uint8_t MDC04_ReadROM(struct MDC04_ATY_Dev *dev) { if (dev == NULL || dev->mode != MDC04_MODE_ONEWIRE) { return MDC04_STATUS_ERROR; } // Auto-initialize if not initialized if (!dev->initialized) { uint8_t initStatus = MDC04_Init(dev); if (initStatus != MDC04_STATUS_OK) { return initStatus; } } __ATY_LOCK(dev); // Reset device if (MDC04_Reset(dev) != MDC04_STATUS_OK) { __ATY_UNLOCK(dev); return MDC04_STATUS_NO_DEVICE; } // Send Read ROM command MDC04_OneWire_WriteByte(dev, MDC04_CMD_READ_ROM); // Read 8 bytes of ROM code for (uint8_t i = 0; i < 8; i++) { dev->romCode[i] = MDC04_OneWire_ReadByte(dev); } // Verify CRC uint8_t crc = MDC04_OneWire_CRC8(dev->romCode, 7); uint8_t status = (crc == dev->romCode[7]) ? MDC04_STATUS_OK : MDC04_STATUS_CRC_ERROR; if (dev->debugEnable == 1 && dev->LOG != NULL) { dev->LOG("\r\nMDC04 ROM: %02X%02X%02X%02X%02X%02X%02X%02X, CRC=%s", dev->romCode[0], dev->romCode[1], dev->romCode[2], dev->romCode[3], dev->romCode[4], dev->romCode[5], dev->romCode[6], dev->romCode[7], (status == MDC04_STATUS_OK) ? "OK" : "ERROR"); } dev->lastStatus = status; __ATY_UNLOCK(dev); return status; } /** * @brief OneWire write byte * * @param dev device structure pointer * @param data byte to write * @return uint8_t status code */ uint8_t MDC04_OneWire_WriteByte(struct MDC04_ATY_Dev *dev, uint8_t data) { if (dev == NULL || dev->mode != MDC04_MODE_ONEWIRE) { return MDC04_STATUS_ERROR; } for (uint8_t i = 0; i < 8; i++) { MDC04_OneWire_WriteBit(dev, (data >> i) & 0x01); } return MDC04_STATUS_OK; } /** * @brief OneWire read byte * * @param dev device structure pointer * @return uint8_t read data */ uint8_t MDC04_OneWire_ReadByte(struct MDC04_ATY_Dev *dev) { if (dev == NULL || dev->mode != MDC04_MODE_ONEWIRE) { return 0; } uint8_t data = 0; for (uint8_t i = 0; i < 8; i++) { if (MDC04_OneWire_ReadBit(dev)) { data |= (1 << i); } } return data; } /** * @brief OneWire write bit * * @param dev device structure pointer * @param bit bit to write (0 or 1) * @return uint8_t status code */ uint8_t MDC04_OneWire_WriteBit(struct MDC04_ATY_Dev *dev, uint8_t bit) { if (dev == NULL || dev->oneWireSetLow == NULL || dev->oneWireSetHigh == NULL || dev->delayUs == NULL) { return MDC04_STATUS_ERROR; } if (bit) { // Write 1: short low pulse dev->oneWireSetLow(); dev->delayUs(MDC04_WRITE_1_LOW_TIME); dev->oneWireSetHigh(); dev->delayUs(MDC04_SLOT_TIME - MDC04_WRITE_1_LOW_TIME); } else { // Write 0: long low pulse dev->oneWireSetLow(); dev->delayUs(MDC04_WRITE_0_LOW_TIME); dev->oneWireSetHigh(); dev->delayUs(MDC04_SLOT_TIME - MDC04_WRITE_0_LOW_TIME); } return MDC04_STATUS_OK; } /** * @brief OneWire read bit * * @param dev device structure pointer * @return uint8_t read bit (0 or 1) */ uint8_t MDC04_OneWire_ReadBit(struct MDC04_ATY_Dev *dev) { if (dev == NULL || dev->oneWireSetLow == NULL || dev->oneWireSetHigh == NULL || dev->oneWireRead == NULL || dev->delayUs == NULL) { return 0; } uint8_t bit; // Initiate read slot dev->oneWireSetLow(); dev->delayUs(MDC04_READ_LOW_TIME); dev->oneWireSetHigh(); dev->delayUs(MDC04_READ_SAMPLE_TIME); // Sample the line bit = dev->oneWireRead(); dev->delayUs(MDC04_SLOT_TIME - MDC04_READ_LOW_TIME - MDC04_READ_SAMPLE_TIME); return bit; } /** * @brief Calculate CRC8 for OneWire * * @param data data array * @param len data length * @return uint8_t CRC8 value */ uint8_t MDC04_OneWire_CRC8(uint8_t *data, uint8_t len) { uint8_t crc = 0; for (uint8_t i = 0; i < len; i++) { uint8_t inbyte = data[i]; for (uint8_t j = 0; j < 8; j++) { uint8_t mix = (crc ^ inbyte) & 0x01; crc >>= 1; if (mix) crc ^= 0x8C; inbyte >>= 1; } } return crc; } /** * @brief I2C write register * * @param dev device structure pointer * @param reg register address * @param data data to write * @return uint8_t status code */ uint8_t MDC04_I2C_WriteRegister(struct MDC04_ATY_Dev *dev, uint8_t reg, uint8_t data) { if (dev == NULL || dev->mode != MDC04_MODE_I2C) { return MDC04_STATUS_ERROR; } if (dev->i2cStart == NULL || dev->i2cStop == NULL || dev->i2cWriteByte == NULL) { return MDC04_STATUS_ERROR; } uint8_t status; // Start condition status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Write device address status = dev->i2cWriteByte(dev->i2cAddress << 1); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Write register address status = dev->i2cWriteByte(reg); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Write data status = dev->i2cWriteByte(data); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Stop condition dev->i2cStop(); return MDC04_STATUS_OK; } /** * @brief I2C read register * * @param dev device structure pointer * @param reg register address * @param data pointer to store read data * @return uint8_t status code */ uint8_t MDC04_I2C_ReadRegister(struct MDC04_ATY_Dev *dev, uint8_t reg, uint8_t *data) { if (dev == NULL || dev->mode != MDC04_MODE_I2C || data == NULL) { return MDC04_STATUS_ERROR; } if (dev->i2cStart == NULL || dev->i2cStop == NULL || dev->i2cWriteByte == NULL || dev->i2cReadByte == NULL) { return MDC04_STATUS_ERROR; } uint8_t status; // Write register address status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte(dev->i2cAddress << 1); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte(reg); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Restart and read data status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte((dev->i2cAddress << 1) | 0x01); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } *data = dev->i2cReadByte(0); // NACK for single byte read dev->i2cStop(); return MDC04_STATUS_OK; } /** * @brief I2C read multiple registers * * @param dev device structure pointer * @param reg starting register address * @param data pointer to store read data * @param len number of bytes to read * @return uint8_t status code */ uint8_t MDC04_I2C_ReadMultiple(struct MDC04_ATY_Dev *dev, uint8_t reg, uint8_t *data, uint8_t len) { if (dev == NULL || dev->mode != MDC04_MODE_I2C || data == NULL || len == 0) { return MDC04_STATUS_ERROR; } if (dev->i2cStart == NULL || dev->i2cStop == NULL || dev->i2cWriteByte == NULL || dev->i2cReadByte == NULL) { return MDC04_STATUS_ERROR; } uint8_t status; // Write register address status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte(dev->i2cAddress << 1); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte(reg); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Restart and read data status = dev->i2cStart(); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } status = dev->i2cWriteByte((dev->i2cAddress << 1) | 0x01); if (status != 0) { dev->i2cStop(); return MDC04_STATUS_ERROR; } // Read multiple bytes for (uint8_t i = 0; i < len; i++) { data[i] = dev->i2cReadByte((i == len - 1) ? 0 : 1); // NACK on last byte } dev->i2cStop(); return MDC04_STATUS_OK; } /** * @brief Convert raw temperature to Celsius * * @param rawTemp raw temperature value * @return float temperature in Celsius */ float MDC04_ConvertRawToTemperature(uint16_t rawTemp) { // Convert based on MDC04 specification // Assuming 12-bit resolution: 0.0625°C per LSB int16_t signedTemp = (int16_t)rawTemp; return (float)signedTemp * 0.0625f; } /** * @brief Get device status * * @param dev device structure pointer * @return uint8_t current device status */ uint8_t MDC04_GetDeviceStatus(struct MDC04_ATY_Dev *dev) { if (dev == NULL) { return MDC04_STATUS_ERROR; } return dev->lastStatus; } /** * @brief Set I2C device address * * @param dev device structure pointer * @param address new I2C address */ void MDC04_SetI2CAddress(struct MDC04_ATY_Dev *dev, uint8_t address) { if (dev != NULL && dev->mode == MDC04_MODE_I2C) { dev->i2cAddress = address; } } /** * @brief Search for devices on OneWire bus * * @param dev device structure pointer * @param deviceCount pointer to store device count * @return uint8_t status code * @note Basic implementation for single device detection */ uint8_t MDC04_SearchDevices(struct MDC04_ATY_Dev *dev, uint8_t *deviceCount) { if (dev == NULL || dev->mode != MDC04_MODE_ONEWIRE || deviceCount == NULL) { return MDC04_STATUS_ERROR; } *deviceCount = 0; // Simple presence check if (MDC04_Reset(dev) == MDC04_STATUS_OK) { *deviceCount = 1; return MDC04_STATUS_OK; } return MDC04_STATUS_NO_DEVICE; } #endif /* __MDC04_ATY_C */ /************************************ etc *************************************/ /* OneWire Mode Usage Example */ /* // GPIO control functions (platform specific) void MDC04_OneWire_SetHigh(void) { // Set GPIO pin high (open-drain or push-pull with external pull-up) GPIO_SET_H(MDC04_GPIO_Port, MDC04_Pin); } void MDC04_OneWire_SetLow(void) { // Set GPIO pin low GPIO_SET_L(MDC04_GPIO_Port, MDC04_Pin); } uint8_t MDC04_OneWire_Read(void) { // Read GPIO pin state return GPIO_READ(MDC04_GPIO_Port, MDC04_Pin); } void MDC04_DelayUs(uint32_t us) { // Microsecond delay implementation // Use timer or DWT for accurate timing } // struct MDC04_ATY_Dev mdc04_dev = { // .mode = MDC04_MODE_ONEWIRE, // .initialized = 0, // Initialize as not initialized // .oneWireSetHigh = MDC04_OneWire_SetHigh, // .oneWireSetLow = MDC04_OneWire_SetLow, // .oneWireRead = MDC04_OneWire_Read, // .delayUs = MDC04_DelayUs, // .lock = _ATY_UNLOCKED, // .debugEnable = 1, // .LOG = printf // }; // Usage // No need to call MDC04_Init() manually - it will be called automatically // MDC04_StartConversion(&mdc04_dev); // Auto-init will be called here // // Wait for conversion (750ms typical) // delay_ms(750); // MDC04_ReadTemperature(&mdc04_dev); // Or auto-init will be called here // printf("Temperature: %.2f°C\n", mdc04_dev.temperature); */ /* I2C Mode Usage Example */ /* // I2C control functions (platform specific) uint8_t MDC04_I2C_Start(void) { // Generate I2C start condition return I2C_Start(); } uint8_t MDC04_I2C_Stop(void) { // Generate I2C stop condition return I2C_Stop(); } uint8_t MDC04_I2C_WriteByte(uint8_t data) { // Write byte and return ACK status (0=ACK, 1=NACK) return I2C_WriteByte(data); } uint8_t MDC04_I2C_ReadByte(uint8_t ack) { // Read byte and send ACK/NACK return I2C_ReadByte(ack); } // struct MDC04_ATY_Dev mdc04_i2c_dev = { // .mode = MDC04_MODE_I2C, // .initialized = 0, // Initialize as not initialized // .i2cStart = MDC04_I2C_Start, // .i2cStop = MDC04_I2C_Stop, // .i2cWriteByte = MDC04_I2C_WriteByte, // .i2cReadByte = MDC04_I2C_ReadByte, // .i2cAddress = MDC04_I2C_ADDR_DEFAULT, // .lock = _ATY_UNLOCKED, // .debugEnable = 1, // .LOG = printf // }; // Usage // No need to call MDC04_Init() manually - it will be called automatically // MDC04_StartConversion(&mdc04_i2c_dev); // Auto-init will be called here // // Wait for conversion // delay_ms(750); // MDC04_ReadTemperature(&mdc04_i2c_dev); // Or auto-init will be called here // printf("Temperature: %.2f°C\n", mdc04_i2c_dev.temperature); */ /******************************************************************************/ /******************************** End Of File *********************************/