Posted on Leave a comment

How to use Bluetooth LE of Raspberry Pi Pico W using MicroPython

Step 1: Download the MicroPython UF2 file from the link below

https://www.raspberrypi.com/documentation/microcontrollers/micropython.html

Download the UF2 file which has Wi-Fi and Bluetooth LE support.

Step 2: Put the UF2 file in your raspberry pi pico w

  1. Push and hold the BOOTSEL button and plug your Pico into the USB port of your Raspberry Pi or other computer. Release the BOOTSEL button after your Pico is connected.
  2. It will mount as a Mass Storage Device called RPI-RP2.
  3. Drag and drop the MicroPython UF2 file onto the RPI-RP2 volume. Your Pico will reboot. You are now running MicroPython.
  4. You can access the REPL via USB Serial.

Step 3: Save the following files in your raspberry pi pico w

As you can see in the image, these files should be saved on the raspberry pi pico w. As they will be imported as modules when you write your application code.

[ Click on the file names to see the complete code ]

ble_advertising.py
# Helpers for generating BLE advertising payloads.

from micropython import const
import struct
import bluetooth

# Advertising payloads are repeated packets of the following form:
#   1 byte data length (N + 1)
#   1 byte type (see constants below)
#   N bytes type-specific data

_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)


# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
    payload = bytearray()

    def _append(adv_type, value):
        nonlocal payload
        payload += struct.pack("BB", len(value) + 1, adv_type) + value

    _append(
        _ADV_TYPE_FLAGS,
        struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
    )

    if name:
        _append(_ADV_TYPE_NAME, name)

    if services:
        for uuid in services:
            b = bytes(uuid)
            if len(b) == 2:
                _append(_ADV_TYPE_UUID16_COMPLETE, b)
            elif len(b) == 4:
                _append(_ADV_TYPE_UUID32_COMPLETE, b)
            elif len(b) == 16:
                _append(_ADV_TYPE_UUID128_COMPLETE, b)

    # See org.bluetooth.characteristic.gap.appearance.xml
    if appearance:
        _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))

    return payload


def decode_field(payload, adv_type):
    i = 0
    result = []
    while i + 1 < len(payload):
        if payload[i + 1] == adv_type:
            result.append(payload[i + 2 : i + payload[i] + 1])
        i += 1 + payload[i]
    return result


def decode_name(payload):
    n = decode_field(payload, _ADV_TYPE_NAME)
    return str(n[0], "utf-8") if n else ""


def decode_services(payload):
    services = []
    for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
        services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
    for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
        services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
    for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
        services.append(bluetooth.UUID(u))
    return services


def demo():
    payload = advertising_payload(
        name="micropython",
        services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
    )
    print(payload)
    print(decode_name(payload))
    print(decode_services(payload))


if __name__ == "__main__":
    demo()

ble_simple_peripheral.py
# This example demonstrates a UART periperhal.

import bluetooth
import random
import struct
import time
from ble_advertising import advertising_payload

from micropython import const

_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)

_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)

_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_TX = (
    bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
    _FLAG_READ | _FLAG_NOTIFY,
)
_UART_RX = (
    bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
    _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE,
)
_UART_SERVICE = (
    _UART_UUID,
    (_UART_TX, _UART_RX),
)


class BLESimplePeripheral:
    def __init__(self, ble, name="mpy-uart"):
        self._ble = ble
        self._ble.active(True)
        self._ble.irq(self._irq)
        ((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,))
        self._connections = set()
        self._write_callback = None
        self._payload = advertising_payload(name=name, services=[_UART_UUID])
        self._advertise()

    def _irq(self, event, data):
        # Track connections so we can send notifications.
        if event == _IRQ_CENTRAL_CONNECT:
            conn_handle, _, _ = data
            print("New connection", conn_handle)
            self._connections.add(conn_handle)
        elif event == _IRQ_CENTRAL_DISCONNECT:
            conn_handle, _, _ = data
            print("Disconnected", conn_handle)
            self._connections.remove(conn_handle)
            # Start advertising again to allow a new connection.
            self._advertise()
        elif event == _IRQ_GATTS_WRITE:
            conn_handle, value_handle = data
            value = self._ble.gatts_read(value_handle)
            if value_handle == self._handle_rx and self._write_callback:
                self._write_callback(value)

    def send(self, data):
        for conn_handle in self._connections:
            self._ble.gatts_notify(conn_handle, self._handle_tx, data)

    def is_connected(self):
        return len(self._connections) > 0

    def _advertise(self, interval_us=500000):
        print("Starting advertising")
        self._ble.gap_advertise(interval_us, adv_data=self._payload)

    def on_write(self, callback):
        self._write_callback = callback


def demo():
    ble = bluetooth.BLE()
    p = BLESimplePeripheral(ble)

    def on_rx(v):
        print("RX", v)

    p.on_write(on_rx)

    i = 0
    while True:
        if p.is_connected():
            # Short burst of queued notifications.
            for _ in range(3):
                data = str(i) + "_"
                print("TX", data)
                p.send(data)
                i += 1
        time.sleep_ms(100)


