Guillermo Alberto Perez Guillen
Created February 2, 2019 © CC BY-NC-ND

PID Light Meter Controller

PID Control System of a Light Meter that measures and regulates the lighting of a lamp.

AdvancedFull instructions providedOver 2 days343

Things used in this project

Hardware components

Nucleo 144 STM32F7
ST STM32L4, STM32F7 Nucleo 144 STM32F7
Rapid IoT Prototyping Kit
NXP Rapid IoT Prototyping Kit
Photo resistor
Photo resistor
Infineon CoolMOS C7 Gold SJ MOSFET
L293B Driver
Resistor 10k ohm
Resistor 10k ohm
Resistor 1k ohm
Resistor 1k ohm
Resistor 30 ohm
LED (generic)
LED (generic)

Software apps and online services

GNAT Community
AdaCore GNAT Community
AdaCore GNAT Pro
NXP Rapid IoT Studio
AdaCore Ada Drivers Library
PID example By Lowell Cady

Hand tools and fabrication machines

PICkit 2
Mastech MS8217 Autorange Digital Multimeter
Digilent Mastech MS8217 Autorange Digital Multimeter


Read more


Schematic Diagram

Schematic diagram of the project: "PID Light Meter Controller"
Schematic diagram blzdpshg3r

Circuit Diagram

Electric diagram of the project: "PID Light Meter Controller"
Electric diagram rple0m2hru



Ada body file
--  February 2, 2019
--  This demonstration illustrates the use of:
--  1) PWM PID signal to control a LIGHT on PD15, 

with Last_Chance_Handler;  pragma Unreferenced (Last_Chance_Handler);

with STM32.Board;  use STM32.Board;
with STM32.Device; use STM32.Device;
with STM32.PWM;    use STM32.PWM;
with STM32.Timers; use STM32.Timers;

with HAL;          use HAL; --adc library
with STM32.ADC;    use STM32.ADC; --adc library
with STM32.GPIO;   use STM32.GPIO; --adc library

with Ada.Real_Time;  use Ada.Real_Time; --adc library

procedure Pid_Light_Control is

   Converter     : Analog_To_Digital_Converter renames ADC_1; --adc instruction
   Input_Channel : constant Analog_Input_Channel := 1; --adc instruction, channel 1
   Input1         : constant GPIO_Point := PA1; --adc instruction, PA1 port

   All_Regular_Conversions : constant Regular_Channel_Conversions :=
          (1 => (Channel => Input_Channel, Sample_Time => Sample_144_Cycles)); --adc instruction

   Raw : UInt32 := 0; --adc instruction

   Successful : Boolean; --adc instruction

   Selected_Timer : STM32.Timers.Timer renames Timer_4;
   --  NOT arbitrary! We drive the on-board LEDs that are tied to the channels
   --  of Timer_4 on some boards. Not all boards have this association. If you
   --  use a different board, select a GPIO point connected to your selected
   --  timer and drive that instead.

   Timer_AF : constant STM32.GPIO_Alternate_Function := GPIO_AF_TIM4_2;
   --  Note that this value MUST match the corresponding timer selected!

   Output_Channel : constant Timer_Channel := Channel_4; -- Blue LED is selected
   --  The LED driven by this example is determined by the channel selected.
   --  That is so because each channel of Timer_4 is connected to a specific
   --  LED in the alternate function configuration on this board. We will
   --  initialize all of the LEDs to be in the AF mode. The
   --  particular channel selected is completely arbitrary, as long as the
   --  selected GPIO port/pin for the LED matches the selected channel.

   LED_For : constant array (Timer_Channel) of User_LED :=
               (Channel_1 => Green_LED,
                Channel_2 => Orange_LED,
                Channel_3 => Red_LED,
                Channel_4 => Blue_LED);

   Requested_Frequency : constant Hertz := 30_000;  -- PWM frequency

   Power_Control : PWM_Modulator;

   procedure Configure_Analog_Input is --adc instruction
   begin -- adc
      Enable_Clock (Input1); --adc instruction
      Configure_IO (Input1, (Mode => Mode_Analog, Resistors => Floating)); -- adc instruction
   end Configure_Analog_Input; --adc instruction


   Initialize_LEDs; --adc instruction

   Configure_Analog_Input; --adc instruction

   Enable_Clock (Converter); --adc instruction

   Reset_All_ADC_Units; --adc instruction

   Configure_Common_Properties --adc instruction
     (Mode           => Independent, --adc instruction
      Prescalar      => PCLK2_Div_2, --adc instruction
      DMA_Mode       => Disabled, --adc instruction
      Sampling_Delay => Sampling_Delay_5_Cycles); --adc instruction

   Configure_Unit --adc instruction
     (Converter, --adc instruction
      Resolution => ADC_Resolution_12_Bits, --adc instruction
      Alignment  => Right_Aligned); --adc instruction

   Configure_Regular_Conversions --adc instruction
     (Converter, --adc instruction
      Continuous  => False, --adc instruction
      Trigger     => Software_Triggered, --adc instruction
      Enable_EOC  => True, --adc instruction
      Conversions => All_Regular_Conversions); --adc instruction

   Enable (Converter); --adc instruction

   Configure_PWM_Timer (Selected_Timer'Access, Requested_Frequency);

      LED_For (Output_Channel),


      Value     : Percentage;
      Raw1      : Long_Float;
--      setpoint  : constant := 1480.0; -- 1.084 volts approx - 43 lx
      setpoint  : constant := 2067.0; -- 1.514 volts approx - 86 lx
      error     : Long_Float := 0.0;
      output    : Long_Float;
      integral  : Long_Float := 0.0;
      dt        : constant := 0.0005;
      Kp        : constant := 0.025;
      Ki        : constant := 0.025;

         Start_Conversion (Converter); --adc instruction
         Poll_For_Status (Converter, Regular_Channel_Conversion_Complete, Successful); --adc instruction
         Raw := UInt32 (Conversion_Value (Converter)); -- reading PA1
         Raw1 := Long_Float(Raw * 1);
         error := (setpoint - Raw1);
         integral := (integral + (error*dt));
         output := ((Kp*error) + (Ki*integral));
         Value := Percentage (output); -- duty cycle value

         if Value < 10 then
            Power_Control.Set_Duty_Cycle (10);
         elsif Value > 90 then
            Power_Control.Set_Duty_Cycle (90);

            Power_Control.Set_Duty_Cycle (Value); -- PWM signal
         end if;

         delay until Clock + Milliseconds (10); -- slow it down to ease reading
      end loop;
end Pid_Light_Control;


GNAT project file
with "../../../../../boards/stm32f407_discovery/stm32f407_discovery_full.gpr";

project Pid_Light_Control extends "../../../../../examples/shared/common/common.gpr" is
	for Languages use ("Ada");
	for Main use ("pid_light_control.adb");
    for Source_Dirs use ("src");
    for Object_Dir use "obj/" & STM32F407_Discovery_Full.Build;
    for Runtime ("Ada") use STM32F407_Discovery_Full'Runtime("Ada");
    for Create_Missing_Dirs use "true";

    package Builder is
       for Global_Configuration_Pragmas use "gnat.adc";
    end Builder;

    package Compiler renames STM32F407_Discovery_Full.Compiler;
end Pid_Light_Control;

Project repository: "PID Light Meter Controller”

This project contains the project codes: "PID Light Meter Controller" Programming Language: AdaCore


Guillermo Alberto Perez Guillen

Guillermo Alberto Perez Guillen

25 projects • 20 followers
Communications and Electronics Engineering, Military Engineer and Writer... "Don´t Expect Different Results If Your Habits Are The Same" AE