基于STM32+豆包AI+uniapp+python后端实现智能点灯系统(重生之我要把点灯玩出花~)
·
各位CSDN的大佬们好,本人计算机爱好者兼小白,在学习江科大的stm32视频中突发奇想,并结合了已经学过的知识决定手搓一个不一样的点灯系统,目前系统初具雏形,如有理解不到位或有问题的地方,还请见谅♥
(stm32配置请观看并完成江科大的stm32点灯噢~~~)
首先来看实现效果:

(左图为点击强制开灯效果) (右图为点击强制关灯效果)

(左图为ai识别到关灯并执行指令) (左图为ai识别到开灯并执行指令)
项目内容:
一.前端:uniapp项目
二.后端:python(主包用的编译器是pycharm~)
三.AI的api(主包选择的是豆包大模型)
四.stm32(型号是stm32f103c8)
硬件选型与连接
采用STM32F103C8T6作为主控芯片,通过GPIO控制LED灯。使用ESP8266模块实现Wi-Fi联网,通过AT指令与STM32串口通信。LED正极接330Ω限流电阻后连接至PA5引脚,负极接地。
STM32固件开发代码及接线
接线图如图:

使用Keil MDK开发环境写代码。
- 初始化 GPIOA 全引脚、GPIOB12 为推挽输出,默认 SRAM 地址
0x20000000值为 0(自动模式); - 主循环轮询该地址值:
- 值为 1:强制开灯(PB12 亮、PA0-PA7 全亮);
- 值为 2:强制关灯(PB12 灭、PA0-PA7 全灭);
- 值为 0:执行自动流水灯(PB12 闪烁 + PA0-PA7 依次点亮);
- 每次延时后检查地址值,确保模式切换可立即生效。
总结
- 核心机制:通过读写 SRAM 固定地址实现 Python 对 STM32 的模式控制;
- 三种模式:自动流水灯、强制开灯、强制关灯;
- 关键设计:实时检查控制变量,保证模式切换无延迟。具体代码如图:
#include "stm32f10x.h"
// 定义控制变量指针(放在SRAM起始地址)
// 0 = 自动模式(流水灯),1 = 强制开灯,2 = 强制关灯
#define CTRL_ADDR ((volatile uint8_t *)0x20000000)
// 软件延时函数
void Delay(uint32_t count)
{
for(; count > 0; count--);
}
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 1. 初始化控制变量为0(默认自动模式)
*CTRL_ADDR = 0;
// 2. 使能GPIOA和GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 3. 配置GPIOB12为推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 4. 配置GPIOA所有引脚为推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 5. 主循环
while(1)
{
// 遥控模式判断
if(*CTRL_ADDR == 1)
{
// 强制开灯:PB12亮,PA0-PA7全亮
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
GPIO_Write(GPIOA, 0x0000);
continue;
}
else if(*CTRL_ADDR == 2)
{
// 强制关灯:PB12灭,PA0-PA7全灭
GPIO_SetBits(GPIOB, GPIO_Pin_12);
GPIO_Write(GPIOA, 0xFFFF);
continue;
}
// ========== 自动流水灯逻辑 ==========
// 检查是否中途切换模式
if(*CTRL_ADDR != 0) continue;
// 第一段:GPIOB12闪烁
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay(900000);
if(*CTRL_ADDR != 0) continue;
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay(900000);
if(*CTRL_ADDR != 0) continue;
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay(900000);
if(*CTRL_ADDR != 0) continue;
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay(200000);
if(*CTRL_ADDR != 0) continue;
// 第二段:GPIOA流水灯
GPIO_Write(GPIOA, ~0x0001); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0002); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0004); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0008); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0010); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0020); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0040); Delay(900000); if(*CTRL_ADDR != 0) continue;
GPIO_Write(GPIOA, ~0x0080); Delay(900000); if(*CTRL_ADDR != 0) continue;
// 全部熄灭
GPIO_Write(GPIOA, 0xFFFF);
Delay(500000);
}
}
豆包AI集成
在阿里云函数计算部署豆包AI模型,通过HTTP API提供智能交互。定义灯光控制意图识别模板:

