用STM32F103和L298N做个智能窗帘:从光敏电阻到电机驱动的保姆级教程
2026/7/5 5:18:58 网站建设 项目流程

从零打造光控智能窗帘:STM32F103与L298N实战指南

清晨的阳光透过窗帘缝隙洒进房间,你是否想过让窗帘自动适应光线变化?本文将带你用STM32F103单片机和L298N电机驱动模块,构建一个能感知光线、自主调节的智能窗帘系统。不同于简单的代码展示,我们将从元器件选型、电路搭建、代码编写到系统调试,完整呈现每个环节的技术细节与实战技巧。

1. 项目规划与硬件选型

1.1 核心组件功能解析

一个完整的智能窗帘系统需要感知环境光线、处理信号并驱动电机。我们选择的硬件组合在性价比和易用性上达到了良好平衡:

  • STM32F103C8T6:作为主控芯片,内置12位ADC可精准采集光敏电阻电压,同时提供丰富GPIO控制外围设备
  • L298N双H桥驱动模块:最大支持2A驱动电流,可同时控制两个直流电机正反转,内置续流二极管保护电路
  • GL5528光敏电阻:光照强度与电阻值呈非线性关系,10-20KΩ@10Lux,适合室内光线检测
  • LCD1602液晶屏:2行16字符显示,通过HD44780控制器与MCU通信,实时反馈系统状态

1.2 硬件连接要点

正确连接是项目成功的第一步。以下是关键接口的对应关系:

STM32引脚连接模块功能说明
PA0光敏电阻分压ADC1通道0,采集光照强度
PC0-PC5L298N控制端IN1-IN4及两个使能信号
PB0-PB7LCD1602数据8位数据总线(D0-D7)
PB8-PB9LCD控制线RS(寄存器选择)、E(使能)

提示:L298N模块需要单独供电,建议使用12V/2A电源适配器。逻辑控制部分可与STM32共用3.3V电源。

2. 开发环境搭建

2.1 软件工具链配置

工欲善其事,必先利其器。推荐使用以下开发工具组合:

  1. Keil MDK-ARM:官方推荐的STM32开发环境,提供完善的调试功能
  2. STM32CubeMX:图形化配置工具,自动生成初始化代码
  3. Proteus 8 Professional:电路仿真与代码调试一体化平台
  4. 串口调试助手:实时监测系统运行状态

安装完成后需进行关键配置:

# 安装STM32F1系列设备支持包 $ STM32CubeMX → Help → Manage embedded software packages → STM32F1xx

2.2 工程创建与基础配置

使用STM32CubeMX快速建立工程框架:

  1. 选择STM32F103C8Tx系列芯片
  2. 配置时钟树:使用8MHz外部晶振,系统时钟设置为72MHz
  3. 启用外设:
    • ADC1通道0,连续转换模式
    • GPIO端口:PC0-PC5推挽输出,PB0-PB9复用推挽输出
  4. 生成MDK-ARM工程代码
// 生成的时钟配置代码片段 void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 配置HSE振荡器 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&RCC_OscInitStruct); // 配置系统时钟 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); }

3. 光强检测模块实现

3.1 光敏电阻电路设计

光敏电阻需要配合分压电路才能被ADC采集。推荐以下设计方案:

VCC(3.3V) → 10KΩ固定电阻 → GL5528光敏电阻 → GND ↓ ADC输入

该电路特性:

  • 光照越强,光敏电阻值越小,ADC读数越高
  • 10KΩ电阻可提供良好的线性工作区间
  • 需在ADC输入引脚添加0.1μF滤波电容

3.2 ADC采集与数据处理

STM32的ADC需要正确初始化和校准:

// ADC初始化配置 ADC_HandleTypeDef hadc1; void ADC1_Init(void) { hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; HAL_ADC_Init(&hadc1); // 配置ADC通道 ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES5; HAL_ADC_ConfigChannel(&hadc1, &sConfig); // 校准ADC HAL_ADCEx_Calibration_Start(&hadc1); }

采集到的数据需要转换为实际光照强度值:

