STM32智能台灯设计及实现

器材:LED,独立按键,OLED,光敏电阻,stm32f1。

功能1,由环境亮度控制LED亮度模式: 按下KEY1进入自动调节亮度模式,OLED实时显示环境光照强度和PWM占空比,按下KEY4退出该模式。使用函数关系(这里我取的最简单的一次函数)建立光敏电阻采集转换后的ADC值与PWM的CCR3的值,从而使LED灯的亮度连续变化。

while(1)
{
key1=KEY_Scan(0);	
adcx=Lsens_Get_Val();
TIM_SetCompare2(TIM3,1.8*adcx-44);
OLED_ShowNum(0,0,adcx,2,16);
OLED_ShowString(20,0,"%",16);
OLED_ShowNum(0,2,1.8*adcx-44,2,16);
if(key1==KEY4_PRES)
 {  
 TIM_SetCompare2(TIM3,100);
 TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);			
 LED_Clear();
 break;
 }
}

功能2,按下KEY2进入按键控制模式:KEY1亮度递减,KEY2亮度递增,KEY3直接变为最亮模式,OLED实时显示PWM占空比,按下KEY4退出该模式。

while(1)
{					
  TIM_SetCompare2(TIM3,ccrx);
  OLED_ShowNum(0,0,ccrx,2,16);
  key2=KEY_Scan(0);	
  if(key2==KEY1_PRES)
  {ccrx+=20;TIM_SetCompare2(TIM3,ccrx);
  OLED_ShowNum(0,0,ccrx,2,16);}
					 
if(ccrx==100&&key2==KEY1_PRES)ccrx=0;
					 
if(key2==KEY2_PRES)
 {ccrx-=20;TIM_SetCompare2(TIM3,ccrx);OLED_ShowNum(0,0,ccrx,2,16);}
					
if(ccrx==0&&key2==KEY2_PRES)ccrx=100;
					 
if(key2==KEY3_PRES)
{ccrx=0;TIM_SetCompare2(TIM3,ccrx);OLED_ShowNum(0,0,ccrx,2,16);}
					
if(key2==KEY4_PRES)
 { TIM_SetCompare2(TIM3,100);
  TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	
 OLED_Clear();ccrx=0;break;}
} 

功能3,按下KEY3进入定时模式:每按下一次KEY1分钟数加一,没每按下一次KEY2秒数加10,按下KEY3进入定时模式,LED变亮,OLED实时显示分钟数和秒数,当分钟数和秒数均归零后LED灯熄灭,按下KEY4退出该模式。

while(1)
 {
	OLED_ShowNum(0,0,min,2,16);
	OLED_ShowString(20,0,"m",16);
	OLED_ShowString(30,0,"i",16);
	OLED_ShowString(40,0,"n",16);
	OLED_ShowNum(60,0,sec,2,16);
	 OLED_ShowString(80,0,"s",16);
				  
	TIM_SetCompare2(TIM3,100);
	key3=KEY_Scan(0);	//µÃµ½¼üÖµ
	if(key3==KEY1_PRES)
   { TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	sec+=10;}
	if(key3==KEY2_PRES)
	{ TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	min+=1;}
	 if(key3==KEY3_PRES)
	 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	{
	if(cnt==1)TIM_SetCompare2(TIM3,0);
	 else TIM_SetCompare2(TIM3,100);
	}
	if(key3==KEY4_PRES)
	 { OLED_Clear(); TIM_SetCompare2(TIM3,100);
	   TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	
						
		sec=min=0;break;}
}

原理:令定时器2的ARR=10000-1,PSC=7200-1,使得每1s执行一次中断服务函数,在中断服务函数和mian.c中使用if语句和对变量的灵活赋值达到了想要的效果。

定时器2中断服务函数:

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		
		cnt=1;
		num++;
		if(num==11)num=0;
		if(sec==0&&min==0)cnt=0;
		if(cnt==1)
		{
			if(sec==0&&min>0)min--,sec=60;
			if(sec>0)sec--;
			if(sec==0&&min>0)sec=60,min--;
			if(sec==0&&min==0)cnt=0;
		}
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

在main.c用extern声明num,sec,min,cnt变量。

mian.c:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "adc.h"
#include "lsens.h"
#include "myiic.h"
#include "oled.h"
#include "dht11.h"
#include "rtc.h"
vu8 key0=0;	 
 	vu8 key1=0;
	vu8 key2=0;
	vu8 key3=0;
	u8 adcx;
  u8 time=0;
  u8 ccrx=0;	
 u16 num=0,sec=0,min=0;
u8 cnt=0;
 

