基於stm32的仿真實現溫溼度檢測,蜂鳴器,跑馬燈及其速度的控制

這幾天,學習組織了爲期5天的關於基於stm32的仿真的課程設計,最後一天,我們要進行實訓項目的測驗,要獨立完成一個項目,具體有以下要求:

原理圖繪製:

按鍵 6個

LED燈 4盞+1盞

蜂鳴器 1個

溫溼度傳感器 1個

要求:

(1)按下按鍵key1 , 開啓LED跑馬燈(4盞)

(2)按下按鍵key2 , 關閉LED跑馬燈(4盞)

(3)按下按鍵key3 , 控制獨立的LED 每500ms 閃爍一次-----使用定時器   TIM_cmd(TIM2,ENABLE)

(4)按下按鍵key4 , 關閉獨立的LED 閃爍-----使用定時器   TIM_cmd(TIM2,DISENABLE)

(5)按下按鍵key5 , 開啓蜂鳴器

(6)按下按鍵key6 , 關閉蜂鳴器

(7)溫溼度檢測報警,當溫度超過30度或者溼度超過80%時,蜂鳴器報警

加分項1:

       添加2個按鍵

       按下按鍵7,跑馬燈加速,按下按鍵8,跑馬燈減速

滿分項:

       添加顯像管(seg),把溫溼度顯示在顯像管中。

因爲博主並不是主攻嵌入式開發的,所以5天時間對於嵌入式開發的研究還遠遠不夠,因此,對於此次作業項目,並沒有完成最後一個滿分項,但我還是想將此次完成的項目進行記錄,以作紀念。

 

一、Protues仿真部分

二、keil工程

#include "stm32f4xx.h"
#include "sys.h"



int SIGN = 10000;

void delay(int x)
{
	int i,j;
	for(i=0;i<x;i++)
		for(j=0;j<SIGN;j++);
}


//延時函數--毫秒級別
//VAL計數器是24bit的寄存器,所以最大值是16777215
//所以nms的最大值是 199
void delay_ms(int nms){
	uint32_t temp;
	
	//延時nms毫秒需要的計數數值,把它交給重載計數器
	SysTick->LOAD = 84000*nms;
	
	//將VAL計數器的數值賦值爲0
	SysTick->VAL = 0;
	
	//將控制器的0bit位賦值爲1,開啓計數
	SysTick->CTRL |= 0x1;
	
	//循環檢測控制器得到16bit,當它爲1的時候,表示計數器由1減到0了
	do{
		temp = SysTick->CTRL;
	}while( !(temp>>16 & 1) && (temp&0x1));
	
	//temp>>16 & 1 結果爲真的時候,表示16bit數值已經爲1了,要跳出循環
	//結果爲假的時候,表示16bit數值還是0,要繼續循環
	//但是while的判斷語句是  邏輯真--循環  邏輯假---結束
	//所以在最外面加上 ! 取反。
	//temp&0x1爲真是要求控制器的0bit位數值爲1,即計數器一直在計數
	
	//將控制器的0bit位賦值爲0,停止計數
	SysTick->CTRL &= ~0x1;
	
	//將計數器數值設置爲0
	SysTick->VAL = 0;
}


//1微秒是84次脈衝
void delay_us(int nus){
	uint32_t temp;
	
	//延時nms毫秒需要的計數數值,把它交給重載計數器---會忽略小數
	SysTick->LOAD = 84*nus;
	
	SysTick->VAL = 0;
	
	SysTick->CTRL |= 0x1;
	
	do{
		temp = SysTick->CTRL;
	}while( !(temp>>16 & 1) && (temp&0x1));
	
	SysTick->CTRL &= ~0x1;
	
	SysTick->VAL = 0;
}

