目录
一、项目需求
- 红外传感器检测是否有人,有人的话实时检测距离,过近则报警;同时计时,超过固定时间则警;
- 按键 1 切换工作模式:智能模式、按键模式、远程模式;
- 智能模式下,根据光照强度自动调整光照档位(低亮、中亮、高亮),没人则自动光灯;
- 按键模式下,按键 2 可以手动调整光照档位;
- 远程模式下,可以通过蓝牙控制光照档位、计时等;
- 按键 3 暂停/开始计时,按键 4 清零计时;
- OLED 显示各项数据/状态。
二、硬件清单
- 蓝牙模块
- 超声波传感器
- 红外传感器
- 光敏电阻传感器
- OLED
- 高功率LED灯
- 蜂鸣器
- KEY × 4
- 杜邦线
- STM32
- ST-Link
- USB转TTL
三、硬件接线


四、项目框图



五、完整代码
main.c
c
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "led.h"
#include "beep.h"
#include "bluetooth.h"
#include "hcsr04.h"
#include "ia_sensor.h"
#include "key.h"
#include "light_sensor.h"
#include "oled.h"
#include "timer.h"
enum lamp_mode
{
AUTO_MODE = 0,
MANUAL_MODE,
REMOTE_MODE
};
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
//LED初始化
led_init();
//串口1初始化
uart1_init(115200);
printf("打印测试:hello world\r\n");
//蜂鸣器初始化
beep_init();
//蓝牙模块初始化
bt_init(115200);
//超声波传感器初始化
hcsr04_init();
//红外传感器初始化
ia_init();
//按键初始化
key_init();
//光敏传感器初始化
ls_init();
//OLED初始化
oled_init();
//定时器初始化
timer_init(10000 - 1, 7200 - 1);
//OLED屏幕显示初始化
oled_show_init();
//定义是否有人标志位
uint8_t person_flag = 0;
//定义第一次有人状态
uint8_t first_loop = 1;
//定义距离变量
uint8_t dis = 0;
//定义距离显示变量
uint8_t dis_str[3] = {0};
//定义坐下时间显示变量
uint8_t sit_time_str[3] = {0};
//定义按键变量
uint8_t key_num = 0;
//定义模式
uint8_t mode = AUTO_MODE;
//定义光照强度
uint8_t light_value = 0;
//定义LED亮度值
uint8_t led_level = 0;
while(1)
{
person_flag = ia_flag_get();
//判断附近是否有人
if(person_flag == TRUE){ //有人
oled_show_chinese(10, 4, 9); //OLED显示有人
if(first_loop){ //第一次有人,语句中代码只执行一次
//已经有人了
first_loop = 0;
//开始计时
timer_start();
}
//测距
dis = hcsr04_get_length();
//判断距离
if(dis < 10){
beep1_on(); //报警
}else{
beep1_off(); //关闭报警
}
//判断时间
if(sit_time_get() >= 5){
beep1_on();
}
}else{ //无人
oled_show_chinese(10, 4, 10); //OLED显示无人
//清零计时器
timer_stop();
sit_time_set(0);
first_loop = 1;
beep1_off();
dis = 0;
}
//拼接距离字符串并且显示
sprintf((char *)dis_str, "%3d", dis);
oled_show_string(60, 4, (char *)dis_str, 16);
//拼接距离字符串并且显示
sprintf((char *)sit_time_str, "%3d", sit_time_get());
oled_show_string(60, 6, (char *)sit_time_str, 16);
//获取按键值
key_num = key_scan();
if(key_num == 1){
//切换模式
if(mode++ > 1){
mode = AUTO_MODE;
}
}else if(key_num == 3){
//开启或关闭定时器
timer_toggle();
}else if(key_num == 4){
//停止清零定时器
timer_stop();
sit_time_set(0);
}
switch(mode){
case AUTO_MODE:
{
oled_show_chinese(60, 0, 3); //显示智能模式
oled_show_chinese(75, 0, 4);
//如果有人
if(person_flag == TRUE){
light_value = ls_get_value();
if(light_value < 40){ //光线暗灯泡高亮
led_high();
printf("灯泡高亮\r\n");
}else if(light_value >= 40 && light_value <= 70){ //光线适中灯泡中亮
led_medium();
printf("灯泡中亮\r\n");
}else if(light_value > 70){ //光线亮灯泡低亮
led_low();
printf("灯泡低亮\r\n");
}
}else{ //如果没人
led_off(); //关灯
printf("关灯\r\n");
}
break;
}
case MANUAL_MODE:
{
oled_show_chinese(60, 0, 5); //显示按键模式
oled_show_chinese(75, 0, 6);
//判断按键
if(key_num == 2){
led_level = led_level_get();
//改变灯泡亮度
if(led_level++ > 2){
led_level = 0;
}
//调整灯泡亮度
switch(led_level){
case 0:
led_off(); //关灯
printf("关灯\r\n");
break;
case 1:
led_low(); //低亮
printf("灯泡低亮\r\n");
break;
case 2:
led_medium(); //中亮
printf("灯泡中亮\r\n");
break;
case 3:
led_high(); //高亮
printf("灯泡高亮\r\n");
break;
}
}
break;
}
case REMOTE_MODE:
{
oled_show_chinese(60, 0, 7); //显示远程模式
oled_show_chinese(75, 0, 8);
switch(bt_rx_get() - '0'){
case 0:
led_off(); //关灯
printf("关灯\r\n");
break;
case 1:
led_low(); //低亮
printf("灯泡低亮\r\n");
break;
case 2:
led_medium(); //中亮
printf("灯泡中亮\r\n");
break;
case 3:
led_high(); //高亮
printf("灯泡高亮\r\n");
break;
case 4:
timer_start(); //定时器开
break;
case 5:
timer_stop(); //定时器关
break;
case 6:
timer_stop(); //停止并清空定时器
sit_time_set(0);
break;
}
break;
}
default:
{
break;
}
}
delay_ms(20);
}
}
beep.c
c
#include "beep.h"
#include "sys.h"
//初始化GBIO口函数
void beep_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//使能GPIOB时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_13; //beep1对应引脚
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //上拉
gpio_initstruct.Pull = GPIO_PULLUP; //高速
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
//关闭beep1
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
}
//开启beep1的函数
void beep1_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); //拉低beep1引脚,开启beep1
}
//关闭beep1的函数
void beep1_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); //拉高beep1引脚,关闭beep1
}
//翻转beep1的函数
void beep1_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_13); //翻转beep1引脚电平
}
beep.h
c
#ifndef __BEEP_H__
#define __BEEP_H__
//初始化GBIO口函数
void beep_init(void);
//开启beep1的函数
void beep1_on(void);
//关闭beep1的函数
void beep1_off(void);
//翻转beep1的函数
void beep1_toggle(void);
#endif
bluetooth.c
c
#include "sys.h"
#include "bluetooth.h"
#include "string.h"
#include "stdarg.h"
UART_HandleTypeDef uart2_handle; /* uart2句柄 */
uint8_t command = 0;
uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE]; /* uart2接收缓冲区 */
uint16_t uart2_rx_len = 0; /* uart2接收字符长度 */
/**
* @brief 串口1初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @retval 无
*/
void bt_init(uint32_t baudrate)
{
/*UART2 初始化设置*/
uart2_handle.Instance = USART2; /* USART2 */
uart2_handle.Init.BaudRate = baudrate; /* 波特率 */
uart2_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
uart2_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
uart2_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
uart2_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
HAL_UART_Init(&uart2_handle); /* HAL_UART_Init()会使能UART2 */
}
/**
* @brief UART2接收缓冲区清除
* @param 无
* @retval 无
*/
void uart2_rx_clear(void)
{
memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf)); /* 清空接收缓冲区 */
uart2_rx_len = 0; /* 接收计数器清零 */
}
/**
* @brief 串口1中断服务函数
* @note 在此使用接收中断及空闲中断,实现不定长数据收发
* @param 无
* @retval 无
*/
void USART2_IRQHandler(void)
{
uint8_t receive_data = 0;
if(__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_RXNE) != RESET){ /* 获取接收RXNE标志位是否被置位 */
if(uart2_rx_len >= sizeof(uart2_rx_buf)) /* 如果接收的字符数大于接收缓冲区大小, */
uart2_rx_len = 0; /* 则将接收计数器清零 */
HAL_UART_Receive(&uart2_handle, &receive_data, 1, 1000); /* 接收一个字符 */
uart2_rx_buf[uart2_rx_len++] = receive_data; /* 将接收到的字符保存在接收缓冲区 */
}
if (__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_IDLE) != RESET) /* 获取接收空闲中断标志位是否被置位 */
{
printf("recv: %s\r\n", uart2_rx_buf); /* 将接收到的数据打印出来 */
command = uart2_rx_buf[0];
uart2_rx_clear();
__HAL_UART_CLEAR_IDLEFLAG(&uart2_handle); /* 清除UART总线空闲中断 */
}
}
////串口2发送函数
//void bt_send(char *send_buf, uint8_t size)
//{
// HAL_UART_Transmit(&uart2_handle, (uint8_t*)send_buf, size, 100);
//}
//串口2发送不定长数据
void bt_send(char *format, ...)
{
uint8_t send_buf[128] = {0};
va_list arg;
va_start(arg, format);
vsprintf((char *)send_buf, format ,arg);
va_end(arg);
HAL_UART_Transmit(&uart2_handle, send_buf, sizeof(send_buf), 100);
}
//将指令传递出去
uint8_t bt_rx_get(void)
{
uint8_t tmp = command;
command = '9';
return tmp;
}
bluetooth.h
c
#ifndef __BLUETOOTH_H__
#define __BLUETOOTH_H__
#include "stdio.h"
#include "sys.h"
/* UART收发缓冲大小 */
#define UART2_RX_BUF_SIZE 128
#define UART2_TX_BUF_SIZE 64
void bt_init(uint32_t bound); /* 串口初始化函数 */
////串口2发送函数
//void bt_send(char *send_buf, uint8_t size);
//串口2发送不定长数据
void bt_send(char *format, ...);
//将指令传递出去
uint8_t bt_rx_get(void);
#endif
hcsr04.c
c
#include "hcsr04.h"
#include "delay.h"
TIM_HandleTypeDef tim2_handle = {0};
//定时器初始化函数
void tim2_init(void)
{
//开启时钟
__HAL_RCC_TIM2_CLK_ENABLE();
//配置定时器结构体
tim2_handle.Instance = TIM2;
tim2_handle.Init.Prescaler = 72 - 1;
tim2_handle.Init.Period = 6536 - 1;
tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2_handle);
//使能更新中断,启动计数器
//HAL_TIM_Base_Start_IT(&tim2_handle);
}
////msp初始化函数,在HAL_TIM_Base_Init中调用,无须自己调用
//void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
//{
// if(htim->Instance == TIM2){
// //开启时钟
// __HAL_RCC_TIM2_CLK_ENABLE();
// }
//}
//定时器启动函数
void tim2_start(void)
{
HAL_TIM_Base_Start_IT(&tim2_handle);
}
//定时器关闭函数
void tim2_stop(void)
{
HAL_TIM_Base_Stop(&tim2_handle);
}
//读CNT函数
uint16_t tim2_get_cnt(void)
{
return __HAL_TIM_GetCounter(&tim2_handle);
}
//设置CNT函数
void tim2_set_cnt(uint16_t val)
{
__HAL_TIM_SetCounter(&tim2_handle,val);
}
//GPIO初始化
void hcsr04_gpio_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//使能时钟
TRIG_GPIO_CLKENABLE();
ECHO_GPIO_CLKENABLE();
//初始化trig引脚
gpio_initstruct.Pin = TRIG_PIN; //tirg对应引脚
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(TRIG_PORT, &gpio_initstruct);
//初始化echo引脚
gpio_initstruct.Pin = ECHO_PIN; //echo对应引脚
gpio_initstruct.Mode = GPIO_MODE_INPUT; //输入
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(ECHO_PORT, &gpio_initstruct);
}
//初始化超声波传感器
void hcsr04_init(void)
{
tim2_init();
hcsr04_gpio_init();
}
//距离获取函数
float hcsr04_get_length(void)
{
uint16_t total_time = 0;
float distance;
//1、给Trig端口至少10us的高电平
TRIG_HIGH();
delay_us(15);
TRIG_LOW();
//2、Echo引脚由低电平跳转到高电平,表示开始发送波
//波发出去的一瞬间,开始启动定时器
while(ECHO_STATUS() == GPIO_PIN_RESET);
tim2_start();
tim2_set_cnt(0);
//3、Echo引脚由高电平跳转回低电平,表示波回来了
//波回来的那一刻,停止定时器,计算出中间经过多长时间
while(ECHO_STATUS() == GPIO_PIN_SET);
tim2_stop();
total_time = tim2_get_cnt();
//4、距离 = 速度(343m/s) * 时间 / 2
distance = total_time * 0.01715;
return distance;
}
hcsr04.h
c
#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "sys.h"
#define TRIG_PORT GPIOA
#define TRIG_PIN GPIO_PIN_11
#define TRIG_GPIO_CLKENABLE() __HAL_RCC_GPIOA_CLK_ENABLE();
#define TRIG_HIGH() HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET);
#define TRIG_LOW() HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET);
#define ECHO_PORT GPIOA
#define ECHO_PIN GPIO_PIN_12
#define ECHO_GPIO_CLKENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define ECHO_STATUS() HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN)
//距离获取函数
float hcsr04_get_length(void);
//初始化超声波传感器
void hcsr04_init(void);
#endif
is_sensor.c
c
#include "ia_sensor.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
uint8_t ia_flag = FALSE;
//红外传感器初始化
void ia_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//使能GPIOB时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_12; //KEY0引脚
gpio_initstruct.Mode = GPIO_MODE_INPUT; //输入信号下降沿检测
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
}
//读取红外传感器状态
uint8_t ia_flag_get(void)
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET){
return TRUE;
}else{
return FALSE;
}
}
is_sensor.h
c
#ifndef __IA_SENSOR_H__
#define __IA_SENSOR_H__
#include "sys.h"
#define TRUE 1
#define FALSE 0
//红外传感器初始化
void ia_init(void);
//读取红外传感器状态
uint8_t ia_flag_get(void);
#endif
key.c
c
#include "key.h"
#include "delay.h"
//初始化GPIO
void key_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//使能按键GPIO时钟
KEY1_GPIO_CLK_ENABLE();
KEY2_GPIO_CLK_ENABLE();
KEY3_GPIO_CLK_ENABLE();
KEY4_GPIO_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = KEY1_GPIO_PIN; //KEY1对应引脚
gpio_initstruct.Mode = GPIO_MODE_INPUT; //输入
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_initstruct);
gpio_initstruct.Pin = KEY2_GPIO_PIN; //KEY2对应引脚
HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_initstruct);
gpio_initstruct.Pin = KEY3_GPIO_PIN; //KEY3对应引脚
HAL_GPIO_Init(KEY3_GPIO_PORT, &gpio_initstruct);
gpio_initstruct.Pin = KEY4_GPIO_PIN; //KEY4对应引脚
HAL_GPIO_Init(KEY4_GPIO_PORT, &gpio_initstruct);
}
//按键扫描函数
uint8_t key_scan(void)
{
static uint8_t key_up = 1; //按键松开标志
uint8_t key_val = 0; //按键值
if(key_up && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)){
delay_ms(10);
key_up = 0;
if(KEY1 == 0){
key_val = 1;
}
if(KEY2 == 0){
key_val = 2;
}
if(KEY3 == 0){
key_val = 3;
}
if(KEY4 == 0){
key_val = 4;
}
}else if(KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1){
key_up = 1;
}
return key_val;
}
key.h
c
#ifndef __KEY_H__
#define __KEY_H__
#include "sys.h"
//按键端口引脚宏定义
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_PIN GPIO_PIN_4
#define KEY1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define KEY2_GPIO_PORT GPIOA
#define KEY2_GPIO_PIN GPIO_PIN_5
#define KEY2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define KEY3_GPIO_PORT GPIOA
#define KEY3_GPIO_PIN GPIO_PIN_6
#define KEY3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define KEY4_GPIO_PORT GPIOA
#define KEY4_GPIO_PIN GPIO_PIN_7
#define KEY4_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
//读取按键状态宏定义
#define KEY1 HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN)
#define KEY2 HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_GPIO_PIN)
#define KEY3 HAL_GPIO_ReadPin(KEY3_GPIO_PORT, KEY3_GPIO_PIN)
#define KEY4 HAL_GPIO_ReadPin(KEY4_GPIO_PORT, KEY4_GPIO_PIN)
void key_init(void);
uint8_t key_scan(void);
#endif
led.c
c
#include "led.h"
#include "oled.h"
uint8_t led_level = 0;
TIM_HandleTypeDef pwm_handler;
//init函数
void pwm_init(uint16_t arr, uint16_t psc)
{
TIM_OC_InitTypeDef pwm_config = {0};
//时基工作参数初始化
pwm_handler.Instance = TIM3;
pwm_handler.Init.Prescaler = psc;
pwm_handler.Init.Period = arr;
pwm_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
pwm_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_PWM_Init(&pwm_handler); //自动调用msp函数
//PWM模式配置
pwm_config.OCMode = TIM_OCMODE_PWM1;
pwm_config.Pulse = 0;
pwm_config.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&pwm_handler,&pwm_config,TIM_CHANNEL_3);
//使能输出,启动计数器
HAL_TIM_PWM_Start(&pwm_handler,TIM_CHANNEL_3);
}
//msp函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3){
//GPIO初始化
GPIO_InitTypeDef gpio_initstruct;
//使能GPIOB时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//使能定时器4时钟
__HAL_RCC_TIM4_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_0; //定时器3通道3对应引脚
gpio_initstruct.Mode = GPIO_MODE_AF_PP; //复用推挽输出
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
}
}
//修改CCR值的函数
void pwm_compare_set(uint16_t val)
{
__HAL_TIM_SET_COMPARE(&pwm_handler,TIM_CHANNEL_3,val);
}
//LED初始化
void led_init(void)
{
pwm_init(500 - 1, 72 - 1);
}
//LED关闭
void led_off(void)
{
pwm_compare_set(0);
led_level = 0;
oled_show_chinese(70, 2, 17);
}
//LED低亮
void led_low(void)
{
pwm_compare_set(150);
led_level = 1;
oled_show_chinese(70, 2, 14);
}
//LED中亮
void led_medium(void)
{
pwm_compare_set(300);
led_level = 2;
oled_show_chinese(70, 2, 15);
}
//LED高亮
void led_high(void)
{
pwm_compare_set(450);
led_level = 3;
oled_show_chinese(70, 2, 16);
}
//获取LED当前亮度挡位
uint8_t led_level_get(void)
{
return led_level;
}
led.h
c
#ifndef __LED_H__
#define __LED_H__
#include "sys.h"
//init函数
void pwm_init(uint16_t arr, uint16_t psc);
//修改CCR值的函数
void pwm_compare_set(uint16_t val);
//LED初始化
void led_init(void);
//LED关闭
void led_off(void);
//LED低亮
void led_low(void);
//LED中亮
void led_medium(void);
//LED高亮
void led_high(void);
//获取LED当前亮度挡位
uint8_t led_level_get(void);
#endif
light_sensor.c
c
#include "light_sensor.h"
ADC_HandleTypeDef adc_handle = {0};
//ADC配置初始化
void adc_init(void)
{
adc_handle.Instance = ADC1; //选择ADC1
adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据右对齐
adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; //不扫描
adc_handle.Init .ContinuousConvMode = DISABLE; //不连续转换
adc_handle.Init.NbrOfConversion = 1; //转换个数为1
adc_handle.Init.DiscontinuousConvMode = DISABLE; //不采用间断模式
adc_handle.Init.NbrOfDiscConversion = 0; //间断模式个数为0
adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; //采用软件触发
HAL_ADC_Init(&adc_handle); //调用初始化函数
//ADC校准
HAL_ADCEx_Calibration_Start(&adc_handle);
}
//ADC相关硬件配置
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
//确认是否为ADC1
if(hadc->Instance == ADC1){
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
GPIO_InitTypeDef gpio_init_struct = {0};
//开启ADC1时钟
__HAL_RCC_ADC1_CLK_ENABLE();
//使能GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
//设置PIN1口,模拟输入模式
gpio_init_struct.Pin = GPIO_PIN_1;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
//GPIO初始化
HAL_GPIO_Init(GPIOA,&gpio_init_struct);
//设置外设时钟选择为RCC外设ADC时钟
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;
//设置adc时钟分频因子 为6分频
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;
//配置外设时钟
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);
}
}
//ADC通道配置
void adc_channel_config(ADC_HandleTypeDef* hadc, uint32_t ch,uint32_t rank, uint32_t stime)
{
ADC_ChannelConfTypeDef adc_ch_config = {0};
//设置adc通道参数
adc_ch_config.Channel = ch; //设置通道
adc_ch_config.Rank = rank; //设置通道次序
adc_ch_config.SamplingTime = stime; //设置采样时间
//通道配置
HAL_ADC_ConfigChannel(hadc, &adc_ch_config);
}
//获取ADC的值
uint32_t adc_get_result(uint32_t ch)
{
//配置ADC通道
adc_channel_config(&adc_handle, ch, ADC_REGULAR_RANK_1, ADC_SAMPLETIME_239CYCLES_5);
//开始ADC转换
HAL_ADC_Start(&adc_handle);
//轮询方式等待ADC转换完成
HAL_ADC_PollForConversion(&adc_handle, 10);
//获取ADC转换结果
return (uint16_t)HAL_ADC_GetValue(&adc_handle);
}
//光敏传感器初始化
void ls_init(void)
{
adc_init();
}
//获取光敏传感器的值
uint8_t ls_get_value(void)
{
//将ADC值转化为100以内的数,光照值越大,数值越大
return (uint8_t)(100 - adc_get_result(ADC_CHANNEL_1) * 100 / 4096);
}
light_sensor.h
c
#ifndef __LIGHT_SENSOR_H__
#define __LIGHT_SENSOR_H__
#include "sys.h"
//ADC配置初始化
void adc_init(void);
//获取ADC的值
uint32_t adc_get_result(uint32_t ch);
//光敏传感器初始化
void ls_init(void);
//获取光敏传感器的值
uint8_t ls_get_value(void);
#endif
oled.c
c
#include "oled.h"
#include "delay.h"
#include "font.h"
//OLED相关GPIO初始化
void oled_gpio_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//使能SCL和SDA引脚时钟
OLED_I2C_SCL_CLK();
OLED_I2C_SDA_CLK();
//GPIO初始化配置
gpio_initstruct.Pin = OLED_I2C_SCL_PIN; //SCL对应引脚
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(OLED_I2C_SCL_PORT, &gpio_initstruct);
gpio_initstruct.Pin = OLED_I2C_SDA_PIN; //SDA对应引脚
HAL_GPIO_Init(OLED_I2C_SDA_PORT, &gpio_initstruct);
}
//I2C起始信号
void oled_i2c_start(void)
{
OLED_SCL_SET();
OLED_SDA_SET();
OLED_SDA_RESET();
OLED_SCL_RESET();
}
//I2C停止信号
void oled_i2c_stop(void)
{
OLED_SCL_SET();
OLED_SDA_RESET();
OLED_SDA_SET();
}
//I2C应答信号
void oled_i2c_ack(void)
{
OLED_SCL_SET();
OLED_SCL_RESET();
}
//I2C写字节
void oled_i2c_write_byte(uint8_t data)
{
uint8_t i, tmp;
tmp = data;
//往SDA总线上循环写数据位,高位先行
for(i = 0; i <8 ;i++){
//取出最高位
if((tmp & 0x80) == 0x80){
OLED_SDA_SET();
}else{
OLED_SDA_RESET();
}
//逻辑左移一位,去除次高位
tmp = tmp << 1;
OLED_SCL_SET();
OLED_SCL_RESET();
}
}
//OLED写命令
void oled_write_cmd(uint8_t cmd)
{
oled_i2c_start();
oled_i2c_write_byte(0x78);
oled_i2c_ack();
oled_i2c_write_byte(0x00);
oled_i2c_ack();
oled_i2c_write_byte(cmd);
oled_i2c_ack();
oled_i2c_stop();
}
//OLED写数据
void oled_write_data(uint8_t data)
{
oled_i2c_start();
oled_i2c_write_byte(0x78);
oled_i2c_ack();
oled_i2c_write_byte(0x40);
oled_i2c_ack();
oled_i2c_write_byte(data);
oled_i2c_ack();
oled_i2c_stop();
}
//OLED初始化
void oled_init(void)
{
oled_gpio_init();
delay_ms(100);
oled_write_cmd(0xAE); //设置显示开启/关闭,0xAE关闭,0xAF开启
oled_write_cmd(0xD5); //设置显示时钟分频比/振荡器频率
oled_write_cmd(0x80); //0x00~0xFF
oled_write_cmd(0xA8); //设置多路复用率
oled_write_cmd(0x3F); //0x0E~0x3F
oled_write_cmd(0xD3); //设置显示偏移
oled_write_cmd(0x00); //0x00~0x7F
oled_write_cmd(0x40); //设置显示开始行,0x40~0x7F
oled_write_cmd(0xA1); //设置左右方向,0xA1正常,0xA0左右反置
oled_write_cmd(0xC8); //设置上下方向,0xC8正常,0xC0上下反置
oled_write_cmd(0xDA); //设置COM引脚硬件配置
oled_write_cmd(0x12);
oled_write_cmd(0x81); //设置对比度
oled_write_cmd(0xCF); //0x00~0xFF
oled_write_cmd(0xD9); //设置预充电周期
oled_write_cmd(0xF1);
oled_write_cmd(0xDB); //设置VCOMH取消选择级别
oled_write_cmd(0x30);
oled_write_cmd(0xA4); //设置整个显示打开/关闭
oled_write_cmd(0xA6); //设置正常/反色显示,0xA6正常,0xA7反色
oled_write_cmd(0x8D); //设置充电泵
oled_write_cmd(0x14);
oled_write_cmd(0xAF); //开启显示
}
//设置坐标
void oled_set_cursor(uint8_t x, uint8_t y)
{
//指定待写入页
oled_write_cmd(0xB0 + y);
//指定待写入列
oled_write_cmd((x & 0x0F) | 0x00);
oled_write_cmd((x & 0xF0) >> 4 | 0x10);
}
//循环填充
void oled_fill(uint8_t data)
{
uint8_t i,j;
for(i = 0;i < 8;i++){
oled_set_cursor(0, i); //指定一次页,写一次列自动往后偏移
for(j = 0;j < 128;j++){
oled_write_data(data);
}
}
}
//OLED显示一个字符
void oled_show_char(uint8_t x, uint8_t y, uint8_t num, uint8_t size)
{
uint8_t i,j, page;
//ASCII码相对第一个空格字符偏移
num = num - ' ';
//确定字符所占页数
page = size / 8;
if(size % 8){
page++;
}
//循环刷新屏幕
for(j = 0;j < page;j++){
//设定字符坐标
oled_set_cursor(x, y + j);
//分行写数据
for(i = size/2 * j;i < size/2 * (j+1);i++){
if(size == 12){
oled_write_data(ascii_6X12[num][i]);
}else if(size == 16){
oled_write_data(ascii_8X16[num][i]);
}else if(size == 24){
oled_write_data(ascii_12X24[num][i]);
}
}
}
}
//OLED显示字符串
void oled_show_string(uint8_t x, uint8_t y, char *p, uint8_t size)
{
while(*p != '\0'){
oled_show_char(x, y, *p, size);
x += size/2;
p++;
}
}
//OLED显示汉字
void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N)
{
uint8_t i,j;
//循环刷新屏幕
for(j = 0;j < 2;j++){
//设定字符坐标
oled_set_cursor(x, y + j);
//分行写数据
for(i = 16 * j;i < 16 * (j+1);i++){
oled_write_data(lamp_16x16[N][i]);
}
}
}
//上电界面初始化
void oled_show_init(void)
{
oled_fill(0x00); //清屏
oled_show_chinese(10,0,1); //模式:
oled_show_chinese(25,0,2);
oled_show_chinese(40,0,0);
oled_show_chinese(10,2,12); //亮度:
oled_show_chinese(25,2,13);
oled_show_chinese(40,2,0);
oled_show_chinese(25,4,11); // 人 cm
oled_show_string(96,4,"cm",16);
oled_show_chinese(10,6,18); //计时:
oled_show_chinese(25,6,19);
oled_show_chinese(40,6,0);
oled_show_char(100,6,'s',16);
}
//OLED显示图片
void oled_show_image(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t *bmp)
{
uint8_t i, j;
for(j = 0; j < height; j++)
{
oled_set_cursor(x, y + j);
for(i = 0; i < width; i++)
oled_write_data(bmp[width * j + i]);
}
}
oled.h
c
#ifndef __OLED_H__
#define __OLED_H__
#include "sys.h"
#define OLED_I2C_SCL_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SCL_PORT GPIOB
#define OLED_I2C_SCL_PIN GPIO_PIN_6
#define OLED_I2C_SDA_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SDA_PORT GPIOB
#define OLED_I2C_SDA_PIN GPIO_PIN_7
#define OLED_SCL_RESET() HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_RESET)
#define OLED_SCL_SET() HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_SET)
#define OLED_SDA_RESET() HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_RESET)
#define OLED_SDA_SET() HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_SET)
//OLED初始化
void oled_init(void);
//I2C写命令
void oled_write_cmd(uint8_t cmd);
//I2C写数据
void oled_write_data(uint8_t data);
//循环填充
void oled_fill(uint8_t data);
//设置坐标
void oled_set_cursor(uint8_t x, uint8_t y);
//OLED显示一个字符
void oled_show_char(uint8_t x, uint8_t y, uint8_t num, uint8_t size);
//OLED显示字符串
void oled_show_string(uint8_t x, uint8_t y, char *p, uint8_t size);
//OLED显示汉字
void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N);
//OLED显示图片
void oled_show_image(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t *bmp);
//上电界面初始化
void oled_show_init(void);
#endif
timer.c
c
#include "timer.h"
#include "led.h"
//定义坐下时间
uint32_t sit_time = 0;
//定义定时器状态
uint8_t timer_running = 0;
TIM_HandleTypeDef timer_handle = {0};
//定时器初始化函数
void timer_init(uint16_t arr,uint16_t psc)
{
//配置定时器结构体
timer_handle.Instance = TIM4;
timer_handle.Init.Prescaler = psc;
timer_handle.Init.Period = arr;
timer_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
timer_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&timer_handle);
//使能更新中断,启动计数器
HAL_TIM_Base_Start_IT(&timer_handle);
}
//msp初始化函数,在HAL_TIM_Base_Init中调用,无须自己调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4){
//开启时钟
__HAL_RCC_TIM2_CLK_ENABLE();
//设置中断优先级
HAL_NVIC_SetPriority(TIM4_IRQn,2,2);
//使能中断线
HAL_NVIC_EnableIRQ(TIM4_IRQn);
}
}
//中断服务函数
void TIM4_IRQHandler(void)
{
//公共处理函数
HAL_TIM_IRQHandler(&timer_handle);
}
//更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4){
//一秒钟加一次
sit_time++;
// led1_toggle();
}
}
//启动定时器
void timer_start(void)
{
HAL_TIM_Base_Start_IT(&timer_handle);
timer_running = 1;
}
//停止定时器
void timer_stop(void)
{
HAL_TIM_Base_Stop_IT(&timer_handle);
timer_running = 0;
}
//翻转定时器状态
void timer_toggle(void)
{
if(timer_running){
timer_stop();
}else{
timer_start();
}
}
//返回坐下时间值
uint32_t sit_time_get(void)
{
return sit_time;
}
//设置坐下时间值
void sit_time_set(uint32_t value)
{
sit_time = value;
}
timer.h
c
#ifndef __TIMER_H__
#define __TIMER_H__
#include "sys.h"
//定时器初始化
void timer_init(uint16_t arr,uint16_t psc);
//启动定时器
void timer_start(void);
//停止定时器
void timer_stop(void);
//翻转定时器状态
void timer_toggle(void);
//返回坐下时间值
uint32_t sit_time_get(void);
//设置坐下时间值
void sit_time_set(uint32_t value);
#endif
六、实物图