float GetLightIntensity(void) { HAL_ADC_Start(&hadc1); if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) { uint32_t adcValue = HAL_ADC_GetValue(&hadc1); // 转换为电压值(0-3.3V) float voltage = adcValue * 3.3f / 4095.0f; // 自定义光照强度计算公式 return voltage * 100.0f; } return 0.0f; }

4. 电机驱动与控制逻辑

4.1 L298N驱动原理详解

L298N模块包含两个H桥电路,每个H桥可控制电机正反转。关键控制逻辑:

IN1IN2ENA电机状态
101正转
011反转
001快速停止
111慢速停止

注意:实际使用时应先使能ENA,再设置IN1/IN2,避免瞬间短路风险。

4.2 电机控制函数实现

封装三种基本控制函数:

// 初始化电机控制GPIO void Motor_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOC_CLK_ENABLE(); // 配置PC0-PC5为输出 GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2 |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始状态:全部置低 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2 |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET); } // 打开窗帘(电机正转) void Curtain_Open(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET); // ENA=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // ENB=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // IN1=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); // IN2=0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // IN3=0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); // IN4=0 } // 关闭窗帘(电机反转) void Curtain_Close(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET); // ENA=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // ENB=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // IN1=0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); // IN2=0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // IN3=1 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); // IN4=0 } // 停止电机 void Curtain_Stop(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET); // ENA=0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET); // ENB=0 }

5. 系统集成与调试技巧

5.1 主控制逻辑实现

结合各模块功能,编写主控制程序:

int main(void) { // 硬件初始化 HAL_Init(); SystemClock_Config(); ADC1_Init(); Motor_GPIO_Init(); LCD1602_Init(); // 显示初始信息 LCD1602_ShowString(0, 0, "Smart Curtain v1.0"); LCD1602_ShowString(0, 1, "Light: "); // 主循环 while(1) { float light = GetLightIntensity(); char status[16]; // 显示当前光照强度 sprintf(status, "%.1f", light); LCD1602_ShowString(7, 1, status); // 控制逻辑 if(light < 50.0f) // 光线过暗 { LCD1602_ShowString(12, 1, "OPEN "); Curtain_Open(); HAL_Delay(2000); // 运行2秒后停止 Curtain_Stop(); } else if(light > 80.0f) // 光线过强 { LCD1602_ShowString(12, 1, "CLOSE"); Curtain_Close(); HAL_Delay(2000); Curtain_Stop(); } else // 光线适中 { LCD1602_ShowString(12, 1, "OK "); Curtain_Stop(); } HAL_Delay(500); // 每0.5秒检测一次 } }

5.2 常见问题排查指南

在实际组装过程中可能会遇到以下典型问题:

  1. 电机不转动

    • 检查L298N供电是否正常(12V输入)
    • 测量使能引脚(ENA/ENB)是否为高电平
    • 确认控制信号线连接正确
  2. ADC读数不稳定

    • 在光敏电阻分压点添加0.1μF滤波电容
    • 尝试软件滤波:连续采样5次取中值
    • 检查3.3V参考电压是否稳定
  3. LCD显示乱码

    • 确认初始化时序正确,延时足够
    • 检查对比度调节电位器设置
    • 重新插拔数据线,确保接触良好
  4. 电机转动方向相反

    • 交换IN1/IN2或IN3/IN4接线
    • 修改控制函数中的引脚输出逻辑

6. 功能扩展与优化建议

基础功能实现后,可以考虑以下增强功能:

6.1 增加手动控制模式

通过按键切换自动/手动模式:

// 添加按键检测 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) { mode = !mode; // 切换模式 LCD1602_ShowString(0, 0, mode ? "Manual Mode " : "Auto Mode "); }

6.2 加入Wi-Fi远程控制

使用ESP8266模块实现手机控制:

// AT指令配置示例 void ESP8266_Init(void) { UART_SendString("AT+CWMODE=1\r\n"); // 设置为Station模式 UART_SendString("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n"); // 连接WiFi UART_SendString("AT+CIPMUX=1\r\n"); // 启用多连接 UART_SendString("AT+CIPSERVER=1,8080\r\n"); // 启动TCP服务器 }

6.3 添加行程终点检测

使用微动开关防止电机过载:

// 终点检测函数 bool Is_EndStop_Pressed(void) { return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_SET; } // 在电机控制函数中添加检测 void Curtain_Open(void) { while(!Is_EndStop_Pressed()) { // 正常驱动电机... } Curtain_Stop(); }

完成这个项目后,你会发现STM32的外设编程、电机控制原理和传感器应用都有了更深入的理解。在实际部署时,建议先用实验室电源测试整套系统,再转移到实际窗帘轨道上。遇到问题时,分段调试往往比整体排查更有效率——先确保光强检测正常,再测试电机驱动,最后整合全部功能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询