if __name__ == "__main__":
    demo()

Step 4: Create a simple Bluetooth UART Code

which receives the message “Toggle\r\n” and Toggle the onboard LED and sends the state of the led back to the user.

# Import necessary modules
from machine import Pin 
import bluetooth
from ble_simple_peripheral import BLESimplePeripheral

# Create a Bluetooth Low Energy (BLE) object
ble = bluetooth.BLE()

# Create an instance of the BLESimplePeripheral class with the BLE object
sp = BLESimplePeripheral(ble)

# Create a Pin object for the onboard LED, configure it as an output
led = Pin("LED", Pin.OUT)

# Initialize the LED state to 0 (off)
led_state = 0
xWR_flag = 0
# Define a callback function to handle received data
def on_rx(data):
    print("Data received: ", data)  # Print the received data
    global led_state,xWR_flag  # Access the global variable led_state
    if data == b'toggle\r\n':  # Check if the received data is "toggle"
        led.value(not led_state)  # Toggle the LED state (on/off)
        led_state = 1 - led_state  # Update the LED state
        xWR_flag = 1

# Start an infinite loop
while True:
    if sp.is_connected():  # Check if a BLE connection is established
        sp.on_write(on_rx)  # Set the callback function for data reception
        if xWR_flag == 1:            
            # Create a message string                
            msg="LED STATE: "
            # Send the message via BLE
            sp.send(msg)
            sp.send(str(led_state))
            sp.send(str("\r\n"))
            xWR_flag = 0


Posted on 1 Comment

How to use MG90S Servo Motor with Raspberry Pi Pico using micropython

I have this MG90S small servo motor. It is supposed to go from 0° to 180°.

Because of their low cost, they have a short range which is less than 180°. Some go to 135°, 100° or 150°.

PWM signal required by servo to move.

Frequency = 50Hz
Time Period = 0.02 Second or 20 mili second
Pulse width range: 500us to 2500us

Properties of pulse width
At 500us pulse width the servo position will be 0°
At 2500us pulse width the servo position will be 180°

It is a good habit to check the servo controls before putting it in a project and make the adjustments in code or in hardware.

Hardware Connections

Raspberry Pi PicoServo Motor
GNDGND (Brown color wire)
VsysVCC (Red color wire)
GP9Signal (Orange color wire)

Most small and micro Servo operate from 5V to 6V.
If a servo is designed to operate at 3.3V always check it’s datasheet carefully.

Calculations

Raspberry pi pico has a 16 bit PWM controller.
This means we set its frequency to 50Hz by
pwm.freq(50)
This means that one oscillation has 65535 steps

65535 steps = 20 ms

First we convert angles to pulse width time

pulse width = angle/90 + 0.5
then we convert pulse width to step count

steps count = ( 65535 * pulse width ) / 20

Code

import machine
import utime

Led_pin = 25
LED = machine.Pin(Led_pin, machine.Pin.OUT)

# Configure the GPIO pin for PWM
pwm_pin = machine.Pin(9)
pwm = machine.PWM(pwm_pin)

# Set the PWM frequency to 50 kHz
pwm.freq(50)

# Debug Message Print
debug = 0

time_delay = 1/10
increment_step = 100
decrement_step = -200

'''
# Function: deg_to_time
# Parameters: deg : degree (0 - 180)
# Description: This function takes the degree and translates them
                to Pulse Width time.
                For a servo motor we have to use a pulse width of 500us to 2500us

'''
def deg_to_time(deg):
    temp = ((deg/90)+0.5)
    if debug:print("deg ",deg," to timems: ",temp)
    return temp

'''
# Function: timems_to_duty
# Parameters: timems : pulse width time in milli second
# Description: This function takes pulse width duration of 500us to 2500us.
                and generates a duty cycle value.

'''
def timems_to_duty(timems):
    temp = 20/timems
    temp1 = 65535/temp
    if debug:print("timems to duty: ",temp1)
    return temp1

'''
# Function: set_pwm
# Parameters: duty : duty cycle value (0 - 65535)
# Description: This function takes a duty cycle value and set it for the PWM.

'''
def set_pwm(duty):
    pwm.duty_u16(int(duty))
    if debug:print("duty cycle: ",duty)
    
def angle_to_pwm(angle):
    set_pwm(int(timems_to_duty(deg_to_time(angle))))



while(1):
        # sweep from 0  to 180
    for _ in range(0,180,1):
        angle_to_pwm(_)
        utime.sleep(time_delay)
        # sweep from 180  to 0
    for _ in range(180,0,-1):
        angle_to_pwm(_)
        utime.sleep(time_delay)
Posted on Leave a comment

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)
Posted on Leave a comment

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()
Posted on Leave a comment

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

Posted on Leave a comment

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)
Posted on Leave a comment

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

Posted on Leave a comment

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) को टॉगल करता है, जिससे एक लैंप एफेक्ट प्रदर्शित होता है।

Posted on Leave a comment

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)