Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Guillermo Perez Guillen
Published © 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 days5,894

Things used in this project

Hardware components

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

Software apps and online services

GNAT Community
AdaCore GNAT Community
GNAT Pro
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

Story

Read more

Schematics

Schematic Diagram

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

Circuit Diagram

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

Code

pid_light_control.adb

ADA
Ada body file
--  PID LIGHT METER CONTROLLER
--  Author GUILLERMO ALBERTO PEREZ GUILLEN
--  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

begin

   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);

   Power_Control.Attach_PWM_Channel
     (Selected_Timer'Access,
      Output_Channel,
      LED_For (Output_Channel),
      Timer_AF);

   Power_Control.Enable_Output;

   declare
      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;

   begin
      loop
         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);

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

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

pid_light_control,gpr

ADA
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

Credits

Guillermo Perez Guillen

Guillermo Perez Guillen

57 projects • 63 followers
Electronics and Communications Engineer (ECE) & Renewable Energy: 14 prizes in Hackster / Hackaday Prize Finalist 2021-22-23

Comments