嵌入式实践——烟雾产生器

开发工具:Altium Designer 2020、STM32CubeMX 5.3.0、MDK-ARM 5.28

1.设计需求

设计出一套完整的烟雾产生装置,该装置通过按钮来控制烟雾的产生和关闭。装置对体积要求较高,所以控制板需控制在4cm*3cm,同时根据装置所要安装的器件来灵活调整控制板的形状,具体功能需求如下:
(1)能连续产生烟雾;
(2)采用锂电池方式供电,锂电池充电具有正在充电和充电完成指示,电池电量低提醒;
(3)烟雾需呈现蓝色和红色两种颜色,颜色根据需要进行切换;
(4)加热电路电流、电压监测;
(5)采用无线方式控制烟雾效果。

2.设计方案

(1)设备电源

整个设备供电采用小型锂电池,预留有线电源供电接口,能保证整机持续工作约2小时;设计锂电池充电电路,通过Micro USB接口为锂电池充电并在充电进行和充电结束时LED提醒;设计LDO电源为系统控制器及其他电路供电。

(2)烟雾产生

利用加热丝将加热棉中的电子烟油进行加热,以便产生烟雾;为避免加热丝连续通电对使用寿命和烟雾效果造成影响,采用PWM控制电流加热,并将出烟量调节至最佳状态;设计电压与电流检测电路,检测加热过程电压值和电流值。

(3)烟雾效果

①烟雾喷出速度: 通过控制风机转速实现,并设定几个可选择挡位;
②烟雾颜色: 通过不同颜色的LED灯来进行控制,通过不同灯光的照射使烟雾呈现不同的颜色。

(4)出烟控制

出烟控制分为烟雾产生开关、风机开关、双色LED开关,开关的控制均通过STM32F030F4P6控制,并使用 LC12S无线模块控制烟雾大小、风扇转速、烟雾颜色。

(5)低功耗

发烟器3min未接收到控制指令,自动休眠无线模块并将STM32进入停止模式,收到控制命令时自动唤醒。

3.硬件电路

在这里插入图片描述
电路原理图:SMKController.SchDoc
PCB:SMKController.PcbDoc

4.软件代码

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdlib.h>
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
#define Close_LED		  0x00
#define Open_RedLED		  0x01
#define Open_BlueLED	  0x02
#define FAN_Speed_0       0x00
#define FAN_Speed_1       0x01
#define FAN_Speed_2       0x02
#define FAN_Speed_3       0x03
/* USER CODE BEGIN PD */
void ADC_Check(void);
void OUTPUT_PWM(void);
void OUTPUT_PWM_first(void);
void OUTPUT_FAN(uint16_t FAN_MODE);
void LED_Control(void);
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim);
void StopMode_Measure(void);
/* USER CODE END PD */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint16_t dutyCycle1=0;				//占空比0%
uint16_t dutyCycle2=300;			//占空比30%
uint16_t dutyCycle3=500;
uint16_t dutyCycle600=600;
uint16_t dutyCycle4=700;
uint16_t dutyCycle5=800;
uint16_t dutyCycle1000=1000;
uint8_t aTxBuffer1[1];				//串口接收命1缓存
uint8_t aTxBuffer2[1];				//串口接收命2缓存
uint8_t aTxBuffer3[1];				//串口接收命3缓存
uint8_t aRxBuffer[10];				//串口接收的命令
uint8_t i;							//串口命令计数
uint8_t Sum=0;						//串口命令校验和
uint32_t ADC_Value[100];			//ADC_DMA模式采集数据缓存
uint32_t Battery_Value_Check,Res_Current_Check;			//电池电压、发热丝电流
uint16_t FAN_MODE;					//风扇档位
uint8_t aTxCheck_PWM[1];			//PWM输出数据缓存 
uint8_t aTxCheck_LED[1];			//LED灯光控制数据缓存
uint8_t TIM_2S_DONE;				//2s计数完成标志    	  1:完成   0:未完
uint8_t TIM_12S_DONE=2;				//12s计数完成标志  	  1:完成   0:未完
uint8_t TIM_3M_DONE;				//3min计数完成标志  	  1:完成   0:未完				
uint8_t flag = 2;
uint8_t Count_Flag = 0;				//3min计数过程标志 		
uint8_t Wait_Entry_Sleep = 0;		//3min计数
uint8_t uint8_t Stop_Mode_flag;		//停止模式标志位    	  1:True   2:False
uint8_t BlueLED_Flag=0;			    //蓝光控制标志     	  1:开     0:关
uint8_t RedLED_Flag=0;				//红光控制标志	  	  1:开     0:关
uint8_t LED_Close_Flag=0;		    //灯光关闭标志
uint8_t Uart_RX_Date_Flag=0;	    //串口接收数据标志	  1:接收到运行命令  0:接收到结束命令
uint8_t Uart1_PWM_Flag=0;   		//串口发送PWM输出命令标志位
uint8_t dmaflag=0;					//DMA标志位
uint8_t Tim14BaseCnt=0;				//7ms计数
uint8_t Tim14BaseCnt_PWM_first=0;   //12s计数
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
	/* MCU Configuration--------------------------------------------------------*/
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
	/* Configure the system clock */
	SystemClock_Config();
	/* Initialize all configured peripherals */
	MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC_Init();
    MX_TIM3_Init();
    MX_TIM14_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    HAL_ADC_Start_DMA(&hadc, (uint32_t*)ADC_Value, 100);					 //使能ADC_DMA采集模式
    if(HAL_UART_Receive_IT(&huart1,aRxBuffer,10)!=HAL_OK)Error_Handler();	 //开启串口中断接收模式
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); 								 //使能PWM输出
	HAL_TIM_Base_Start_IT(&htim14);											 //使能TIM计时												 				  
    /* USER CODE END 2 */
    
/* USER CODE BEGIN WHILE */
while (1)
{
	ADC_Check();							//ADC采集电池电压及发热丝电流
	OUTPUT_PWM_first();						//PWM输出
	LED_Control();							//双色LED灯光控制
	OUTPUT_FAN(FAN_MODE);					//风扇转速控制
	if(Stop_Mode_flag == 1)					//停止模式标志位判断
	{
		HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_SET);	    //休眠串口无线模块
		Stop_Mode_flag = 2;
		StopMode_Measure();					//进入停止模式  
	}
    /* USER CODE END WHILE */
  }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.HSI14CalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
/* ADC RxdCallback Fuction */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	dmaflag = 1;
	
	HAL_ADC_Stop_DMA(hadc);
}
	
/* Base Timer Callback Fuction */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim)   //每1ms进入一次中断,1ms计数一次
{
	if(htim->Instance == htim14.Instance)
	{
		/* PWM_First 12s计时 */
		if (TIM_12S_DONE == 0)				 
		{
			if(Tim14BaseCnt_PWM_first<12000)
			{
				Tim14BaseCnt_PWM_first++;
			}
			else
			{
				TIM_12S_DONE = 1;
				flag = 1;
				Tim14BaseCnt_PWM_first=0;
			}
		}	
		/* 12s后PWM间隔输出2s计时 */
		if (TIM_12S_DONE == 1)			
		{
			if(Tim14BaseCnt<70)
			{
				Tim14BaseCnt++;
			}
			else
			{
				Tim14BaseCnt= 0;
				TIM_2S_DONE = abs(TIM_2S_DONE-1);
			}
		}	
		/* 接收结束命令后3min计时进入停止模式,3min内有非结束命令时自动退出计时 */
		if (TIM_3M_DONE == 1)				
		{
			if(Wait_Entry_Sleep < 180000)
			{
				if(Uart_RX_Date_Flag==0)
				{
					Wait_Entry_Sleep++;	
					Count_Flag++;
				}
				else if(Uart_RX_Date_Flag==1)
				{
					Count_Flag=200000;
					Wait_Entry_Sleep=180000;
				}
			}
			if(Count_Flag==200000)
			{
				Wait_Entry_Sleep = 0;
				TIM_3M_DONE = 2;
				Count_Flag=0;
			}
			else if(Count_Flag>179998)
			{
				Stop_Mode_flag = 1;
				Wait_Entry_Sleep = 0;
				TIM_3M_DONE = 2;
				Count_Flag=0;
			}
		}
	}
}	

/* Usart RxdCallback Fuction */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		for(i=2;i<=8;i++)
		{
			Sum = Sum + aRxBuffer[i];
		}	
		if(Sum%302==aRxBuffer[9] && aRxBuffer[2]==0x0A)		 //校验和
		{
			Uart_RX_Date_Flag=1;
			/* PWM串口命令分析 */
			if(aRxBuffer[3]==0 && aRxBuffer[4]==0 && aRxBuffer[5]==0)	//当接收到结束命令时,开启3min计时
			{
				TIM_3M_DONE=1;
				Uart_RX_Date_Flag=0;
			}
			aTxBuffer1[0]=aRxBuffer[3];
			if(aTxCheck_PWM[0]==aTxBuffer1[0])      		//防止第二次相同命令重新运行
			{				
				aTxCheck_PWM[0]=aTxBuffer1[0];
			}
			else if(aTxBuffer1[0]==0x00)					//对第一个PWM输出命令进行判断
			{
				Uart1_PWM_Flag = 0;
				flag=0;
				TIM_12S_DONE = 2;	
				aTxCheck_PWM[0]=aTxBuffer1[0];		
			}
			else if(aTxBuffer1[0]==0x01)
			{
				Uart1_PWM_Flag = 1;
				TIM_12S_DONE = 0;
				flag=0;
				TIM_2S_DONE = 0;			
				aTxCheck_PWM[0]=aTxBuffer1[0];		
			}
			/* LED串口命令分析 */
			aTxBuffer2[0]=aRxBuffer[4];
			switch(aTxBuffer2[0])										//对第二个LED灯光控制命令进行判断				
			{
				case Open_BlueLED:
					BlueLED_Flag=1;
				break;
				case Open_RedLED:
					RedLED_Flag=1;
				break;
				case Close_LED:
					LED_Close_Flag=1;
				break;
				default:;
			}
			/* FAN串口命令分析 */
			aTxBuffer3[0]=aRxBuffer[5];							
			switch(aTxBuffer3[0])
			{
				case FAN_Speed_0:
				FAN_MODE = 0;
				break;
				case FAN_Speed_1:
				FAN_MODE = 1;
				break;
				case FAN_Speed_2:
				FAN_MODE = 2;
				break;
				case FAN_Speed_3:
				FAN_MODE = 3;
				break;
				default:;
			}
			Sum=0;
		}
		
		else
		{
			Sum=0;
			memset(aRxBuffer, 0, sizeof aRxBuffer); 	//命令错误清除缓冲区域数据
		}
		HAL_UART_Receive_IT(&huart1,aRxBuffer,10);	//再次开启串口接收
	}
}

