PWM control
-
Hello everyone,
The aim here is to control the speed of a 5v fan with PWM of an arduino nano.
I usualy do it with this code:const byte OC1A_PIN = 9; const byte OC1B_PIN = 10; const word PWM_FREQ_HZ = 25000; //Adjust this value to adjust the frequency const word TCNT1_TOP = 16000000/(2*PWM_FREQ_HZ); byte in = 0; void setup() { pinMode(OC1A_PIN, OUTPUT); Serial.begin(9600); Serial.println("Demarage du PWM"); // so I can keep track of what is loaded // Clear Timer1 control and count registers TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // Set Timer1 configuration // COM1A(1:0) = 0b10 (Output A clear rising/set falling) // COM1B(1:0) = 0b00 (Output B normal operation) // WGM(13:10) = 0b1010 (Phase correct PWM) // ICNC1 = 0b0 (Input capture noise canceler disabled) // ICES1 = 0b0 (Input capture edge select disabled) // CS(12:10) = 0b001 (Input clock select = clock/1) TCCR1A |= (1 << COM1A1) | (1 << WGM11); TCCR1B |= (1 << WGM13) | (1 << CS10); ICR1 = TCNT1_TOP; } void loop() { if (Serial.available()) { // Check if there's data char buf[10]; int in = Serial.readBytesUntil('\n', buf, sizeof buf - 1); buf[in]=0; in = atoi(buf); if (in > 100) in = 100; Serial.println(in);// Pass the value of "in" to the pin} setPwmDuty(in); //Change this value 0-100 to adjust duty cycle } } void setPwmDuty(byte duty) { OCR1A = (word) (duty*TCNT1_TOP)/100; }
Is it possible to do the same with mysensors?
The next step of this would be to connect the arduino via USB and control it using domoticz.
-
@Dovane-Benattar ofcourse! All the initialization and pwm setting code should be copied to the mysensors sketch, and the serial reading could be replaced by mysensors message handling.
-
Thanks Yveaux! I will give it a try like this
-
@Yveaux thank you for your answer!
/** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad <henrik.ekblad@mysensors.org> * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * ******************************* * * DESCRIPTION * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on serial which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * * Wire connections (OPTIONAL): * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * */ // Enable debug prints to serial monitor #define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_RF24 //#define MY_RADIO_NRF5_ESB //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. #define MY_RF24_PA_LEVEL RF24_PA_LOW // Enable serial gateway #define MY_GATEWAY_SERIAL // Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway //#define MY_INCLUSION_BUTTON_FEATURE // Inverses behavior of inclusion button (if using external pullup) //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button //#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Set blinking period #define MY_DEFAULT_LED_BLINK_PERIOD 300 // Inverses the behavior of leds //#define MY_WITH_LEDS_BLINKING_INVERSE // Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED #include <MySensors.h> const byte OC1A_PIN = 9; const byte OC1B_PIN = 10; const word PWM_FREQ_HZ = 25000; //Adjust this value to adjust the frequency const word TCNT1_TOP = 16000000/(2*PWM_FREQ_HZ); byte in = 0; void setup() { // Setup locally attached sensors pinMode(OC1A_PIN, OUTPUT); Serial.begin(9600); Serial.print(0); // Clear Timer1 control and count registers TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // Set Timer1 configuration // COM1A(1:0) = 0b10 (Output A clear rising/set falling) // COM1B(1:0) = 0b00 (Output B normal operation) // WGM(13:10) = 0b1010 (Phase correct PWM) // ICNC1 = 0b0 (Input capture noise canceler disabled) // ICES1 = 0b0 (Input capture edge select disabled) // CS(12:10) = 0b001 (Input clock select = clock/1) TCCR1A |= (1 << COM1A1) | (1 << WGM11); TCCR1B |= (1 << WGM13) | (1 << CS10); ICR1 = TCNT1_TOP; } void presentation() { // Present locally attached sensors } void loop() { // Send locally attached sensor data here if (Serial.available()) { // Check if there's data char buf[10]; int in = Serial.readBytesUntil('\n', buf, sizeof buf - 1); buf[in]=0; in = atoi(buf); if (in >= 100) in = 100; Serial.println(in);// Pass the value of "in" to the pin} setPwmDuty(in); //Change this value 0-100 to adjust duty cycle } } void setPwmDuty(byte duty) { OCR1A = (word) (duty*TCNT1_TOP)/100; }
Can you tell me if this could work? (I tried but it does not.. maybe I do something else wrong)
-
Some news, it works now!
I took some code for a dimmable LED hereThe only problem now is that the fan does a little sound it didn't with the first code.
here is the code:
/** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad <henrik.ekblad@mysensors.org> * Copyright (C) 2013-2019 Sensnology AB * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * ******************************* * * DESCRIPTION * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on serial which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * * Wire connections (OPTIONAL): * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * */ // Enable debug prints to serial monitor #define MY_DEBUG // Enable and select radio type attached //#define MY_RADIO_RF24 //#define MY_RADIO_NRF5_ESB //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. //#define MY_RF24_PA_LEVEL RF24_PA_LOW // Enable serial gateway #define MY_GATEWAY_SERIAL // Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway //#define MY_INCLUSION_BUTTON_FEATURE // Inverses behavior of inclusion button (if using external pullup) //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button //#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Set blinking period #define MY_DEFAULT_LED_BLINK_PERIOD 300 // Inverses the behavior of leds //#define MY_WITH_LEDS_BLINKING_INVERSE // Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED #include <MySensors.h> #define SN "DimmableLED" #define SV "1.1" #define LED_PIN 9 // Arduino pin attached to MOSFET Gate pin #define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) static int16_t currentLevel = 0; // Current dim level... MyMessage dimmerMsg(0, V_DIMMER); MyMessage lightMsg(0, V_LIGHT); void setup() { // Setup locally attached sensors request( 0, V_DIMMER ); } void presentation() { // Present locally attached sensors present( 0, S_DIMMER ); sendSketchInfo(SN, SV); } void loop() { // Send locally attached sensor data here } void receive(const MyMessage &message) { if (message.getType() == V_LIGHT || message.getType() == V_DIMMER) { // Retrieve the power or dim level from the incoming request message int requestedLevel = atoi( message.data ); // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on] requestedLevel *= ( message.getType() == V_LIGHT ? 100 : 1 ); // Clip incoming level to valid range of 0 to 100 requestedLevel = requestedLevel > 100 ? 100 : requestedLevel; requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; Serial.print( "Changing level to " ); Serial.print( requestedLevel ); Serial.print( ", from " ); Serial.println( currentLevel ); fadeToLevel( requestedLevel ); // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... send(lightMsg.set(currentLevel > 0)); // hek comment: Is this really nessesary? send( dimmerMsg.set(currentLevel) ); } } /*** * This method provides a graceful fade up/down effect */ void fadeToLevel( int toLevel ) { int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1; while ( currentLevel != toLevel ) { currentLevel += delta; analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) ); delay( FADE_DELAY ); } }
Do you have any idea why it does this?
-
@doodoovane
not sure if I get it, but the little sound could be generated by pwm freq.Note, your last sketch is not ideal:
- don't send msg in receive(). it's better to update a variable, and check this variable in loop() for sending a msg, to avoid recursive call to receive()
- Same for your fading function, it's better to call it from loop(). Receive() should finish as fast as possible.
- don't use delay() in your fading function, it's a blocking function. It's better to do this async, in a non-blocking way, or use wait() as it can process received msg in background .
-
@scalz the delay() and send() calls are from the MySensors example, my guess is that doodoovane just followed the example.
-
@mfalkvidd
yep I noticed that. I just provided a few feedbacks for his future sketches
-
@scalz that's what I thought but it doesn't make any sound with the first code I posted.
Something to do with the frequency maybe?
-
This post is deleted!
-
Me again!
So the problem seemed to be the frequency as I don't have sound anymore.
With a little hindsight, I looked back at @Yveaux's messages (here and on another post) and here is what I've tried./** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad <henrik.ekblad@mysensors.org> * Copyright (C) 2013-2019 Sensnology AB * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * ******************************* * * DESCRIPTION * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on serial which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * * Wire connections (OPTIONAL): * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * */ // Enable debug prints to serial monitor #define MY_DEBUG // Enable and select radio type attached //#define MY_RADIO_RF24 //#define MY_RADIO_NRF5_ESB //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. //#define MY_RF24_PA_LEVEL RF24_PA_LOW // Enable serial gateway #define MY_GATEWAY_SERIAL // Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway //#define MY_INCLUSION_BUTTON_FEATURE // Inverses behavior of inclusion button (if using external pullup) //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button //#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Set blinking period #define MY_DEFAULT_LED_BLINK_PERIOD 300 // Inverses the behavior of leds //#define MY_WITH_LEDS_BLINKING_INVERSE // Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED #include <MySensors.h> #include <TimerOne.h> #define SN "DimmableLED" #define SV "1.1" #define LED_PIN 9 // Arduino pin attached to MOSFET Gate pin #define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) static int16_t currentLevel = 0; // Current dim level... MyMessage dimmerMsg(0, V_DIMMER); MyMessage lightMsg(0, V_LIGHT); void setup() { // Setup locally attached sensors request( 0, V_DIMMER ); #define PWM_FREQ_HZ (25000) #define PWM_CYCLE_US (1000000/PWM_FREQ_HZ) Timer1.initialize(PWM_CYCLE_US); Timer1.pwm(LED_PIN, 1023); } void presentation() { // Present locally attached sensors present( 0, S_DIMMER ); sendSketchInfo(SN, SV); } void loop() { // Send locally attached sensor data here } void receive(const MyMessage &message) { if (message.getType() == V_LIGHT || message.getType() == V_DIMMER) { // Retrieve the power or dim level from the incoming request message int requestedLevel = atoi( message.data ); // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on] requestedLevel *= ( message.getType() == V_LIGHT ? 100 : 1 ); // Clip incoming level to valid range of 0 to 100 requestedLevel = requestedLevel >= 101 ? 100 : requestedLevel; requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; Serial.print( "Changing level to " ); Serial.print( requestedLevel ); Serial.print( ", from " ); Serial.println( currentLevel ); fadeToLevel( requestedLevel ); // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... send(lightMsg.set(currentLevel > 0)); // hek comment: Is this really nessesary? send( dimmerMsg.set(currentLevel) ); } } /*** * This method provides a graceful fade up/down effect */ void fadeToLevel( int toLevel ) { int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1; while ( currentLevel != toLevel ) { currentLevel += delta; analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) ); delay( FADE_DELAY ); } }
No more sound, but now Can't get it more than 99% in domoticz... The only way to get 100% is to turn it off and turn it back on. As long as you touch the slider, no more 100%...
Any clue of what can cause this?
-
@doodoovane why do you use analogwrite instead of Timer1.setPwmDuty?
Also, the fading should not be required for a fan.
Iirr the maximum duty value is 1023. Likely the fan won't be at its maximum speed then, only when you supply it a continuous high 'pulse'. Is that what you mean by 99%?
-
@Yveaux said in PWM control:
Timer1.setPwmDuty
I did but there must be something wrong with my code as the PWM doesn't work anymore.
Here is my try:#include <MySensors.h> #include <TimerOne.h> #define SN "Fan_PWM" #define SV "1.3" #define LED_PIN 9 // Arduino pin attached to MOSFET Gate pin #define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) static int16_t currentLevel = 0; // Current dim level... MyMessage dimmerMsg(0, V_DIMMER); MyMessage lightMsg(0, V_LIGHT); void setup() { // Setup locally attached sensors request( 0, V_DIMMER ); #define PWM_FREQ_HZ (25000) #define PWM_CYCLE_US (1000000/PWM_FREQ_HZ) Timer1.initialize(PWM_CYCLE_US); Timer1.pwm(LED_PIN, 1023); } void presentation() { // Present locally attached sensors present( 0, S_DIMMER ); sendSketchInfo(SN, SV); } void loop() { // Send locally attached sensor data here } void receive(const MyMessage &message) { if (message.getType() == V_LIGHT || message.getType() == V_DIMMER) { // Retrieve the power or dim level from the incoming request message int requestedLevel = atoi( message.data ); // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on] requestedLevel *= ( message.getType() == V_LIGHT ? 100 : 1 ); // Clip incoming level to valid range of 0 to 100 requestedLevel = requestedLevel > 100 ? 100 : requestedLevel; requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; Serial.print( "Changing level to " ); Serial.print( requestedLevel ); Serial.print( ", from " ); Serial.println( currentLevel ); Timer1.setPwmDuty(LED_PIN, requestedLevel); // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... send(lightMsg.set(currentLevel > 0)); // hek comment: Is this really nessesary? send( dimmerMsg.set(currentLevel) ); } }
What I mean by 99% is that the slider of the dimmer when pulled to 100% come back to 99% (as I can see in my switch log) in domoticz. And there is no "100%" input just like if I pulled the slider to 99%...
-
Hello everyone,
I'm still stuck with my problem as I don't fin any solution.
Is there a way to say in the code "if level is at 100%, stop the PWM regulation (full power fan)" ?Thank you for your help
-
@doodoovane you can change
requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
to
requestedLevel = requestedLevel > 98 ? 100 : requestedLevel;
-
@mfalkvidd said in PWM control:
requestedLevel = requestedLevel > 98 ? 100 : requestedLevel;
Thank You @mfalkvidd it works that way! Domoticz still showing me his 99% but at least the fan is going 100%.
Thank you for your help, sometime thing can get easier