基于STM32的智能灯光亮度调节器【正点原子】(四)

系列文章目录

第一章 PWM调节

第二章 ADC采样

第三章 光敏传感器

第四章 智能灯光亮度调节器(终)


目录

前言

一、准备工作

二、项目详情

三、实现过程 

四、调试过程 

总结


前言

前面三章对PWM、ADC和光敏传感器三个重要的部分进行了学习,本文将对整个项目进行完整地实现,该项目我们使用了PWM、ADC、按键中断、定时器中断、LCD显示、串口打印、LED等模块,该智能灯光亮度调节器有两个模式:手动模式和自动模式;在手动模式下,我们可以使用WK按键和KEY1按键对开发板上的LED0(红色)手动的调节灯光亮度档位,一共有五个档位。按下KEY2按键,进入自动模式。自动模式,LED0的灯光亮度档位会根据光敏传感器采集到的环境亮度进行自动调节,按下KEY0则退回手动模式。


提示:以下是本篇文章正文内容,下面案例可供参考

一、准备工作

本案例使用的是正点原子的战舰开发板,一根烧录线,一根串口线,串口调试助手使用的是XCOM

点赞、收藏和评论留言,私我拿代码我下载使用

二、项目详情

1.功能要求

(1)5档调节灯光亮度,可分为手动和自动两种调节方式,调节方式由按键设置;

(2)自动调节时依据当前亮度变化调节,通过板上的光敏电阻获取环境亮度;

(3) 1秒采集一次当前环境灯光亮度,1秒的时间间隔由定时器设置;

(4)把当前的环境亮度和灯光亮度上传到串口调试助手;

(5)在显示屏上显示出当前的环境亮度和灯光亮度等级。

2.功能实现分析 

(1)对于5档调节灯光亮度可以通过设置按键,让按键来实现对灯光亮度调升和调降,灯光亮度的调节需要设置PWM来调节占空比来调节灯五个不同挡位显现不用的五个灯光亮度;

(2)自动调节灯光亮度需要使用光敏传感器与ADC获取当前环境亮度,再根据环境亮度的不同来调控灯的亮度;

(3)通过设置定时器来实现1秒采集一次当前环境灯光亮度;

(4)配置好串口函数所需参数来实现把当前的环境亮度和灯光亮度上传到串口调试助手;

(5)对LCD显示板块所需参数进行配置能够实现显示屏显示当前环境亮度和灯光亮度等级。

三、实现过程 

1.初始化各模块

下面写出只有部分模块:

TIM3_PWM初始化:

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
 
   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
   //初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OCInitStructure.TIM_Pulse=0;
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
}

TIM4初始化: 

void TIM4_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能

	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断

	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM4, ENABLE);  //使能TIMx外设						 
}

 ADC3初始化:

//初始化ADC3
//这里我们仅以规则通道为例
//我们默认仅开启通道6																	   
void  Adc3_Init(void)
{      
	ADC_InitTypeDef ADC_InitStructure; 

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3	, ENABLE );	  //使能ADC3通道时钟
	
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE);//ADC复位
	
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE);//复位结束	    
	
	ADC_DeInit(ADC3);  //复位ADC3,将外设 ADC3的全部寄存器重设为缺省值
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式: 独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC3, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器  
	
	ADC_Cmd(ADC3, ENABLE);	//使能指定的ADC3
	
	ADC_ResetCalibration(ADC3);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC3));	//等待复位校准结束
	
	ADC_StartCalibration(ADC3);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC3));	 //等待校准结束
}	

 光敏传感器初始化:

//初始化光敏传感器
void Lsens_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);//使能PORTF时钟	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//PF8 anolog输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_Init(GPIOF, &GPIO_InitStructure);	
	Adc3_Init();
}

2.功能一

5档调节灯光亮度可以通过设置按键,让按键来实现对灯光亮度调升和调降,灯光亮度的调节需要设置PWM来调节占空比来调节灯五个不同挡位显现不用的五个灯光亮度;

/***********按键处理函数***********/
void key_handle(u8 key)
{
		 if(key)
		{						   
			switch(key)
			{				 
				case WKUP_PRES:     //手动模式下,按下WK按键,提高一档灯光。	
					delay_ms(10);
				  if(flag_mode == 0)
					{
					  if(LEDlevel<100)LEDlevel+=20;
					}
					break;
					
				case KEY2_PRES:	      //手动模式下,按下KEY2按键,进入自动模式。	
					delay_ms(10);
					flag_mode = 1;
					automatic_mode();
					break;
				
				case KEY1_PRES:	       //手动模式下,按下KEY1按键,降低一档灯光。
					delay_ms(10);
				  if(flag_mode == 0)
					{
					  if(LEDlevel>20)LEDlevel-=20;
	    	   	else LEDlevel=0;
					}
					break;
			}
		}else 
		delay_ms(10); 
		TIM_SetCompare2(TIM3,LEDlevel);	
}

其中,KEY1可以降低灯光档位,WK_UP按键可以提高灯光档位。

