基于STM32F103ZET6的智能灯光亮度调节器
一、系统设计方案
1.1 功能概述
- PWM调光:使用高级定时器TIM1产生PWM信号控制LED亮度
- 按键控制:通过按键实现亮度增减、模式切换
- 光感自动调节:根据环境光照强度自动调整亮度
- 人体感应:PIR传感器检测人体,无人时自动关灯
- 串口控制:通过串口指令远程控制灯光
- OLED显示:实时显示亮度、模式、环境参数
1.2 硬件连接表
| 模块 | STM32引脚 | 说明 |
|---|---|---|
| LED驱动 | PA8 (TIM1_CH1) | PWM输出,接LED驱动电路 |
| 光敏电阻 | PA0 (ADC1_IN0) | 环境光照检测 |
| 人体感应 | PE2 | PIR传感器输入 |
| 按键1 | PE3 | 亮度增加/模式切换 |
| 按键2 | PE4 | 亮度减少/模式确认 |
| OLED SDA | PB7 | I2C数据线 |
| OLED SCL | PB6 | I2C时钟线 |
| 串口TX | PA9 (USART1) | 串口通信 |
| 串口RX | PA10 (USART1) | 串口通信 |
二、代码实现
2.1 主程序 (main.c)
/**
******************************************************************************
* @file main.c
* @brief 智能灯光亮度调节器主程序
******************************************************************************
*/
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "adc.h"
#include "oled.h"
#include "usart.h"
#include "timer.h"
#include "pir.h"
/* 系统参数 */
#define MAX_BRIGHTNESS 100
#define MIN_BRIGHTNESS 5
#define AUTO_MODE 0
#define MANUAL_MODE 1
#define PIR_TIMEOUT 30000 // 30秒无人自动关灯
/* 全局变量 */
volatile uint8_t system_mode = AUTO_MODE; // 系统模式
volatile uint8_t current_brightness = 50; // 当前亮度
volatile uint8_t target_brightness = 50; // 目标亮度
volatile uint8_t light_sensor_value = 0; // 光感值
volatile uint8_t pir_detected = 0; // 人体检测
volatile uint32_t last_pir_time = 0; // 上次检测到人体的时间
volatile uint8_t uart_cmd_received = 0; // 串口命令接收标志
char uart_cmd[20]; // 串口命令缓冲区
/* 函数声明 */
void System_Init(void);
void Update_Brightness(void);
void Auto_Adjust_Brightness(void);
void Manual_Control(void);
void Check_PIR_Status(void);
void Process_UART_Command(void);
void Display_Status(void);
int main(void)
{
/* 系统初始化 */
System_Init();
/* 显示启动画面 */
OLED_ShowString(0, 0, "Smart Light v1.0");
OLED_ShowString(0, 2, "Initializing...");
OLED_Refresh();
Delay_ms(2000);
/* 主循环 */
while(1)
{
/* 读取传感器数据 */
light_sensor_value = Get_Light_Sensor_Value();
pir_detected = PIR_Detect();
/* 更新PIR状态 */
if(pir_detected)
{
last_pir_time = Get_System_Time();
}
/* 检查PIR超时 */
Check_PIR_Status();
/* 根据模式调整亮度 */
if(system_mode == AUTO_MODE)
{
Auto_Adjust_Brightness();
}
else
{
Manual_Control();
}
/* 更新亮度输出 */
Update_Brightness();
/* 处理串口命令 */
if(uart_cmd_received)
{
Process_UART_Command();
uart_cmd_received = 0;
}
/* 更新显示 */
Display_Status();
/* 延时 */
Delay_ms(100);
}
}
/**
* @brief 系统初始化
*/
void System_Init(void)
{
/* 初始化延时函数 */
Delay_Init();
/* 初始化LED PWM */
LED_Init();
/* 初始化按键 */
Key_Init();
/* 初始化ADC光感 */
ADC_Init();
/* 初始化OLED */
OLED_Init();
/* 初始化串口 */
USART_Init();
/* 初始化定时器 */
Timer_Init();
/* 初始化PIR传感器 */
PIR_Init();
/* 设置初始亮度 */
LED_Set_Brightness(current_brightness);
/* 启动系统时间计数 */
Start_System_Timer();
}
/**
* @brief 更新亮度输出
*/
void Update_Brightness(void)
{
static uint8_t last_brightness = 0;
/* 渐变调整亮度,避免突变 */
if(target_brightness > current_brightness)
{
current_brightness++;
}
else if(target_brightness < current_brightness)
{
current_brightness--;
}
/* 限制亮度范围 */
if(current_brightness < MIN_BRIGHTNESS) current_brightness = MIN_BRIGHTNESS;
if(current_brightness > MAX_BRIGHTNESS) current_brightness = MAX_BRIGHTNESS;
/* 更新PWM输出 */
if(current_brightness != last_brightness)
{
LED_Set_Brightness(current_brightness);
last_brightness = current_brightness;
}
}
/**
* @brief 自动模式亮度调节
*/
void Auto_Adjust_Brightness(void)
{
uint8_t light_level = light_sensor_value;
/* 根据光照强度计算目标亮度 */
if(light_level < 50) // 很暗
{
target_brightness = 90;
}
else if(light_level < 100) // 较暗
{
target_brightness = 70;
}
else if(light_level < 200) // 适中
{
target_brightness = 50;
}
else if(light_level < 300) // 较亮
{
target_brightness = 30;
}
else // 很亮
{
target_brightness = 10;
}
/* 如果无人,降低亮度 */
if(!pir_detected && (Get_System_Time() - last_pir_time > PIR_TIMEOUT))
{
target_brightness = MIN_BRIGHTNESS;
}
}
/**
* @brief 手动模式控制
*/
void Manual_Control(void)
{
static uint8_t key1_pressed = 0;
static uint8_t key2_pressed = 0;
/* 读取按键状态 */
if(Key_Scan(KEY1) == KEY_PRESS)
{
if(!key1_pressed)
{
key1_pressed = 1;
target_brightness += 10;
if(target_brightness > MAX_BRIGHTNESS)
target_brightness = MAX_BRIGHTNESS;
}
}
else
{
key1_pressed = 0;
}
if(Key_Scan(KEY2) == KEY_PRESS)
{
if(!key2_pressed)
{
key2_pressed = 1;
target_brightness -= 10;
if(target_brightness < MIN_BRIGHTNESS)
target_brightness = MIN_BRIGHTNESS;
}
}
else
{
key2_pressed = 0;
}
}
/**
* @brief 检查PIR状态
*/
void Check_PIR_Status(void)
{
static uint8_t last_pir_state = 0;
if(pir_detected != last_pir_state)
{
if(pir_detected)
{
USART_SendString("PIR Detected: Person In\r\n");
}
else
{
USART_SendString("PIR Detected: Person Out\r\n");
}
last_pir_state = pir_detected;
}
}
/**
* @brief 处理串口命令
*/
void Process_UART_Command(void)
{
USART_SendString("Received Command: ");
USART_SendString(uart_cmd);
USART_SendString("\r\n");
/* 解析命令 */
if(strstr(uart_cmd, "BRIGHTNESS"))
{
char *value_str = strchr(uart_cmd, ':');
if(value_str)
{
value_str++; // 跳过冒号
uint8_t brightness = atoi(value_str);
if(brightness >= MIN_BRIGHTNESS && brightness <= MAX_BRIGHTNESS)
{
target_brightness = brightness;
USART_SendString("Brightness set to: ");
USART_SendNumber(brightness);
USART_SendString("\r\n");
}
}
}
else if(strstr(uart_cmd, "MODE:AUTO"))
{
system_mode = AUTO_MODE;
USART_SendString("Mode switched to AUTO\r\n");
}
else if(strstr(uart_cmd, "MODE:MANUAL"))
{
system_mode = MANUAL_MODE;
USART_SendString("Mode switched to MANUAL\r\n");
}
else if(strstr(uart_cmd, "GET_STATUS"))
{
USART_SendString("=== Smart Light Status ===\r\n");
USART_SendString("Mode: ");
USART_SendString(system_mode == AUTO_MODE ? "AUTO" : "MANUAL");
USART_SendString("\r\n");
USART_SendString("Brightness: ");
USART_SendNumber(current_brightness);
USART_SendString("%\r\n");
USART_SendString("Light Level: ");
USART_SendNumber(light_sensor_value);
USART_SendString("\r\n");
USART_SendString("PIR Status: ");
USART_SendString(pir_detected ? "Detected" : "Not Detected");
USART_SendString("\r\n");
}
else if(strstr(uart_cmd, "HELP"))
{
USART_SendString("Available Commands:\r\n");
USART_SendString("BRIGHTNESS:xx - Set brightness (5-100)\r\n");
USART_SendString("MODE:AUTO - Switch to auto mode\r\n");
USART_SendString("MODE:MANUAL - Switch to manual mode\r\n");
USART_SendString("GET_STATUS - Get current status\r\n");
USART_SendString("HELP - Show this help\r\n");
}
}
/**
* @brief 显示系统状态
*/
void Display_Status(void)
{
char display_buffer[20];
/* 第一行:模式 */
OLED_ShowString(0, 0, "Mode:");
if(system_mode == AUTO_MODE)
OLED_ShowString(40, 0, "AUTO");
else
OLED_ShowString(40, 0, "MANUAL");
/* 第二行:亮度 */
sprintf(display_buffer, "Bright:%3d%%", current_brightness);
OLED_ShowString(0, 2, display_buffer);
/* 第三行:光照 */
sprintf(display_buffer, "Light:%3d", light_sensor_value);
OLED_ShowString(0, 4, display_buffer);
/* 第四行:PIR状态 */
OLED_ShowString(0, 6, "PIR:");
if(pir_detected)
OLED_ShowString(40, 6, "DETECT");
else
OLED_ShowString(40, 6, "NOBODY");
OLED_Refresh();
}
2.2 LED PWM驱动 (led.c)
/**
******************************************************************************
* @file led.c
* @brief LED PWM驱动
******************************************************************************
*/
#include "led.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/* PWM参数 */
#define PWM_PERIOD 999 // PWM周期值
#define PWM_PRESCALER 71 // 预分频器,72MHz/72=1MHz
/**
* @brief LED初始化
*/
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* 使能时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);
/* 配置PA8为复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置TIM1基本参数 */
TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD;
TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRESCALER;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* 配置PWM通道1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* 使能预装载寄存器 */
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
/* 启动TIM1 */
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
/**
* @brief 设置LED亮度
* @param brightness: 亮度值 (0-100)
*/
void LED_Set_Brightness(uint8_t brightness)
{
uint16_t pwm_value;
/* 将亮度百分比转换为PWM值 */
if(brightness >= 100)
pwm_value = PWM_PERIOD;
else if(brightness <= 0)
pwm_value = 0;
else
pwm_value = (PWM_PERIOD * brightness) / 100;
/* 设置PWM比较值 */
TIM_SetCompare1(TIM1, pwm_value);
}
2.3 光敏电阻ADC (adc.c)
/**
******************************************************************************
* @file adc.c
* @brief 光敏电阻ADC驱动
******************************************************************************
*/
#include "adc.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/**
* @brief ADC初始化
*/
void ADC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* 使能时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
/* 配置PA0为模拟输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* ADC配置 */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* 配置ADC通道 */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
/* 使能ADC */
ADC_Cmd(ADC1, ENABLE);
/* ADC校准 */
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
/* 启动ADC转换 */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
/**
* @brief 获取光敏电阻值
* @return 光照强度值 (0-4095)
*/
uint16_t Get_Light_Sensor_Value(void)
{
return ADC_GetConversionValue(ADC1);
}
2.4 按键驱动 (key.c)
/**
******************************************************************************
* @file key.c
* @brief 按键驱动
******************************************************************************
*/
#include "key.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/**
* @brief 按键初始化
*/
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能GPIOE时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
/* 配置PE3、PE4为上拉输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
/**
* @brief 扫描按键
* @param key: 按键编号 (KEY1 或 KEY2)
* @return 按键状态
*/
uint8_t Key_Scan(uint8_t key)
{
if(key == KEY1)
{
if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3) == 0)
{
Delay_ms(10); // 消抖
if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3) == 0)
{
while(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3) == 0); // 等待松开
return KEY_PRESS;
}
}
}
else if(key == KEY2)
{
if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)
{
Delay_ms(10);
if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)
{
while(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0);
return KEY_PRESS;
}
}
}
return KEY_RELEASE;
}
2.5 串口通信 (usart.c)
/**
******************************************************************************
* @file usart.c
* @brief 串口通信驱动
******************************************************************************
*/
#include "usart.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include <stdio.h>
#include <stdarg.h>
/* 外部变量 */
extern volatile uint8_t uart_cmd_received;
extern char uart_cmd[20];
/**
* @brief 串口初始化
*/
void USART_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* 配置PA9为复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置PA10为浮空输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART参数配置 */
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* 使能串口接收中断 */
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
/* 配置NVIC */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 使能USART */
USART_Cmd(USART1, ENABLE);
}
/**
* @brief 发送字符串
*/
void USART_SendString(char *str)
{
while(*str)
{
USART_SendData(USART1, *str++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
/**
* @brief 发送数字
*/
void USART_SendNumber(uint32_t num)
{
char buffer[12];
sprintf(buffer, "%lu", num);
USART_SendString(buffer);
}
/**
* @brief 串口接收中断处理函数
*/
void USART1_IRQHandler(void)
{
static uint8_t index = 0;
uint8_t receive_data;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
receive_data = USART_ReceiveData(USART1);
/* 接收命令 */
if(receive_data == '\r' || receive_data == '\n')
{
uart_cmd[index] = '\0';
uart_cmd_received = 1;
index = 0;
}
else if(index < sizeof(uart_cmd) - 1)
{
uart_cmd[index++] = receive_data;
}
}
}
2.6 OLED显示 (oled.c)
/**
******************************************************************************
* @file oled.c
* @brief OLED显示屏驱动 (I2C接口)
******************************************************************************
*/
#include "oled.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/* OLED I2C地址 */
#define OLED_ADDRESS 0x78
/* OLED命令 */
#define OLED_CMD 0x00
#define OLED_DATA 0x40
/* 字符字库 */
static const unsigned char OLED_Font[][6] = {
{0x00,0x00,0x00,0x00,0x00,0x00}, // 空格
{0x00,0x00,0x00,0x2f,0x00,0x00}, // !
{0x00,0x00,0x07,0x00,0x07,0x00}, // "
// ... 更多字符
};
/**
* @brief OLED初始化
*/
void OLED_Init(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* 配置I2C引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* I2C配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
I2C_Init(I2C1, &I2C_InitStructure);
/* 使能I2C */
I2C_Cmd(I2C1, ENABLE);
/* OLED初始化序列 */
OLED_Write_Command(0xAE); // 关闭显示
OLED_Write_Command(0xD5); // 设置时钟分频
OLED_Write_Command(0x80);
OLED_Write_Command(0xA8); // 设置多路复用比率
OLED_Write_Command(0x3F);
OLED_Write_Command(0xD3); // 设置显示偏移
OLED_Write_Command(0x00);
OLED_Write_Command(0x40); // 设置起始行
OLED_Write_Command(0x8D); // 电荷泵设置
OLED_Write_Command(0x14);
OLED_Write_Command(0x20); // 内存地址模式
OLED_Write_Command(0x02);
OLED_Write_Command(0xA1); // 段重映射
OLED_Write_Command(0xC8); // COM扫描方向
OLED_Write_Command(0xDA); // COM硬件配置
OLED_Write_Command(0x12);
OLED_Write_Command(0x81); // 对比度设置
OLED_Write_Command(0xCF);
OLED_Write_Command(0xD9); // 预充电周期
OLED_Write_Command(0xF1);
OLED_Write_Command(0xDB); // VCOMH设置
OLED_Write_Command(0x40);
OLED_Write_Command(0xA4); // 显示内容来自GDDRAM
OLED_Write_Command(0xA6); // 正常显示
OLED_Write_Command(0xAF); // 开启显示
OLED_Clear();
}
/**
* @brief 写命令到OLED
*/
void OLED_Write_Command(uint8_t command)
{
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, OLED_CMD);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, command);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);
}
/**
* @brief 写数据到OLED
*/
void OLED_Write_Data(uint8_t data)
{
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, OLED_DATA);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, data);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);
}
/**
* @brief 清屏
*/
void OLED_Clear(void)
{
uint8_t i, j;
for(i = 0; i < 8; i++)
{
OLED_Write_Command(0xB0 + i);
OLED_Write_Command(0x00);
OLED_Write_Command(0x10);
for(j = 0; j < 128; j++)
{
OLED_Write_Data(0x00);
}
}
}
/**
* @brief 显示字符串
*/
void OLED_ShowString(uint8_t x, uint8_t y, char *str)
{
uint8_t i = 0;
while(str[i] != '\0')
{
OLED_ShowChar(x + i*6, y, str[i]);
i++;
}
}
/**
* @brief 显示字符
*/
void OLED_ShowChar(uint8_t x, uint8_t y, char chr)
{
uint8_t c = chr - ' ';
uint8_t i;
OLED_Write_Command(0xB0 + y);
OLED_Write_Command(((x & 0xF0) >> 4) | 0x10);
OLED_Write_Command(x & 0x0F);
for(i = 0; i < 6; i++)
{
OLED_Write_Data(OLED_Font[c][i]);
}
}
/**
* @brief 刷新显示
*/
void OLED_Refresh(void)
{
// OLED自动刷新,无需额外操作
}
2.7 PIR人体感应 (pir.c)
/**
******************************************************************************
* @file pir.c
* @brief PIR人体感应传感器驱动
******************************************************************************
*/
#include "pir.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/**
* @brief PIR传感器初始化
*/
void PIR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能GPIOE时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
/* 配置PE2为上拉输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
/**
* @brief 检测人体
* @return 1:检测到人体,0:未检测到
*/
uint8_t PIR_Detect(void)
{
return (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) ? 1 : 0;
}
2.8 定时器 (timer.c)
/**
******************************************************************************
* @file timer.c
* @brief 系统定时器
******************************************************************************
*/
#include "timer.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
static volatile uint32_t system_time = 0;
/**
* @brief 定时器初始化
*/
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能TIM2时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* 配置TIM2基本参数:1ms中断 */
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1ms
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 72MHz/72=1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* 使能TIM2更新中断 */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* 配置NVIC */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 启动TIM2 */
TIM_Cmd(TIM2, ENABLE);
}
/**
* @brief 启动系统时间计数
*/
void Start_System_Timer(void)
{
system_time = 0;
}
/**
* @brief 获取系统时间(毫秒)
*/
uint32_t Get_System_Time(void)
{
return system_time;
}
/**
* @brief TIM2中断处理函数
*/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
system_time++;
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
2.9 延时函数 (delay.c)
/**
******************************************************************************
* @file delay.c
* @brief 延时函数
******************************************************************************
*/
#include "delay.h"
static uint32_t fac_us = 0;
static uint32_t fac_ms = 0;
/**
* @brief 延时初始化
*/
void Delay_Init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us = SystemCoreClock / 8000000;
fac_ms = (uint32_t)fac_us * 1000;
}
/**
* @brief 微秒延时
*/
void Delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = nus * fac_us;
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do
{
temp = SysTick->CTRL;
}
while((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
/**
* @brief 毫秒延时
*/
void Delay_ms(uint32_t nms)
{
uint32_t temp;
SysTick->LOAD = nms * fac_ms;
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do
{
temp = SysTick->CTRL;
}
while((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
三、头文件定义
3.1 led.h
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
void LED_Init(void);
void LED_Set_Brightness(uint8_t brightness);
#endif
3.2 key.h
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#define KEY1 1
#define KEY2 2
#define KEY_PRESS 1
#define KEY_RELEASE 0
void Key_Init(void);
uint8_t Key_Scan(uint8_t key);
#endif
3.3 usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
void USART_Init(void);
void USART_SendString(char *str);
void USART_SendNumber(uint32_t num);
#endif
3.4 oled.h
#ifndef __OLED_H
#define __OLED_H
#include "stm32f10x.h"
void OLED_Init(void);
void OLED_ShowString(uint8_t x, uint8_t y, char *str);
void OLED_ShowChar(uint8_t x, uint8_t y, char chr);
void OLED_Clear(void);
void OLED_Refresh(void);
#endif
3.5 timer.h
#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x.h"
void Timer_Init(void);
void Start_System_Timer(void);
uint32_t Get_System_Time(void);
#endif
3.6 delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f10x.h"
void Delay_Init(void);
void Delay_us(uint32_t nus);
void Delay_ms(uint32_t nms);
#endif
四、系统工作流程
4.1 启动流程
1. 系统时钟初始化 (72MHz)
2. 延时函数初始化
3. LED PWM初始化
4. 按键初始化
5. ADC光感初始化
6. OLED显示初始化
7. 串口初始化
8. 定时器初始化
9. PIR传感器初始化
10. 显示启动画面
11. 进入主循环
4.2 主循环逻辑
while(1)
{
1. 读取光感值
2. 检测人体感应
3. 检查PIR超时
4. 根据模式调整亮度
5. 渐变更新PWM输出
6. 处理串口命令
7. 更新OLED显示
8. 延时100ms
}
4.3 自动模式亮度调节逻辑
光照强度 < 50 → 亮度90%
光照强度 < 100 → 亮度70%
光照强度 < 200 → 亮度50%
光照强度 < 300 → 亮度30%
光照强度 >= 300 → 亮度10%
如果无人且超时30秒 → 亮度5%(最低)
参考代码 基于STM32F103ZET6实现的智能灯光亮度调节器 www.youwenfan.com/contentcnv/115934.html
五、串口命令示例
5.1 设置亮度
BRIGHTNESS:80
5.2 切换模式
MODE:AUTO
MODE:MANUAL
5.3 查询状态
GET_STATUS
5.4 帮助
HELP
六、硬件制作注意事项
- LED驱动电路:建议使用MOSFET(如IRF540)驱动大功率LED
- 光敏电阻:串联10kΩ电阻分压,接ADC引脚
- PIR传感器:需要3.3V供电,输出高电平表示检测到人体
- 电源:建议使用5V/2A电源适配器
- PCB布局:注意电源走线宽度,避免干扰
浙公网安备 33010602011771号