/**
* @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 *********************************/