【Portable Programmable Meter】Project Submission
[Copy link]
USB portable programmable instrument -Multifunctional USB power supply
Author: Shao Ziyang Zhou Yuwei Chen Tao Huang Yuyin Zhang Mengjun
1. Introduction
Name : USB portable programming instrument (multi -function USB power supply)
photo :
Function introduction :
The core idea of the USB portable programmable instrument is to provide electronic engineers and enthusiasts with a series of low -cost, portable, supporting networks, programming control, and open source practical tools. Low -rate, inconvenient to carry, and not flexible power supply methods. With the popularity of the USB PD function, more and more chargers support the USB PD function, and the new requirements of the Internet of Things era have given us new choices.
Key Features :
- USB Type-C power supply, support PD
- Support buck-boost mode
- Can be controlled by USB, Bluetooth, Wifi and other methods, supports remote control
- Support user secondary programming development
- Can automatically record operating data and upload it to the cloud
- Hardware modular design facilitates future hardware upgrades and function expansions
- Small size and high efficiency
- low cost
- Open Source
2. System Block Diagram
Hardware description
Main chips (domestic chips are selected)
- Controller: Shanghai Lexin's ESP32-S3
- Power: Nanxin SC8721A
- PD: Nanjing Qinheng CH224K
Hardware Block Diagram
In order to facilitate future upgrade and functional expansion, the hardware part is modularly designed according to the function.
Software Description
The software is divided into 5 parts:
- MCU logic control
- LCD display button processing
- Wifi control
- Bluetooth control
- Power chip control
3. Functional description of each part
Control board physical map
Main control module
The main control module completes functions such as communication (USB, Wifi, Bluetooth), power control, data recording, and human-computer interaction.
The system uses ESP32-S3 as the controller. This is an MCU chip that integrates 2.4 GHz Wi-Fi and Bluetooth 5 (LE), supports long distance mode (Long Range). (TCM), with 45 programmable GPIO foot and rich communication interfaces. ESP32-S3 supports larger high-speed high-speed OCTAL SPI Flash and outer RAM, supporting users to configure data cache and instruction cache.
Compared with the early ESP32, ESP32-S3 has a USB interface, which can directly connect to the computer without converting chips, which is faster. In addition, ESP32-S3 increases the vector instructions for accelerating neural network computing and signal processing (Vector Instructor).
In order to facilitate the upgrade, the main control section has designed a general interface. PWM output, UART, I2C, SPI and other functions are convenient for future function expansion.
In order to ensure the ADC sampling accuracy, the system also uses a 0.5% accuracy external reference source (U2, TL431).
Power Module
The power module implements the voltage transformation function.
The power supply part uses Nanxin's SC8721, which is a lifting and booming DC chip. The input and output range are 2.7 V to 22 V. It is very suitable for the range of USB PD. This voltage range is suitable for the general needs of electronic engineers, which is particularly suitable for embedded engineers.
SC8721 can set the output voltage, current, and mode through the I2C interface.
The power supply part also uses a modular design. In addition to the power input VBUS and power output Vout, the interface part also has related control interfaces.
[Attach] 649440 [/Attach]
Baseboard with USB PD function
Some of the bottom plates are relatively large, mainly USB PD, USB communication, auxiliary power supply, power output, etc.
The USB PD is implemented by Qinheng's CH224K. CH224 integrates a variety of fast charge protocols such as USB PD, supports PD3.0/2.0, BC1.2 and other boost fast charge protocols, automatically detect VCONN and analog E-Mark chip, and supports 100W power. Different PD devices to get the maximum input power as much as possible.
The other USB is used for ESP32-S3 to communicate with the computer, realizing various functions such as program download, software debugging, PC control, etc. When there is no USB PD input, this channel can also be used as a power input, but the power will be lower.
The auxiliary power supply is used to convert the 3.3V working voltage required by the controller from the power supply.
[Attach] 649441 [/Attach]
Software Features
In order to facilitate use and reflect the convenience brought by the Internet of Things, in addition to being able to be controlled through a computer via USB, the more important use is to control the system through the network. You can directly view the system status and set system parameters in the browser (including computer, mobile phone, tablet, etc.), and you can also control it through Bluetooth and WeChat applet. Remote control and cloud functions will be added later.
4. Source Code
The hardware part of the system is developed using Micropython (it is planned to be transplanted to the Circuitpython in the next step to facilitate the second development of different users), and some source code is as follows (the complete code will be gradually sorted into github, see the link at the end of the article):
The directory structure of the source code:
File name Size
---------------------------------------------------------------- ------
ppps\
aioble.py 7,872
BLE.py 8,013
boot.py 538
bt.py 2,836
demo.py 970
demoxiaozi.py 1,181
font.py 1,859
Font_12x24.py 14,619
Font_16x32.py 25,544
Font_6x8.py 2,267
Font_8x16.py 5,689
hanzi.py 4,946
main.py 111
oled.py 7,891
ppps.CatalogMaker 3,052
show.py 992
ssd1306.py 4,584
test.py 2,223
tryi2c.py 6,424
web.py 6,031
ppps\config\
emp_wifi.json 86
webrepl.pass 5
ppps\lib\
@PaxHeader 22
emp_boot.py 2,260
emp_ide.py 1,647
emp_utils.py 3,249
emp_webrepl.py 3,355
emp_wifi.py 7,657
pkg_resources.py 698
sdist_upip.py 3,674
ppps\lib\mdns_client\
__init__.py 49
client.py 8,956
constants.py 712
parser.py 6,600
responder.py 8,173
structs.py 5,690
util.py 4,462
ppps\lib\mdns_client\service_discovery\
__init__.py 108
discovery.py 11,051
service_monitor.py 373
service_response.py 2,476
txt_discovery.py 1,316
ppps\lib\picoweb\
__init__.py 11,173
utils.py 809
ppps\lib\uasyncio\
__init__.py 9,058
core.py 10,356
ppps\static\
jquery.min.js 84,349
logo.png 1,691
ppps.png 1,277
File: web.py
import picoweb
import tryi2c
import time
import ujson
app = picoweb.WebApp(None)
def webpage():
htmlContent = """<!DOCTYPE html> <meta charset="UTF-8"><head><script src="/bbs/static/jquery.min.js"></script>
<title>PPPS网页控制界面</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3333; padding: 2vh;style="line-height: 1em;}p{font-size: 1rem;style="line-height: 1em;}.button{display: inline-block; background-color: #e7bd3b; border: none;
border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 2rem; margin: 2px; cursor: pointer;}
.button2{background-color: #4286f4;font-size: 1rem;}input{ font-size: 1rem;}</style>
</head><body> <img src='static/ppps.png' width="128" height="128"><br />
<h1><font color="red">PPPS网页控制界面</font></h1>
<blockquote>
<blockquote>
</blockquote>
<table width="300" border="0" align="center">
<tr>
<td width="100"><p>输入电压:</p></td>
<td width="100" bordercolor="#FFFFFF"><p><strong><span id="votage_in" value=0>0</span></strong></p></td>
<td width="100"> </td>
</tr>
<tr>
<td><p>输出电压:</p></td>
<td bordercolor="#FFFFFF"><p><strong><span id="votage" value=0>0</span></strong></p></td>
<td> </td>
</tr>
<tr>
<td><p>输出电流:</p></td>
<td bordercolor="#FFFFFF"><p><strong><span id="current">0 </span></strong></p></td>
<td> </td>
</tr>
<tr>
<td><p>电压设置:</p></td>
<td bordercolor="#FFFFFF"><p><strong><span id="votage_set">0</span></strong></p></td>
<td><input name="text" type="text" class="txt" id="votage_set_input" onKeyUp="this.value=this.value.replace(/[^0-9\.]/g,'')" value="0" size="8" maxlength="4" ></td>
</tr>
<tr>
<td><p>电流设置:</p></td>
<td bordercolor="#FFFFFF"><p><strong><span id="current_set">0</span></strong></p></td>
<td><input name="text2" type="text" class="txt" id="current_set_input" onKeyUp="this.value=this.value.replace(/[^0-9\.]/g,'')" value="0" size="8" maxlength="4" ></td>
</tr>
</table>
<p>
<button class="button" type="submit" name="btn" id="btn" onclick="generate();return false">
<div align="center">发送</div>
</button>
</br>
</p>
</blockquote>
<p><img src='static/logo.png'></p>
<script>
var votage_in = document.getElementById("votage_in");
var votage = document.getElementById("votage");
var current = document.getElementById("current");
var votage_set = document.getElementById("votage_set");
var current_set = document.getElementById("current_set");
var current_set_input = document.getElementById("current_set_input")
var votage_set_input = document.getElementById("votage_set_input")
var btn = document.getElementById("btn")
btn
let num = 0
var timer = setInterval(function() {
num++;
btn.innerText='发送';
$.ajax({
url : "/getdata",
type : "POST",
datatype : "JSON",
success:function(datas){
votage_in.innerText= datas.votage_in;
votage.innerText= datas.votage;
current.innerText= datas.current;
votage_set.innerText= datas.votage_set;
current_set.innerText= datas.current_set;
}
})
},500)
function generate() {
fetch("/", {
method: "POST",
body: JSON.stringify({
votage_set_input :votage_set_input.value,
current_set_input :current_set_input.value,
}),
headers: {
'Content-Type': 'Content-Length'
},
});
btn.innerText="下发成功!"
}
</script>
</body></html>"""
return htmlContent
@app.route('/getdata',methods=['GET', 'POST'])
def return_data(req, resp):
print('return data')
votage_in=str(round(tryi2c.aVin.read_uv()/1000000.0*11,2))
print (votage_in)
votage=str(round(tryi2c.aVout.read_uv()/1000000.0*11,2))
current=str(round(tryi2c.aIout.read_uv()/1000.0*2/640,2))
current_set=str(round(tryi2c.sc.IOUT_ILIM,2))
votage_set=str(round(tryi2c.sc.VOUT_SET,2))
jsonData = {"votage":votage,"current":current,"votage_set":votage_set,"votage_in":votage_in,"current_set":current_set}
encoded = ujson.dumps(jsonData)
yield from picoweb.start_response(resp, content_type = "application/json")
yield from resp.awrite(encoded)
@app.route("/")
def index(req, resp):
if req.method == 'POST':
#print('1111')
size = int(req.headers[b"Content-Length"])
#print(size)
data = yield from req.reader.readexactly(size)
#print(data)
form=ujson.loads(data)
#print('1111',form)
votage_set_input = float(form["votage_set_input"])
current_set_input=float(form["current_set_input"])
print(votage_set_input,current_set_input)
if votage_set_input<=4:
level=0
elif votage_set_input<=8:
level=1
elif votage_set_input<=11:
level=2
elif votage_set_input<=14:
level=3
else:level=4
# print(level)
# tryi2c.SET_INPUT_LEVEL(level)
tryi2c.sc.Output_Voltage_Setting(votage_set_input)
tryi2c.sc.Output_Current_Limit(current_set_input)
else:
yield from picoweb.start_response(resp,content_type = "text/html")
yield from resp.awrite(webpage())
level=0
File: test.py
from machine import Timer,Pin
import show
tim0 = Timer(0)
import uasyncio as asyncio
import tryi2c
from emp_wifi import Wifi
from neopixel import NeoPixel
def handle_callback(timer):
global modenow,web_run_flag,np,mode#定时器中断服务函数
tryi2c.sc.readall(0)
if mode=="BLE" and modenow!="BLE":
try:
web_deinit()
web_run_flag=1
BLE.init()
modenow="WIFI"
show.oled.HZ16(112,0,15)
np[0] = (10, 0, 0)
np.write()
except Exception as e:
print (e)
if mode=="BLE":
BLE.run()
if mode=="WIFI" and modenow!="WIFI":
try:
BLE.deinit()
web_run_flag=2
modenow="WIFI"
np[0] = (0, 10, 0)
np.write()
show.oled.HZ16(112,0,14)
except Exception as e:
print (e)
ss=tryi2c.aVout.read_uv()
s = "%02d" % int((ss/1000000.0*11)//1)+ ".%d" % int(((ss/1000000.0*11)%1)*10)
show.oled.text(32, 2, s+' V')
ss=tryi2c.aIout.read_uv()
s = "%02d" % int((ss/1000000.0*11)//1)+ ".%d" % int(((ss/1000000.0*11)%1)*10)
show.oled.text(32, 5, s+' A')
if tryi2c.sc.OCP==0:
if np[0] != (0, 10, 0):
np[0] = (0, 10, 0)
np.write()
show.oled.HZ16(32,0,7)
show.oled.HZ16(48,0,1)
LED1.value(0)
else:
if np[0] != (10, 0, 0):
np[0] = (10, 0, 0)
np.write()
show.oled.HZ16(48,0,2)
show.oled.HZ16(32,0,7)
LED1.value(1)
import web,BLE
web_run_flag=0
mode="WIFI"
modenow="BLE"
LED1=Pin(13,Pin.OUT)
np = NeoPixel(LED1, 3)
np[0] = (0, 10, 0)
np[1] = (0, 0, 0)
np[2] = (0, 0, 10)
np.write()
tim0.init(period=200, mode=Timer.PERIODIC, callback=handle_callback)
def web_run():
global web_run_flag
while 1:
if web_run_flag==2:
web.app.run(debug=True, host = Wifi.ifconfig()[0][0])
web_run_flag=1
if web_run_flag==1:
pass
time.sleep(1)
def web_deinit():
loop = asyncio.get_event_loop()
loop.stop()
web_run()
5. Demonstration video of the work’s functions
6. Project Summary
This activity shows a long -term idea of we planning. It is to provide an open source tool for electronic engineers and enthusiasts to provide some low cost, strong practicality, and improvement of the usual development and DIY. Such functions to make up for their shortcomings in this area, more suitable for changes in the Internet age, and more suitable for our use.
This activity is fully used to develop the open source scheme and free software. The address is at the end of the article), which is convenient for more enthusiasts to participate in and improved and turn it into a truly practical tool.
This activity also gave us a good exercise in teamwork. From creativity to demand analysis, to circuit design, proofing, welding, programming, debugging, and finally to the final video and documentation, everyone participated and completed the task well. Due to time constraints, some functions have not been fully implemented and need further improvement, but the main functions have been completed and can well demonstrate our ideas.
Finally, I would like to thank Digi-Key and EEworld for organizing this excellent event, which provides electronic engineers with an opportunity to showcase their creativity.
Activity post summary
VII. Others
The project has created repositories on github and gitee, and the documents will be gradually organized and uploaded.
Warehouse Address:
|