Funpack3-5__BeagleBone® Black__从网页中控制LED的开关与闪烁
该项目使用了BeagleBone® Black,实现了从网页中控制LED的开关与闪烁的设计,它的主要功能为:在系统中建立一个网页,并且与LED联动,使用网线连接到设备上时,可以从网页中控制LED的开关与闪烁。
标签
嵌入式系统
Funpack活动
MPU
开发板
Nicole_Du
更新2025-01-15
44

一.项目介绍

项目基于BeagleBone® Black平台(以下简称BBB),实现任务二:在系统中建立一个网页,并且与LED联动,使用网线连接到设备上时,可以从网页中控制LED的开关与闪烁


二.设计思路

2.1 系统架构

在BBB板上创建一个基于Flask的Web服务器,该服务器允许用户通过网络浏览器访问HTML页面,并通过该页面上的交互元素来控制连接到BBB板的LED灯。用户可以通过输入BBB板的IP地址和指定端口号来访问Web界面,进而实现对LED的开关控制。


2.2 硬件介绍

如下图所示,PC电脑和BBB各通过一条以太网线与路由器相连,形成局域网络。led实现使用BBB板载的四个led灯。

image.png

2.3 配置说明

​整个局域网络的ip地址由路由器静态分配,其中路由器地址为192.168.2.1,为BBB分配的ip地址为192.168.2.28,pc端的ip地址为192.168.2.10,该应用的端口号选择4000,不与其他应用冲突。

在/etc/systemd/中创建一个服务led_control.service,用于上电启动python文件Eth_Flask_Local.py,led_control.service配置如下。

[Unit]
Description=My Python Script
After=network.target multi-user.target

[Service]
Type=simple
User=debian
ExecStart=/usr/bin/python3.7 /var/lib/cloud9/BeagleBone/Black/Eth_Flask_Local.py
Restart=on-failure

[Install]
WantedBy=multi-user.target


第三部分:功能介绍

3.1 前端功能实现

使用HTML、CSS以及JavaScript实现前端功能。

设置页面标题为“LED Control”,创建一个CSS样式类.button用于统一按钮外观和行为,其中:hover伪类用于鼠标悬停在按钮上时改变背景颜色,:active伪类用于按钮被按下时调整背景颜色和阴影位置,模拟物理按钮的按下效果。

<head>
    <meta charset="UTF-8">
    <title>LED Control</title>
    <style>
        .button {
            display: inline-block;
            padding: 10px 20px;
            margin: 10px;
            font-size: 16px;
            cursor: pointer;
            text-align: center;
            text-decoration: none;
            outline: none;
            color: #fff;
            background-color: #4CAF50;
            border: none;
            border-radius: 15px;
            box-shadow: 0 9px #999;
        }
        .button:hover {background-color: #3e8e41}
        .button:active {
            background-color: #3e8e41;
            box-shadow: 0 5px #666;
            transform: translateY(4px);
        }
    </style>
</head>

主标题显示“Control LEDs”,放置4个容器分别用于4个led灯的控制,每个led灯分别设置3个按钮:"Turn on"、"Turn off""Blink",每个按钮使用一个onclick事件处理程序,当用户点击时会调用相应的JavaScript函数(sendCommand)来发送命令给服务器。

    <div>
        <h2>LED 1</h2>
        <button onclick="sendCommand(1)" class="button">Turn On</button>
        <button onclick="sendCommand(2)" class="button">Turn Off</button>
        <button onclick="sendCommand(3)" class="button">Blink</button>
    </div>
    <div>
        <h2>LED 2</h2>
        <button onclick="sendCommand(11)" class="button">Turn On</button>
        <button onclick="sendCommand(12)" class="button">Turn Off</button>
        <button onclick="sendCommand(13)" class="button">Blink</button>
    </div>
    <div>
        <h2>LED 3</h2>
        <button onclick="sendCommand(21)" class="button">Turn On</button>
        <button onclick="sendCommand(22)" class="button">Turn Off</button>
        <button onclick="sendCommand(23)" class="button">Blink</button>
    </div>
    <div>
        <h2>LED 4</h2>
        <button onclick="sendCommand(31)" class="button">Turn On</button>
        <button onclick="sendCommand(32)" class="button">Turn Off</button>
        <button onclick="sendCommand(33)" class="button">Blink</button>
    </div>

async function sendCommand(command):异步函数,用于向服务器发送控制LED的命令。

参数command:表示要执行的操作,如开启、关闭或闪烁特定的LED。命令值根据按钮的不同而变化。

fetch API:使用fetch函数发起HTTP POST请求到服务器的/led端点,同时传递一个包含command键值对的JSON字符串作为请求体。

await response.json():等待服务器返回的数据并解析为JavaScript对象。

        async function sendCommand(command) {
            const response = await fetch(`/led`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ command: command })
            });
            const data = await response.json();
            document.getElementById('response').innerText = `Result: ${data.result}`;
        }


3.2 指令执行功能实现

使用python实现Flask服务器和控制gpio使led闪烁功能。

首先在主函数中初始化global_led_flag列表,将其所有元素设置为False,这表示所有LED灯初始状态下都不闪烁。然后启动后台线程,依次调用start_background_thread0()start_background_thread3()函数,分别创建并启动四个后台线程,用于控制每个LED灯的闪烁行为。最后调用app.run(host='0.0.0.0', port=4000)来启动Flask Web服务器,监听所有网络接口上的4000端口。这意味着任何连接到BBB板所在网络的设备都可以通过IP地址和4000端口访问这个Web服务器。

