Add MCP3201 A/D converter

Add support for the Microcip MCP3201 1-channel 12-bit A/D converter

This ADC is similar to the already supported MCP3204, but since it only
exposes a single channel it uses a slightly different wire protocol.
This commit is contained in:
Björn Stenberg 2024-11-24 15:32:30 +01:00
parent dea297c8d7
commit 02116524be
8 changed files with 182 additions and 0 deletions

View File

@ -256,6 +256,7 @@ esphome/components/mcp23x08_base/* @jesserockz
esphome/components/mcp23x17_base/* @jesserockz
esphome/components/mcp23xxx_base/* @jesserockz
esphome/components/mcp2515/* @danielschramm @mvturnho
esphome/components/mcp3201/* @zagor
esphome/components/mcp3204/* @rsumner
esphome/components/mcp4728/* @berfenger
esphome/components/mcp47a1/* @jesserockz

View File

@ -0,0 +1,26 @@
import esphome.codegen as cg
from esphome.components import spi
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_REFERENCE_VOLTAGE
DEPENDENCIES = ["spi"]
MULTI_CONF = True
CODEOWNERS = ["@zagor"]
mcp3201_ns = cg.esphome_ns.namespace("mcp3201")
MCP3201 = mcp3201_ns.class_("MCP3201", cg.Component, spi.SPIDevice)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(MCP3201),
cv.Optional(CONF_REFERENCE_VOLTAGE, default="3.3V"): cv.voltage,
}
).extend(spi.spi_device_schema(cs_pin_required=True))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE]))
await cg.register_component(var, config)
await spi.register_spi_device(var, config)

View File

@ -0,0 +1,32 @@
#include "mcp3201.h"
#include "esphome/core/log.h"
namespace esphome {
namespace mcp3201 {
static const char *const TAG = "mcp3201";
float MCP3201::get_setup_priority() const { return setup_priority::HARDWARE; }
void MCP3201::setup() {
ESP_LOGCONFIG(TAG, "Setting up mcp3201");
this->spi_setup();
}
void MCP3201::dump_config() {
ESP_LOGCONFIG(TAG, "MCP3201:");
LOG_PIN(" CS Pin:", this->cs_);
ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_);
}
float MCP3201::read_data() {
this->enable();
uint8_t byte0 = this->transfer_byte(0x00);
uint8_t byte1 = this->transfer_byte(0x00);
this->disable();
uint16_t digital_value = (((byte0 & 0b00011111) << 7) | (byte1 >> 1));
return float(digital_value) / 4096.000 * this->reference_voltage_;
}
} // namespace mcp3201
} // namespace esphome

View File

@ -0,0 +1,28 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace mcp3201 {
class MCP3201 : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
spi::DATA_RATE_1MHZ> {
public:
MCP3201() = default;
void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
float read_data();
protected:
float reference_voltage_;
};
} // namespace mcp3201
} // namespace esphome

View File

@ -0,0 +1,32 @@
import esphome.codegen as cg
from esphome.components import sensor, voltage_sampler
import esphome.config_validation as cv
from esphome.const import CONF_ID
from .. import MCP3201, mcp3201_ns
AUTO_LOAD = ["voltage_sampler"]
DEPENDENCIES = ["mcp3201"]
MCP3201Sensor = mcp3201_ns.class_(
"MCP3201Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
)
CONF_MCP3201_ID = "mcp3201_id"
CONFIG_SCHEMA = (
sensor.sensor_schema(MCP3201Sensor)
.extend(
{
cv.GenerateID(CONF_MCP3201_ID): cv.use_id(MCP3201),
}
)
.extend(cv.polling_component_schema("60s"))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_parented(var, config[CONF_MCP3201_ID])
await cg.register_component(var, config)
await sensor.register_sensor(var, config)

View File

@ -0,0 +1,20 @@
#include "mcp3201_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace mcp3201 {
static const char *const TAG = "mcp3201.sensor";
float MCP3201Sensor::get_setup_priority() const { return setup_priority::DATA; }
void MCP3201Sensor::dump_config() {
LOG_SENSOR("", "MCP3201 Sensor", this);
LOG_UPDATE_INTERVAL(this);
}
float MCP3201Sensor::sample() { return this->parent_->read_data(); }
void MCP3201Sensor::update() { this->publish_state(this->sample()); }
} // namespace mcp3201
} // namespace esphome

View File

@ -0,0 +1,27 @@
#pragma once
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "../mcp3201.h"
namespace esphome {
namespace mcp3201 {
class MCP3201Sensor : public PollingComponent,
public Parented<MCP3201>,
public sensor::Sensor,
public voltage_sampler::VoltageSampler {
public:
MCP3201Sensor() = default;
void update() override;
void dump_config() override;
float get_setup_priority() const override;
float sample() override;
};
} // namespace mcp3201
} // namespace esphome

View File

@ -0,0 +1,16 @@
spi:
- id: spi_mcp3201
clk_pin: 14
mosi_pin: 13
miso_pin: 12
mcp3201:
- id: mcp3201_hub
cs_pin: 15
reference_voltage: 4.096V
sensor:
- platform: mcp3201
id: mcp3201_sensor
mcp3201_id: mcp3201_hub
update_interval: 5s