case WKUP_PRES:     //手动模式下,按下WK按键,提高一档灯光。    
                    delay_ms(10);
                    if(flag_mode == 0)
                    {
                      if(LEDlevel<100)LEDlevel+=20;
                    }
                    break;

 case KEY1_PRES:           //手动模式下,按下KEY1按键,降低一档灯光。
                    delay_ms(10);
                    if(flag_mode == 0)
                    {
                      if(LEDlevel>20)LEDlevel-=20;
                      else LEDlevel=0;
                    }
                    break;

WK_UP按键按下后,变量LEDlevel会增加20; KEY1按键按下后,变量LEDlevel会减少20;

改变LEDlevel后,会对TIM3的比较值进行赋值。

TIM_SetCompare2(TIM3,LEDlevel);    

 而在main函数中,我们已经对TIM3配置为:

TIM3_PWM_Init(100,0);//ARR为100,CCR为0

 假设我们初始值LEDlevel为0,按下WK_UP按键后,LEDlevel值增加为20,并使用TIM_SetCompare2(TIM3,LEDlevel)赋值给CCR,现在PWM为20/100,为灯光的第一档。

3.功能二

自动调节灯光亮度需要使用光敏传感器与ADC获取当前环境亮度,再根据环境亮度的不同来调控灯的亮度

//读取Light Sens的值
//0~100:0,最暗;100,最亮 
u8 Lsens_Get_Val(void)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<LSENS_READ_TIMES;t++)
	{
		temp_val+=Get_Adc3(LSENS_ADC_CHX);	//读取ADC值
		delay_ms(5);
	}
	temp_val/=LSENS_READ_TIMES;//得到平均值 
	if(temp_val>4000)temp_val=4000;
	return (u8)(100-(temp_val/40)); 
}
//获得ADC3某个通道的值
//ch:通道值 0~16
//返回值:转换结果
u16 Get_Adc3(u8 ch)   
{
  //设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC3,ADC通道,采样时间为239.5周期	  			    
  
	ADC_SoftwareStartConvCmd(ADC3, ENABLE);		//使能指定的ADC3的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC3);	//返回最近一次ADC3规则组的转换结果
} 

 通过Lsens_Get_Val()函数,我们可以采集当前的环境亮度,该函数中调用了ADC的采样函数。

/***********自动模式函数***********/
void automatic_mode(void)
{
     while(flag_mode == 1)
    {
			if(KEY0 == 0)flag_mode = 0;                     //按下KEY0按键,退出自动模式
			else
			{
				if((adcx>0)&&(adcx<=20))                        //当前环境亮度小于20,灯光亮度调至最高的第五档
				{
					TIM_SetCompare2(TIM3,100);
					LEDlevel=100;
				}
				if((adcx>20)&&(adcx<=40))                       //当前环境亮度小于40大于20,灯光亮度调至第四档
				{
					TIM_SetCompare2(TIM3,80);
					LEDlevel=80;
				}
				if((adcx>40)&&(adcx<=60))                       //当前环境亮度小于60大于40,灯光亮度调至第三档
				{
					TIM_SetCompare2(TIM3,60);
					LEDlevel=60;
				}
				if((adcx>60)&&(adcx<=80))                        //当前环境亮度小于80大于60,灯光亮度调至第二档
				{
					TIM_SetCompare2(TIM3,40);
					LEDlevel=40;
				}
				if((adcx>80)&&(adcx<=95))                        //当前环境亮度小于95大于80,灯光亮度调至第一档
				{
					TIM_SetCompare2(TIM3,20);
					LEDlevel=20;
				}
				if((adcx>95)&&(adcx<=100))                       //当前环境亮度小于100大于95,关闭灯光
				{
					TIM_SetCompare2(TIM3,0);
					LEDlevel=0;
				}
			}
	  }
}

 其中,adcx为Lsens_Get_Val()函数的返回值,即当前的环境亮度,自动模式函数中我们对adcx进行判断,在使用TIM_SetCompare2(TIM3,CCR)进行赋值,改变PWM值从而改变了LED0的亮度,实现自动根据环境亮度改变LED亮度。

4.功能三、四、五

通过设置定时器来实现1秒采集一次当前环境灯光亮度;

配置好串口函数所需参数来实现把当前的环境亮度和灯光亮度上传到串口调试助手;

LCD显示板块所需参数进行配置能够实现显示屏显示当前环境亮度和灯光亮度等级。

//定时器4中断服务程序
void TIM4_IRQHandler(void)   //TIM4中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)   //检查指定的TIM中断发生与否:TIM 中断源 
		{
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );          //清除TIMx的中断待处理位:TIM 中断源 
		adcx=Lsens_Get_Val();
		LCD_ShowxNum(30+10*8,140,adcx,3,16,0);                 //显示ADC的值  显示环境亮度
		LCD_ShowxNum(30+10*8,160,LEDlevel,3,16,0);           //显示ADC的值   显示灯光等级
		printf("===========================\r\n\r\n");
		printf("         环境亮度:%d   \r\n\r\n",adcx);                  //串口打印环境亮度
		printf("         灯光亮度:%d   \r\n\r\n",LEDlevel);            //串口打印灯光亮度
		if(flag_mode == 0)printf("\n=========手动模式==========\r\n\r\n\r\n\r\n");
		if(flag_mode == 1)printf("\n=========自动模式==========\r\n\r\n\r\n\r\n");
		}
} 

 在main函数中,我们对TIM4初始化为每1秒中断一次,是通过一下函数实现:

TIM4_Int_Init(1999,35999);//ARR为1999,PSC为35999

 TIM4的时钟频率为72M,计算公式为

72M/(ARR+1)/(PSC+1)

 所以本次项目TIM4的频率为72000000/(1999+1)/(35999+1)为1,所以每1秒中断一次。

中断服务函数中:

adcx=Lsens_Get_Val();

使用变量adcx保存光敏传感器获取环境亮度函数的返回值,该操作则实现了功能三:每秒采集一次环境亮度。

LCD_ShowxNum(30+10*8,140,adcx,3,16,0);                 //显示ADC的值  显示环境亮度
LCD_ShowxNum(30+10*8,160,LEDlevel,3,16,0);           //显示ADC的值   显示灯光等级
printf("===========================\r\n\r\n");
printf("         环境亮度:%d   \r\n\r\n",adcx);                  //串口打印环境亮度
printf("         灯光亮度:%d   \r\n\r\n",LEDlevel);            //串口打印灯光亮度
if(flag_mode == 0)printf("\n=========手动模式==========\r\n\r\n\r\n\r\n");
if(flag_mode == 1)printf("\n=========自动模式==========\r\n\r\n\r\n\r\n");

 在TIM4中断服务函数中,我们通过以上语句分别在LCD与串口打印窗口上输出了环境亮度与灯光亮度,实现了项目的功能四与功能五。

四、调试过程 

1.烧录代码

代码可点赞、收藏和评论留言找我拿哦。

2.显示界面初始

 LSENS_VAL为当前环境亮度,范围为0~100;LED_LEVEL为当前灯光亮度,范围为0~100。

3.手动模式 

 上电后,模式为手动模式Manual mode,灯光亮度为0,在LCD屏上可看到。

(1)按下WK_UP按键,灯光亮度增加一档,灯光亮度值为20。再次按下WK_UP按键,灯光亮度增加至第二档,灯光亮度值为40;

第一档灯光亮度为20

第二档灯光亮度为40

(2) 按下KEY1按键,灯光亮度降低一档,灯光亮度值为20。

4.自动模式

(1) 按下KEY2按键,进入自动模式Automatic mode:

  进入自动模式后,光敏传感器将自动感应环境亮度,并且根据环境亮度改变灯光亮度;

(2)盖住光敏传感器使得检测到的环境亮度为0,灯光亮度自动调节为100,最高档。

 (3)打开手电筒照射光敏传感器,使得检测到的环境亮度为97,灯光亮度自动调节为0。

(4)按下KEY0按键,退出自动模式Automatic mode,回到手动模式Manual mode

5.串口显示

(1)连接上串口线,打开XCOM串口调试助手(网盘资料中有)。

(2)手动模式

(3)自动模式 


总结

到这里你已经完成属于你的第一个STM32小项目啦!!!你已经学习收获了许多功能: PWM、LED、KEY、UART、ADC、光敏传感器等等。希望能在后续关注我的文章,感谢观看!!

  • 94
    点赞
  • 239
    收藏
    觉得还不错? 一键收藏
  • 98
    评论
STM32F103正点原子精英版战舰是一款基于ARM Cortex-M3内核的微控制器开发板,配备了丰富的外设资源,包括多个通信接口、GPIO口、模数转换器等。正点原子公司给出了开源的固件库和示例代码,方便开发者使用。 在该开发板上实现示波器功能需要利用其中的ADC模数转换器、DMA控制器、LCD显示等资源。示波器的原理是通过采样输入信号并将其转换为数字信号后,通过DMA传输到内存中,再通过LCD实时绘制波形图。 首先,需要使用开发板上的ADC模块对输入信号进行采样。可以通过设置ADC控制寄存器来配置采样精度、采样速率等参数。采样数据可以通过DMA控制器直接传输到内存中,减少了CPU的负担。 然后,利用采样得到的数据,在LCD上绘制波形图。可以使用开发板上的TFT LCD模块,通过驱动程序将数据转换为对应的像素点,并实时刷新到LCD屏幕上,从而形成波形图。可以选择不同的显示方式,例如线性、点阵等,以适应不同的需求。 对于更高级的示波器功能,例如闭锁显示、触发功能、自动测量等,还需要进一步的算法和逻辑设计。可以通过编写相应的软件程序,结合硬件资源,实现这些功能。 总之,基于STM32F103正点原子精英版战舰的示波器的实现涉及到采样、数字信号处理和波形绘制等多个方面。通过充分利用该开发板的硬件资源和开源的固件库,可以实现一个功能强大的示波器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值