# 如果这个文件是主程序,启动Flask应用
if __name__ == '__main__':
    global_led_flag = [False,False,False,False]
    print(global_led_flag)
    start_background_thread0()
    start_background_thread1()
    start_background_thread2()
    start_background_thread3()
    app.run(host='0.0.0.0', port=4000)
# 创建led灯闪烁线程函数
def start_background_thread0():
    thread = threading.Thread(target=led_blingbling_task0)
    thread.daemon = True  
    thread.start()
def start_background_thread1():
    thread = threading.Thread(target=led_blingbling_task1)
    thread.daemon = True  
    thread.start()
def start_background_thread2():
    thread = threading.Thread(target=led_blingbling_task2)
    thread.daemon = True  
    thread.start()
def start_background_thread3():
    thread = threading.Thread(target=led_blingbling_task3)
    thread.daemon = True  
    thread.start()

home()函数用于flask服务器的应用主页

@app.route('/')
def home():
    return render_template('led.html')

接收和处理信息的函数如下,若有预检请求进行处理,允许前端从不同域访问此API端点。获取和解析POST请求中的JSON数据,command的十位为用于控制哪颗le灯,个位用于控制led灯状态,分别通过整除和取余进行区分。若为闪烁,则给全局变量global_led_flag置位,在其余四个led灯闪烁线程会对此全局变量进行处理。处理结束后返回结果JSON数据。

# 定义一个POST请求的API端点,用于执行命令
@app.route('/led', methods=['POST', 'OPTIONS'])
def post_command():
    if request.method == "OPTIONS":
        # 处理预检请求
        return '', 204


    data = request.json  # 获取POST请求中的JSON数据
    command = data.get('command')  # 从JSON数据中提取命令
    #print(f"Received command: {command}, type: {type(command)}")
 
    if command:
        ledNumber = command // 10
        ledStatus = command % 10
        #result = execute_command(command)  # 执行命令
        global global_led_flag
        global_led_flag[ledNumber] = False
        print(global_led_flag)
        if ledStatus == 1 :
            GPIO.output("USR%d" % ledNumber, GPIO.HIGH)
        elif ledStatus == 2:
            GPIO.output("USR%d" % ledNumber, GPIO.LOW)
        elif ledStatus == 3:
            global_led_flag[ledNumber] = True
            print(global_led_flag)
        return jsonify({'result': 'Executed successfully'}), 200
    else:
        return jsonify({'error': 'No command provided'}), 400

4个线程分别被相应的全局变量控制,闪烁时以0.5s每次的频率闪烁。

# led灯闪烁函数
def led_blingbling_task0():
    while True:
        while global_led_flag[0]:
            GPIO.output("USR%d" % 0, GPIO.HIGH)
            time.sleep(0.5)
            if global_led_flag[0]:
                GPIO.output("USR%d" % 0, GPIO.LOW)
                time.sleep(0.5)
def led_blingbling_task1():
    while True:
        while global_led_flag[1]:
            GPIO.output("USR%d" % 1, GPIO.HIGH)
            time.sleep(0.5)
            if global_led_flag[1]:
                GPIO.output("USR%d" % 1, GPIO.LOW)
                time.sleep(0.5)
def led_blingbling_task2():
    while True:
        while global_led_flag[2]:
            GPIO.output("USR%d" % 2, GPIO.HIGH)
            time.sleep(0.5)
            if global_led_flag[2]:
                GPIO.output("USR%d" % 2, GPIO.LOW)
                time.sleep(0.5)
def led_blingbling_task3():
    while True:
        while global_led_flag[3]:
            GPIO.output("USR%d" % 3, GPIO.HIGH)
            time.sleep(0.5)
            if global_led_flag[3]:
                GPIO.output("USR%d" % 3, GPIO.LOW)
                time.sleep(0.5)

3.3 软件流程图

image.png

第四部分:功能展示

BBB上电等待系统初始化完成,打开浏览器访问http://192.168.2.28:4000/加载出LED Control界面

image.png

此时四个灯全部熄灭

27c012dd10482f06c8c4549abeac2f0.jpg

点击LED 2的Turn On按键,第二个灯亮起。

f52160bbc3fcc8e69006dfcd523d0fa.jpg

点击LED 3 Blink按键,第三个灯开始闪烁,具体可见视频,点击Turn Off灯熄灭。




总结及心得体会

本项目成功地在BeagleBone Black上搭建了一个基于Flask的Web服务器,并实现了远程控制led灯开关和闪烁的功能。在实现功能的过程中,从选择方案开始我就走了很多弯路,但经过了这个项目,我从一个对网络编程一无所知的小小白,到现在对web服务器略有了解,并进行实践,迈出了我个人的一大步,感到很有成就感,非常感谢这次活动。

如果要说有什么意见建议,那就是还是期待主办方提供更多的课程或者资料支持,交流群中有很多大佬,也有如我这样的小白,希望后面的小伙伴可以少走一些弯路,学到更多有用的实用的技能。

再次感谢硬禾学堂。

附件下载
Eth_Flask_Local.py
flask服务器代码
led.html
前端页面代码
团队介绍
杜子曼
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号