void Mode_1(void);
void Mode_2(void);
void Mode_3(void);
void Mode_4(void);

 int main(void)
 {		
	delay_init();	    	 //
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //
	uart_init(115200);	
 	//LED_Init();			     //
	 KEY_Init();         //
	 TIM2_Int_Init(10000-1,7200-1);
 	TIM3_PWM_Init(100,0);	 //
	 Lsens_Init();//
	 OLED_Init();			//
	 OLED_Clear(); 
	 LED0=0;
while(1)
{
key0=KEY_Scan(0);	//
		 
if(key0==KEY1_PRES)//
 {
	OLED_Clear();
				 
   Mode_1();
}
			
if(key0==KEY2_PRES)//
{
 OLED_Clear();
 Mode_2();
}
if(key0==KEY3_PRES)//
{
OLED_Clear();
 Mode_3();
}
			
if(key0==KEY4_PRES)
 Mode_4();
 }
}

 void Mode_1(void)
 {
  while(1)
{
  key1=KEY_Scan(0);	//
  adcx=Lsens_Get_Val();
 TIM_SetCompare2(TIM3,1.8*adcx-44);
 OLED_ShowNum(0,0,adcx,2,16);
 OLED_ShowString(20,0,"%",16);
 OLED_ShowNum(0,2,1.8*adcx-44,2,16);
 if(key1==KEY4_PRES)
 { TIM_SetCompare2(TIM3,100);
    TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);			
	OLED_Clear();break;}
 }
  }
 void Mode_2(void)
 {
while(1)
 {			
     TIM_SetCompare2(TIM3,ccrx);
	OLED_ShowNum(0,0,ccrx,2,16);
	key2=KEY_Scan(0);	//
	if(key2==KEY1_PRES)
	 {ccrx+=20;TIM_SetCompare2(TIM3,ccrx);OLED_ShowNum(0,0,ccrx,2,16);}
	 //Ö𽥱䰵
	if(ccrx==100&&key2==KEY1_PRES)ccrx=0;
	 if(key2==KEY2_PRES)
		{ccrx-=20;TIM_SetCompare2(TIM3,ccrx);OLED_ShowNum(0,0,ccrx,2,16);}
		 //Öð½¥±äÁÁ
	if(ccrx==0&&key2==KEY2_PRES)ccrx=100;
	 if(key2==KEY3_PRES)
	 {ccrx=0;TIM_SetCompare2(TIM3,ccrx);OLED_ShowNum(0,0,ccrx,2,16);}
		 //×îÁÁ
	if(key2==KEY4_PRES)
		{ TIM_SetCompare2(TIM3,100);
	 TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	
	OLED_Clear();ccrx=0;break;}
	 } 
 }

 void Mode_3(void)
 {
     while(1)
 {
	OLED_ShowNum(0,0,min,2,16);
	OLED_ShowString(20,0,"m",16);
	OLED_ShowString(30,0,"i",16);
	OLED_ShowString(40,0,"n",16);
	OLED_ShowNum(60,0,sec,2,16);
	OLED_ShowString(80,0,"s",16);
	TIM_SetCompare2(TIM3,100);
    key3=KEY_Scan(0);	//
	if(key3==KEY1_PRES)
	{ TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	sec+=10;}
		if(key3==KEY2_PRES)
	 { TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	min+=1;}
	if(key3==KEY3_PRES)
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	 {
		if(cnt==1)TIM_SetCompare2(TIM3,0);
	    else TIM_SetCompare2(TIM3,100);
	 }
	if(key3==KEY4_PRES)
	{ OLED_Clear(); TIM_SetCompare2(TIM3,100);
	TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	
	sec=min=0;break;}
	}
 }
 void Mode_4(void)
 {
  while(1)
  { OLED_Clear();TIM_SetCompare2(TIM3,100);
	TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);	break;}
 }
 
 

遇到的坑:

  1. 在同一个工程中使用定时器的两个功能时,要使用两个不同的定时器(本实验使用的定时器二的中断和定时器三的PWM),否则达不到应有的效果。
  2. 在led.c设置GPIO模式为推挽输出,在time.c的PWM设置GPIO模式为复用推挽输出,使得在程序中诸如LED=0;LED01;等语句失效。解决办法:可不调用LED初始化函数,在PWM初始化后,若要实现LED=0;或LED=1;可使用TIM_SetComparex();函数使占空比为0或最大值达到同样效果。
  3. 定时器2初始化的中断会干扰其他模式的正常运行。可使用TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);函数在对应处,使定时器2失能
物联沃分享整理
物联沃-IOTWORD物联网 » STM32智能台灯设计及实现

发表评论