Skip to content

Commit 43d13dc

Browse files
authored
Add files via upload
1 parent 03d5362 commit 43d13dc

File tree

3 files changed

+325
-0
lines changed

3 files changed

+325
-0
lines changed

PID-Controlled Cooling Fan/DS18B20.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from micropython import const
2+
from pyb import Pin
3+
from onewire import OneWire
4+
from utime import sleep_ms
5+
6+
7+
convert_T = const(0x44)
8+
read_scratchpad = const(0xBE)
9+
write_scratchpad = const(0x4E)
10+
copy_scratchpad = const(0x48)
11+
recall_E2 = const(0xB8)
12+
read_power_supply = const(0xB4)
13+
skip_ROM = const(0xCC)
14+
15+
16+
class DS18B20():
17+
18+
def __init__(self, _pin):
19+
self.pin = Pin(_pin, Pin.IN, Pin.PULL_UP)
20+
self.ow = OneWire(self.pin)
21+
22+
self.init()
23+
24+
25+
def init(self):
26+
self.ow.reset()
27+
sleep_ms(400)
28+
29+
30+
def get_T(self):
31+
msb = 0
32+
lsb = 0
33+
temp = 0.0
34+
35+
self.ow.reset()
36+
self.ow.writebyte(skip_ROM)
37+
self.ow.writebyte(convert_T)
38+
sleep_ms(800)
39+
40+
self.ow.reset()
41+
self.ow.writebyte(skip_ROM)
42+
self.ow.writebyte(read_scratchpad)
43+
44+
lsb = self.ow.readbyte()
45+
msb = self.ow.readbyte()
46+
47+
temp = msb
48+
temp <<= 8
49+
temp |= lsb
50+
temp *= 0.0625
51+
52+
return temp