//配置LED引腳
void led(){
		//定義GPIO結構體
	GPIO_InitTypeDef a;
	
	//使能LED燈GPIO分組的時鐘
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//GPIO結構體賦值---也就是選擇引腳的配置參數
	a.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_9;//選中引腳
	a.GPIO_Mode = GPIO_Mode_OUT;//配置輸出模式----是主動設置引腳電平高低
	a.GPIO_Speed = GPIO_Speed_100MHz;//選擇高速
	a.GPIO_OType = GPIO_OType_PP;//推輓輸出
	a.GPIO_PuPd = GPIO_PuPd_NOPULL;//無上下拉電阻
	
	//配置GPIO的引腳函數---將選好的配置放入到GPIOA組裏面
	GPIO_Init(GPIOA,&a);
	
	
}

//初始化蜂鳴器
void beep_init()
{
	//定義GPIO結構體
	GPIO_InitTypeDef a;
	
	//使能LED燈的GPIO分組
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	//對GPIO結構體進行賦值
	a.GPIO_Pin  = GPIO_Pin_8;
	a.GPIO_Mode = GPIO_Mode_OUT;//配置輸出模式----是主動設置引腳電平高低
	a.GPIO_Speed = GPIO_Speed_100MHz;//選擇高速
	a.GPIO_OType = GPIO_OType_PP;//推輓輸出
	a.GPIO_PuPd = GPIO_PuPd_NOPULL;//無上下拉電阻
	
	//配置GPIO的引腳函數---將選好的配置放入到GPIOA組裏面
	GPIO_Init(GPIOB,&a);

	//讓蜂鳴器停下
	PEout(8)=0;
}

//蜂鳴器響
void beep_up(){
	int i = 0;
	for(i=0;i<2;i++)
			delay_ms(100);

		PBout(8)=1;
		
		for(i=0;i<2;i++)
			delay_ms(100);

		PBout(8)=0;
}

//配置開關引腳
void btns(){
	
	GPIO_InitTypeDef k;//定義GPIO結構體
	EXTI_InitTypeDef b;//定義外部中斷控制器結構體
	NVIC_InitTypeDef c;//定義中斷配置結構體
	
	//使能KEY按鍵GPIO分組的時鐘
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	
	//使能EXTI的時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	//GPIO結構體賦值---也就是選擇引腳的配置參數
	k.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	k.GPIO_Mode =GPIO_Mode_IN;//配置輸入模式---是檢測引腳電平高低
	k.GPIO_Speed=GPIO_Speed_100MHz;//選擇高速
	k.GPIO_PuPd = GPIO_PuPd_NOPULL;//無上下拉電阻
	GPIO_Init(GPIOE,&k);
	
	
	//發生外部中斷時的引腳
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource0);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource1);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource5);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource6);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource7);

	
	//對EXTI結構體進行賦值
	b.EXTI_Line = EXTI_Line0 | EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4 | EXTI_Line5 | EXTI_Line6 | EXTI_Line7;//選擇輸入線0,1,2,3,4,5,6,7
	b.EXTI_Mode = EXTI_Mode_Interrupt;//選擇中斷
	b.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿觸發
	b.EXTI_LineCmd = ENABLE;//使能
	EXTI_Init(&b);//根據配置好的EXTI參數初始化外部中斷控制器
	
	//開啓跑馬燈
	c.NVIC_IRQChannel =  EXTI0_IRQn;//通道爲EXTI0_IRQHandler
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 3;//搶佔優先級
	c.NVIC_IRQChannelSubPriority = 0;//響應優先級
	//根據配置好的NVIC參數初始化中斷服務
	NVIC_Init(&c);
	
	//關閉跑馬燈
	c.NVIC_IRQChannel =  EXTI1_IRQn;//通道爲EXTI1_IRQHandler
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 0;
	c.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&c);
	
	//開啓獨立燈
	c.NVIC_IRQChannel =  EXTI2_IRQn;//通道爲EXTI2_IRQHandler
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 1;//搶佔優先級
	c.NVIC_IRQChannelSubPriority = 0;//響應優先級
	//根據配置好的NVIC參數初始化中斷服務
	NVIC_Init(&c);
	
	//關閉獨立燈
	c.NVIC_IRQChannel =  EXTI3_IRQn;//通道爲EXTI3_IRQHandler
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 0;
	c.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&c);
	
	//開啓蜂鳴器
	c.NVIC_IRQChannel =  EXTI4_IRQn;//通道爲EXTI4_IRQHandler
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 2;
	c.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&c);
	
	//關閉蜂鳴器等
	c.NVIC_IRQChannel =  EXTI9_5_IRQn;
	c.NVIC_IRQChannelCmd = ENABLE;//使能
	c.NVIC_IRQChannelPreemptionPriority = 1;
	c.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&c);
	

}


//目的:初始化TIM4,讓定時器每1秒發生五次中斷
//當前輸入頻率 84MHz , 可以設置預分頻器 8399 重裝載值 9999
void tim4_init(){
	
	TIM_TimeBaseInitTypeDef a;//定義定時器的結構體
	NVIC_InitTypeDef b;//定義中斷結構體
	
	//開啓TIM4的時鐘使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	//設置時基單元
	a.TIM_Prescaler = 8399;//預分頻器數值
	a.TIM_Period = 4999;//重裝載值
	a.TIM_CounterMode = TIM_CounterMode_Up;//計數器遞增模式
	//a.TIM_CounterMode = 0;//定時的時候用不到濾波
	//a.TIM_RepetitionCounter;//重複計數器僅限高級定時器使用
	TIM_TimeBaseInit(TIM4, &a);

	//初始化中斷配置
	b.NVIC_IRQChannel = TIM4_IRQn;//中斷服務通道
	b.NVIC_IRQChannelCmd = ENABLE;//中斷使能
	b.NVIC_IRQChannelPreemptionPriority = 2;//搶佔優先級
	b.NVIC_IRQChannelSubPriority = 0;//響應優先級
	NVIC_Init(&b);
	
	
	
	
}

void TIM4_IRQHandler()
{
	//判斷中斷是否真的發生----檢查中斷標誌位是否爲1
	if( TIM_GetITStatus(TIM4,TIM_IT_Update) == SET )
	{
		//LED燈閃爍
		PAout(9) ^=1;
		
		
		//清除中斷標誌位
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	}
}

//中斷服務函數
void EXTI0_IRQHandler()
{
	SIGN=10000;
	//判斷中斷是否真的發生
	while(EXTI_GetITStatus(EXTI_Line0)==SET)//確實發生了中斷
	{
				PAout(0)=1;
				delay(200);

				PAout(0)=0;
				PAout(1)=1;
				delay(200);
	
				PAout(1)=0;
				PAout(2)=1;
				delay(200);

				PAout(2)=0;
				PAout(3)=1;
				delay(200);
				PAout(3)=0;												
	}
}


void EXTI1_IRQHandler()
{
	//判斷中斷是否真的發生
	if(EXTI_GetITStatus(EXTI_Line1)==SET)//確實發生了中斷
	{
			
		//清除中斷標誌位,防止CPU認爲中斷在不停的發生
		EXTI_ClearITPendingBit(EXTI_Line0);
		//清除中斷標誌位,防止CPU認爲中斷在不停的發生
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}



void EXTI2_IRQHandler()
{
		//判斷中斷是否真的發生
		if(EXTI_GetITStatus(EXTI_Line2)==SET)//確實發生了中斷
		{
				//開啓定時器中斷
				TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
				//開啓定時器
				TIM_Cmd(TIM4,ENABLE);
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line2);			
		}
		
}

void EXTI3_IRQHandler()
{
		//判斷中斷是否真的發生
		if(EXTI_GetITStatus(EXTI_Line3)==SET)//確實發生了中斷
		{	
				//關閉定時器中斷
				TIM_ITConfig(TIM4,TIM_IT_Update,DISABLE);
				//關閉定時器
				TIM_Cmd(TIM4,DISABLE);
				PAout(9)=0;			
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line3);
		}
}

void EXTI4_IRQHandler()
{
		//判斷中斷是否真的發生
		while(EXTI_GetITStatus(EXTI_Line4)==SET)//確實發生了中斷
		{	
				//開啓蜂鳴器
				beep_up();
				
		}
		PBout(8)=0;
}

void EXTI9_5_IRQHandler()
{
		//判斷中斷是否真的發生
		if(EXTI_GetITStatus(EXTI_Line5)==SET)//確實發生了中斷
		{	
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line4);
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line5);
		}
		//判斷中斷是否真的發生
		if(EXTI_GetITStatus(EXTI_Line0)==SET && EXTI_GetITStatus(EXTI_Line6)==SET)//確實發生了中斷
		{	
				SIGN = 2000;
				
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line6);
		}
		//判斷中斷是否真的發生
		if(EXTI_GetITStatus(EXTI_Line0)==SET && EXTI_GetITStatus(EXTI_Line7)==SET)//確實發生了中斷
		{	
				SIGN=20000;
				
				//清除中斷標誌位,防止CPU認爲中斷在不停的發生
				EXTI_ClearITPendingBit(EXTI_Line7);
		}
}



//空閒狀態
void idle(){
		//定義GPIO結構體
	GPIO_InitTypeDef a;
	
	//使能按鍵GPIO分組的時鐘
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	
	//GPIO結構體賦值---也就是選擇引腳的配置參數
	a.GPIO_Pin  = GPIO_Pin_0;//選中0引腳
	a.GPIO_Mode = GPIO_Mode_OUT;//配置輸出模式----是主動設置引腳電平高低
	a.GPIO_Speed = GPIO_Speed_100MHz;//選擇高速
	a.GPIO_OType = GPIO_OType_PP;//推輓輸出
	a.GPIO_PuPd = GPIO_PuPd_NOPULL;//無上下拉電阻
	
	//配置GPIO的引腳函數---將選好的配置放入到GPIOA組裏面
	GPIO_Init(GPIOD,&a);
	PDout(0)=1;
	
}

void work(){
	//定義GPIO結構體
	GPIO_InitTypeDef k;
	
	//使能KEY按鍵GPIO分組的時鐘
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	//GPIO結構體賦值---也就是選擇引腳的配置參數
	k.GPIO_Pin = GPIO_Pin_0;
	k.GPIO_Mode =GPIO_Mode_IN;//配置輸入模式---是檢測引腳電平高低
	k.GPIO_Speed=GPIO_Speed_100MHz;//選擇高速
	k.GPIO_PuPd = GPIO_PuPd_NOPULL;//無上下拉電阻
	//k.GPIO_OType 不需要設置,因爲電流沒經過輸出控制器
	GPIO_Init(GPIOD,&k);
}

//開始啓動
void start(){
	idle();
	PDout(0)=0;
	delay_ms(18);
	PDout(0)=1;
	delay_us(30);
	work();
}

//檢測DHT11是否啓動
int detect(){
	int i=0,j=0;

	while(PDin(0)==0){
		delay_us(10);
		i++;
		if(i>10){
			return -1;
		}
	}
	while(PDin(0)==1){
		delay_us(10);
		j++;
		if(j>10){
			return -1;
		}
	}
	return 0;
}

//接收輸入數據
int readdata(){
	
	int a=0,i=0;
	for(i=0;i<8;i++){
		
		while(PDin(0)==0);
		delay_us(50);
		if(PDin(0)==1)
			a |=1<<(7-i);
		while(PDin(0)==1);
		
	}
	return a;
}

//判斷溫溼度
void judge(int T,int H){
		if(T>30 || H>80){
			
		//開啓蜂鳴器
		beep_up();
			
		}
		
}




int main()
{
	
	int i,data[5];
	int T=0,H=0;
	//設置滴答定時器的輸入頻率
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
	//設置中斷優先級分組
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	led();
	tim4_init();
	btns();
	beep_init();
	
	while(1)
	{
	
		for(i=0;i<5;i++)
			delay_ms(100);
		
		start();
		if(detect() != 0)
			continue;
		for(i=0;i<5;i++)
			data[i]=readdata();
		T=data[2];
		H=data[0];
		
		judge(T,H);
		
	
	}
	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章