目录
一、前言
项目成品图片:

哔哩哔哩视频链接:
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的智能书桌
功能如下:
- 主控芯片为STM32F103C8T6单片机
- 超声波传感器测量距离
- 光敏传感器监测环境光照强度
- 红外光电传感器用来监测是否有人
- OLED显示屏实时显示距离、是否有人、光照强度
- 按键可设置阈值和模式切换
- 自动模式下距离、光照值超过阈值范围触发蜂鸣器报警,并播放语音
- 手动模式下可通过按键控制LED和舵机的开关
- 蓝牙APP显示信息并完成控制指令下发
2.主要器件
- STM32F103C8T6单片机
- OLED 屏幕
- 红外光电传感器
- 超声波传感器
- 光敏传感器
- 继电器
- 蜂鸣器
三、原理图设计

四、PCB硬件设计
PCB图


五、程序设计
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "usart2.h"
#include "delay.h"
#include "jdq.h"
#include "ds18b20.h"
#include "LDR.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "TIM3.h"
#include "adcx.h"
#include "flash.h"
#include "fan.h"
#include "bump.h"
#include "water.h"
#include "ph.h"
/****************异方辰电子工作室******************
STM32
*文件 : STM32智能书桌
*版本 : V1.0
*日期 : 2025.10.13
*MCU : STM32F103C8T6
*接口 : 见代码
*BILIBILI : 异方辰电子
*小红书 : 异方辰电子
*CSDN : 异方辰电子
*授权IP : 辰哥单片机设计、异方辰、YFC电子、北海单片机设计
**********************BEGIN***********************/
#define KEY_Long1 11
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
#define KEY_4 4
#define FLASH_START_ADDR 0x0801f000 //写入的起始地址
//传感器变量声明
u16 lux;//光照值变量
u16 soil_temp;//土壤温度变量
u16 soil_Humi;//土壤湿度变量
u32 dat;
u16 co2Data;//二氧化碳变量
uint16_t time_num = 0; //10ms计时
SensorModules sensorData; //声明传感器数据结构体变量
SensorThresholdValue Sensorthreshold; //声明传感器阈值结构体变量
DriveModules driveData; //声明驱动器状态结构体变量
static uint8_t app_cmd = 0; // 0 无指令 3 开 4 关
uint8_t mode = 0; //系统模式 1自动 2手动 3设置
//系统静态变量
static uint8_t count_a = 1; //自动模式按键数
uint8_t count_m = 1; //手动模式按键数
static uint8_t count_s = 1; //设置模式按键数
extern uint8_t usart2_buf[256]; //串口2接收数组
char display_buf[16]; //显示数组
/**
* @brief 显示菜单内容
* @param 无
* @retval 无
*/
enum
{
AUTO_MODE = 0,
MANUAL_MODE,
SETTINGS_MODE
}MODE_PAGES;
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init(72);
ADCX_Init();
Key_Init();
BEEP_Init();
MOTOR_Init();
Ultrasonic_Init();
USART3_Config();
TIM2_Init(9,14398);
TIM3_Init(20000-1,72 - 1);
USART2_Init();
USART1_Config();//串口初始化
OLED_Init();
OLED_Clear();
OLED_Refresh();
Sensorthreshold.distanceValue = FLASH_R(FLASH_START_ADDR); //从指定页的地址读FLASH
Sensorthreshold.luxValue = FLASH_R(FLASH_START_ADDR+2); //从指定页的地址读FLASH
sensorData.gaodu = FLASH_R(FLASH_START_ADDR+4); //从指定页的地址读FLASH
sensorData.LED = FLASH_R(FLASH_START_ADDR+6); //从指定页的地址读FLASH
sensorData.jiaodu = FLASH_R(FLASH_START_ADDR+8); //从指定页的地址读FLASH
TimeData.H = FLASH_R(FLASH_START_ADDR+10); //从指定页的地址读FLASH
TimeData.M = FLASH_R(FLASH_START_ADDR+12); //从指定页的地址读FLASH
TimeData.S = FLASH_R(FLASH_START_ADDR+14); //从指定页的地址读FLASH
if(TimeData.H > 24) TimeData.H = 12;
if(TimeData.M > 60) TimeData.M = 00;
if(TimeData.S > 60) TimeData.S = 00;
sensorData.LED = 0;
sensorData.gaodu = 1;
sensorData.jiaodu = 0;
if(Sensorthreshold.luxValue > 999) Sensorthreshold.luxValue = 100;
if(Sensorthreshold.distanceValue > 80) Sensorthreshold.distanceValue = 20;
USART3_SendString((uint8_t*)"AF:30");
delay_ms(500);
USART3_SendString((uint8_t*)"A7:00001");
delay_ms(1000);
TimeData.New = 1;
TimeData.Time_f = 0;
while (1)
{
USART2_ProcessCmd(); //从蓝牙模块接收数据
SensorScan(); //获取传感器数据
if(sensorData.lux > 999)
sensorData.lux = 999; //999 光照值最大值
if(sensorData.distance > 99)
sensorData.distance = 99; //99 距离值最大值
sendControl(); //发送数据到蓝牙模块
switch(mode)
{
case AUTO_MODE:
AutoControl();
Control_Manager();
if(SetAuto() ==1 )
{
OLED_autoPage1(); //显示主页面1固定信息
SensorDataDisplay1(); //显示传感器1数据
}
else
{
OLED_autoPage2(); //显示主页面2固定信息
SensorDataDisplay2(); //显示传感器2数据
}
/*按键1按下时切换模式*/
if (KeyNum == KEY_1) //系统模式mode 1自动 2手动 3设置
{
KeyNum = 0;
mode = MANUAL_MODE;
count_m = 1;
OLED_Clear();
}
if (KeyNum == KEY_Long1)
{
KeyNum = 0;
mode = SETTINGS_MODE;
count_s = 1;
OLED_Clear();
}
break;
case MANUAL_MODE:
OLED_manualOption(SetManual());
ManualControl(SetManual());
TimeData.Time_D = 0;
if (SetManual() <= 4)
{
OLED_manualPage1();
ManualSettingsDisplay1();
}
if (KeyNum == KEY_1) //系统模式mode 0手动 1自动(默认)
{
KeyNum = 0;
mode = AUTO_MODE;
count_a = 1;
OLED_Clear();
}
Control_Manager();
break;
case SETTINGS_MODE:
OLED_settingsOption(SetSelection()); //实现阈值设置页面的选择功能
ThresholdSettings(SetSelection()); //实现阈值调节功能
if (Time_f1 == 1)
{
OLED_settingsPage1(); //显示阈值设置界面1固定信息
SettingsThresholdDisplay1(); //显示传感器阈值1数据
}
else if(Time_f1 == 2) //否则显示设置页面2
{
OLED_settingsPage2(); //显示阈值设置界面2固定信息
SettingsThresholdDisplay2(); //显示传感器阈值3数据
}
else if(Time_f1 == 3)
{
OLED_settingsPage3(); //显示阈值设置界面4固定信息
SettingsThresholdDisplay3(); //显示传感器阈值2数据
}
//判断是否退出阈值设置界面
if (KeyNum == KEY_1)
{
KeyNum = 0;
if(Time_f1 == 1)
{
mode = AUTO_MODE;
count_a = 1;
count_s = 1;
OLED_Clear(); //清屏
}
else if(Time_f1 == 2)
{
mode = SETTINGS_MODE;
Time_f1 = 1;
count_s = 1;
Time_f3 = 0;
TimeData.New = 1;
OLED_Clear(); //清屏
}
else if(Time_f1 == 3)
{
mode = SETTINGS_MODE;
TimeData.Time_f = 1;
Time_f1 = 1;
Time_f3 = 0;
count_s = 2;
OLED_Clear(); //清屏
}
}
break;
default: break;
}
//存储修改的传感器阈值至flash内
FLASH_W(FLASH_START_ADDR, Sensorthreshold.distanceValue, Sensorthreshold.luxValue,
sensorData.gaodu, sensorData.LED,sensorData.jiaodu,TimeData.H,TimeData.M,TimeData.S);
}
}
六、实验效果 
七、包含内容

1万+

被折叠的 条评论
为什么被折叠?



