Continue to Site

Welcome to

Welcome to our site! is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.



Jul 17, 2023
Reaction score
Trophy points
Activity points
I'm relatively new in C program ( I'm using MPLAB X IDE XC8 ), and first time trying to make a PID control, using a PIC16F15223

This is what I want to make:

  • The pic has an analog input that reads a SHUNT resistor. This will oscillate between 0-3V, so in the code between 0-615.
  • The pic has a PWM output with a fixed frequency of 100hz, the duty cycle will oscillate between 0% and 100%.
  • This is for controlling the current charge of a battery ( lead-acid ). The control is made with two SCRs making a full bridge rectifier ( with the transformer with a center tap ), the gate of the SCRs its controlled by a MOC3021 ( optocoupler ), and the MOC3021 its controlled by the PWM output of the PIC16F15223.
  • I'm having troubles with the code in C. Firstly because I never made a PID control, and then because I search some of them in the internet but I dont know how to implement them.
  • I read the current and store it in an INT variable called measured_current. Then I put it in the calculate_PID program, and that return's me a value. So that value it's the current that I will have to send as a PWM signal until it reaches a SET POINT, and then it will maintain this current to work as a constant current charge. The problem it's that I don't know how to turn this output value of the pid as a pwm duty cycle. In fact I'm not sure that the PID code its ok, because it was taked from a general PID code from internet...
  • I know that its not necessary a PID control for my case, but i dont know another one, maybie you can help me with that to...
  • I let you the code and schematic:

current_pid = calculatePID(measured_current);
            if (current_pid>0)
            else if (current_pid<0)
            else if (current_pid==0)
The PID control:

#include <stdint.h>

// Variables del control PID
double kp = 1.0;  // Ganancia proporcional
double ki = 0.5;  // Ganancia integral
double kd = 0.2;  // Ganancia derivada
double setPoint = 0;  // Valor deseado

double error = 0.0;
double prevError = 0.0;
double integral = 0.0;
double derivative = 0.0;

double calculatePID(double inputValue) {
    error = setPoint - inputValue;
    double proportional = kp * error;
    integral += ki * error;
    derivative = kd * (error - prevError);
    prevError = error;
    double output = proportional + integral + derivative;
    return output;

The PWM duty cycle can be calculated as:


Where in PWM3DCL store the 2 less significative bits and PWM3DCH the remaining ones.
I'm using PR2=155.
I would look at the electrical problem first: The SCRs probably won't trigger properly with that configuration, you probably want to trigger from the transformer output voltage instead of the battery voltage and the diodes do nothing but increase the gate voltage needed to turn them on.

The inputs to the optocouplers are better driven in parallel and ideally by a dedicated driver, the PIC will manage to produce the needed minimum 3V at say 10mA but without much safety margin.

If you are using PWM to control rectifiers you have to do it synchronously. There is nothing in your code to ensure the PWM 'turn on' part of the cycle coincides with the AC zero crossing so although the duty cycle may be correct, you could be turning the SCRs on at any part of the AC cycle. Also consider that when the SCR conducts, it stays conducting until the voltage across it causes the current through it to drop below holding threshold.

this sounds unnecessarily complex to me. you have to synchronize two SCRs for the positive and negative half cycles. I would just have a diode bridge and apply the PWM to a MOSFET.

I agree with Brian.
The inputs to the optocouplers are better driven in parallel and ideally by a dedicated driver, the PIC will manage to produce the needed minimum 3V at say 10mA but without much safety margin.
Indeed the diode forward voltage is 1.15V (1.5V max) @ 10mA.(3V is the reverse voltage)

It´s not a classical PWM. Controlling an SCR in an AC mains system with a classical (non synchronized) PWM causes the load just to get random and varying voltage. The PWM duty cycle will not even lead to highr or lower output voltage at all. Like said: random.
Thus I personally don´t like the term "PWM" in combination with a SCR phase control circuit.

--> The SCR needs to be controlled by a variable "time delay with respect to zero cross".

Off topic slightly but with these small 8-bit MCUs try VERY HARD not to use floating point.
Your inputs and outputs are integers and (form the little snippet that you have shown us) the 2 constants are to 1 decimal place. Therefore used scaled integers instead. (You could multiply the values by powers of 10. but powers of 2 are better so that you can use shifts to do the scaling.)
(The reason is that these tiny MCUs do not even have a hardware integer multiplier, let alone a floating point one. Therefore all multiplication/division is done via library functions that are brought in by the compiler. These take a lot of memory - you only have 3.5 KB flash - and are slow.)
You might need to do this sooner than you think as your code grows and you quickly run out of flash and RAM.

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to