前言
楼道灯是楼道专用的照明灯,属于新型建筑照明系统,楼道灯单灯采用声光控,实现人来灯亮,人走灯灭,达到节能,降耗,使用方便,性能安全可靠,可满足住宅楼及办公楼的不同需要。既符合了国家绿色节能建筑的要求,也提升了楼宇建筑的品位.
视频链接:https://www.bilibili.com/video/BV1xf4y1J7cB/ 进阶版视频:https://www.bilibili.com/video/BV1qU4y1P7GW/
准备材料
一、硬件方面
- stm32单片机
- 灯模块(可以使用led代替)
- 环境光传感器
- 声音传感器
二、软件方面
- STM32CubeIDE
- STM32CubeProgrammer
三、建立工程
1.代码编写
①ADC配置:
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
adc.c
enum
{
ADCCHN_NOISY,
ADCCHN_LUX,
ADCCHN_MAX,
};
int adc_sample_lux_noisy(uint32_t *lux, uint32_t *noisy)
{
uint8_t i;
uint32_t timeout = 0xffffff;
for(i=0; i<ADCCHN_MAX; i++)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, timeout);
if(ADCCHN_NOISY == i)
{
*noisy = HAL_ADC_GetValue(&hadc1);
}
else if(ADCCHN_LUX == i)
{
*lux = HAL_ADC_GetValue(&hadc1);
}
HAL_Delay(10);
}
HAL_ADC_Stop(&hadc1);
return 0;
}
②ADC配置:
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, jidianqi1_Pin|jidianqi2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, SysLed_Pin|BlueLed_Pin|RedLed_Pin|GreenLed_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = KEY1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = DHT11_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = jidianqi1_Pin|jidianqi2_Pin|SysLed_Pin|BlueLed_Pin
|RedLed_Pin|GreenLed_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = KEY0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY0_GPIO_Port, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
gpio.c
gpio_t leds[LedMax] =
{
{ "SysLed", GPIOB, SysLed_Pin},
{ "BlueLed", GPIOB, BlueLed_Pin},
{ "RedLed", GPIOB, RedLed_Pin},
{ "GreenLed", GPIOB, GreenLed_Pin},
};
void turn_led(int led,int status)
{
GPIO_PinState level;
if(led >= LedMax || led < 0) return;
level = (status == OFF)? GPIO_PIN_SET : GPIO_PIN_RESET;
HAL_GPIO_WritePin(leds[led].group, leds[led].pin,level);
}
③main函数
简易法:
uint32_t lux,noisy;
uint32_t start = 0;
uint8_t light_status = OFF;
while (1)
{
if( OFF == light_status )
{
adc_sample_lux_noisy(&lux, &noisy);
printf("LUX=[%lu],NOISY[%lu]\r\n", lux, noisy);
if( lux > 30 && noisy > 800 )
{
printf("Light_status is ON\r\n");
turn_led(GreenLed, ON);
HAL_Delay(5000);
turn_led(GreenLed, OFF);
}
}
不过这个代码还不够完善,就是你还希望做其他的事的的时候就不行了,因为进入delay函数,就干不了其他的了。
升级版: 运用巧妙的超时控制(time_after();) 很好的解决可以一边干别的事一边实现这个功能。(解决时间回绕问题) 在这里我还加上了蜂鸣器,当晚上有人经过的时候,发出提示声音并亮灯十五秒。 使用的是无源蜂鸣器,利用PWM来使它发出声响。 tim.c
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 80-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 370-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 185;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim2);
void buzzer_Start(uint8_t times,uint16_t interval)
{
while( times-- )
{
if(HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(interval);
if(HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(interval);
}
}
main.c
while (1)
{
if( OFF == light_status )
{
adc_sample_lux_noisy(&lux, &noisy);
if( lux < 30 && noisy > 850 )
{
printf("Light_status is ON\r\n");
turn_led(GreenLed, ON);
light_status = ON;
start = HAL_GetTick();
}
}
else
{
if( time_after(HAL_GetTick(), start + 15000) )
{
printf("Light_status is ON\r\n");
turn_led(GreenLed, OFF);
HAL_Delay(200);
light_status = OFF;
}
}
HAL_Delay(10);
2.工程的初建立
选择对应的芯片型号 然后命名选择 点击ioc进入配置设置 选择下载模式 这里我用的是USB方式下载,选择的是这个,如果你选择ST-Link下载你可选择JTAG(4pins)。 RCC 配置界面。以外部时钟为例,STM32CubeMX中外部时钟配置可选类型为 Disable 、 BYPASS Clock Source(旁路时钟源) 、Crystal/Ceramic Resonator(石英/陶瓷 晶振) 三种类型. 选择Crystal/Ceramic Resonator(石英/陶瓷 晶振) 选择你需要的灯GPIO口,配置输出模式 选择你想选用的ADC模块端口进行声音传感器和环境光传感器连接,并配置 这里我选择的是PA4和PA6(可以去芯片的datasheet查看哪些是adc的串口) 使能这两个通道,并配置 时钟配置 adc时钟配置,最好不要太高,这里我选择12MHZ 然后保存ctrl+s即可。
|