PID-Controlled Cooling Fan/SSD1309.py

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
from micropython import const
2+
from machine import Pin
3+
from utime import sleep_ms
4+
import framebuf
5+
6+
7+
disp_width = const(128)
8+
disp_height = const(64)
9+
disp_pages = const((disp_height >> 3))
10+
11+
# Constants
12+
SSD1309_SET_CONTRAST = const(0x81)
13+
SSD1309_DISPLAY_ALL_ON_RESUME = const(0xA4)
14+
SSD1309_DISPLAY_ALL_ON = const(0xA5)
15+
SSD1309_NORMAL_DISPLAY = const(0xA6)
16+
SSD1309_INVERT_DISPLAY = const(0xA7)
17+
SSD1309_DISPLAY_OFF = const(0xAE)
18+
SSD1309_DISPLAY_ON = const(0xAF)
19+
SSD1309_SET_DISPLAY_OFFSET = const(0xD3)
20+
SSD1309_SET_COM_PINS = const(0xDA)
21+
SSD1309_SET_VCOM_DETECT = const(0xDB)
22+
SSD1309_SET_DISPLAY_CLOCK_DIV = const(0xD5)
23+
SSD1309_SET_PRECHARGE = const(0xD9)
24+
SSD1309_SET_MULTIPLEX = const(0xA8)
25+
SSD1309_SET_LOW_COLUMN = const(0x00)
26+
SSD1309_SET_HIGH_COLUMN = const(0x10)
27+
SSD1309_SET_START_LINE = const(0x40)
28+
SSD1309_MEMORY_MODE = const(0x20)
29+
SSD1309_COLUMN_ADDR = const(0x21)
30+
SSD1309_PAGE_ADDR = const(0x22)
31+
SSD1309_COM_SCAN_INC = const(0xC0)
32+
SSD1309_COM_SCAN_DEC = const(0xC8)
33+
SSD1309_SEG_REMAP = const(0xA0)
34+
SSD1309_CHARGE_PUMP = const(0x8D)
35+
SSD1309_EXTERNAL_VCC = const(0x01)
36+
SSD1309_SWITCH_CAP_VCC = const(0x02)
37+
38+
# Scrolling constants
39+
SSD1309_ACTIVATE_SCROLL = const(0x2F)
40+
SSD1309_DEACTIVATE_SCROLL = const(0x2E)
41+
SSD1309_SET_VERTICAL_SCROLL_AREA = const(0xA3)
42+
SSD1309_RIGHT_HORIZONTAL_SCROLL = const(0x26)
43+
SSD1309_LEFT_HORIZONTAL_SCROLL = const(0x27)
44+
SSD1309_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = const(0x29)
45+
SSD1309_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = const(0x2A)
46+
47+
LOW = const(0)
48+
HIGH = const(1)
49+
50+
CMD = LOW
51+
DAT = HIGH
52+
53+
54+
class OLED1309(framebuf.FrameBuffer):
55+
56+
def __init__(self, _spi, _dc, _rst, _cs):
57+
self.width = disp_width
58+
self.height = disp_height
59+
self._pages = disp_pages
60+
61+
self.WHITE = 1
62+
self.BLACK = 0
63+
64+
self.spi = _spi
65+
self.cs = Pin(_cs, Pin.OUT)
66+
self.rst = Pin(_rst, Pin.OUT)
67+
self.dc = Pin(_dc, Pin.OUT)
68+
69+
self.buffer = bytearray(self._pages * self.width)
70+
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
71+
self.init_display()
72+
73+
74+
def write_command(self, value):
75+
self.dc.value(CMD)
76+
self.cs.value(LOW)
77+
self.spi.write(bytearray([value]))
78+
self.cs.value(HIGH)
79+
80+
81+
def reset(self):
82+
self.rst.value(HIGH)
83+
sleep_ms(1)
84+
self.rst.value(LOW)
85+
sleep_ms(10)
86+
self.rst.value(HIGH)
87+
88+
89+
def init_display(self):
90+
self.reset()
91+
92+
self.write_command(SSD1309_DISPLAY_OFF)
93+
self.write_command(SSD1309_SET_DISPLAY_CLOCK_DIV)
94+
self.write_command(0x80)
95+
96+
self.write_command(SSD1309_SET_MULTIPLEX)
97+
self.write_command((self.height - 1))
98+
99+
self.write_command(SSD1309_SET_DISPLAY_OFFSET)
100+
self.write_command(0x00)
101+
102+
self.write_command((SSD1309_SET_START_LINE | 0x00))
103+
104+
self.write_command(SSD1309_CHARGE_PUMP)
105+
self.write_command(0x14) # 0x10 # 0x14
106+
107+
self.write_command(SSD1309_MEMORY_MODE)
108+
self.write_command(0x00)
109+
110+
self.write_command((SSD1309_SEG_REMAP | 0x01))
111+
self.write_command(SSD1309_COM_SCAN_DEC)
112+
self.write_command(SSD1309_SET_COM_PINS)
113+
self.write_command(0x12)
114+
115+
self.write_command(SSD1309_SET_CONTRAST)
116+
self.write_command(0xCF) # 0x9F # 0xCF
117+
118+
self.write_command(SSD1309_SET_PRECHARGE)
119+
self.write_command(0xF1) # 0x22 # 0xF1
120+
121+
self.write_command(SSD1309_SET_VCOM_DETECT)
122+
self.write_command(0x40)
123+
124+
self.write_command(SSD1309_DISPLAY_ALL_ON_RESUME)
125+
self.write_command(SSD1309_NORMAL_DISPLAY)
126+
self.write_command(SSD1309_DISPLAY_ON)
127+
128+
129+
def show(self):
130+
x0 = 0
131+
x1 = self.width - 1
132+
if (self.width == 64):
133+
# displays with width of 64 pixels are shifted by 32
134+
x0 += 32
135+
x1 += 32
136+
137+
self.write_command(SSD1309_COLUMN_ADDR)
138+
self.write_command(x0)
139+
self.write_command(x1)
140+
self.write_command(SSD1309_PAGE_ADDR)
141+
self.write_command(0x00)
142+
self.write_command((self._pages - 1))
143+
144+
self.dc.value(DAT)
145+
self.cs.value(LOW)
146+
self.spi.write(self.buffer)
147+
self.cs.value(HIGH)

