简体   繁体   中英

Raspberry Pi LED brightness calculation

I am currently doing smart light by using the Grove light sensor to retrieve the sensor value(light intensity) to control the Grove LED socket kit brightness, I didn't use GPIO. I followed the code from the seeed wiki http://wiki.seeedstudio.com/Grove-Light_Sensor/ and modified some of the code but I still not able to change the brightness of the LED into dim when the surrounding light intensity is high, I just keep on getting bright LED. I am trying is to get the brightness of LED to become brighter when the surrounding light intensity is low. Here is my code.

import time
from grovepi import *
import datetime
from guizero import App, Text, PushButton, Box

# Connect the Grove Light Sensor to analog port A0
light_sensor = 0

# Connect the LED to digital port D3
led = 3

# Connect the Grove PIR Motion Sensor to digital port D8
pir_sensor = 8

# Turn on LED once sensor exceeds threshold resistance (light sensor gets covered will turn on the LED)
threshold = 20

pinMode(pir_sensor,"INPUT")
pinMode(light_sensor,"INPUT")
pinMode(led,"OUTPUT")

# Title and format
app = App(title="Smart Light")
Titletext = Text(app, text="Smart Light Controller", size=40,
             font="Times New Roman", color="lightblue")

# define actions
def action1():
    Statustext.value = "Light Turn On"
    digitalWrite(led,1)     
    print ("Light ON!")

def action2():
    Statustext.value = "Light Turn Off"
    digitalWrite(led,0)
    print ("Light OFF!")

def action3():
   while True:
        Statustext.value = "Light Auto"

        # Get sensor value = light intensity
        sensor_value = analogRead(light_sensor)
        g = str(sensor_value)

        a = analogRead(light_sensor)
        max_pwn = 100
        max_analog_read = 1023

        pwn_desired = (float)(a * max_pwn) / max_analog_read

    # Calculate resistance of sensor in K
        resistance = (float)(1023 - sensor_value) * 10 / sensor_value

    # Sense motion, usually human, within the target range
        if digitalRead(pir_sensor) and resistance > threshold:
            print ('Motion Detected')
            print ('Light On')

        # Send HIGH to switch on LED
            digitalWrite(led,1)

            analogWrite(led, pwn_desired)    
            time.sleep(3)

        else :
        # Send LOW to switch off LED
        # NO motion but intensity low = off
        # Motion detected but intensity high = off
            digitalWrite(led,0)
            print ('No Motion')
            print ('Light Off')

            print("sensor_value = %d resistance = %.2f" %(sensor_value,  resistance))
            time.sleep(2)

def line():
Text(app, "----------------------------------")

# Buttons' format
buttons_box = Box(app, layout="grid")
Onbutton = PushButton(buttons_box, action1, text="On",
                  width=20, height=10,grid=[0,0] )

Offbutton = PushButton(buttons_box, action2, text="Off",
                   width=20, height=10,grid=[1,0])

Autobutton = PushButton(buttons_box, action3, text="Auto",
                   width=20, height=10,grid=[2,0])

# Status title
Status = Text(app, text="Light Status", size = 30)
line()

# The status text will change when the each light button is clicked
Statustext = Text(app, text="Idle", color="red", size = 20)
line()

#all code must before app.display
app.display()

Pulse Width Modulation... PWM.

In other words, apply a duty cycle on the GPIO (the LED).

Brighter light? Use a higher duty cycle. Eg., when the sensor value indicates the need for more light from the LED?

Dimmer light? Use a lower duty cycle. Eg., when the sensor value indicates the need for less light from the LED?

The ADC {Analog to Digital Conversion} analogRead is input to a calculation to find a duty cycle.

Your equation needs to reflect that minimum analogRead is mininum duty cycle and maximum analogRead is maximum duty cycle.

Suppose your maximum analogRead is 1023.

Pseudo code:

a = analogRead
max_pwm = 100
max_analog_read = 1023

pwm_desired = (a * max_pwm) / max_analog_read

If the use case is that a higher pwm is needed for a lower analog sensor reading, then compute the complement:

// ...

pwm_desired = (a * max_pwm) / max_analog_read
inverted_pwm_desired = max_pwm - pwm_desired

In either case, I believe that after you've computed it, then you can configure the GPIO as an output PWM pin. And by the jist of your question, that appears to be what is needed.

https://raspberrypi.stackexchange.com/questions/298/can-i-use-the-gpio-for-pulse-width-modulation-pwm

Edit based on comment:

It can be implemented a number of ways. Let's pick a simple one.

Another way to look at it is this:
Imagine a square wave. It is high or low. The duration it's high is an active high duty cycle. A full cycle is from the rising edge to the next rising edge. A portion of the time, it was 'high' and a portion of the time it was 'low'. We need to mimic this.

In your loop you need to mimic a 'value' that is high for a period of time proportional to the sensor value.

When the 'value' is high, you turn on the LED and when it is low, you turn it off.

The transition needs to be rapid (the onset of the rising edge-- the start of the cycle is rapid) .. on order of a few milliseconds -- it depends on your hardware and how much light is diffused in the LED package, etc.. "it depends".

Anyway,

The LED brightness is imitated by pulsing the LED on for a computed length of time. The LED is a digital component, at least from this point of view. Once it's biased more than the 'diode drop', it'll be in saturation -- on. If the LED is biased more than the 0.6V drop off, then it'll be on. That's what your low level LED driver code is essentially doing -- asserting the GIO (3.3V or there about) with a bit of resistance (10k Ohms or there about)in series so the current through the GIO isn't too much. The LED isn't going to vary brightness if the voltage bias is changed. It's not an incandescent bulb, it's not analog.

Experiment.

Let's suppose we don't know what frequency your loop iterates. We can choose metrics and conversions that get close. After trying one set of metrics and conversion factors, you can alter them to achieve the right PWM effect.

Let's begin:

Capture the analog sensor reading. Normalize it to a percentage (0 to 100%) as shown earlier. This value is our duty cycle.

Then, turn on the LED. Then wait, spin waiting in a loop for a time proportional to the duty cycle. When the waiting is over (simply mimic a delay counter) Then turn off the LED. Then wait for the complement of the duty cycle. Repeat.

In pseudo code:


while (true)
{
   pwm = computePercentageBasedOnAnalogSignal(analog_signal)

   turn_on_led();
   on_counter = MAX_LOOP * pwm
   off_counter = MAX_LOOP - on_counter

   // scale on/off counter values appropriately if you have a sleep()

   // replace with a sleep(on_counter) function if you have it
   while(on_counter) {
      on_counter--
   }

   // now turn it off.
   turn_off_led()

   // same comment re: sleep.  remember to scale the value as necessary
   while (off_counter) {
      off_counter--
   }

   // The LED is either on or off for a MAX_LOOP total time.
   // If the LED was on 90% of the MAX_LOOP and off 10% of MAX_LOOP
   // AND the LOOP iterates rapidly enough it will appear to be brighter
   // than if the pwm were swtiched.   The loop needs to iterate rapidly 
   // for best effect!

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM