器材: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;}
}
遇到的坑:
- 在同一个工程中使用定时器的两个功能时,要使用两个不同的定时器(本实验使用的定时器二的中断和定时器三的PWM),否则达不到应有的效果。
- 在led.c设置GPIO模式为推挽输出,在time.c的PWM设置GPIO模式为复用推挽输出,使得在程序中诸如LED=0;LED01;等语句失效。解决办法:可不调用LED初始化函数,在PWM初始化后,若要实现LED=0;或LED=1;可使用TIM_SetComparex();函数使占空比为0或最大值达到同样效果。
- 定时器2初始化的中断会干扰其他模式的正常运行。可使用TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);函数在对应处,使定时器2失能