8. Chapter Photoresistor & LED
Earlier we learned how to use ADC and PWM. In this chapter, we learn to control the brightness of an LED by using a potentiometer.
8.1. Project Soft Light
In this project, we will make a soft light. We will use an ADC Module to read ADC values of a potentiometer and map it to duty cycle ratio of the PWM used to control the brightness of an LED. Then you can change the brightness of an LED by adjusting the potentiometer.
8.1.1. Component List
|
|
Rotary potentiometer x1 |
|
ADC module x1
|
LED x1 |
Jumper Wire M/M x15 |
|
8.1.2. Circuit with ADS7830
Schematic diagram
|
Hardware connection. If you need any support,please feel free to contact us via:
|
8.1.3. Sketch
In this project, we will change the brightness of the LED based on the light intensity received by the photoresistor.
8.1.3.1. Sketch_08_Nightlamp
First, enter where the project is located:
$ cd ~/Freenove_Kit/Pi4j/Sketches/Sketch_08_Nightlamp
Enter the command to run the code.
$ jbang Nightlamp.java
When the code is running, use light to illuminate the photosensitive module, or cover the photosensitive module with your hand, and you can observe that the brightness of the LED on the board changes accordingly.
On the terminal, you can see the ADC and voltage values of the photoresistor are printed.
Press Ctrl+C to exit the program.
You can open the code with Geany with the following command to view and edit it.
$ geany Nightlamp.java
Click the icon to run the code.
If the code fails to run, please check Geany Configuration.
The following is program code:
1///usr/bin/env jbang "$0" "$@" ; exit $?
2
3//DEPS org.slf4j:slf4j-api:2.0.12
4//DEPS org.slf4j:slf4j-simple:2.0.12
5//DEPS com.pi4j:pi4j-core:2.6.0
6//DEPS com.pi4j:pi4j-plugin-raspberrypi:2.6.0
7//DEPS com.pi4j:pi4j-plugin-gpiod:2.6.0
8//DEPS com.pi4j:pi4j-plugin-linuxfs:2.6.0
9
10import com.pi4j.Pi4J;
11import com.pi4j.context.Context;
12import com.pi4j.io.i2c.I2C;
13import com.pi4j.io.i2c.I2CConfig;
14import com.pi4j.io.i2c.I2CProvider;
15import com.pi4j.util.Console;
16import com.pi4j.io.gpio.digital.DigitalOutput;
17import java.util.HashMap;
18import java.util.Map;
19
20class PWMController implements Runnable {
21 private DigitalOutput pwm;
22 private int pwmFrequency;
23 private double pwmDutyCycle;
24 private boolean running = true;
25 private long period;
26 private long highTime;
27 private long lowTime;
28
29 public PWMController(DigitalOutput pwm) {
30 this.pwm = pwm;
31 this.pwmFrequency = 1000;
32 this.pwmDutyCycle = 0.5;
33 this.period = (int) (1000000 / pwmFrequency);
34 this.highTime = (int) (period * pwmDutyCycle);
35 this.lowTime = (int) (period - highTime);
36 }
37
38 @Override
39 public void run() {
40 while (running) {
41 if(highTime!=0){
42 pwm.high();
43 delayUs(highTime);
44 }
45 if(lowTime!=0){
46 pwm.low();
47 delayUs(lowTime);
48 }
49 }
50 }
51
52 public void setPwmFrequency(int frequency) {
53 if(frequency!=0){
54 this.pwmFrequency = frequency;
55 this.period = (int) (1000000 / pwmFrequency);
56 this.highTime = (int) (period * pwmDutyCycle);
57 this.lowTime = (int) (period - highTime);
58 }
59 else{
60 this.pwmFrequency = 0;
61 this.period = (int) (1000);
62 this.highTime = (int) (0);
63 this.lowTime = (int) (period - highTime);
64 }
65 }
66
67 public void setPwmDutyCycle(double dutyCycle) {
68 this.pwmDutyCycle = dutyCycle;
69 this.highTime = (int) (period * pwmDutyCycle);
70 this.lowTime = (int) (period - highTime);
71 }
72
73 private void delayUs(long us) {
74 long startTime = System.nanoTime();
75 long endTime = startTime + (us * 1000);
76 while (System.nanoTime() < endTime) {
77 }
78 }
79
80 public void requestStop() {
81 running = false;
82 }
83}
84
85class ADCDevice {
86 private final I2C adcChip;
87 private final int adcChipAddr;
88
89 public ADCDevice(Context pi4j, I2CProvider provider, int adcChipAddr) throws Exception {
90 this.adcChipAddr = adcChipAddr;
91 I2CConfig i2cConfig = I2C.newConfigBuilder(pi4j).id("ADCDevice").bus(1).device(adcChipAddr).build();
92 this.adcChip = provider.create(i2cConfig);
93 }
94
95 public boolean detectI2C() throws Exception {
96 try {
97 adcChip.write(0);
98 byte[] data = new byte[1];
99 int bytesRead = adcChip.read(data, 0, 1);
100 return bytesRead == 1;
101 } catch (Exception e) {
102 return false;
103 }
104 }
105
106 public int analogRead(int chn) {
107 byte command = (byte) (0x84 | (((chn << 2 | chn >> 1) & 0x07) << 4));
108 adcChip.write(command);
109 byte[] data = new byte[1];
110 int bytesRead = adcChip.read(data, 0, 1);
111 if (bytesRead == 1) {
112 int adcValue = data[0] & 0xFF;
113 return adcValue;
114 } else {
115 return -1;
116 }
117 }
118}
119
120public class Nightlamp{
121 private static int LED_PIN = 17;
122 private static int ADC_CHIP_ADDR = 0x4B;
123 private static int ADC_CHANNEL = 0;
124
125 private static final Context pi4j = Pi4J.newAutoContext();
126 private static final Map<Integer, PWMController> pwmControllers = new HashMap<>();
127
128 public static void setPwmConfig(int pin) throws Exception {
129 DigitalOutput pwm = pi4j.dout().create(pin);
130 PWMController pwmController = new PWMController(pwm);
131 Thread pwmThread = new Thread(pwmController, "PWM Controller " + pin);
132 pwmControllers.put(pin, pwmController);
133 pwmThread.start();
134 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
135 pwmController.requestStop();
136 try {
137 pwmThread.join();
138 } catch (InterruptedException e) {
139 Thread.currentThread().interrupt();
140 }
141 }));
142 }
143
144 public static void myPrintln(String format, Object... args) {
145 Console console = new Console();
146 console.println(String.format("\u001B[32m" + format + "\u001B[0m", args));
147 }
148
149 public static void main(String[] args) throws Exception {
150 Context pi4j = Pi4J.newAutoContext();
151 I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c");
152 setPwmConfig(LED_PIN);
153 PWMController led = pwmControllers.get(LED_PIN);
154
155 try {
156 ADCDevice adc = new ADCDevice(pi4j, i2CProvider, ADC_CHIP_ADDR);
157 if (adc.detectI2C()) {
158 while (true) {
159 int adcValue = adc.analogRead(ADC_CHANNEL);
160 if (adcValue != -1) {
161 led.setPwmDutyCycle(((double)adcValue/255.0));
162 double voltage = (double)adcValue / 255.0 * 5.0;
163 myPrintln("ADC value:%d, Voltage:%.2fV", adcValue, voltage);
164 } else {
165 myPrintln("Failed to read data from ADC.");
166 }
167 Thread.sleep(100);
168 }
169 } else {
170 myPrintln("ADS7830 device not detected at address 0x" + Integer.toHexString(ADC_CHIP_ADDR));
171 }
172 } finally {
173 pi4j.shutdown();
174 }
175 }
176}
The ADC value at the photosensor is obtained every 100 milliseconds, converted into a PWM duty cycle value for controlling the LED, and then a prompt message is printed on the terminal.
1while (true) {
2 int adcValue = adc.analogRead(ADC_CHANNEL);
3 if (adcValue != -1) {
4 led.setPwmDutyCycle(((double)adcValue/255.0));
5 double voltage = (double)adcValue / 255.0 * 5.0;
6 myPrintln("ADC value:%d, Voltage:%.2fV", adcValue, voltage);
7 } else {
8 myPrintln("Failed to read data from ADC.");
9 }
10 Thread.sleep(100);
11}





