最终实现效果
设计目标
- 火焰检测报警(4方向),指示灯红色,蜂鸣器一直鸣叫。
- 烟雾报警,指示灯蓝色,蜂鸣器周期性鸣叫。
- 正常状态,指示灯绿色,蜂鸣器不叫。
硬件设计
总电路图
电源部分
电路供电可使用单个锂电池或外部5V供电,电路集成锂电池充电电路(TP4056),外部电源与锂电池供电自动切换,有外部供电时,使用外部电源,5V电源由SX1308经过升压得到,一个拨动开关控制系统电源(不控制锂电池充电,即系统未开,有外部供电也会对锂电池进行充电),3.3V由升压得到的5V经过稳压得到,火焰检测方向指示灯的电源可控,即可以控制指示灯是否显示。
四方向火焰检测
使用四个红外接收二极管作为火焰检测传感器,使用4路电压比较器LM339进行电压比较,检测到火焰输出低电平。可调整比较值VREF1,调整检测灵敏度。
烟雾与温度检测
烟雾检测使用MQ-2B烟雾传感器,温度使用NTC,分别设置比较阈值VREF2,VREF3,通过二路比较器LM393进行电压比较,输出端使用二极管来实现5V转3.3V。
软件设计
代码功能较为简单,有注释,就不多讲了。
#include "stm8l15x.h"//STM8L051/151公用库函数
#include "bsp_led.h"
#include "stdio.h"
void delay_us(u16 nCount);
void delay_ms(u16 nCount);
/**********************************************************************************************************
* 函 数 名: delay_us
* 功能说明: 微秒延时程序
* 形 参:nCount要延时的微秒数
* 返 回 值: 无
**********************************************************************************************************/
void delay_us(u16 nCount)
{
nCount *= 3;
while (--nCount);
}
/**********************************************************************************************************
* 函 数 名: delay_ms
* 功能说明: 毫秒延时程序
* 形 参:nCount要延时的毫米数
* 返 回 值: 无
**********************************************************************************************************/
void delay_ms(u16 nCount)
{
while (nCount--)
{
delay_us(1000);
}
}
void UART1_Send_byte(unsigned char byte) //发送一个8位的数据
{
USART_SendData8(USART1, byte);//将接收到的数据发送出去
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void UART1_Send_str(unsigned char *str) //发送字符串的数据
{
while (*str)
{
UART1_Send_byte(*str);
str++;
}
}
//将有符合整数转换为字符串
char *itoa(int num, char *str, int radix)
{
char index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //索引表
unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
int i = 0, j, k; //i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
//获取要转换的整数的绝对值
if (radix == 10 && num < 0) //要转换成十进制数并且是负数
{
unum = (unsigned) - num; //将num的绝对值赋给unum
str[i++] = '-'; //在字符串最前面设置为'-'号,并且索引加1
}
else unum = (unsigned)num; //若是num为正,直接赋值给unum
//转换部分,注意转换后是逆序的
do
{
str[i++] = index[unum % (unsigned)radix]; //取unum的最后一位,并设置为str对应位,指示索引加1
unum /= radix; //unum去掉最后一位
}
while (unum);//直至unum为0退出循环
str[i] = '\0'; //在字符串最后添加'\0'字符,c语言字符串以'\0'结束。
//将顺序调整过来
if (str[0] == '-') k = 1; //如果是负数,符号不用调整,从符号后面开始调整
else k = 0; //不是负数,全部都要调整
char temp;//临时变量,交换两个值时用到
for (j = k; j <= (i - 1) / 2; j++) //头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1
{
temp = str[j]; //头部赋值给临时变量
str[j] = str[i - 1 + k - j]; //尾部赋值给头部
str[i - 1 + k - j] = temp; //将临时变量的值(其实就是之前的头部值)赋给尾部
}
return str;//返回转换后的字符串
}
void Init_Timer4(void)
{
/* Init TIMER 4 */
CLK_PeripheralClockConfig(CLK_Peripheral_TIM4, ENABLE);//将主时钟信号送给定时器4(L系列单片机必需)
/* HSI div by 1 --> Auto-Reload value: 16M / 64 = 1/4M, 1/4M / 1k = 250*/
// TIM4_DeInit();
TIM4_TimeBaseInit(TIM4_Prescaler_64, 250); //T=1ms 64分频 X=16M/64 中断溢出=X/250 进中断一次1ms
TIM4_SetCounter(250);
TIM4_ClearFlag(TIM4_FLAG_Update);
TIM4_ITConfig(TIM4_IT_Update, ENABLE);
TIM4_Cmd(ENABLE);
}
/* Includes ------------------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
uint8_t Scan_Flag = 0;
uint16_t Fire_Scan_Count = 0;
uint16_t Smoke_Scan_Count = 0;
//uint8_t Temp_Humi_GET = 0;
uint8_t Warning_Flag = 0;
uint8_t Sec_Flag = 0;
uint8_t Sec_Count = 0;
uint8_t BEEP_Flag = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
uint8_t showstr[20] = {0};
void main(void)
{
// uint8_t i = 0;
// int16_t Temp = 10;
// uint16_t Humi = 20;
// uint8_t data_temp = 0;
uint8_t scan_temp = 0;
/* Infinite loop */
//使用内部HSI 16M 不分频
CLK_HSICmd(ENABLE);//开始内部高频RC
CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);//HSI为系统时钟
CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);//不分频,16M
CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);//开启USART时钟
//SYSCFG_REMAPPinConfig(REMAP_Pin_USART1TxRxPortA,ENABLE);//端口重映射,去掉注释之后USART1为PA2-TX、PA3-RX;注释之后USART1为TX-PC5、RX-PC6;复位之后USART会自动恢复至PC5、PC6
USART_Init(USART1, (uint32_t)9600, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Tx | USART_Mode_Rx)); //设置USART参数9600,8N1,接收/发送
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能接收中断
USART_Cmd(USART1, ENABLE);//使能USART
Init_Timer4();
enableInterrupts(); //中断使能
LED_Init(); //LED GPIO 管脚初始化
// LED_POWER_ON();
GPIO_Init(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4, GPIO_Mode_In_PU_No_IT); //输入上拉无中断
GPIO_Init(GPIOC, GPIO_Pin_4, GPIO_Mode_In_PU_No_IT); //输入上拉无中断
GPIO_Init(GPIOA, GPIO_Pin_2, GPIO_Mode_Out_PP_Low_Fast); //快速推挽输出默认低电平
UART1_Send_str("\r\nHELLO,STM8L051!!!\r\n");
while (1)
{
if (Sec_Flag)
{
if (++Sec_Count == 5)
{
if ((Fire_Scan_Count >= 20))
{
Warning_Flag |= 0x80;//火灾警报
}
else
{
Warning_Flag &= 0x7D;
}
if (Smoke_Scan_Count >= 20)
{
Warning_Flag |= 0x40;//烟雾警报
}
else
{
Warning_Flag &= 0xBF;
}
Fire_Scan_Count = 0;
Smoke_Scan_Count = 0;
Sec_Count = 0;
}
if ((Warning_Flag & 0x80) == 0x80)//火灾警报
{
LED2_L();
LED_POWER_ON();
LED1_H();
BEEP_Flag = 1;
}
else
{
LED_POWER_OFF();
LED1_L();
if ((Warning_Flag & 0x40) == 0x40)//烟雾警报
{
LED2_L();
LED3_H();
BEEP_Flag = 2;
}
else
{
BEEP_Flag = 0;
LED3_L();
LED2_H();
}
}
switch (BEEP_Flag)
{
case 0:
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
break;
case 1:
GPIO_SetBits(GPIOA, GPIO_Pin_2);
break;
case 2:
GPIO_ToggleBits(GPIOA, GPIO_Pin_2);
break;
}
Sec_Flag = 0;
}
if (Scan_Flag)
{
scan_temp = GPIO_ReadInputData(GPIOB) & 0x1F;
if (scan_temp != 0x1F)
{
if ((scan_temp >> 4) == 0)
{
Smoke_Scan_Count++;
}
else
{
Fire_Scan_Count++;
}
}
scan_temp = GPIO_ReadInputData(GPIOC) & 0x10;//NTC检测
if (scan_temp != 0x10)//温度过高
{
Fire_Scan_Count++;
}
Scan_Flag = 0;
}
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval : None
*/
void assert_failed(u8 *file, u32 line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif