一.硬件介绍
本项目选用的是BeagleBone Black板卡,BeagleBone Black 是一款基于 TI 公司 AM3358 处理器的开发套件,处理器集成了高达 1GHz 的 ARM Cortex™ A8 内核,并提供了丰富的外设接口,包括网口、USB Host、USB OTG、TF卡接口、串口、JTAG接口(默认不焊)、HDMI D Type 接口、eMMC、ADC、I2C、SPI 、PWM 和 LCD 接口。
- BeagleBone 与 Arduino 和 Raspberry Pi(树莓派)可以说是目前应用最广泛的三大嵌入式开源平台。而 BeagleBone 在一定程度上可视为融合了 Arduino 与树莓派的优点,它有比 Arduino 更多的 GPIO 口,有着比树莓派更高的性能和更好的开源(软件硬件全部开源)。
- BeagleBone 可以运行完整的 Linux 系统,程序的编写、编译和调试都可以在板子上进行,而且支持多种编程语言,如常用的 C、C++、Python、perl 都可以在 BeagleBone 内使用。此外,BeagleBone 还自带了基于 Web 的 Cloud9 编辑器以及对应的 BoneScript 语言,可以方便的在电脑浏览器中对 BeagleBone 进行编程。
二.项目设计思路
项目采用BBB板作为核心主控,其中网页搭建部分基于Flask框架实现。
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。Flask框架的主要特征是核心构成比较简单,但具有很强的扩展性和兼容性,程序员可以使用Python语言快速实现一个网站或Web服务。
当然了选择这个框架的原因也包括BBB板上集成了这个库,可以直接进行使用。基于Flask框架的网页收集人机交互的信息,从而对LED灯等外设进行控制。
三.实现细节
1.系统更新烧录
到手的板卡系统可能较旧,可以更新一下板载emmc中承载的系统。
最新版镜像下载地址:Latest Software Images - BeagleBoard
下载好后,通过Win32DiskImage等软件将系统烧录到SD卡中,再插入SD卡,按住BOOT键,上电再松开,BBB板就会自动更新内置系统,自动烧录时,四个灯会成流水灯变化。等过一会四个灯全亮,即代表烧录完成。重新上电拔掉sd卡即可进入新系统使用。
2.代码实现
首先给出app.py的代码如下
from flask import Flask, render_template, request
import Adafruit_BBIO.GPIO as GPIO
import time
import threading
app = Flask(__name__)
# 配置 GPIO 引脚 (USR0 到 USR3)
LED_PINS = ["USR0", "USR1", "USR2", "USR3"]
for pin in LED_PINS:
GPIO.setup(pin, GPIO.OUT)
# 初始化 LED 状态
led_states = {"USR0": False, "USR1": False, "USR2": False, "USR3": False} # 记录 LED 是否开
led_modes = {"USR0": "off", "USR1": "off", "USR2": "off", "USR3": "off"} # 记录 LED 模式:常亮或闪烁
# 控制 LED 闪烁的线程函数
def blink_led(pin):
while True:
if led_modes[pin] == "blink" and led_states[pin]: # 如果 LED 是闪烁模式并且是开启的
GPIO.output(pin, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(pin, GPIO.LOW)
time.sleep(0.5)
time.sleep(0.1) # 稍微降低 CPU 占用
# 启动线程控制每个 LED 的闪烁
for pin in LED_PINS:
threading.Thread(target=blink_led, args=(pin,), daemon=True).start()
# Web 路由
@app.route('/')
def index():
return render_template('index.html', led_states=led_states, led_modes=led_modes)
@app.route('/toggle_led/<led>', methods=['POST'])
def toggle_led(led):
global led_states
if led in led_states:
led_states[led] = not led_states[led] # 切换 LED 状态
if not led_states[led]: # 如果关闭 LED,停止闪烁模式
led_modes[led] = "off"
GPIO.output(led, GPIO.LOW) # 关闭 LED
else:
GPIO.output(led, GPIO.HIGH) # 打开 LED
return render_template('index.html', led_states=led_states, led_modes=led_modes)
@app.route('/toggle_mode/<led>', methods=['POST'])
def toggle_mode(led):
if led in led_modes and led_states[led]: # 只有当 LED 是打开状态时,才允许切换模式
led_modes[led] = "blink" if led_modes[led] == "off" else "off" # 切换模式(闪烁或常亮)
if led_modes[led] == "off":
GPIO.output(led, GPIO.HIGH) # 常亮模式下开启 LED
else:
GPIO.output(led, GPIO.HIGH) # 切换到闪烁模式后,LED 初始为开启状态
return render_template('index.html', led_states=led_states, led_modes=led_modes)
# 启动应用
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
具体分析如下:
1. 导入库
from flask import Flask, render_template, request
import Adafruit_BBIO.GPIO as GPIO
import time
import threading
Flask用于构建 Web 应用,render_template用于渲染 HTML 页面,request用于处理 HTTP 请求。Adafruit_BBIO.GPIO是 BeagleBone Black 的 GPIO 控制库,用于控制板载 LED。time用于控制延时。threading用于多线程处理,控制 LED 闪烁。
2. 初始化 Flask 应用
app = Flask(__name__)
初始化 Flask 应用对象 app,这是创建 Web 服务的标准步骤。
3. GPIO 配置
LED_PINS = ["USR0", "USR1", "USR2", "USR3"]
for pin in LED_PINS:
GPIO.setup(pin, GPIO.OUT)
- 定义了一个包含 BeagleBone Black 上四个板载 LED 的引脚列表(
USR0到USR3)。 - 对每个引脚,使用
GPIO.setup(pin, GPIO.OUT)配置为输出模式,使其能够控制 LED 开关。
4. LED 状态初始化
led_states = {"USR0": False, "USR1": False, "USR2": False, "USR3": False} # 记录 LED 是否开
led_modes = {"USR0": "off", "USR1": "off", "USR2": "off", "USR3": "off"} # 记录 LED 模式:常亮或闪烁
led_states字典记录每个 LED 的开关状态。True表示 LED 开启,False表示 LED 关闭。led_modes字典记录每个 LED 的工作模式。"off"表示常亮模式,"blink"表示闪烁模式。
5. LED 闪烁控制
def blink_led(pin):
while True:
if led_modes[pin] == "blink" and led_states[pin]: # 如果 LED 是闪烁模式并且是开启的
GPIO.output(pin, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(pin, GPIO.LOW)
time.sleep(0.5)
time.sleep(0.1) # 稍微降低 CPU 占用
blink_led是一个后台线程函数,控制每个 LED 在闪烁模式下的闪烁效果。- 如果 LED 处于闪烁模式并且开启,则每隔 0.5 秒切换 LED 的状态(开/关),从而产生闪烁效果。
time.sleep(0.1)用来降低 CPU 占用,避免过度占用资源。
6. 启动线程控制闪烁
for pin in LED_PINS:
threading.Thread(target=blink_led, args=(pin,), daemon=True).start()
- 为每个 LED 创建一个线程来运行
blink_led函数,这样每个 LED 都会在独立的线程中控制闪烁。 - 线程设置为
daemon=True,意味着当主程序退出时,线程也会自动退出。
7. Web 路由
@app.route('/')
def index():
return render_template('index.html', led_states=led_states, led_modes=led_modes)
/路由:访问首页时,渲染index.html页面,并将led_states和led_modes传递给模板,表示每个 LED 的当前状态和模式。
@app.route('/toggle_led/<led>', methods=['POST'])
def toggle_led(led):
global led_states
if led in led_states:
led_states[led] = not led_states[led] # 切换 LED 状态
if not led_states[led]: # 如果关闭 LED,停止闪烁模式
led_modes[led] = "off"
GPIO.output(led, GPIO.LOW) # 关闭 LED
else:
GPIO.output(led, GPIO.HIGH) # 打开 LED
return render_template('index.html', led_states=led_states, led_modes=led_modes)
/toggle_led/<led>路由:用于切换指定 LED 的开关状态。- 如果 LED 当前是关闭状态,则将其打开;如果是开启状态,则将其关闭,并同时停止闪烁模式。
@app.route('/toggle_mode/<led>', methods=['POST'])
def toggle_mode(led):
if led in led_modes and led_states[led]: # 只有当 LED 是打开状态时,才允许切换模式
led_modes[led] = "blink" if led_modes[led] == "off" else "off" # 切换模式(闪烁或常亮)
if led_modes[led] == "off":
GPIO.output(led, GPIO.HIGH) # 常亮模式下开启 LED
else:
GPIO.output(led, GPIO.HIGH) # 切换到闪烁模式后,LED 初始为开启状态
return render_template('index.html', led_states=led_states, led_modes=led_modes)
/toggle_mode/<led>路由:用于切换指定 LED 的工作模式(常亮或闪烁)。- 只有当 LED 处于开启状态时,才可以切换模式。常亮模式下,LED 会保持常亮;闪烁模式下,LED 会以一定频率闪烁。
8. 启动 Flask 应用
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
- 启动 Flask 应用,设置监听
0.0.0.0(允许外部访问)并使用端口5000。debug=True使得在开发时可以自动重载,并显示调试信息。
除了app.py的主代码,还需要有web前端页面的渲染代码,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LED Control</title>
</head>
<body>
<h1>LED Control</h1>
{% for pin in ['USR0', 'USR1', 'USR2', 'USR3'] %}
<h2>{{ pin }}</h2>
<!-- LED 开关控制 -->
<p>Current LED State: {% if led_states[pin] %} ON {% else %} OFF {% endif %}</p>
<form action="/toggle_led/{{ pin }}" method="POST">
<input type="submit" value="Toggle LED">
</form>
<!-- 切换常亮和闪烁模式 -->
{% if led_states[pin] %}
<p>Current Mode: {% if led_modes[pin] == 'off' %} Constant ON {% else %} Blinking {% endif %}</p>
<form action="/toggle_mode/{{ pin }}" method="POST">
<input type="submit" value="Toggle Mode (ON / Blinking)">
</form>
{% endif %}
<br>
{% endfor %}
</body>
</html>
具体分析情况如下:
1. 页面标题和基础结构
html
复制代码<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LED Control</title>
</head>
<body>
<h1>LED Control</h1>
<!DOCTYPE html>:声明文档类型为 HTML5。<html lang="en">:指定页面的语言为英语。<meta charset="UTF-8">:声明页面使用 UTF-8 字符编码,确保页面中的特殊字符能够正确显示。<meta name="viewport" content="width=device-width, initial-scale=1.0">:用于响应式设计,确保页面在不同设备(如手机、平板)上正确显示。<title>LED Control</title>:设置网页的标题为 "LED Control"。
2. 循环遍历 LED 引脚
html
复制代码{% for pin in ['USR0', 'USR1', 'USR2', 'USR3'] %}
<h2>{{ pin }}</h2>
{% for pin in ['USR0', 'USR1', 'USR2', 'USR3'] %}:这是 Flask 模板中的 Jinja2 模板语法。for循环遍历一个列表['USR0', 'USR1', 'USR2', 'USR3'],代表 BeagleBone Black 上的 4 个 LED 引脚。<h2>{{ pin }}</h2>:对于每个 LED 引脚(pin),生成一个标题显示 LED 引脚的名称(例如,USR0、USR1等)。
3. LED 开关控制
html
复制代码<p>Current LED State: {% if led_states[pin] %} ON {% else %} OFF {% endif %}</p>
<form action="/toggle_led/{{ pin }}" method="POST">
<input type="submit" value="Toggle LED">
</form>
<p>Current LED State: {% if led_states[pin] %} ON {% else %} OFF {% endif %}</p>:显示当前 LED 的状态。如果led_states[pin]为True(表示 LED 开启),则显示 "ON";否则显示 "OFF"。<form action="/toggle_led/{{ pin }}" method="POST">:为每个 LED 创建一个表单,点击按钮时发送 POST 请求到/toggle_led/{{ pin }},即控制该 LED 的开关状态。通过{{ pin }}动态传递具体的 LED 引脚名。<input type="submit" value="Toggle LED">:按钮的文本为 "Toggle LED",点击按钮时提交表单,触发toggle_led路由中的处理逻辑。
4. LED 模式切换(常亮和闪烁)
html
复制代码{% if led_states[pin] %}
<p>Current Mode: {% if led_modes[pin] == 'off' %} Constant ON {% else %} Blinking {% endif %}</p>
<form action="/toggle_mode/{{ pin }}" method="POST">
<input type="submit" value="Toggle Mode (ON / Blinking)">
</form>
{% endif %}
{% if led_states[pin] %}:只有当 LED 处于开启状态时,才会显示模式控制部分。<p>Current Mode: {% if led_modes[pin] == 'off' %} Constant ON {% else %} Blinking {% endif %}</p>:显示当前 LED 的模式。如果led_modes[pin]为'off',表示 LED 处于常亮模式,则显示 "Constant ON";如果为'blink',表示 LED 处于闪烁模式,则显示 "Blinking"。<form action="/toggle_mode/{{ pin }}" method="POST">:为每个 LED 创建一个表单,点击按钮时发送 POST 请求到/toggle_mode/{{ pin }},用于切换 LED 的模式(常亮或闪烁)。<input type="submit" value="Toggle Mode (ON / Blinking)">:按钮的文本为 "Toggle Mode (ON / Blinking)",点击按钮时提交表单,触发toggle_mode路由中的处理逻辑。
5. 结束循环和 HTML 结构
html
复制代码<br>
{% endfor %}
</body>
</html>
<br>:添加换行符,使每个 LED 控制部分之间有空隙。{% endfor %}:结束for循环。</body>和</html>:结束 HTML 文档结构。
3.实现效果展示
BBB板内置了cloud9的开发IDE,在其中的终端可以很容易就运行相关代码,启动系统服务:
根据链接地址,进入web前端界面
点击按钮,完成LED灯泡的状态切换
四.总结与感悟
感谢eetree提供这样的机会,能让我学习到Linux的SBC的相关基础知识,并且在活动期间,也可以了解学习前端相关概念并结合Flask框架进行实践,我受益匪浅,最后也希望可以举办更多类似的活动,在新的一年中也祝eetree越办越好。