mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	add support for SN74HC595 shift register (#1083)
* add support for SN74HC595 shift register * fix linter errors * more linter reported issues fixed * hopefully last linter error cleanup * one more linter fix * looks like the linter is always keeping stuff for later, is this the final fix? * add test Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
This commit is contained in:
		
							
								
								
									
										54
									
								
								esphome/components/sn74hc595/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/sn74hc595/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import pins | ||||
| from esphome.const import CONF_ID, CONF_NUMBER, CONF_INVERTED, CONF_DATA_PIN, CONF_CLOCK_PIN | ||||
|  | ||||
| DEPENDENCIES = [] | ||||
| MULTI_CONF = True | ||||
|  | ||||
| sn74hc595_ns = cg.esphome_ns.namespace('sn74hc595') | ||||
|  | ||||
| SN74HC595Component = sn74hc595_ns.class_('SN74HC595Component', cg.Component) | ||||
| SN74HC595GPIOPin = sn74hc595_ns.class_('SN74HC595GPIOPin', cg.GPIOPin) | ||||
|  | ||||
| CONF_SN74HC595 = 'sn74hc595' | ||||
| CONF_LATCH_PIN = 'latch_pin' | ||||
| CONF_OE_PIN = 'oe_pin' | ||||
| CONF_SR_COUNT = 'sr_count' | ||||
| CONFIG_SCHEMA = cv.Schema({ | ||||
|     cv.Required(CONF_ID): cv.declare_id(SN74HC595Component), | ||||
|     cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, | ||||
|     cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, | ||||
|     cv.Required(CONF_LATCH_PIN): pins.gpio_output_pin_schema, | ||||
|     cv.Optional(CONF_OE_PIN): pins.gpio_output_pin_schema, | ||||
|     cv.Optional(CONF_SR_COUNT, default=1): cv.int_range(1, 4) | ||||
| }).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     yield cg.register_component(var, config) | ||||
|     data_pin = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) | ||||
|     cg.add(var.set_data_pin(data_pin)) | ||||
|     clock_pin = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) | ||||
|     cg.add(var.set_clock_pin(clock_pin)) | ||||
|     latch_pin = yield cg.gpio_pin_expression(config[CONF_LATCH_PIN]) | ||||
|     cg.add(var.set_latch_pin(latch_pin)) | ||||
|     oe_pin = yield cg.gpio_pin_expression(config[CONF_OE_PIN]) | ||||
|     cg.add(var.set_oe_pin(oe_pin)) | ||||
|     cg.add(var.set_sr_count(config[CONF_SR_COUNT])) | ||||
|  | ||||
|  | ||||
| SN74HC595_OUTPUT_PIN_SCHEMA = cv.Schema({ | ||||
|     cv.Required(CONF_SN74HC595): cv.use_id(SN74HC595Component), | ||||
|     cv.Required(CONF_NUMBER): cv.int_, | ||||
|     cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||
| }) | ||||
| SN74HC595_INPUT_PIN_SCHEMA = cv.Schema({}) | ||||
|  | ||||
|  | ||||
| @pins.PIN_SCHEMA_REGISTRY.register(CONF_SN74HC595, | ||||
|                                    (SN74HC595_OUTPUT_PIN_SCHEMA, SN74HC595_INPUT_PIN_SCHEMA)) | ||||
| def sn74hc595_pin_to_code(config): | ||||
|     parent = yield cg.get_variable(config[CONF_SN74HC595]) | ||||
|     yield SN74HC595GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_INVERTED]) | ||||
							
								
								
									
										70
									
								
								esphome/components/sn74hc595/sn74hc595.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								esphome/components/sn74hc595/sn74hc595.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #include "sn74hc595.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace sn74hc595 { | ||||