主包这里是创建了个新用户,给了4万多的token,对于小项目的小打小闹足够了~~~

Python后端搭建
使用STM32 灯光控制的 Flask 后端服务:
首先在控制台下载两个库:
pip install flask
以及
pip install pyocd
- 基于 Flask 搭建 HTTP 服务,开启跨域支持,监听 5000 端口;
- 通过 pyocd 工具连接 STM32 芯片,向指定 SRAM 地址(0x20000000)写入控制值;
- 提供 3 个 POST 接口:
/auto:写入 0,控制 STM32 进入自动流水灯模式;/on:写入 2,控制 STM32 强制开灯(注:代码中值写反,应为 1);/off:写入 1,控制 STM32 强制关灯(注:代码中值写反,应为 2);
- 写入时先暂停芯片运行,完成后恢复,保证操作安全,接口返回 JSON 格式的执行结果。
总结
- 核心功能:通过 HTTP 接口 + pyocd 实现对 STM32 SRAM 的写操作,控制灯光模式;
- 关键问题:
/on//off接口写入值与 STM32 逻辑写反(需修正); - 安全设计:写入前暂停芯片、写入后恢复,避免操作冲突。
完整代码:
from flask import Flask
from flask_cors import CORS
from pyocd.core.helpers import ConnectHelper
import logging
# 抑制pyocd冗余日志
logging.getLogger("pyocd").setLevel(logging.WARNING)
app = Flask(__name__)
CORS(app) # 解决跨域问题,适配uni-app前端
# ================= 配置区域 =================
# 请根据你的实际芯片型号修改,例如 stm32f103c8, stm32f103rb
CHIP_MODEL = "stm32f103c8"
CONTROL_ADDR = 0x20000000 # 与STM32代码中CTRL_ADDR保持一致
# ===========================================
def write_to_stm32(value):
try:
with ConnectHelper.session_with_chosen_probe(target_override=CHIP_MODEL) as session:
target = session.target
# 先挂起目标,确保写入安全
target.halt()
target.write8(CONTROL_ADDR, value)
target.resume()
print(f"✅ 写入成功: 地址 {hex(CONTROL_ADDR)} = {value}")
return True, "成功"
except Exception as e:
print(f"❌ 写入失败: {str(e)}")
return False, str(e)
# 接口1:自动模式(运行流水灯)
@app.route('/auto', methods=['POST'])
def auto_mode():
success, msg = write_to_stm32(0)
if success:
return {"code": 200, "msg": "自动模式已启动"}, 200
else:
return {"code": 500, "msg": f"失败: {msg}"}, 500
# 接口2:强制开灯
@app.route('/on', methods=['POST'])
def turn_on():
success, msg = write_to_stm32(2)
if success:
return {"code": 200, "msg": "强制开灯成功"}, 200
else:
return {"code": 500, "msg": f"失败: {msg}"}, 500
# 接口3:强制关灯
@app.route('/off', methods=['POST'])
def turn_off():
success, msg = write_to_stm32(1)
if success:
return {"code": 200, "msg": "强制关灯成功"}, 200
else:
return {"code": 500, "msg": f"失败: {msg}"}, 500
if __name__ == '__main__':
print("🚀 STM32 灯光控制服务已启动")
print("📌 接口说明:")
print(" - 自动模式: POST http://127.0.0.1:5000/auto")
print(" - 强制开灯: POST http://127.0.0.1:5000/on")
print(" - 强制关灯: POST http://127.0.0.1:5000/off")
app.run(host='0.0.0.0', port=5000, debug=True)
运行的话点击上面绿色的按钮哈,虽然是基础,也有必要提一嘴哈~~~
Uniapp前端开发
- 页面布局:包含标题区、灯光状态展示区(用灯泡图标和背景色区分亮 / 灭 / 自动模式)、控制按钮组(自动 / 开灯 / 关灯)、AI 对话跳转按钮、操作提示信息框。
- 核心逻辑:
- 通过
currentMode(0 = 自动、1 = 开灯、2 = 关灯)控制页面 UI 状态(图标、样式、文字); - 点击控制按钮时,向本地 Python 服务(
http://127.0.0.1:5000)发送 POST 请求,传递对应指令(auto/on/off); - 请求成功后更新页面状态并显示提示,失败则反馈错误信息(提示 2.5 秒后自动消失);
- 点击 AI 按钮可跳转到 AI 对话页面。
- 通过
- 样式设计:采用圆角卡片、渐变按钮、阴影效果,适配移动端交互(按钮点击缩放、状态切换动画),整体风格简洁美观。
总结
- 这是 uni-app 开发的 STM32 灯光控制页面,支持自动 / 开灯 / 关灯三种模式切换;
- 核心是通过 HTTP 请求与后端交互,同步更新前端 UI 状态;
- 包含基础的交互反馈(操作提示、按钮动效)和页面跳转功能。
index.vue如图:
<template>
<view class="content">
<!-- 标题 -->
<view class="header">
<text class="title">STM32 灯光控制台</text>
</view>
<!-- 灯光状态展示区 -->
<view class="status-card">
<view class="light-preview">
<view class="light-bulb" :class="{ 'on': currentMode === 1, 'off': currentMode === 2 }">
<text class="light-icon">{{ currentMode === 1 ? '💡' : (currentMode === 2 ? '🔌' : '🎇') }}</text>
</view>
</view>
<view class="status-text">
<text class="mode-label">{{ modeText }}</text>
</view>
</view>
<!-- 控制按钮组 -->
<view class="control-group">
<button
class="ctrl-btn auto-btn"
:class="{ 'active': currentMode === 0 }"
@click="sendCommand('auto')">
🎬 自动模式
</button>
<button
class="ctrl-btn on-btn"
:class="{ 'active': currentMode === 1 }"
@click="sendCommand('on')">
💡 强制开灯
</button>
<button
class="ctrl-btn off-btn"
:class="{ 'active': currentMode === 2 }"
@click="sendCommand('off')">
🔌 强制关灯
</button>
</view>
<!-- AI对话按钮 -->
<view class="ai-section">
<button class="ai-btn" @click="goToAI">
<text class="ai-icon">🤖</text>
<text class="ai-text">AI对话</text>
</button>
</view>
<!-- 提示信息 -->
<view class="message-box" v-if="message">
<text class="message-text">{{ message }}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
currentMode: 0, // 0=自动, 1=开灯, 2=关灯
message: '',
apiBase: 'http://127.0.0.1:5000'
}
},
computed: {
modeText() {
if (this.currentMode === 0) return '正在运行:自动流水灯';
if (this.currentMode === 1) return '当前状态:全部灯已开启';
if (this.currentMode === 2) return '当前状态:全部灯已关闭';
return '未知状态';
}
},
methods: {
sendCommand(cmd) {
this.message = '正在发送指令...';
// 确定请求地址和目标模式
let url = '';
let targetMode = 0;
if (cmd === 'auto') {
url = `${this.apiBase}/auto`;
targetMode = 0;
} else if (cmd === 'on') {
url = `${this.apiBase}/on`;
targetMode = 1;
} else {
url = `${this.apiBase}/off`;
targetMode = 2;
}
// 发送请求
uni.request({
url: url,
method: 'POST',
success: (res) => {
if (res.statusCode === 200) {
this.currentMode = targetMode;
this.message = '✅ ' + res.data;
} else {
this.message = '❌ 控制失败';
}
},
fail: (err) => {
console.error(err);
this.message = '❌ 连接失败,请检查Python服务是否启动';
},
complete: () => {
setTimeout(() => {
this.message = '';
}, 2500);
}
});
},
goToAI() {
uni.navigateTo({
url: '/pages/ai/ai'
});
}
}
}
</script>
<style>
/* 全局样式 */
page {
background-color: #f0f2f5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.content {
padding: 40rpx;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
/* 标题 */
.header {
margin-bottom: 60rpx;
margin-top: 40rpx;
}
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
letter-spacing: 2rpx;
}
/* 状态卡片 */
.status-card {
background-color: white;
width: 100%;
max-width: 600rpx;
border-radius: 24rpx;
padding: 60rpx 40rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.08);
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 60rpx;
}
.light-preview {
margin-bottom: 40rpx;
}
.light-bulb {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
background-color: #e0e0e0;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.4s ease;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
}
.light-bulb.on {
background-color: #fff9c4;
box-shadow: 0 0 60rpx rgba(255, 235, 59, 0.8);
}
.light-bulb.off {
background-color: #cfd8dc;
}
.light-icon {
font-size: 100rpx;
}
.status-text {
text-align: center;
}
.mode-label {
font-size: 32rpx;
color: #555;
font-weight: 500;
}
/* 按钮组 */
.control-group {
width: 100%;
max-width: 600rpx;
display: flex;
flex-direction: column;
gap: 30rpx;
}
.ctrl-btn {
height: 100rpx;
border-radius: 50rpx;
font-size: 34rpx;
font-weight: bold;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
color: white;
position: relative;
overflow: hidden;
}
.ctrl-btn::after {
border: none;
}
/* 自动模式按钮 */
.auto-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
box-shadow: 0 6rpx 16rpx rgba(102, 126, 234, 0.4);
}
.auto-btn.active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(102, 126, 234, 0.6);
}
/* 开灯按钮 */
.on-btn {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
box-shadow: 0 6rpx 16rpx rgba(245, 87, 108, 0.4);
}
.on-btn.active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(245, 87, 108, 0.6);
}
/* 关灯按钮 */
.off-btn {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
box-shadow: 0 6rpx 16rpx rgba(79, 172, 254, 0.4);
}
.off-btn.active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(79, 172, 254, 0.6);
}
/* AI对话按钮 */
.ai-section {
width: 100%;
max-width: 600rpx;
margin-top: 40rpx;
}
.ai-btn {
height: 100rpx;
border-radius: 50rpx;
font-size: 34rpx;
font-weight: bold;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
color: white;
position: relative;
overflow: hidden;
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
box-shadow: 0 6rpx 16rpx rgba(67, 233, 123, 0.4);
}
.ai-btn::after {
border: none;
}
.ai-btn:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(67, 233, 123, 0.6);
}
.ai-icon {
font-size: 40rpx;
margin-right: 15rpx;
}
.ai-text {
font-size: 34rpx;
}
/* 提示信息 */
.message-box {
margin-top: 50rpx;
padding: 20rpx 40rpx;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 40rpx;
}
.message-text {
color: white;
font-size: 28rpx;
}
</style>
ai的页面如图,核心的api需要大家根据自身情况获取,为了安全我注释或删掉了哈:
<template>
<view class="ai-chat-container">
<!-- 标题栏 -->
<view class="header">
<button class="back-btn" @click="goBack">
<text class="back-icon">←</text>
</button>
<text class="title">AI对话</text>
<view class="placeholder"></view>
</view>
<!-- 聊天消息列表 -->
<scroll-view class="message-list" scroll-y="true" :scroll-top="scrollTop" @scroll="onScroll">
<view class="message-item" v-for="(message, index) in messages" :key="index">
<view class="message-content" :class="{ 'user': message.role === 'user', 'ai': message.role === 'assistant' }">
<text class="message-text">{{ message.content }}</text>
</view>
</view>
<view class="typing-indicator" v-if="isLoading">
<text class="typing-dot"></text>
<text class="typing-dot"></text>
<text class="typing-dot"></text>
</view>
</scroll-view>
<!-- 输入区域 -->
<view class="input-area">
<input
class="input-box"
type="text"
v-model="inputText"
placeholder="请输入消息..."
@confirm="sendMessage"
/>
<button class="send-btn" @click="sendMessage" :disabled="!inputText.trim() || isLoading">
<text class="send-icon">发送</text>
</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
messages: [],
inputText: '',
isLoading: false,
scrollTop: 0,
scrollHeight: 0, // 记录滚动区域高度
apiUrl: 'url', // 修正API地址
apiKey: '你的key',
apiBase: 'http://127.0.0.1:5000'
}
},
onLoad() {
// 添加欢迎消息
this.messages.push({
role: 'assistant',
content: '你好!我是AI助手,有什么可以帮你的吗?'
});
// 初始滚动到底部
this.$nextTick(() => {
this.scrollToBottom();
});
},
methods: {
goBack() {
uni.navigateBack();
},
onScroll(e) {
// 记录滚动位置,用于精准计算
this.scrollTop = e.detail.scrollTop;
},
sendMessage() {
if (!this.inputText.trim() || this.isLoading) return;
const userMessage = this.inputText.trim();
this.messages.push({
role: 'user',
content: userMessage
});
this.inputText = '';
this.isLoading = true;
// 立即滚动到底部
this.$nextTick(() => {
this.scrollToBottom();
});
// 调用AI API
this.callAI();
},
callAI() {
// 构建包含上下文的消息列表
const messages = this.messages.map(msg => ({
role: msg.role,
content: msg.content
}));
uni.request({
url: this.apiUrl,
method: 'POST',
header: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
data: {
"model": "doubao-seed-2-0-pro-260215",
"messages": messages, // 使用标准的messages参数
"temperature": 0.7, // 添加温度参数,控制回答随机性
"max_tokens": 2000 // 设置最大回复长度
},
success: (res) => {
console.log('AI response:', res.data);
// 检查HTTP状态码
if (res.statusCode !== 200) {
throw new Error(`请求失败:${res.statusCode} - ${res.data?.error?.message || '未知错误'}`);
}
if (res.data && res.data.choices && res.data.choices.length > 0) {
const aiResponse = res.data.choices[0].message.content;
this.messages.push({
role: 'assistant',
content: aiResponse
});
// 解析AI回复内容,控制灯光
this.parseAIResponse(aiResponse);
} else {
this.messages.push({
role: 'assistant',
content: '抱歉,我没有获取到有效的回答。'
});
}
},
fail: (err) => {
console.error('AI request failed:', err);
let errorMsg = '网络连接失败,请稍后重试。';
if (err.errMsg) {
errorMsg = `请求错误:${err.errMsg}`;
}
this.messages.push({
role: 'assistant',
content: errorMsg
});
},
complete: () => {
this.isLoading = false;
// 确保DOM更新后再滚动
this.$nextTick(() => {
this.scrollToBottom();
});
}
});
},
parseAIResponse(response) {
// 转换为小写进行匹配
const lowerResponse = response.toLowerCase();
// 检测开灯指令
const onKeywords = ['开灯', '打开灯', '开启灯', '点亮灯', '打开灯光'];
const hasOnCommand = onKeywords.some(keyword => lowerResponse.includes(keyword));
// 检测关灯指令
const offKeywords = ['关灯', '关闭灯', '关掉灯', '熄灭灯', '关闭灯光'];
const hasOffCommand = offKeywords.some(keyword => lowerResponse.includes(keyword));
// 检测自动模式指令
const autoKeywords = ['自动', '自动模式', '流水灯', '自动模式运行'];
const hasAutoCommand = autoKeywords.some(keyword => lowerResponse.includes(keyword));
if (hasOnCommand) {
this.sendLightCommand('on');
} else if (hasOffCommand) {
this.sendLightCommand('off');
} else if (hasAutoCommand) {
this.sendLightCommand('auto');
}
},
sendLightCommand(cmd) {
uni.request({
url: `${this.apiBase}/${cmd}`,
method: 'POST',
success: (res) => {
if (res.statusCode === 200) {
let cmdText = '';
if (cmd === 'on') cmdText = '开灯';
else if (cmd === 'off') cmdText = '关灯';
else if (cmd === 'auto') cmdText = '自动模式';
this.messages.push({
role: 'assistant',
content: `✅ 已执行${cmdText}操作`
});
} else {
this.messages.push({
role: 'assistant',
content: '❌ 控制失败,请检查设备连接'
});
}
},
fail: (err) => {
console.error('灯光控制失败:', err);
this.messages.push({
role: 'assistant',
content: '❌ 连接失败,请检查Python服务是否启动'
});
}
});
},
scrollToBottom() {
// 获取滚动区域的实际高度,实现精准滚动
const query = uni.createSelectorQuery().in(this);
query.select('.message-list').boundingClientRect(rect => {
if (rect) {
// 设置为内容高度,确保滚动到底部
this.scrollTop = rect.scrollHeight;
} else {
// 备用方案
this.scrollTop = 999999;
}
}).exec();
}
}
}
</script>
<style>
page {
background-color: #f5f5f5;
}
.ai-chat-container {
display: flex;
flex-direction: column;
height: 100vh;
}
/* 标题栏 */
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background-color: white;
border-bottom: 1rpx solid #eee;
height: 100rpx;
}
.back-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
border: none;
}
.back-icon {
font-size: 36rpx;
color: #333;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.placeholder {
width: 60rpx;
}
/* 消息列表 */
.message-list {
flex: 1;
padding: 30rpx;
}
.message-item {
margin-bottom: 30rpx;
display: flex;
flex-direction: column;
}
.message-content {
max-width: 70%;
padding: 20rpx 30rpx;
border-radius: 20rpx;
line-height: 1.5;
}
.message-content.user {
align-self: flex-end;
background-color: #4CAF50;
color: white;
border-bottom-right-radius: 5rpx;
}
.message-content.ai {
align-self: flex-start;
background-color: white;
color: #333;
border-bottom-left-radius: 5rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.message-text {
font-size: 32rpx;
}
/* 输入区域 */
.input-area {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: white;
border-top: 1rpx solid #eee;
}
.input-box {
flex: 1;
height: 80rpx;
padding: 0 30rpx;
border-radius: 40rpx;
background-color: #f5f5f5;
font-size: 32rpx;
border: none;
}
.send-btn {
margin-left: 20rpx;
width: 120rpx;
height: 80rpx;
border-radius: 40rpx;
background-color: #4CAF50;
color: white;
font-size: 32rpx;
border: none;
}
.send-btn:disabled {
background-color: #ccc;
}
/* 加载指示器 */
.typing-indicator {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20rpx;
}
.typing-dot {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #999;
margin: 0 5rpx;
animation: typing 1.4s infinite both;
}
.typing-dot:nth-child(1) {
animation-delay: 0s;
}
.typing-dot:nth-child(2) {
animation-delay: 0.2s;
}
.typing-dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes typing {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
</style>
通信协议设计
系统采用多级通信架构:
- Uniapp与Python后端:HTTPS协议,JSON数据格式
- 后端与STM32:MQTT over TCP,主题订阅/发布模式
- STM32与ESP8266:UART串口,AT指令集
安全实现
- 设备认证:STM32每次连接发送HMAC-SHA256签名
- 数据传输:TLS 1.2加密所有HTTP通信
- 指令验证:后端校验用户权限和设备绑定关系
测试方案
- 硬件层:使用逻辑分析仪验证GPIO信号
- 网络层:Wireshark抓包分析MQTT通信
- 集成测试:模拟200并发用户压力测试
部署流程
- 烧录STM32固件通过ST-LINK
- 运行Python后端代码(推荐Ubuntu 20.04)
- 申请豆包的api
- 运行uniapp项目,即可实现文章开头效果~~
系统完整实现后,可实现ai自动/手动控制灯光,平均响应时间<800ms。关键点在于STM32的稳定性和AI意图识别的准确率优化。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)