/**
* ADC_DMA模式采集函数
* 判断电池电压及发热丝电流,用led灯显示
*/
void ADC_Check(void)													
{
	if(dmaflag == 1)   //判断中断标志,调用ADC Check函数。
		{
			dmaflag = 0;
			for(i=0,Battery_Value_Check=0,Res_Current_Check=0; i<100;i++)
			{
				Battery_Value_Check = ADC_Value[i]*3000/4096*2;
				Res_Current_Check = ADC_Value[i+1]*3000/4069/0.05/100;
				if(Battery_Value_Check>0 && Res_Current_Check>0)
				{
					HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);
				}
				HAL_ADC_Start_DMA(&hadc, (uint32_t*)ADC_Value, 100);			//重新使能ADC_DMA采集模式
			}
		
		}
}

/**
* 电阻丝加热控制,加热开始阶段
* 前12s阶段PWM输出控制函数
* PWM_first输出控制,前12s输出占空比为80%的PWM波
*/
void OUTPUT_PWM_first(void)
{
	if (Uart1_PWM_Flag == 1)
		{
			if(flag == 1)
			{
				OUTPUT_PWM();
			}
			if(flag == 0)				//前12s阶段PWM输出控制函数
			{
				HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);	
				__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,dutyCycle5);  //输出占空比为80%的PWM波
			}
		}
	if(Uart1_PWM_Flag == 0)
	{
		HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_2);
		TIM_2S_DONE = 0;
	}	
}

/**
* 12秒后阶段PWM输出控制函数
* PWM输出控制,12s后输出80%占空比的PWM波
*/
void OUTPUT_PWM(void)
{
	if(TIM_2S_DONE == 1)
	{
		HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);	
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,dutyCycle5);
	}
	if(TIM_2S_DONE == 0)
	{
		HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_2);
	}
}
	
/**
* LED灯光控制函数
* 分别对红蓝光进行开关控制
*/
void LED_Control(void)
{
	if(BlueLED_Flag==1)
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
		BlueLED_Flag=0;
	}
	if(RedLED_Flag==1)
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
		RedLED_Flag=0;
	}
	if(LED_Close_Flag==1)
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
		LED_Close_Flag=0;
	}
}

/**
* 风扇转速控制函数
* PWM输出控制,进行各个风扇档位进行控制,默认档位为占空比60%
*/
void OUTPUT_FAN(uint16_t FAN_MODE)
{
	switch(FAN_MODE)
	{
		case 0:
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,dutyCycle1);
		break;
		case 1:
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,dutyCycle2);
		break;
		case 2:
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,dutyCycle3);
		break;
		case 3:
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,dutyCycle4);
		break;
		default:
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,dutyCycle600);
	}
}

/**
* 停止模式函数
* 进入停止模式,等待EXTI唤醒 
*/
void StopMode_Measure(void)
{
	HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
	HAL_Delay(200);
}

/**
* EXTI_Callback函数
* 按键中断将单片机从停止模式唤醒
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == SW_Pin)
	{
		SystemClock_Config();										//重新使能时钟,因为停止模式将其关闭
		HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_RESET);	 	//唤醒串口无线模块	
		HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);						//按键提示灯,可删除
		__HAL_GPIO_EXTI_CLEAR_IT(SW_Pin);							//Clear the EXTI's line pending bits.
	}
}
/* USER CODE END 4 */
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

本次实践的烟雾发生器是三年前导师项目中所需的一个小装置,软硬件基础功能都已实现,这算是自己做的第一个嵌入式实践,硬件和软件设计可能还不规范,在此做一个整理记录。在烟雾效果的调试过程中很有趣,需将加热电流大小、加热时间、风力大小、加热丝粗细以及加热棉材料等因素进行合理的选择,才能达到烟雾的最佳效果,否则会导致烟雾效果不佳和加热丝熔断的情况发生。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值