|  | ||||
| static const char *TAG = "sn74hc595"; | ||||
|  | ||||
| void SN74HC595Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up SN74HC595..."); | ||||
|  | ||||
|   if (this->have_oe_pin_) {  // disable output | ||||
|     pinMode(this->oe_pin_->get_pin(), OUTPUT); | ||||
|     digitalWrite(this->oe_pin_->get_pin(), HIGH); | ||||
|   } | ||||
|  | ||||
|   // initialize output pins | ||||
|   pinMode(this->clock_pin_->get_pin(), OUTPUT); | ||||
|   pinMode(this->data_pin_->get_pin(), OUTPUT); | ||||
|   pinMode(this->latch_pin_->get_pin(), OUTPUT); | ||||
|   digitalWrite(this->clock_pin_->get_pin(), LOW); | ||||
|   digitalWrite(this->data_pin_->get_pin(), LOW); | ||||
|   digitalWrite(this->latch_pin_->get_pin(), LOW); | ||||
|  | ||||
|   // send state to shift register | ||||
|   this->write_gpio_(); | ||||
| } | ||||
|  | ||||
| void SN74HC595Component::dump_config() { ESP_LOGCONFIG(TAG, "SN74HC595:"); } | ||||
|  | ||||
| bool SN74HC595Component::digital_read_(uint8_t pin) { return bitRead(this->output_bits_, pin); } | ||||
|  | ||||
| void SN74HC595Component::digital_write_(uint8_t pin, bool value) { | ||||
|   bitWrite(this->output_bits_, pin, value); | ||||
|   this->write_gpio_(); | ||||
| } | ||||
|  | ||||
| bool SN74HC595Component::write_gpio_() { | ||||
|   for (int i = this->sr_count_ - 1; i >= 0; i--) { | ||||
|     uint8_t data = (uint8_t)(this->output_bits_ >> (8 * i) & 0xff); | ||||
|     shiftOut(this->data_pin_->get_pin(), this->clock_pin_->get_pin(), MSBFIRST, data); | ||||
|   } | ||||
|  | ||||
|   // pulse latch to activate new values | ||||
|   digitalWrite(this->latch_pin_->get_pin(), HIGH); | ||||
|   digitalWrite(this->latch_pin_->get_pin(), LOW); | ||||
|  | ||||
|   // enable output if configured | ||||
|   if (this->have_oe_pin_) { | ||||
|     digitalWrite(this->oe_pin_->get_pin(), LOW); | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| float SN74HC595Component::get_setup_priority() const { return setup_priority::IO; } | ||||
|  | ||||
| void SN74HC595GPIOPin::setup() {} | ||||
|  | ||||
| bool SN74HC595GPIOPin::digital_read() { return this->parent_->digital_read_(this->pin_) != this->inverted_; } | ||||
|  | ||||
| void SN74HC595GPIOPin::digital_write(bool value) { | ||||
|   this->parent_->digital_write_(this->pin_, value != this->inverted_); | ||||
| } | ||||
|  | ||||
| SN74HC595GPIOPin::SN74HC595GPIOPin(SN74HC595Component *parent, uint8_t pin, bool inverted) | ||||
|     : GPIOPin(pin, OUTPUT, inverted), parent_(parent) {} | ||||
|  | ||||
| }  // namespace sn74hc595 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										55
									
								
								esphome/components/sn74hc595/sn74hc595.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/sn74hc595/sn74hc595.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/esphal.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace sn74hc595 { | ||||
|  | ||||
| class SN74HC595Component : public Component { | ||||
|  public: | ||||
|   SN74HC595Component() = default; | ||||
|  | ||||
|   void setup() override; | ||||
|   float get_setup_priority() const override; | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_data_pin(GPIOPin *pin) { data_pin_ = pin; } | ||||
|   void set_clock_pin(GPIOPin *pin) { clock_pin_ = pin; } | ||||
|   void set_latch_pin(GPIOPin *pin) { latch_pin_ = pin; } | ||||
|   void set_oe_pin(GPIOPin *pin) { | ||||
|     oe_pin_ = pin; | ||||
|     have_oe_pin_ = true; | ||||
|   } | ||||
|   void set_sr_count(uint8_t count) { sr_count_ = count; } | ||||
|  | ||||
|  protected: | ||||
|   friend class SN74HC595GPIOPin; | ||||
|   bool digital_read_(uint8_t pin); | ||||
|   void digital_write_(uint8_t pin, bool value); | ||||
|   bool write_gpio_(); | ||||
|  | ||||
|   GPIOPin *data_pin_; | ||||
|   GPIOPin *clock_pin_; | ||||
|   GPIOPin *latch_pin_; | ||||
|   GPIOPin *oe_pin_; | ||||
|   uint8_t sr_count_; | ||||
|   bool have_oe_pin_{false}; | ||||
|   uint32_t output_bits_{0x00}; | ||||
| }; | ||||
|  | ||||
| /// Helper class to expose a SC74HC595 pin as an internal output GPIO pin. | ||||
| class SN74HC595GPIOPin : public GPIOPin { | ||||
|  public: | ||||
|   SN74HC595GPIOPin(SN74HC595Component *parent, uint8_t pin, bool inverted = false); | ||||
|  | ||||
|   void setup() override; | ||||
|   bool digital_read() override; | ||||
|   void digital_write(bool value) override; | ||||
|  | ||||
|  protected: | ||||
|   SN74HC595Component *parent_; | ||||
| }; | ||||
|  | ||||
| }  // namespace sn74hc595 | ||||
| }  // namespace esphome | ||||
| @@ -1465,6 +1465,14 @@ switch: | ||||
|         id: my_stepper | ||||
|         position: 0 | ||||
|  | ||||
|   - platform: gpio | ||||
|     name: "SN74HC595 Pin #0" | ||||
|     pin: | ||||
|       sn74hc595: sn74hc595_hub | ||||
|       # Use pin number 0 | ||||
|       number: 0 | ||||
|       inverted: False | ||||
|  | ||||
| fan: | ||||
|   - platform: binary | ||||
|     output: gpio_26 | ||||
| @@ -1715,3 +1723,11 @@ text_sensor: | ||||
|     name: "BSSID" | ||||
|   mac_address: | ||||
|     name: "Mac Address" | ||||
|  | ||||
| sn74hc595: | ||||
|   - id: 'sn74hc595_hub' | ||||
|     data_pin: GPIO21 | ||||
|     clock_pin: GPIO23 | ||||
|     latch_pin: GPIO22 | ||||
|     oe_pin: GPIO32 | ||||
|     sr_count: 2 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user