• How to use bipolar stepper motor using l298n module and raspberry pi pico w

    The stepper motor that i have is a bipolar stepper motor.

    On it one side there is information about it.

    TYPE: 17PM-k310-33VS
    NO.   T4508-03
        Minebea-Matsushita
        Motor Corporation
         Made in Thailand

    It is a NEMA 17
    17 stands for 1.7inches

    Raspberry Pi Pico WL298N Module
    GNDGND
    GP0IN1
    GP1IN2
    GP2IN3
    GP3IN4

    The two coils pair are found using the multimeter in resistance mode.

    Since I am using a regular motor driver. I cannot do the micro stepping.
    But even with micro stepping, it can do a lot of stuff.

    So there are two coil pair.
    step angle of 1.8o degrees.

    So to make a 360o
    we need 360o / 1.8o = 200 steps

    So we can make a full rotation with 200 steps of 1.8 degrees each.
    This is what is known as the full step.
    In full step, we only excite 1 pole at a time. There are two poles per coil.

    We can excite two poles at a time. Which will half the step angle to 0.9 degrees.
    The following is the table I have made to see how many steps I will be made by employing a 0.9 deg angle. It is only up to 300 steps or 270 deg. You can calculate from then on.

    Micropython Code

    from machine import Pin
    import utime
    motor_pins = [Pin(0, Pin.OUT), Pin(1, Pin.OUT), Pin(2, Pin.OUT), Pin(3, Pin.OUT)]
    step_sequence = [
        [1,0,0,0],#1
        [1,0,1,0],#13
        [0,0,1,0],#3
        [0,1,1,0],#23
        [0,1,0,0],#2
        [0,1,0,1],#24
        [0,0,0,1],#4
        [1,0,0,1]#41  
    ]
    off_seq = [(0,0,0,0)]
    length_step_sequence = len(step_sequence)
    one_rotation_length = 400/length_step_sequence
    step_delay = (1/1000)*10 #ms
    def step_off():
        #print("step off")
        motor_pins[0].value(0)
        motor_pins[1].value(0)
        motor_pins[2].value(0)
        motor_pins[3].value(0)
        utime.sleep(step_delay)
    '''
    Function Name: move_step
    Description:
    It takes the step sequence and assigns the motor pins to the value
    according to the step sequence.
    It moves one step seqence at a time.
    For a half step sequence
    each step will be 0.9 degrees.
    For a full step sequence
    each step will be 1.8 degrees.
    '''
    def move_step(seq):
        ygh = seq
        #print(ygh)
        for step1,pins in zip(ygh,motor_pins):
            pins.value(step1)
    '''
    Function Name: move one step
    Description:
    It moves all the steps in the sequence.
    For a half wave steps => 8 * 0.9 = 7.2 deg
    For a full wave steps => 4 * 1.8 = 7.2 deg
    '''
    def move_one_step(forward,reverse):
        for i in range(0,length_step_sequence,1):
            if forward == 1:
                move_step((step_sequence[i]))
            elif reverse == 1:
                move_step(reversed(step_sequence[i]))
            utime.sleep(step_delay)
    def rotation(steps,forward,reverse):
        
        if forward == 1:
            for i in range(steps):
                move_one_step(1,0)
                print("Forward steps: ",steps)
        elif reverse == 1:
            for i in range(steps):
                move_one_step(0,1)
                print("Reverse steps: ",steps)
        
            #step_off()
    
    '''
    Half step calculations
    8 Steps of 0.9 deg each.
    total degree of 8 steps => 8 * 0.9 = 7.2
    (8 step sequence) * (50 repeated steps) * 0.9 deg = 360
    So, a total of 400 steps are required to make 360 degree.
    7.2 deg x (50 repeated steps) = 360 degrees
    7.2 deg x 25 = 180 degree
    '''
    while True:
        rotation(25,1,0) # move 180 forward(CW) 
        utime.sleep(1)
        rotation(50,0,1) # move 366 reverse (CCW)
        utime.sleep(1)
    
  • 12V PC Fan Control Using Raspberry Pi Pico W By PWM

    How to control a 12V PC fan using Pulse Width Modulation (PWM) signals with the Raspberry Pi Pico W board and an L298N motor driver module. I will use the MicroPython programming language and the Thonny IDE to write and run the code.

    Raspberry Pi Pico WL298n Module
    GP9IN1
    GNDGND
    VSYS
    (Connect this only when you save as “main.py” in raspberry pi.)
    +5V
    12V PC FANL298n Module
    Positive Lead(+12V wire)OUT1
    Negative Lead OUT2

    Micropython Code

    import network
    import socket
    import time
    from time import sleep
    from picozero import pico_temp_sensor, pico_led
    import machine
    
    ssid = 'Abhay'
    password = 'AK26@#36'
    
    wdt = machine.WDT(timeout=5000)  # Timeout in milliseconds (e.g., 5000ms = 5 seconds)
    def feed_watchdog(timer):
        wdt.feed()  # Feed the watchdog timer to reset the countdown
    
    timerWdt = machine.Timer()
    timerWdt.init(period=1000, mode=machine.Timer.PERIODIC, callback=feed_watchdog)
    
    GPIO_PIN_9 = machine.Pin(9)
    pwm9 = machine.PWM(GPIO_PIN_9)
    pwm9.freq(25000)
        
    current_pwm_duty = 0
    sleep_duration = 0.01
    def updateFan(x,y):
        global current_pwm_duty,sleep_duration
        current_pwm_duty = x
        
        if sleep_duration > 0 and sleep_duration <= 2:
            sleep_duration = y
        else:
            sleep_duration = 0.01
    
    def fanon(timer):
        global current_pwm_duty,sleep_duration
        pwm9.duty_u16(current_pwm_duty)
        time.sleep(sleep_duration)
        pwm9.duty_u16(0)
        
    def fanoff():
        pwm9.duty_u16(0)
    
    timerUpdate = machine.Timer()
    timerUpdate.init(period=2000, mode=machine.Timer.PERIODIC, callback=fanon)
    def connect():
        #Connect to WLAN
        wlan = network.WLAN(network.STA_IF)
        wlan.active(True)
        wlan.connect(ssid, password)
        while wlan.isconnected() == False:
            print('Waiting for connection...')
            sleep(1)
        ip = wlan.ifconfig()[0]
        print(f'Connected on {ip}')
        return ip
    
    def open_socket(ip):
        # Open a socket
        address = (ip, 80)
        connection = socket.socket()
        connection.bind(address)
        connection.listen(1)
        return connection
    
    def webpage(temperature, state,user_value):
        #Template HTML
        
        html = f"""
                <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <form action="./lighton" style="display: flex; justify-content: center;">
            <input type="submit" value="Light on" style="font-size: 40px;" />
        </form>
        <form action="./lightoff" style="display: flex; justify-content: center;">
            <input type="submit" value="Light off" style="font-size: 40px;" />
        </form>
        <p style="font-size: 20px;">LED is {state}</p>
        <p style="font-size: 20px;">Temperature is {temperature}</p>
        
        
        <form action="./fanon_LOW" style="display: flex; justify-content: center;">
            <input type="submit" value="FAN on LOW" style="font-size: 40px;" />
        </form>
         <form action="./fanon_MID" style="display: flex; justify-content: center;">
            <input type="submit" value="FAN on MID" style="font-size: 40px;" />
        </form>
        <form action="./fanon_FULL" style="display: flex; justify-content: center;">
            <input type="submit" value="FAN off FULL" style="font-size: 40px;" />
        </form>
        <form action="./fanoff" style="display: flex; justify-content: center;">
            <input type="submit" value="FAN off" style="font-size: 40px;" />
        </form>
        
        <h1>Numeric Form</h1>
        <form method=POST action="/usrval">
            <label for="value">Enter a numeric value:</label><br>
            <input type="number" id="value" name="value" min="30" max="65" value="30"required><br><br>
            <input type="submit" value="Submit">
        </form>
        <p>User value: {user_value}</p>  <!-- Display the user-submitted value -->
    </body>
    </html>
    
    
                """
        return str(html)
    def serve(connection):
        #Start a web server
        state = 'OFF'
        pico_led.off()
        temperature = 0
        user_value = None  # Variable to store the user-submitted value
        usr_int = 0
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            rqst1 = request.split()
            '''
            for x1 in rqst1:
                if(x1.find("usrval") != -1):
                    print(rqst1)
                    #print(x1)
            #print(rqstfind)
            '''
            try:
                
                for x1 in rqst1:
                    if "value=" in x1:
                        user_value = x1.split("=")[2].strip("'")
                        usr_int = int(user_value) * 1000
                        if usr_int >= 65535:
                            usr_int = 65535
                        if usr_int <= 0:
                            usr_int = 0
                        print(user_value," ",type(user_value)," int:",usr_int," ",type(usr_int))
                        
                        
                        
            except:
                pass
            
            try:
                request = request.split()[1]
            except IndexError:
                pass
            if request == '/lighton?':
                pico_led.on()
                state = 'ON'
            elif request =='/lightoff?':
                pico_led.off()
                state = 'OFF'
            elif request == '/fanon_LOW?':
                #put the usr value in the pwm duty
                updateFan(30000,1.75)
            elif request == '/fanon_MID?':
                #put the usr value in the pwm duty
                updateFan(45000,1.5)
            elif request == '/fanon_FULL?':
                #put the usr value in the pwm duty
                updateFan(65000,1.6) 
            elif request == '/fanoff?':
                updateFan(0,1)
            
              
            temperature = pico_temp_sensor.temp
            html = webpage(temperature, state,user_value)
            client.send(html)
            client.close()
    
    try:
        ip = connect()
        connection = open_socket(ip)
        serve(connection)
    except KeyboardInterrupt:
        machine.reset()
    
  • How to Use C SDK to Create UF2 file which Interface Ultrasonic Sensor with Raspberry Pi Pico

    Hardware setup

    HC-SR04Raspberry Pi Pico
    VCCVSYS
    GNDGND
    TrigGP2
    ECHOGP3

    I am using raspberry pi model 3 b+ for the code compilation.

    1. Create the folder named “distance” inside the pico folder
    1. Then Create the test.c and CMakeLists.txt files using touch command.
    touch test.c CMakeLists.txt
    1. Copy the pico_sdk_import.cmake file from pico/pico-sdk/external
    2. make the build directory using mkdir command
    mkdir build
    1. Here is the CMakeLists.txt code
    # Set the minimum required version of CMake
    cmake_minimum_required(VERSION 3.13)
    
    # Import the Pico SDK CMake configuration file
    include(pico_sdk_import.cmake)
    
    # Set the project name and languages
    project(test_project C CXX ASM)
    
    # Set the C and C++ language standards
    set(CMAKE_C_STANDARD 11)
    set(CMAKE_CXX_STANDARD 17)
    
    # Initialize the Pico SDK
    pico_sdk_init()
    
    # Create an executable target called "test" from the source file "test.c"
    add_executable(test
        test.c
    )
    
    # Enable USB stdio for the "test" target (used for serial communication)
    pico_enable_stdio_usb(test 1)
    
    # Disable UART stdio for the "test" target
    pico_enable_stdio_uart(test 0)
    
    # Add extra outputs for the "test" target (e.g., UF2 file)
    pico_add_extra_outputs(test)
    
    # Link the "test" target with the pico_stdlib library
    target_link_libraries(test pico_stdlib)
    
    1. Here is the c code that you put inside the test.c file
    #include <stdio.h>
    #include "pico/stdlib.h"
    #include "hardware/gpio.h"
    #include "hardware/timer.h"
    
    #define TRIG_PIN 2
    #define ECHO_PIN 3
    
    float measure_distance() {
        gpio_put(TRIG_PIN, 1);
        sleep_us(10);
        gpio_put(TRIG_PIN, 0);
    
        uint32_t start_ticks = 0;
        uint32_t end_ticks = 0;
    
        while (gpio_get(ECHO_PIN) == 0) {
            start_ticks = time_us_32();
        }
    
        while (gpio_get(ECHO_PIN) == 1) {
            end_ticks = time_us_32();
        }
    
        uint32_t elapsed_time_us = end_ticks - start_ticks;
        float distance_cm = elapsed_time_us * 0.0343 / 2;
    
        return distance_cm;
    }
    
    int main() {
        stdio_init_all();
        sleep_ms(2000);  // Wait for sensor to stabilize
    
        gpio_init(TRIG_PIN);
        gpio_set_dir(TRIG_PIN, GPIO_OUT);
    
        gpio_init(ECHO_PIN);
        gpio_set_dir(ECHO_PIN, GPIO_IN);
    
        while (1) {
            float distance = measure_distance();
            printf("Distance: %.2f cm\n", distance);
            sleep_ms(1000);
        }
    
        return 0;
    }
    
    1. after this you need to execute this line of code in the terminal
    export PICO_SDK_PATH=../../pico
    1. then execute the following code in the given order
    cd build
    cmake ..
    make

    If everything worked, you will have your ulf2 file in your build directory

  • Interfacing a 5V Ultrasonic Sensor with 3.3V GPIO of Raspberry Pi Pico: A Voltage Divider Solution

    I have an old HC-Sr04 ultrasonic sensor. I don’t know if it’s GPIO voltage compatible with the 3.3V microcontroller.
    On the internet, I found that the old sensors work with 5V.

    So, I used a voltage divider made of 1K ohm and 1.5K ohm Surface mount resistors. To bring down the 5V to a suitable 3V.

    I want to reduce the voltage level on the ECHO pin of the ultrasonic sensor to a safe level for the Raspberry Pi Pico’s GPIO pins. Let’s assume we have chosen resistors R1 and R2 with values of 1K and 1.5K, respectively.

    You can also use the voltage divider calculator for this
    Voltage Divider Calculator

    Using the voltage divider formula, we can calculate the output voltage at the midpoint (E_3) of the voltage divider circuit:

    V_out = V_in * (R2 / (R1 + R2))

    Since the Vsys pin of the Raspberry Pi Pico provides a voltage of 5V, we can calculate the output voltage:

    V_out = 5V * (1.5K / (1K + 1.5K))
    = 5V * (1.5K / 2.5K)
    = 5V * 0.6
    = 3V

    With the given resistor values, the output voltage at the midpoint of the voltage divider circuit will be 3V. This 3V output is within the safe voltage range for the GPIO pins of the Raspberry Pi Pico.

    Code Implementation:

    To implement the interface between the ultrasonic sensor and the Raspberry Pi Pico, we will utilize MicroPython, a lightweight Python implementation for microcontrollers. The following code snippet demonstrates the necessary steps:

    from machine import Pin
    import utime
    trigger = Pin(2, Pin.OUT)
    echo = Pin(3, Pin.IN)
    def ultra():
       trigger.low()
       utime.sleep_us(2)
       trigger.high()
       utime.sleep_us(10)
       trigger.low()
       while echo.value() == 0:
           signaloff = utime.ticks_us()
       while echo.value() == 1:
           signalon = utime.ticks_us()
       timepassed = signalon - signaloff
       distance = (timepassed * 0.0343) / 2
       print("The distance from object is ",distance,"cm")
       
    while True:
       ultra()
       utime.sleep(1)
    
  • Integral Control Demo in Control Systems Engineering Using Slider in Tkinter

    Introduction:

    Control systems engineering plays a crucial role in regulating and optimizing various processes in industries, robotics, and automation. One fundamental concept in control systems is integral control, which aims to reduce steady-state error and improve system performance. In this blog post, we will explore integral control, its implementation in Python using tkinter, and discuss its importance in control systems.

    Understanding Integral Control:

    Integral control is a control technique that integrates the error signal over time and uses the accumulated integral term to adjust the control signal. It helps to compensate for any steady-state error and drive the system towards the desired setpoint. The integral control component is typically employed alongside proportional and derivative control, forming the PID control algorithm.

    Implementation using Python tkinter:

    To better grasp the concept of integral control, let’s examine a Python code snippet that demonstrates its implementation using the tkinter library:

    import tkinter as tk
    import time
    import threading
    import webbrowser
    # Integral control function
    def integral_control(error, integral_sum):
        # Integral gain
        Ki = 0.1
        integral_sum += error
        integral_term = Ki * integral_sum
        return integral_term, integral_sum
    
    # Main loop
    def main_loop():
        setpoint = 50  # Desired setpoint
        process_variable = 0  # Initial process variable
        integral_sum = 0  # Accumulated integral sum
        while True:
            # Read process variable from the slider
            process_variable = slider.get()
    
            # Calculate the error
            error = setpoint - process_variable
    
            # Apply integral control
            integral_term, integral_sum = integral_control(error, integral_sum)
    
            # Actuate the control signal (in this example, update the label)
            control_label.configure(text="Integral Term: {:.2f}".format(integral_term))
    
            time.sleep(0.1)  # Sleep for 0.1 seconds
    
    
    # Callback function for the slider
    def slider_callback(value):
        feedback_label.configure(text="Feedback Stimulus: {:.2f}".format(float(value)))
    
    # Open exasub.com in a web browser
    def open_link(event):
        webbrowser.open("http://www.exasub.com")
    
    # Create the main Tkinter window
    window = tk.Tk()
    window.title("Integral Control Demo")
    
    # Create the slider for adjusting the feedback stimulus
    slider = tk.Scale(window, from_=0, to=100, orient=tk.HORIZONTAL, length=300, command=slider_callback)
    slider.pack()
    
    # Create a label to display the feedback stimulus value
    feedback_label = tk.Label(window, text="Feedback Stimulus: {:.2f}".format(slider.get()))
    feedback_label.pack()
    
    # Create a label to display the integral term value
    control_label = tk.Label(window, text="Integral Term: ")
    control_label.pack()
    
    # Add a link to exasub.com
    link = tk.Label(window, text="Visit exasub.com", fg="blue", cursor="hand2", font=("Arial", 14))
    link.pack()
    link.bind("<Button-1>", open_link)
    
    # Start the main loop in a separate thread
    import threading
    main_loop_thread = threading.Thread(target=main_loop)
    main_loop_thread.start()
    
    # Start the Tkinter event loop
    window.mainloop()
    

    Explanation:

    In the code snippet, we begin by setting up the graphical user interface (GUI) using tkinter. The GUI consists of a slider for adjusting the feedback stimulus, labels to display the feedback stimulus value and the integral term value, and a link to a website. The slider is used to simulate the process variable, while the labels provide real-time feedback on the control system’s behavior.

    The integral control algorithm is implemented within the integral_control function. It calculates the integral term based on the error and the accumulated integral sum. The integral gain, represented by Ki, determines the contribution of the integral term to the control signal. By adjusting the integral gain, the system’s response can be fine-tuned.

    The main loop continuously reads the process variable from the slider and calculates the error by comparing it to the desired setpoint. It then calls the integral_control function to compute the integral term. The integral term is used to actuate the control signal or update the label in the GUI, providing a visual representation of the control system’s behavior.

    Importance of Integral Control:

    Integral control is essential in control systems engineering for several reasons:

    1. Reducing Steady-state Error: Integral control helps to eliminate or minimize any steady-state error, ensuring that the system reaches and maintains the desired setpoint accurately.
    2. System Stability: By continuously adapting the control signal based on the accumulated error, integral control improves the system’s stability and responsiveness. It enables the system to overcome disturbances and maintain optimal performance.
    3. Robustness: Integral control enhances the control system’s robustness by accounting for systematic biases and external disturbances. It enables the system to adapt to changing conditions and maintain accurate control.

    Conclusion:

    Integral control is a key component of control systems engineering, enabling precise regulation and optimization of processes. By integrating the error over time, integral control reduces steady-state error and enhances system performance. In this blog post, we explored integral control and its implementation using Python’s tkinter library. We also discussed the importance of integral control in achieving robust and stable control systems.

    As you delve further into control systems engineering, consider exploring additional control techniques, such as proportional and derivative control, to create more advanced control systems. Experimenting with different control strategies will deepen your understanding of control systems and their practical applications.

  • Proportional Control Demo using Slider in Tkinter

    Understanding Proportional Control:
    Proportional control is a basic feedback control technique that adjusts the control signal proportionally to the error between a desired setpoint and the process variable. The process variable represents the current state of the system being controlled. By continuously monitoring and adjusting the control signal, the system strives to minimize the error and achieve the desired setpoint.

    I have created this simple program using python and tkinter library.

    When this program is run. A slider will appear which you can move.

    A set point of 50 is given as the default value.
    When you start the program the slider will be at 0 position. As you increase your slider you will see a change in the control signal parameter.

    This Control Signal will be 0 at your set point which is 50.
    As you go past the set point the control signal will become negative.

    The system will keep changing the control signal to make the slider reach it’s set point.

    Code

    import tkinter as tk
    import time
    import webbrowser
    
    # Proportional control function
    def proportional_control(error):
        # Proportional gain
        Kp = 0.5
        control_signal = Kp * error
        return control_signal
    
    # Main loop
    def main_loop():
        setpoint = 50  # Desired setpoint
        process_variable = 0  # Initial process variable
        while True:
            # Read process variable from the slider
            process_variable = slider.get()
    
            # Calculate the error
            error = setpoint - process_variable
    
            # Apply proportional control
            control_signal = proportional_control(error)
    
            # Actuate the control signal (in this example, update the label)
            control_label.configure(text="Control Signal: {:.2f}".format(control_signal))
    
            time.sleep(0.1)  # Sleep for 0.1 seconds
    
    
    # Callback function for the slider
    def slider_callback(value):
        feedback_label.configure(text="Feedback Stimulus: {:.2f}".format(float(value)))
    
    # Open exasub.com in a web browser
    def open_link(event):
        webbrowser.open("http://www.exasub.com")
    
    # Create the main Tkinter window
    window = tk.Tk()
    window.title("Proportional Control Demo")
    
    # Create the slider for adjusting the feedback stimulus
    slider = tk.Scale(window, from_=0, to=100, orient=tk.HORIZONTAL, length=300, command=slider_callback)
    slider.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
    
    # Create a label to display the feedback stimulus value
    feedback_label = tk.Label(window, text="Feedback Stimulus: {:.2f}".format(slider.get()))
    feedback_label.grid(row=1, column=0, padx=10, pady=5)
    
    # Create a label to display the control signal value
    control_label = tk.Label(window, text="Control Signal: ")
    control_label.grid(row=1, column=1, padx=10, pady=5)
    
    # Add a link to exasub.com
    link = tk.Label(window, text="Visit exasub.com", fg="blue", cursor="hand2", font=("Arial", 14))
    link.grid(row=2, column=0, columnspan=2, padx=10, pady=5)
    link.bind("<Button-1>", open_link)
    
    # Start the main loop in a separate thread
    import threading
    main_loop_thread = threading.Thread(target=main_loop)
    main_loop_thread.start()
    
    # Start the Tkinter event loop
    window.mainloop()
    


    Let’s dive into the code provided and understand how the proportional control demo works.

    # Main loop
    def main_loop():
        setpoint = 50  # Desired setpoint
        process_variable = 0  # Initial process variable
        while True:
            # Read process variable from the slider
            process_variable = slider.get()
    
            # Calculate the error
            error = setpoint - process_variable
    
            # Apply proportional control
            control_signal = proportional_control(error)
    
            # Actuate the control signal (in this example, update the label)
            control_label.configure(text="Control Signal: {:.2f}".format(control_signal))
    
            time.sleep(0.1)  # Sleep for 0.1 seconds

    Explanation of the Code:
    The provided code demonstrates a simple scenario where the process variable is obtained from a slider widget. Here’s a breakdown of the code’s key components:

    1. Setpoint: The setpoint variable represents the desired value or setpoint that we want the process variable to reach.
    2. Process Variable: The process_variable variable holds the current value of the system being controlled, obtained from the slider widget.
    3. Error Calculation: The error is calculated by subtracting the process variable from the setpoint. The error represents the deviation of the process variable from the desired value.
    4. Proportional Control: The proportional_control function, not provided in the code snippet, applies the proportional control algorithm. This function takes the error as input and computes the control signal accordingly.
    5. Actuation: In this example, the control signal is applied by updating a label (control_label) to display the control signal value. In a real-world scenario, the control signal would be used to actuate a physical system, such as adjusting a motor’s speed or a valve’s position.
    6. Timing: To ensure the control loop operates at a reasonable speed, a small delay of 0.1 seconds is introduced using time.sleep(0.1). This delay allows the control system to stabilize before the next iteration.

    Understanding Proportional Control:
    Proportional control works by adjusting the control signal in proportion to the error. The control signal can be interpreted as an effort or corrective action to reduce the error. In this demo, the control signal is calculated by the proportional_control function, which is not provided in the code snippet.

    The proportional control algorithm typically involves multiplying the error by a constant gain, known as the proportional gain (Kp). The control signal is then obtained by multiplying the error with Kp. The value of Kp determines the system’s responsiveness to the error, and finding the appropriate gain is crucial for stable and efficient control.

    Conclusion:
    The proportional control demo showcased in this blog post provides a basic understanding of how proportional control operates within a control system. By continuously adjusting the control signal based on the error between the setpoint and the process variable, proportional control helps bring the system closer to the desired state. Proportional control is just one of many control techniques, and understanding its principles is vital for delving into more advanced control strategies.

    Remember that proportional control alone may not be sufficient for complex systems, as it lacks the ability to anticipate and account for system dynamics. Nonetheless, it forms the foundation for more advanced control techniques like PID (Proportional-Integral-Derivative) control.

    So go ahead, experiment with the demo code, and explore the fascinating world of control systems!

  • How to Transmit Data via UART with ATmega328P in AVR C using Arduino IDE

    EnglishDeutschHindi

    To transmit data via UART with the ATmega328P microcontroller in AVR C using the Arduino IDE, you can follow these steps:

    1. Include the necessary header files:
       #include <avr/io.h>
       #include <util/delay.h>
       #include <avr/interrupt.h>
       #include <stdlib.h>
    1. Define the UART settings:
       #define BAUDRATE 9600
       #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    1. Initialize UART by configuring the baud rate and other settings:
       void uart_init() {
         UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
         UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
         UCSR0B = (1 << TXEN0);  // Enable transmitter
         UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
       }
    1. Implement the function to transmit data:
       void uart_transmit(uint8_t data) {
         while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
         UDR0 = data;  // Put data into the buffer, sends the data
       }
    1. Call the uart_init() function in your setup() function to initialize UART communication:
       void setup() {
         // Other setup code...
         uart_init();
         // More setup code...
       }
    1. Use uart_transmit() to send data:
       void loop() {
         // Transmit a character
         uart_transmit('A');
    
         // Delay between transmissions
         _delay_ms(1000);
       }

    Make sure to connect the appropriate UART pins (TX) to the corresponding pins on your Arduino board. Additionally, set the correct BAUDRATE value based on your desired communication speed.

    Complete Code
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    void setup() {
      // Other setup code...
      uart_init();
      // More setup code...
    }
    void loop() {
      // Transmit a character
      uart_transmit('A');
    
      // Delay between transmissions
      _delay_ms(1000);
    }
    

    Demo Program That Transmits String of Characters

    #include <avr/io.h>
    #include <util/delay.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
        _delay_ms(100);  // Delay between character transmissions
      }
    }
    
    void setup() {
      // Initialize UART
      uart_init();
    }
    
    void loop() {
      // Transmit a string
      uart_transmit_string("Hello, world!");
    
      // Delay before transmitting again
      _delay_ms(2000);
    }
    

    Um Daten über UART mit dem ATmega328P Mikrocontroller in AVR C unter Verwendung der Arduino IDE zu übertragen, können Sie die folgenden Schritte befolgen:

    Fügen Sie die erforderlichen Header-Dateien ein:

       #include <avr/io.h>
       #include <util/delay.h>
       #include <avr/interrupt.h>
       #include <stdlib.h>

    Definieren Sie die UART-Einstellungen:

       #define BAUDRATE 9600
       #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

    Initialisieren Sie UART, indem Sie die Baudrate und andere Einstellungen konfigurieren:

       void uart_init() {
         UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
         UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
         UCSR0B = (1 << TXEN0);  // Sender aktivieren
         UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-Bit Datenformat
       }

    Implementieren Sie die Funktion zum Senden von Daten:

       void uart_transmit(uint8_t data) {
         while (!(UCSR0A & (1 << UDRE0)));  // Warten auf leeren Sendepuffer
         UDR0 = data;  // Daten in den Puffer schreiben und senden
       }

    Rufen Sie die Funktion uart_init() in Ihrer setup() Funktion auf, um die UART-Kommunikation zu initialisieren:

       void setup() {
         // Andere Setup-Code...
         uart_init();
         // Weitere Setup-Code...
       }

    Verwenden Sie uart_transmit(), um Daten zu senden:

       void loop() {
         // Ein Zeichen übertragen
         uart_transmit('A');
    
         // Verzögerung zwischen den Übertragungen
         _delay_ms(1000);
       }

    Stellen Sie sicher, dass Sie die entsprechenden UART-Pins (TX) mit den entsprechenden Pins auf Ihrem Arduino-Board verbinden. Stellen Sie außerdem den korrekten BAUDRATE-Wert entsprechend Ihrer gewünschten Kommunikationsgeschwindigkeit ein.

    Vollständiger Code
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    void setup() {
      // Other setup code...
      uart_init();
      // More setup code...
    }
    void loop() {
      // Transmit a character
      uart_transmit('A');
    
      // Delay between transmissions
      _delay_ms(1000);
    }
    

    Demo-Programm zum Senden einer Zeichenkette von Zeichen

    #include <avr/io.h>
    #include <util/delay.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
        _delay_ms(100);  // Delay between character transmissions
      }
    }
    
    void setup() {
      // Initialize UART
      uart_init();
    }
    
    void loop() {
      // Transmit a string
      uart_transmit_string("Hello, world!");
    
      // Delay before transmitting again
      _delay_ms(2000);
    }
    

    एटीमेगा328पी माइक्रोकंट्रोलर के साथ AVR C और Arduino IDE का उपयोग करके UART के माध्यम से डेटा भेजने के लिए, आप निम्नलिखित चरणों का पालन कर सकते हैं:

    आवश्यक हेडर फ़ाइलें शामिल करें:

       #include <avr/io.h>
       #include <util/delay.h>
       #include <avr/interrupt.h>
       #include <stdlib.h>

    UART सेटिंग्स को परिभाषित करें:

       #define BAUDRATE 9600
       #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

    बॉड दर और अन्य सेटिंग्स को कॉन्फ़िगर करके UART को प्रारंभ करें:

       void uart_init() {
         UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
         UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
         UCSR0B = (1 << TXEN0);  // ट्रांसमीटर सक्षम करें
         UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-बिट डेटा फ़ॉर्मेट
       }

    डेटा भेजने के लिए फ़ंक्शन को लागू करें:

       void uart_transmit(uint8_t data) {
         while (!(UCSR0A & (1 << UDRE0)));  // खाली ट्रांसमिट बफर के लिए प्रतीक्षा करें
         UDR0 = data;  // डेटा को बफर में डालें, डेटा भेजें
       }

    आपकी सेटअप() फ़ंक्शन में uart_init() फ़ंक्शन को कॉल करें, UART संचार को प्रारंभ करने के लिए:

       void setup() {
         // अन्य सेटअप कोड...
         uart_init();
         // अधिक सेटअप कोड...
       }

    डेटा भेजने के लिए uart_transmit() का उपयोग करें:

       void loop() {
         // एक वर्ण भेजें
         uart_transmit('A');
    
         // भेजने के बीच में विलंब
         _delay_ms(1000);
       }

    उचित UART पिन (TX) को अपने Arduino बोर्ड के संबंधित पिनों से कनेक्ट करने का सुनिश्चित करें। इसके अलावा, अपनी इच्छित संचार गति के आधार पर सही BAUDRATE मान सेट करें।

    पूरा कोड:
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    void setup() {
      // Other setup code...
      uart_init();
      // More setup code...
    }
    void loop() {
      // Transmit a character
      uart_transmit('A');
    
      // Delay between transmissions
      _delay_ms(1000);
    }
    

    वर्ण स्ट्रिंग भेजने का डेमो प्रोग्राम

    #include <avr/io.h>
    #include <util/delay.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << TXEN0);  // Enable transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
        _delay_ms(100);  // Delay between character transmissions
      }
    }
    
    void setup() {
      // Initialize UART
      uart_init();
    }
    
    void loop() {
      // Transmit a string
      uart_transmit_string("Hello, world!");
    
      // Delay before transmitting again
      _delay_ms(2000);
    }
    

  • How to Initialize UART Communication with ATmega328P in AVR C using Arduino IDE

    EnglishDeutschHindi

    To initialize UART communication with the ATmega328P microcontroller in AVR C using the Arduino IDE, you can follow these steps:

    Include the necessary header files:

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>

    Define the UART settings:

    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

    Initialize UART by configuring the baud rate and other settings:

    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);  // Enable receiver and transmitter
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-bit data format
    }

    Implement functions for transmitting and receiving data:

    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Wait for empty transmit buffer
      UDR0 = data;  // Put data into the buffer, sends the data
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));  // Wait for data to be received
      return UDR0;  // Get and return received data from buffer
    }

    (Optional) Implement a function to transmit a string:

    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }

    Finally, call the uart_init() function in your setup() function to initialize UART communication:

    void setup() {
      // Other setup code...
      uart_init();
      // More setup code...
    }

    Now, you can use uart_transmit() to send individual characters and uart_receive() to receive data. If needed, you can use uart_transmit_string() to send strings.

    Note that the above code assumes you are using the default hardware UART (UART0) on the ATmega328P, and the UART pins (RX and TX) are connected to the corresponding pins on your Arduino board.

    Make sure to set the correct BAUDRATE value based on your desired communication speed. Also, ensure that the F_CPU macro is defined with the correct clock frequency of your microcontroller.

    Remember to include the necessary header files in your Arduino sketch and define the setup() and loop() functions as required for Arduino compatibility.

    Please note that configuring the UART in this way bypasses some of the Arduino’s built-in serial functionality, so you won’t be able to use Serial.print() or Serial.read() with this setup.

    Code for a demo program

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));
      UDR0 = data;
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));
      return UDR0;
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }
    
    void setup() {
      // Initialize UART
      uart_init();
    
      // Set PB5 (Arduino digital pin 13) as output
      DDRB |= (1 << PB5);
    }
    
    void loop() {
      // Read input from UART
      uint8_t receivedData = uart_receive();
    
      // Echo back received data
      uart_transmit(receivedData);
    
      // Toggle the built-in LED (PB5) on each received character
      PORTB ^= (1 << PB5);
    
      // Delay for a short period to observe the LED blink
      _delay_ms(500);
    }

    In this demo program, the ATmega328P’s UART is initialized in the setup() function, and then in the loop() function, it continuously reads incoming data and sends it back (echo) over UART. Additionally, it toggles the built-in LED (PB5) on each received character, providing a visual indication.

    Um die UART-Kommunikation mit dem ATmega328P-Mikrocontroller in AVR C mithilfe der Arduino IDE zu initialisieren, können Sie den folgenden Schritten folgen:

    Fügen Sie die erforderlichen Header-Dateien hinzu:

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>

    Definieren Sie die UART-Einstellungen:

    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

    Initialisieren Sie UART, indem Sie die Baudrate und andere Einstellungen konfigurieren:

    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);  // Empfänger und Sender aktivieren
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8-Bit-Datenformat
    }

    Implementieren Sie Funktionen zum Senden und Empfangen von Daten:

    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // Auf leeren Sendepuffer warten
      UDR0 = data;  // Daten in den Puffer schreiben und senden
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));  // Auf empfangene Daten warten
      return UDR0;  // Empfangene Daten aus dem Puffer lesen und zurückgeben
    }

    (Optional) Implementieren Sie eine Funktion zum Senden einer Zeichenkette:

    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }

    Rufen Sie schließlich die Funktion uart_init() in Ihrer setup() Funktion auf, um die UART-Kommunikation zu initialisieren:

    void setup() {
      // Anderer Setup-Code...
      uart_init();
      // Weitere Setup-Code...
    }

    Jetzt können Sie uart_transmit() verwenden, um einzelne Zeichen zu senden, und uart_receive() zum Empfangen von Daten. Bei Bedarf können Sie uart_transmit_string() verwenden, um Zeichenketten zu senden.

    Beachten Sie, dass der obige Code davon ausgeht, dass Sie die standardmäßige Hardware-UART (UART0) des ATmega328P verwenden und dass die UART-Pins (RX und TX) mit den entsprechenden Pins auf Ihrem Arduino-Board verbunden sind.

    Stellen Sie sicher, dass Sie den korrekten BAUDRATE-Wert entsprechend Ihrer gewünschten Übertragungsgeschwindigkeit festlegen. Stellen Sie außerdem sicher, dass die F_CPU-Makrodefinition die richtige Taktgeschwindigkeit Ihres Mikrocontrollers enthält.

    Vergessen Sie nicht, die erforderlichen Header-Dateien in Ihren Arduino-Sketch einzufügen und die setup() und loop() Funktionen gemäß den Anforderungen der Arduino-Kompatibilität zu definieren.

    Bitte beachten Sie, dass durch die Konfiguration der UART auf diese Weise einige der integrierten seriellen Funktionen des Arduino umgangen werden. Sie können daher nicht Serial.print() oder Serial.read() mit dieser Konfiguration verwenden.

    Code für ein Demo-Programm

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));
      UDR0 = data;
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));
      return UDR0;
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }
    
    void setup() {
      // UART initialisieren
      uart_init();
    
      // PB5 (Arduino digitaler Pin 13) als Ausgang festlegen
      DDRB |= (1 << PB5);
    }
    
    void loop() {
      // Eingabe von UART lesen
      uint8_t receivedData = uart_receive();
    
      // Empfangene Daten zurückschicken (Echo)
      uart_transmit(receivedData);
    
      // Die integrierte LED (PB5) bei jedem empfangenen Zeichen umschalten
      PORTB ^= (1 << PB5);
    
      // Eine kurze Verzögerung, um das Blinken der LED zu beobachten
      _delay_ms(500);
    }

    In diesem Demo-Programm wird die UART des ATmega328P im setup() Funktion initialisiert. In der loop() Funktion liest es kontinuierlich eingehende Daten und sendet sie zurück (Echo) über UART. Darüber hinaus wird die integrierte LED (PB5) bei jedem empfangenen Zeichen umgeschaltet, um eine visuelle Anzeige zu bieten.

    ATmega328P माइक्रोकंट्रोलर के साथ AVR C और Arduino IDE का उपयोग करके UART संचार को प्रारंभ करने के लिए, आप निम्नलिखित चरणों का पालन कर सकते हैं:

    आवश्यक हैडर फ़ाइलें शामिल करें:

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>

    UART सेटिंग्स को परिभाषित करें:

    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

    बॉडरेट और अन्य सेटिंग्स को कॉन्फ़िगर करके UART को प्रारंभ करें:

    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);  // प्राप्तकर्ता और प्रेषक को सक्षम करें
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8 बिट डेटा प्रारूप
    }

    डेटा भेजने और प्राप्त करने के लिए फ़ंक्शन को अमल में लाएं:

    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));  // खाली भेजने वाले बफ़र के लिए प्रतीक्षा करें
      UDR0 = data;  // डेटा बफ़र में डेटा डालें, डेटा भेजें
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));  // डेटा प्राप्त होने की प्रतीक्षा करें
      return UDR0;  // बफ़र से प्राप्त और डेटा लौटाएं
    }

    (ऐच्छिक) स्ट्रिंग भेजने के लिए एक फ़ंक्शन को अमल में लाएं:

    void uart_transmit_string(const char* str) {
      for (size_t i =
    
     0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }

    अंतिम रूप में, अपने सेटअप() फ़ंक्शन में uart_init() फ़ंक्शन को बुलाएं और UART संचार को प्रारंभ करें:

    void setup() {
      // अन्य सेटअप कोड...
      uart_init();
      // अधिक सेटअप कोड...
    }

    अब, आप uart_transmit() का उपयोग अक्षरों को भेजने के लिए कर सकते हैं और uart_receive() का उपयोग डेटा प्राप्त करने के लिए कर सकते हैं। आवश्यकता होने पर, आप uart_transmit_string() का उपयोग स्ट्रिंग भेजने के लिए कर सकते हैं।

    ध्यान दें कि ऊपर का कोड मानता है कि आप ATmega328P पर डिफ़ॉल्ट हार्डवेयर UART (UART0) का उपयोग कर रहे हैं, और UART पिन (RX और TX) आपके Arduino बोर्ड पर संबंधित पिनों से कनेक्ट हैं।

    अपनी Arduino स्केच में आवश्यक हैडर फ़ाइलें शामिल करने और Arduino संगतता के लिए सेटअप() और लूप() फ़ंक्शन को परिभाषित करने के लिए याद रखें।

    कृपया ध्यान दें कि इस तरीके से UART को कॉन्फ़िगर करने से अर्डुइनो के कुछ निर्मित सीरियल कार्यक्षमता का बाहर जाना होता है, इसलिए इस सेटअप के साथ Serial.print() या Serial.read() का उपयोग नहीं कर सकेंगे।

    डेमो प्रोग्राम के लिए कोड

    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    
    #define BAUDRATE 9600
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
    
    void uart_init() {
      UBRR0H = (uint8_t)(BAUD_PRESCALLER >> 8);
      UBRR0L = (uint8_t)(BAUD_PRESCALLER);
    
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    }
    
    void uart_transmit(uint8_t data) {
      while (!(UCSR0A & (1 << UDRE0)));
      UDR0 = data;
    }
    
    uint8_t uart_receive() {
      while (!(UCSR0A & (1 << RXC0)));
      return UDR0;
    }
    
    void uart_transmit_string(const char* str) {
      for (size_t i = 0; str[i] != '\0'; ++i) {
        uart_transmit(str[i]);
      }
    }
    
    void setup() {
      // UART को प्रारंभ करें
      uart_init();
    
      // PB5 (Arduino डिजिटल पिन 13) को आउटपुट के रूप में सेट करें
      DDRB |= (1 << PB5);
    }
    
    void loop() {
      // UART से इनपुट पढ़ें
      uint8_t receivedData = uart_receive();
    
      // प्राप्त डेटा को वापस भेजें (इको)
      uart_transmit(receivedData);
    
      // प्राप्त वर्णकों पर बिल्ट-इन LED (PB5) को टॉगल करें, यह दिखाने के लिए
      PORTB ^= (1 << PB5);
    
      // LED ब्लिंक को देखने के लिए थोड़ी सी देरी के लिए विलंब करें
      _delay_ms(500);
    }

    इस डेमो प्रोग्राम में, ATmega328P का UART सेटअप() फ़ंक्शन में प्रारंभित होता है, और फिर लूप() फ़ंक्शन में, यह निरंतर आने वाले डेटा को पढ़ता है और उसे वापस (इको) UART के माध्यम से भेजता है। इसके अलावा, यह प्राप्त प्रत्येक आंकड़े पर बिल्ट-इन LED (PB5) को टॉगल करता है, जिससे एक लैंप एफेक्ट प्रदर्शित होता है।

  • Raspberry Pi Pico Internal Temperature Sensor Based Fan Speed Control using PID Algorithm with Anti-Windup Logic

    This system uses the Raspberry pi pico development board which has an RP2040 microcontroller. The RP2040 microcontroller has an internal temperature sensor.

    Using its internal temperature sensor I have devised a very simple setup that demonstrates the PID algorithm. Using PID Algorithm control technique I am controlling the fan speed by changing the PWM duty cycle.

    Component required:

    1. Raspberry Pi Pico
    2. PC Fan (+12V)
    3. L298n Module
    4. +12V Power supply

    Commonly the PC fan changes its speed by PWM signal, I am sending a PWM signal of frequency 29Khz. Most PC fans operate from 25Khz to 30Khz. PWM signal duty cycle can be from 30% to 100%. At duty cycle lower than 30% PC fan won’t start.

    We will dive into the code and explain each step of the implementation.

    Code Overview:
    The code provided is written in MicroPython and utilizes the machine module for hardware interactions. Here’s an overview of the key components and functionalities:

    1. PWM Configuration: The code configures a GPIO pin for Pulse Width Modulation (PWM) and sets the frequency to 29 kHz. PWM is used to control the speed of the fan.
    2. Temperature Sensor Configuration: The internal temperature sensor is configured using the ADC (Analog-to-Digital Converter) module. The conversion factor is calculated to convert the raw ADC readings to temperature values.
    3. PID Algorithm Implementation: The PID algorithm is implemented using proportional (P), integral (I), and derivative (D) control constants. The target temperature is set, and the error between the target temperature and the measured temperature is calculated. The code calculates the proportional, integral, and derivative terms and combines them to obtain the PID value.
    4. Anti-Windup Logic: To prevent windup issues, an anti-windup logic is implemented. It limits the PID value within a valid range to avoid saturation or unstable behavior.
    5. Timer Interrupts: Timer objects are created to trigger callback functions at regular intervals. The 100 ms timer callback updates the PID value and adjusts the fan speed accordingly, while the 1-second timer callback prints relevant information for monitoring and debugging purposes.

    Implementation Walkthrough:

    1. PWM and Temperature Sensor Configuration: The code starts by configuring the PWM pin and the internal temperature sensor.
    2. PID Constants and Variables: The proportional control constant (kp), minimum duty cycle value (min_duty_cycle), and target temperature (target_temp) are set. Variables for duty cycle, error, temperature, integral error (i_err), integral count (i_cnt), derivative count (d_cnt), previous error (prev_err), and PID value (PID) are initialized.
    3. Timer Interrupts: Timer objects are created and initialized to trigger the respective callback functions every 100 ms and 1 second.
    4. PID Calculation and Fan Control: In the timer callback function for 100 ms, the raw temperature is converted to a temperature value. The error, integral error, derivative count, proportional count, and PID value are calculated. The PID value is limited to a valid range and converted to an appropriate duty cycle value for the PWM. The duty cycle is applied to control the fan speed.
    5. Monitoring and Debugging: The timer callback function for 1 second prints relevant information such as the PID value, error, duty cycle, temperature, derivative count, integral count, and proportional count.
    import machine
    import utime
    
    # Configure the GPIO pin for PWM
    pwm_pin = machine.Pin(9)
    pwm = machine.PWM(pwm_pin)
    
    # Set the PWM frequency to 29 kHz
    pwm.freq(29000)
    
    # Configure the internal temperature sensor
    sensor_temp = machine.ADC(machine.ADC.CORE_TEMP)
    conversion_factor = 3.3 / 65535
    
    # Set the proportional control constants
    #target_temp = 25  # Set the desired target temperature
    # Set the proportional control constants
    #target_temp = 25.63997  # Set the desired target temperature
    target_temp = 25.17182  # Set the desired target temperature
    #target_temp = 24.70368
    #target_temp = 24.23554
    #target_temp = 23.76739
    #target_temp = 23.29925
    kp = (((2**16)-1) * -1)
    min_duty_cycle = (((2**16)-1) * 0.3)  # Minimum duty cycle value to start the fan
    
    duty_cycle = 0
    error = 0
    temperature = 0
    
    # Initialize the timestamp for 1 second intervals
    timestamp_1s = utime.time()
    p_cnt = 0
    i_err = 0
    Ki = -200
    i_cnt = 0
    
    prev_err = 0
    Kd = -2500
    d_cnt = 0
    PID = 0
    # Timer interrupt callback function for 100 ms interval
    def timer_callback_100ms(timer):
        global duty_cycle, error, temperature,i_err,i_cnt,prev_err,Kd,d_cnt,p_cnt,PID,Ki
    
        raw_temp = sensor_temp.read_u16() * conversion_factor
        temperature = (27 - (raw_temp - 0.706) / 0.001721)
        error = target_temp - temperature
        i_err += (error)
        i_cnt = int(i_err * Ki)
        d_cnt = ((error - prev_err) * Kd)/0.1
        p_cnt = error * kp
        PID = (p_cnt + d_cnt + i_cnt)
        if PID >= 65535:
            PID = 65535
        if PID <= 0 :
            PID = 0
        duty_cycle = int(PID)
        
        pwm.duty_u16(duty_cycle)
        '''
        if error >= 0:
            #duty_cycle = max((duty_cycle - int(error * kp)), 0)
            duty_cycle = int(max(( d_cnt + i_cnt + (1 * error * kp)), 0))
            if duty_cycle <= 0:
                duty_cycle = 0
            pwm.duty_u16(duty_cycle)
        elif error < 0:
            duty_cycle = int(min( d_cnt + i_cnt +  error * kp), 65535))
            
            #duty_cycle = min(max((duty_cycle + int(-1 * error * kp)), int(min_duty_cycle)), 65535)
            pwm.duty_u16(int(duty_cycle))
        '''
        prev_err = error
    
    # Timer interrupt callback function for 1 second interval
    def timer_callback_1s(timer):
        print(f"pid: {PID}\terror: {error}\tduty: {duty_cycle}\tTemp: {temperature}\td_cnt: {d_cnt}\ti_cnt: {i_cnt}\tp_cnt: {p_cnt}")
    
    # Create timer objects
    timer_100ms = machine.Timer()
    timer_1s = machine.Timer()
    
    # Configure the timer to trigger the 100 ms callback function every 100 milliseconds
    timer_100ms.init(period=100, mode=machine.Timer.PERIODIC, callback=timer_callback_100ms)
    
    # Configure the timer to trigger the 1 second callback function every 1 second
    timer_1s.init(period=1000, mode=machine.Timer.PERIODIC, callback=timer_callback_1s)
    
    # Main loop
    while True:
        # Add any other desired non-blocking operations here
        
        # Sleep briefly to avoid excessive CPU usage
        utime.sleep(0.01)
    
    
  • Wireless Plant Watering System using Raspberry Pi Pico W

    Every morning my mom waters the plant. She has to water them every day and sometimes in summer, she must provide water twice a day.

    In winter plant needs water when necessary.

    Solution:

    For the above problem, I developed this project using raspberry pi pico w.

    Here is what it does:

    1. It connects to the WiFi router. The wifi router allocates a fixed IP address. For that, I created a new entry in the DHCP bindings of the router.
    2. When you visit the IP address 192.168.1.101
    3. It samples the soil moisture sensor through the ADC. And display an HTML page that shows the status of ADC and the onboard LED.
    4. The HTML page also has a button for turning on the pump.
      I have kept it manual.
    5. When the PUMP ON button is pressed the water pump is turned ON. The water pump is connected via the L298n module. Which is controlled by a PWM signal of 1Khz frequency. The duty cycle is slowly increased to 75%.
      There is a timeout of 10 Seconds. If the timeout is reached the water pump will be turned off.

    Schematic Diagram

    Schematic Diagram

    Micropython Code

    import network
    import socket
    import time
    from time import sleep
    from picozero import pico_temp_sensor, pico_led
    import machine
    
    ssid = 'Abhay'
    password = 'AK26@#36'
    '''
    # Pin GP9 (physical pin 5) on PicoZero
    GPIO_PIN = 9
    
    # Set up the GPIO pin as an output
    pin9 = machine.Pin(GPIO_PIN, machine.Pin.OUT)
    
    # Turn off the GPIO pin
    pin9.off()
    '''
    GPIO_PIN_9 = machine.Pin(9)
    pwm9 = machine.PWM(GPIO_PIN_9)
    
        
    def ADC():
        adc = machine.ADC(0)  # Initialize ADC on pin A0
        sensor_value = adc.read_u16()  # Read the analog value from the sensor
        # Add your code to process and display the sensor value as per your requirements
        #print(sensor_value)
        #time.sleep_ms(500)  # Delay between readings (adjust as needed)
        #sensor_value = 18756
        percentage = 100 - ((sensor_value / 65535) * 100)
        #print(f"sensor_value: {sensor_value} percentage: {percentage}")
        return sensor_value,percentage
        
        
    def gen_pwm(duration, timeout):
        # Set PWM frequency
        pwm9.freq(1000)  # Set frequency to 1 kHz
    
        start_time = time.ticks_ms()  # Get the initial timestamp
        pump_started = False
    
        while time.ticks_diff(time.ticks_ms(), start_time) < timeout:
            # Check water level using ADC
            ADC_Read = ADC()
            water_level = ADC_Read[1]
            #adc.read()
    
            if not pump_started and water_level < 50:
                # Start the pump by gradually increasing the duty cycle
                for duty in range(0, 32767, 100):
                    pwm9.duty_u16(duty)
                    time.sleep_ms(duration)  # Adjust the delay as needed for smooth transition
                    ADC_Read = ADC()
                    water_level = ADC_Read[1]
                    
                    if water_level >=50 :
                        break
                pump_started = True
    
            if water_level >= 50 or pump_started and water_level <= 0:
                # Stop the pump by setting the duty cycle to 0
                pwm9.duty_u16(0)
                break
    
        # Stop the PWM signal
        pwm9.duty_u16(0)
    
    def connect():
        #Connect to WLAN
        wlan = network.WLAN(network.STA_IF)
        wlan.active(True)
        wlan.connect(ssid, password)
        while wlan.isconnected() == False:
            print('Waiting for connection...')
            sleep(1)
        ip = wlan.ifconfig()[0]
        print(f'Connected on {ip}')
        return ip
    
    def open_socket(ip):
        # Open a socket
        address = (ip, 80)
        connection = socket.socket()
        connection.bind(address)
        connection.listen(1)
        return connection
    
    def webpage(temperature, state,user_value):
        #Template HTML
        ADC_Value = ADC()
        html = f"""
                <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <form action="./lighton" style="display: flex; justify-content: center;">
            <input type="submit" value="Light on" style="font-size: 40px;" />
        </form>
        <form action="./lightoff" style="display: flex; justify-content: center;">
            <input type="submit" value="Light off" style="font-size: 40px;" />
        </form>
        <p style="font-size: 20px;">LED is {state}</p>
        <p style="font-size: 20px;">Temperature is {temperature}</p>
        <p style="font-size: 20px;">ADC Value is {ADC_Value[0]}</p>
        <p style="font-size: 20px;">ADC % is {ADC_Value[1]}</p>
        
        <form action="./pumpon" style="display: flex; justify-content: center;">
            <input type="submit" value="Pump on" style="font-size: 40px;" />
        </form>
        <form action="./pumpoff" style="display: flex; justify-content: center;">
            <input type="submit" value="Pump off" style="font-size: 40px;" />
        </form>
        
        <h1>Numeric Form</h1>
        <form method=POST action="/usrval">
            <label for="value">Enter a numeric value:</label><br>
            <input type="number" id="value" name="value" required><br><br>
            <input type="submit" value="Submit">
        </form>
        <p>User value: {user_value}</p>  <!-- Display the user-submitted value -->
    </body>
    </html>
    
    
                """
        return str(html)
    def serve(connection):
        #Start a web server
        state = 'OFF'
        pico_led.off()
        temperature = 0
        user_value = None  # Variable to store the user-submitted value
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            rqst1 = request.split()
            '''
            for x1 in rqst1:
                if(x1.find("usrval") != -1):
                    print(rqst1)
                    #print(x1)
            #print(rqstfind)
            '''
            try:
                
                for x1 in rqst1:
                    if "value=" in x1:
                        user_value = x1.split("=")[2].strip("'")
                        print(user_value)
            except:
                pass
            
            try:
                request = request.split()[1]
            except IndexError:
                pass
            if request == '/lighton?':
                pico_led.on()
                state = 'ON'
            elif request =='/lightoff?':
                pico_led.off()
                state = 'OFF'
            elif request =='/pumpon?':
                #pin9.on()
                gen_pwm(10,10000)
                print("\n\n"+request)
                #state = 'OFF'
            elif request =='/pumpoff?':
                #pin9.off()
                print("Pump OFF")
            elif request == '/usrval':
              #  print("\n\n"+request)
                index = request.find('value=')
                
                if index != -1:
                    end_index = request.find(' ', index)
                    if end_index == -1:
                        end_index = len(request)
                    user_value = request[index + len('value='):end_index]
                    print(f"\n\nValue: \t {user_value}\n\n")
            temperature = pico_temp_sensor.temp
            html = webpage(temperature, state,user_value)
            client.send(html)
            client.close()
    
    try:
        ip = connect()
        connection = open_socket(ip)
        serve(connection)
    except KeyboardInterrupt:
        machine.reset()