I have used this FAST PWM mode to trigger two interrupt service routines. The timer compares register A sets the frequency. I have not enabled the output compare pins. since it was used by some other peripheral. So by doing this, I generate a PWM signal by issuing a command in the ISR.
/*
* main.c
*
* Created: 10 July 2023 10:47:23 PM
* Author: abhay
*/
#define F_CPU 16000000
#include <xc.h>
#include <stdio.h>
#include "util/delay.h"
#include <avr/interrupt.h>
#include "uart.h"
#define LED_ON PORTB |= (1<<5)
#define LED_OFF PORTB &= ~(1<<5)
// Function to send a character via UART
int UART_putchar(char c, FILE *stream) {
if (c == '\n')
UART_putchar('\r', stream); // Add carriage return before newline
while (!(UCSR0A & (1 << UDRE0))); // Wait for the transmit buffer to be empty
UDR0 = c; // Transmit the character
return 0;
}
// Create a FILE structure to redirect the printf stream to UART
FILE uart_output = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);
ISR(TIMER3_COMPA_vect){
PORTD |= (1<<6);
}
ISR(TIMER3_COMPB_vect){
PORTD &= ~(1<<6);
}
int main(void)
{
USART_Init();
// Redirect stdout stream to UART
stdout = &uart_output;
DDRB |= (1<<5); // set Data direction to output for PB5
LED_OFF; // set output to high
DDRD |= (1 << 6); //set PD6 as output
/*
F_CPU = 16000000
Prescaler = 64
Frequency = 50Hz
Period = 0.020 s
step time = 1/(F_CPU/Prescaler) = 0.000004 s
number of steps = 0.020/0.000004 = 5000
*/
TCNT3 = 0; // Timer counter initial value = 0
// Output Compare A value = 5000 or 20 Milli second
OCR3A = 5000;
// Output Compare B value = 500 or 2 Milli second
OCR3B = 500;
// Fast PWM
TCCR1A |= (1 << WGM31)|(1 << WGM30);
// Prescaler: 64
TCCR3B |= (1 << WGM32)|(1<<WGM32)|(1 << CS31)|(1 << CS30);
// Enable Timer Interrupt for Overflow, Compare match A and Compare Match B
TIMSK3 |= (1 << OCIE3B)|(1 << OCIE3A)|(1<<TOIE3);
// Enable Global Interrupt
sei();
while(1)
{
OCR3B = 250;//5% 1ms
_delay_ms(500);
OCR3B = 375;//7.5% 1.5ms
_delay_ms(100);
OCR3B = 500;//10% 2ms
_delay_ms(500);
}
}
Timers are essential components in microcontrollers that allow precise timing and synchronization for various applications. The ATmega328PB microcontroller offers several timer/counters, including Timer/Counter 1 (TC1), which is a 16-bit timer with advanced features. In this blog post, I will explore how to utilize Timer 1 in CTC (Clear Timer on Compare Match) mode on the ATmega328PB microcontroller.
Hardware Setup
Before we proceed with the code, ensure you have the necessary hardware setup. You will need an ATmega328PB microcontroller, a 16MHz crystal oscillator, and any additional components required for your specific application. Connect the crystal oscillator to the XTAL1 and XTAL2 pins of the microcontroller to provide a stable clock signal.
UART Communication Initialization
In this example, we will utilize UART communication for debugging or output purposes. Make sure you have already implemented the necessary UART functions or library. The UART initialization code should include setting the baud rate, enabling the transmitter and receiver, and configuring the data format (e.g., number of data bits, parity, and stop bits). We will also redirect the stdout stream to the UART using the stdio.h library, allowing us to use the printf function for UART output.
Timer 1 Configuration in CTC Mode
Let’s dive into the code and configure Timer 1 in CTC mode. Here’s an example code snippet:
/*
* main.c
*
* Created: 7/9/2023 12:47:23 AM
* Author: abhay
*/
#define F_CPU 16000000
#include <xc.h>
#include <stdio.h>
#include "util/delay.h"
#include <avr/interrupt.h>
#include "uart.h"
// Function to send a character via UART
int UART_putchar(char c, FILE *stream) {
if (c == '\n')
UART_putchar('\r', stream); // Add carriage return before newline
while (!(UCSR0A & (1 << UDRE0))); // Wait for the transmit buffer to be empty
UDR0 = c; // Transmit the character
return 0;
}
// Create a FILE structure to redirect the printf stream to UART
FILE uart_output = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);
ISR(TIMER1_COMPA_vect){
printf("2. compare match A\n");
}
ISR(TIMER1_COMPB_vect){
printf("1. compare match B\n");
}
int main(void)
{
USART_Init();
// Redirect stdout stream to UART
stdout = &uart_output;
DDRB |= (1<<5); // set Data direction to output for PB5
PORTB |= (1<<5); // set output to high
/*
* Timer 1
* Mode of operation : CTC
* When Output Compare A register value equals the
* Timer Counter register (TCNT1) it resets the Timer-Counter-register value
* and generates a interrupt.
* Only OCR1A will reset the timer counter.
* OCR1B can be used to generate a compare match between TCNT1 = 0 and OCR1A
*
*/
TCNT1 = 0; // Timer counter initial value = 0
OCR1BH = 0x3D; // Output Compare B value = 0x3d09 or 1 second
OCR1BL = 0x09;
OCR1AH = 0x7a; // Output Compare A value = 0x7a12 or 2 second
OCR1AL = 0x12;
TCCR1B |= (1<<WGM02)|(1 << CS12)|(1 << CS10); // CTC Prescaler: 1024
TIMSK1 |= (1 << OCIE1B)|(1 << OCIE1A)|(1<<TOIE1);
sei(); // Enable Global Interrupt
while(1)
{
printf(" This is Main:\n");
_delay_ms(2500);
//TODO:: Please write your application code
}
}
In this code snippet, we first initialize the UART communication and redirect the stdout stream to the UART output using the FDEV_SETUP_STREAM macro. The UART_putchar function is used to send a character via UART, ensuring that newline characters (\n) are preceded by a carriage return character (\r) for proper line endings.
Next, we configure Timer/Counter 1 (TC1) for CTC mode and set the prescaler to 1024, which divides the clock frequency to generate a suitable timebase. The TCCR1A and TCCR1B registers are set accordingly.
We then set the compare values (OCR1A and OCR1B) to determine the time intervals at which we want to generate interrupts. In this example, OCR1A is set for 2 second delay, and OCR1B is set for approximately 1 seconds delay.
Finally, we enable the Timer/Counter TC1 compare match interrupts (OCIE1A and OCIE1B) using the TIMSK1 register, and we enable global interrupts with the sei() function.
Interrupt Service Routines (ISRs)
The code snippet defines two Interrupt Service Routines (ISRs): TIMER1_COMPA_vect and TIMER1_COMPB_vect. These ISRs will be executed when a compare match occurs for Output Compare A and Output Compare B, respectively. In this example, we use these ISRs to print messages to the UART output. You can modify these ISRs to perform any desired actions based on your specific application requirements.
Putting It All Together
Once you have set up the UART communication, configured Timer 1 in CTC mode, and defined the necessary ISRs, you can utilize the precise timing capabilities of Timer 1 in your main program loop. Use the printf function to output information via UART, and the compare match interrupts will handle the precise timing events.
while (1) {
printf(" This is Main:\n");
_delay_ms(2500);
// Additional code and operations
// ...
}
In the above example, the main program loop will execute continuously, printing “This is the main program loop” every 1 second using the printf function. The _delay_ms function provides a delay of 2500 milliseconds (2.5 second) between each iteration of the loop.
Conclusion
Utilizing Timer 1 in CTC mode on the ATmega328PB microcontroller provides precise timing capabilities for various applications. By configuring Timer 1, setting compare match values, and utilizing compare match interrupts, you can achieve accurate timing control in your embedded systems. When combined with UART communication, you can easily monitor and debug your code by printing relevant information via the UART interface.
Remember to consult the ATmega328PB datasheet and relevant documentation for more details on Timer 1, CTC mode, and other timer features. Ensure that you have correctly configured your hardware setup, including the crystal oscillator and UART connection, to match the code requirements.
Using Timer 1 in CTC mode
with UART communication opens up a range of possibilities for precise timing and debugging capabilities in your projects. Experiment with different compare match values and integrate this functionality into your applications to enhance timing accuracy and control.
The simplest mode of operation is the Normal mode (WGM0[2:0] = 0x0). In this mode, the counting direction is always up (incrementing), and no counter clear is performed. The counter simply overruns when it passes its maximum 8-bit value (TOP=0xFF) and then restarts from the bottom (0x00). In Normal mode operation, the Timer/Counter Overflow flag (TOV0) will be set in the same clock cycle in which the TCNT0 becomes zero. In this case, the TOV0 flag behaves like a ninth bit, except that it is only set, not cleared. However, combined with the timer overflow interrupt that automatically clears the TOV0 flag, the timer resolution can be increased by software. There are no special cases to consider in the Normal mode, a new counter value can be written any time.
The output compare unit can be used to generate interrupts at some given time. Using the output compare to generate waveforms in Normal mode is not recommended since this will occupy too much of the CPU time.
The counter will always count from 0 to 255 and then after 255 it will set the overflow bit and start the counting from 0.
Without Interrupt
We can use this to generate delays. But This is a type of blocking code.
/*
* main.c
*
* Created: 7/9/2023 12:47:23 AM
* Author: abhay
*/
#define F_CPU 16000000UL
#include <xc.h>
#include <util/delay.h>
void T0delay();
int main(void)
{
DDRB |= (1<<5);
PORTB |= (1<<5);
while(1)
{
PORTB |= (1<<PINB5);
T0delay();
PORTB &= ~(1<<PINB5);
T0delay();
//TODO:: Please write your application code
}
}
void T0delay()
{
/*
F_CPU/prescaler = clock for timer
1/clock for timer = timer step time
for 1 second the timer will take : 1/timer step time
16000000/1024 = 15625 clock
1/15625 = 0.000064 = 64us (counter step size)
64us x 256 = 0.016384 sec (0verflow time)
64us x 255 - tcnt +1 = 0.016384 sec (0verflow time)
64us x (255 - tcnt +1 )= x
tcnt = x / 64us ) -256
for 1 sec Delay
=> 1/0.016384 sec = 61.03515625
Taking only integer
so 61 overflows needs to occur for 0.999424 Seconds
1-0.999424 = 0.000576 seconds
0.000576/ (counter step size) = required steps
0.000576/0.00064 = 9 steps
Note: this will be close to 1 second. but it will be longer due to overhead added by the instructions.
*/
for(int i = 0; i< 61;i++){
TCNT0 = 0;
TCCR0A = 0;
TCCR0B |= (1<<CS00)|(1<<CS02); //prescaler 1024
while( (TIFR0 & 0x1) == 0); // Wait for overflow flag
TCCR0B = 0;
TIFR0 = 0x1;
}
//9 steps timer code
TCNT0 = 255-9;
TCCR0A = 0;
TCCR0B |= (1<<CS00)|(1<<CS02); //prescaler 1024
while( (TIFR0 & 0x1) == 0); // Wait for overflow flag
TCCR0B = 0;
TIFR0 = 0x1;
}
Normal Mode with Interrupt
#define F_CPU 16000000UL
#include <xc.h>
#include <avr/interrupt.h>
ISR(TIMER0_OVF_vect){
PORTB ^= (1<<PINB5); // Toggle the GPIO
}
int main(void)
{
DDRB |= (1<<5); // set Data direction to output for PB5
PORTB |= (1<<5); // set output to high
TCNT0 = 0;
TCCR0A = 0; // Normal Mode
TCCR0B |= (1<<CS00)|(1<<CS02); //prescaler 1024
TIMSK0 |= (1 << TOIE0); // Overflow Interrupt Enable Bit
sei(); // Enable Global Interrupt
while(1)
{
//TODO:: Please write your application code
}
}
When I opened the case. I found a PCB which is screwed to a big heatsink. I unscrewed the bolts and saw that there is S109AFTG. The IC is sandwiched between the PCB and the heatsink. A small aluminum block is also used for heat transfer between the IC and the heatsink.
It has a different step size which can be selected by the DIP switches. The motor driver has a maximum of 1/32 step size.
which means 1.8°/ 32 = 0.05625°
360°/ 0.05625° = 6400 steps
So a full rotation will be in 6400 steps.
You will need a power source such as a Switched Mode Power Supply which can supply at least 2 Amps.
If your application needs more torque you will need a power source that can provide a high current without dropping the voltage.
Control systems engineering plays a crucial role in various industries, enabling precise and efficient control of processes and systems. One fundamental concept in control systems is derivative control, which helps improve the system’s response to changes and disturbances. In this blog post, we’ll explore a simple demonstration of derivative control using a slider in Tkinter, a popular Python GUI toolkit.
Understanding Derivative Control
Derivative control is a control strategy that utilizes the derivative of the error signal to adjust the control output. By calculating the rate of change of the error, derivative control can anticipate the system’s response to changes and take corrective actions to minimize the error. It provides a damping effect and improves the system’s stability and responsiveness.
The derivative control algorithm consists of three main components:
Derivative Control Function: The derivative control function calculates the derivative term based on the current error, previous error, and a time interval. The derivative term is obtained by multiplying the derivative gain (Kd) with the difference in error divided by the time interval.
Main Loop: The main loop of the control system continuously monitors the process variable and applies derivative control to update the control output. It calculates the error by subtracting the desired setpoint from the process variable. The derivative control function is then invoked to compute the derivative term. The control output is actuated, and the previous error is updated.
Slider and GUI: To interact with the control system, we’ll create a graphical user interface (GUI) using Tkinter. A slider widget allows us to adjust the feedback stimulus, representing the process variable. Labels display the feedback stimulus value and the computed derivative term in real-time. Additionally, a hyperlink is provided to visit a website for further information.
Implementation with Tkinter
Let’s delve into the implementation of the derivative control demo using Tkinter. Here’s the code:
import tkinter as tk
import time
import webbrowser
# Derivative control function
def derivative_control(error, prev_error, dt):
# Derivative gain
Kd = 0.2
derivative_term = Kd * (error - prev_error) / dt
return derivative_term
# Main loop
def main_loop():
setpoint = 50 # Desired setpoint
process_variable = 0 # Initial process variable
prev_error = 0 # Previous error
dt = 0.1 * 9 # Time interval for derivative control
while True:
# Read process variable from the slider
process_variable = slider.get()
# Calculate the error
error = setpoint - process_variable
# Apply derivative control
derivative_term = derivative_control(error, prev_error, dt)
# Actuate the control signal (in this example, update the label)
control_label.configure(text="Derivative Term: {:.2f}".format(derivative_term))
# Update the previous error
prev_error = error
time.sleep(dt) # Sleep for the time interval
# 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("Derivative 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 derivative term value
control_label = tk.Label(window, text="Derivative 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()
Exploring the Code
Let’s break down the code to understand how the derivative control demo works:
We begin by importing the necessary modules: tkinter for GUI, time for time-related operations, and webbrowser for opening web links.
The derivative_control function calculates the derivative control term based on the error, previous error, and a specified time interval. It multiplies the derivative gain (Kd) with the difference in error and divides it by the time interval. Adjusting the value of Kd can impact the system’s response.
The main_loop function serves as the central control loop of the demo. It sets the desired setpoint and initializes variables for the process variable and previous error. The time interval (dt) determines the frequency of derivative control updates. Within the loop, the process variable is read from the slider, the error is calculated, derivative control is applied, and the control output is displayed in the GUI label. The previous error is updated, and the loop pauses for the specified time interval.
The slider_callback function is triggered whenever the slider value changes. It updates the feedback label to display the current value of the feedback stimulus, representing the process variable.
The open_link function opens the “exasub.com” website in a web browser when the “Visit exasub.com” link is clicked. This functionality provides an opportunity to learn more about derivative control or related topics.
The main Tkinter window is created, titled “Derivative Control Demo”.
A slider widget is added to the window, allowing the user to adjust the feedback stimulus. It spans from 0 to 100, is oriented horizontally, and has a length of 300 pixels. The slider_callback function is bound to this slider to update the feedback label.
A label is created to display the current value of the feedback stimulus.
Another label is created to display the computed derivative term. Initially, it displays the placeholder text “Derivative Term: “.
A hyperlink labeled “Visit exasub.com” is added to the window. It appears in blue and changes the cursor to a hand when hovered over. The open_link function is bound to this label to open the specified website.
The main loop is started in a separate thread using the threading module. This allows the control loop to run concurrently with the Tkinter event loop and ensures the GUI remains responsive.
Finally, the Tkinter event loop is started using the mainloop() method of the window object. It listens for user interactions and updates the GUI accordingly.
Running the Derivative Control Demo
To run the derivative control demo, you’ll need to have Python and the Tkinter library installed. Save the code in a Python file (e.g., derivative_control_demo.py) and execute it. A window will appear with a slider and two labels.
Adjusting the slider will update the feedback stimulus
value label in real-time. As you adjust the slider, the derivative control algorithm will calculate the derivative term, which will be displayed in the “Derivative Term” label. The calculated derivative term reflects the system’s response to changes in the feedback stimulus.
Additionally, clicking the “Visit exasub.com” link will open a web browser and direct you to the “exasub.com” website, providing an opportunity to explore further resources on derivative control or related topics.
Conclusion
In this blog post, we’ve explored a derivative control demo implemented using Tkinter in Python. By adjusting a slider representing the feedback stimulus, you can observe the real-time calculation of the derivative term. This demonstration showcases the principles of derivative control and its role in control systems engineering.
Understanding derivative control and its application can be valuable in various fields, such as robotics, industrial automation, and process control. By manipulating the derivative gain and other control parameters, engineers can fine-tune the system’s response to optimize performance, stability, and efficiency.
By experimenting with this derivative control demo and further exploring control systems engineering, you can deepen your understanding of control strategies and their impact on system behavior.
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 W
L298N Module
GND
GND
GP0
IN1
GP1
IN2
GP2
IN3
GP3
IN4
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)
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 W
L298n Module
GP9
IN1
GND
GND
VSYS (Connect this only when you save as “main.py” in raspberry pi.)
+5V
12V PC FAN
L298n 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()
I am using raspberry pi model 3 b+ for the code compilation.
Create the folder named “distance” inside the pico folder
Then Create the test.c and CMakeLists.txt files using touch command.
touch test.c CMakeLists.txt
Copy the pico_sdk_import.cmake file from pico/pico-sdk/external
make the build directory using mkdir command
mkdir build
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)
Here is the c code that you put inside the test.c file