一、项目和创意方向介绍
大学生宿舍楼内使用的小台灯通常需要手动关闭,很不方便。而且有时候会忘记关灯,造成能源浪费。所以想设计一款能人走灯灭的台灯,从而起到节能的目的。其次还要自主选择是否启动这种模式,使其更加人性化。还想要能让使用者选择舒适灯光颜色。
二、项目设计思路及实现方法
首先选择STMicroelectronics公司的STM32F103C8T6作为主控,再加上HC-SR505人体识别模块(HC—SR505人体识别模块可以通过被动式的红外感应元检测特定波长的红外线进行感应人体,如果感应到人的话,红外感应元就会失去电荷平衡,向外发射电荷,后续电路经过检测处理后就能产生报警信号,从而传递给STM32,没感应到人时电荷稳定,不会发出信号),就可以实现人走灯灭、人来灯亮的效果。再通过按键来向主控传输数据,从而达到选择是否开启自动开关灯的模式。然后通过OLED屏幕显示出当前模式,最后加上WS2812B可编程灯珠实现对灯光颜色的调整。
三、项目方案框图和原理图介绍
方框图:
如方框图所显示:
STMicroelectronics公司的STM32F103C8T6作为主控,从HC-SR505和按键模块中输入数据后,向OLED屏幕和WS2812B传输数据。
原理图:
从原理图能看出本次项目主要通过模块化实现的,电源模块提供5V供电,分别给单片机,灯光模块和人体识别模块供电,单片机在输出稳定的3.3V电压给OLED屏幕供电。给单片机供电时,5V会通过开发板内部的降压电路输出3.3V为单片机供电。单片机再通过对应的引脚连接对应的模块的引脚,接收并传输数据。
四、设计中用到的指定厂商元器件及介绍
STM32F103C8T6:它是STMicroelectronics公司的一款多功能的最小系统板,它基于Cortex-M3内核的32位微控制器,主频高达72MHz,内置flash存储器64KB,硬件采用LQFP48封装,包括多个GPIO口、USART、I2C、SPI等通信接口,可以满足各种应用的外设需求,具有多种低功耗模式,可以有效降低功耗,延长电池寿命,属于ST公司微控制器种的STM32系列。产品还具有48个引脚,可满足多种需求。
适合STM32F103RCT6的应用场景包括:
1. 工业控制:STM32F103C8T6具有丰富的外设和高性能的处理能力,可以满足工业控制领域的需求。
2. 智能家居:STM32F103C8T6可以通过多种接口与各种传感器和执行器进行通信,可以实现智能家居领域的应用。
3. 汽车电子:STM32F103C8T6具有高性能和低功耗的特点,可以满足汽车电子领域的需求。
4. 医疗设备:STM32F103C8T6具有多种低功耗模式,可以延长电池寿命,适合医疗设备等需要长时间运行的应用。
五、PCB设计介绍及遇到的问题和解决方法
PCB图:
PCB按照原理图导出连接没有问题,采取双层板,电源线进行加粗。
问题:
对PCB绘制不熟悉,进行了全面铺铜。
解决方法:
对整体电路没有影响可以不用管。
六、关键代码及说明
TIM3:
#include "stm32f10x.h"
void (*TIM3_Handler)(void);
void TIM3_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_DeInit(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 1000-1;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );
TIM_Cmd(TIM3, ENABLE);
}
void TIM3_Cmd(FunctionalState NewState)
{
TIM_Cmd(TIM3, NewState);
}
void TIM3_SetIRQHandler(void (*Function)(void))
{
TIM3_Handler=Function;
}
void TIM3_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update))
{
TIM3_Handler();
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
}
}
TIM3用来开启中断
TIM2:
#include "stm32f10x.h"
void TIM2_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_DeInit(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 90-1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM2, ENABLE);
TIM_DMAConfig(TIM2,TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer);
TIM_DMACmd(TIM2,TIM_DMA_Update,ENABLE);
TIM_Cmd(TIM2, DISABLE);
}
void TIM2_Cmd(FunctionalState NewState)
{
TIM_Cmd(TIM2, NewState);
}
void TIM2_SetCompare1(uint16_t Value)
{
TIM_SetCompare1(TIM2,Value);
}
TIM2是用来开启PWM,发送给DMA,从PA0输出给WS2812B灯条
WS2812B灯条:
#include "stm32f10x.h"
#include "TIM2.h"
#include "DMA1.h"
#define WS2812B_LED_QUANTITY 30
uint32_t WS2812B_Buf[WS2812B_LED_QUANTITY]; //0xGGRRBB
uint16_t WS2812B_Bit[24*WS2812B_LED_QUANTITY+1];
uint8_t WS2812B_Flag;
void WS2812B_IRQHandler(void);
void WS2812B_Init(void)
{
DMA1_SetIRQHandler(WS2812B_IRQHandler);
DMA1_Init((uint32_t)(&WS2812B_Bit));
TIM2_Init();
}
void WS2812B_ClearBuf(void)
{
uint8_t i;
for(i=0;i<WS2812B_LED_QUANTITY;i++)
{
WS2812B_Buf[i]=0x000000;
}
}
void WS2812B_SetBuf(uint32_t Color)
{
uint8_t i;
for(i=0;i<WS2812B_LED_QUANTITY;i++)
{
WS2812B_Buf[i]=Color;
}
}
void WS2812B_UpdateBuf(void)
{
uint8_t i,j;
for(j=0;j<WS2812B_LED_QUANTITY;j++)
{
for(i=0;i<24;i++)
{
if(WS2812B_Buf[j]&(0x800000>>i)){WS2812B_Bit[j*24+i+1]=60;}
else{WS2812B_Bit[j*24+i+1]=30;}
}
}
DMA1_Start(24*WS2812B_LED_QUANTITY+1);
TIM2_Cmd(ENABLE);
while(WS2812B_Flag==0);
WS2812B_Flag=0;
}
void WS2812B_IRQHandler(void)
{
TIM2_SetCompare1(0);
TIM2_Cmd(DISABLE);
WS2812B_Flag=1;
}
宏定义WS2812B_LED_QUANTITY可以调整灯珠的数量,将灯位量的地址存放到DMA。
void WS2812B_ClearBuf(void)用来定位每个小灯珠的位置。
void WS2812B_SetBuf(uint32_t Color)用来设置灯珠颜色。
HC-SR505:
#include "stm32f10x.h" // Device header
void HC_SR505_Init(void)
{
//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIO
//初始化GPIO
GPIO_InitTypeDef GPIO_HC_SR505;//结构名
GPIO_HC_SR505.GPIO_Mode = GPIO_Mode_IPD;
GPIO_HC_SR505.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB,&GPIO_HC_SR505);
}
uint16_t HC_SR505_GetData(void)
{
uint16_t tempData;
tempData=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
return tempData;
}
通过读取GPIO13口的高低电平来确认变化
七、功能展示图及说明
焊接完成后:
通电后:
八、对本大赛的心得体会(包括意见或建议),及整个设计过程中遇到的难点和解决方法
很感谢举办的这次FastBond3活动,让我有机会通过这个活动使用一些未曾尝试过的芯片来做一些不大但很有意义的制作。这之中虽然遇到了很多难题,比如原理部分、第一次使用STM32F103C8T6作为主控芯片,但跨过之后尽是收获。项目之中所做的成品确实很粗糙,稳定性实用性还有所改进空间,我将继续完善,在我的寝室中让他发挥自己最大的作用。