PID-Controlled Cooling Fan/main.py

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
from pyb import Pin, SPI, Timer
2+
from SSD1309 import OLED1309
3+
from DS18B20 import DS18B20
4+
from utime import sleep_ms, sleep_us
5+
from micropython import const
6+
7+
8+
points = const(32)
9+
10+
j = 0
11+
k = 0
12+
pv = 0
13+
sv = 35
14+
kp = 4.69
15+
kd = 0.06
16+
ki = 0.09
17+
rpm = 0
18+
pulse = 1
19+
error = 0
20+
integral = 0
21+
derivative = 0
22+
last_capture = 0
23+
previous_error = 0
24+
pwm_duty_cycle = 0
25+
bar = bytearray(b'\x3F' * points)
26+
27+
cs_pin = Pin('PB7', Pin.OUT_PP)
28+
dc_pin = Pin('PB8', Pin.OUT_PP)
29+
rst_pin = Pin('PB9', Pin.OUT_PP)
30+
cap_pin = Pin('PA1', Pin.IN)
31+
pwm_pin = Pin('PB4', Pin.OUT_PP)
32+
33+
spi = SPI(2, mode = SPI.MASTER, baudrate = 1000000, polarity = 0, phase = 0, bits = 8, firstbit = SPI.MSB)
34+
35+
oled = OLED1309(spi, dc_pin, rst_pin, cs_pin)
36+
37+
tmp = DS18B20('PA3')
38+
39+
40+
def input_capture(timer):
41+
global last_capture, pulse
42+
43+
pulse = (in_cap.capture() - last_capture)
44+
last_capture = in_cap.capture()
45+
pulse &= 0x0FFFFFFF
46+
47+
48+
TIM2 = Timer(2,
49+
prescaler = 83,
50+
period = 0x0FFFFFFF)
51+
52+
in_cap = TIM2.channel(2,
53+
mode = Timer.IC,
54+
pin = cap_pin,
55+
polarity = Timer.RISING,
56+
callback = input_capture)
57+
58+
59+
TIM3 = Timer(3,
60+
mode = Timer.UP,
61+
prescaler = 20,
62+
period = 999)
63+
64+
pwm = TIM3.channel(1,
65+
mode = Timer.PWM,
66+
pin = pwm_pin)
67+
68+
69+
def map_value(v, x_min, x_max, y_min, y_max):
70+
return int(y_min + (((y_max - y_min) / (x_max - x_min)) * (v - x_min)))
71+
72+
73+
def constrain(value, min_value, max_value):
74+
if(value > max_value):
75+
return max_value
76+
77+
elif(value < min_value):
78+
return min_value
79+
80+
else:
81+
return value
82+
83+
84+
oled.fill(oled.BLACK)
85+
oled.show()
86+
87+
88+
while(True):
89+
rpm = (15000000 / (pulse + 0.00001))
90+
rpm = constrain(rpm, 0, 3500)
91+
pv = tmp.get_T()
92+
93+
error = (pv - sv)
94+
integral += error
95+
derivative = (error - previous_error)
96+
97+
integral = constrain(integral, -600, 600)
98+
99+
print("E: " + str("%2.2f" %error)
100+
+ " I: " + str("%2.2f" %integral)
101+
+ " D: " + str("%2.2f" %derivative))
102+
103+
pwm_duty_cycle = ((kp * error) + (kd * derivative) + (ki * integral))
104+
pwm_duty_cycle = constrain(pwm_duty_cycle, 0, 100)
105+
106+
pwm.pulse_width_percent(pwm_duty_cycle)
107+
108+
bar[j] = map_value(rpm, 0, 3500, 63, 35)
109+
110+
oled.fill(oled.BLACK)
111+
oled.text("PID Fan Control", 6, 4, oled.WHITE)
112+
oled.text((str("%4u" %rpm) + " RPM"+ " " + str("%3u" %pwm_duty_cycle) + "%"), 1, 15, oled.WHITE)
113+
oled.text(("PV: " + str("%2u" %pv) + " SV: " + str("%2u" %sv)), 1, 25, oled.WHITE)
114+
115+
for k in range (0, points, 1):
116+
oled.fill_rect((k * 4), bar[k], 2, (63 - bar[k]), oled.WHITE)
117+
118+
j += 1
119+
120+
if(j >= points):
121+
j = 0
122+
123+
oled.show()
124+
125+
previous_error = error
126+
sleep_ms(200)

0 commit comments

Comments
 (0)