Proteus仿真基於stm32的PM2.5報警器

要求:

1.使用stm32做主控,芯片自選
2.使用LCD1602顯示PM2.5的上下限值,並顯示PM2.5的當前值
3.使用按鍵調節上下限的值
4.使用滑動變阻器代替PM2.5吸合傳感器
5.使用ADC0832,測量滑動變阻器的電壓代表PM2.5的當前值
6.若PM2.5的值低於下限報警(蜂鳴器)高於上限報警並繼電器吸合

開發工具

  • 標準庫
  • Keil
  • Protues

Protues&&電路圖

Protues這個軟件好久沒用了,很多都忘記了,最近下載了一個8.9版本的,真的挺好看的。
下面說一下,我使用的時候遇到的小問題:

  • 使用STM32,首先就是要畫最小系統:晶振電路,復位電路。但是好奇怪,我在芯片上居然看不到電源,後來發現,在工具欄Design裏面有一個configure Power Rails裏面就可以設置了
    在這裏插入圖片描述
    在這裏插入圖片描述

  • 點一盞LED燈我點了一個小時還沒點亮,這是最基本的東西,應該不會錯纔對。
    結果發現,LED燈要設置一下不然真的點不亮。雙擊LED燈會出現如下畫面,圈住的那裏,如果是I/O口輸入高低電平去控制LED的亮滅就一定要選擇digital,如果使用繼電器去控制的話就改爲analog
    在這裏插入圖片描述

  • 後面也沒有遇到什麼問題了,下面是我這個小作品的電路圖
    在這裏插入圖片描述

程序

  • LCD1602
    LCD1602在學51單片機的時候經常使用,但是用在STM32上和51上還是有點小區別,51的時候可以整個P0/P1/P2口一起操作,可是32我不會整個PA/PB…一起操作所以命令只能單個I/O操作,不過也還好不會太麻煩。
    顯示字符的話就去查看ACSII碼,然後操作對應的I/O口即可
    以下是部分代碼:(太多了不好全部顯示)
/*---------------------------------------LCD引腳初始化-----------------------------------*/
void LCD_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(LCD_CLOCK,ENABLE);
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin=LCD_D0_PIN|LCD_D1_PIN|LCD_D2_PIN|LCD_D3_PIN|
							 LCD_D4_PIN|LCD_D5_PIN|LCD_D6_PIN|LCD_D7_PIN|
							 LCD_E_PIN|LCD_RW_PIN|LCD_RS_PIN;
	GPIO_Init(LCD_GPIO_PORT,&GPIO_InitStruct);
}

/*-----------------------------------清屏命令------------------------------------------*/
void LcdCom_0x01(void)
{
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_RS_PIN);//RS = 0;	  選擇發送命令
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_RW_PIN);//RW = 0;	  選擇寫入
	GPIO_SetBits(LCD_GPIO_PORT,LCD_D0_PIN);
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_D1_PIN|LCD_D2_PIN|LCD_D3_PIN|LCD_D4_PIN|LCD_	D5_PIN|LCD_D6_PIN|LCD_D7_PIN);
	Lcd1602_Delay1ms(5);		//等待數據穩定
	GPIO_SetBits(LCD_GPIO_PORT,LCD_E_PIN);//E = 1;寫入時序
	Lcd1602_Delay1ms(25);	  //保持時間
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_E_PIN);//E = 0;關閉使能
}

/*------------------------------字符A---------------------------------*/
void LcdData_A(void)			
{
	GPIO_SetBits(LCD_GPIO_PORT,LCD_RS_PIN);//RS = 1;	選擇輸入數據
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_RW_PIN);//RW = 0;	選擇寫入
	GPIO_SetBits(LCD_GPIO_PORT,LCD_D0_PIN|LCD_D6_PIN);//寫入數據
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_D4_PIN|LCD_D1_PIN|LCD_D2_PIN|
	LCD_D3_PIN|LCD_D5_PIN|LCD_D7_PIN);
	Lcd1602_Delay1ms(5);
	GPIO_SetBits (LCD_GPIO_PORT,LCD_E_PIN);//E = 1;   //寫入時序
	Lcd1602_Delay1ms(25);   //保持時間
	GPIO_ResetBits(LCD_GPIO_PORT,LCD_E_PIN);//E = 0;
}
/*-----------------------------初始化LCD---------------------*/
void LCD_Init(void)						  //LCD初始化子程序
{
 	LcdCom_0x38();  //開顯示
	Lcd1602_Delay1ms(25);
	LcdCom_0x38();
	Lcd1602_Delay1ms(25);
	LcdCom_0x38();
	Lcd1602_Delay1ms(25);
	LcdCom_0x0C();//LcdWriteCom(0x0c);  //開顯示不顯示光標
	LcdCom_0x06();//LcdWriteCom(0x06);  //寫一個指針加1
	LcdCom_0x01();//LcdWriteCom(0x01);  //清屏
	Lcd1602_Delay1ms(25);
	LcdCom_0x0C();
}
  • ADC0832
    這塊芯片我也第一次用,很多人在51上使用這塊芯片,他們都是把DO和DI接在一起,一開始我打算移植一下別人的51的代碼就應該可以用,是因爲我太懶,後來發現移植了也不可以用,又不知道有什麼問題,後來還是自己寫了。時許這種東西還是相信自己吧。
  • 51 可以把DO/DI接在一起,共用一個I/O口,可是stm32不可以,因爲stm32初始化引腳的時候要設置模式 DI是輸出模式,DO是輸入模式
    ADC0832的時序:
    1.CS:片選,通信過程中全程保持低電平
    2.CLK第一個脈衝下降前DI必須爲低電平,表示起始信號
    3.第二第三個脈衝下降前DI應輸入兩位數據用於選擇通道,CH0=10’b CH1=11’b
    4.第三個脈衝下降後DI無效,此後利用DO進行數據轉換讀取
    5.第四個脈衝下降後,開始又DO端進行數據轉換最高位開始讀,隨後,每一個脈衝的下降沿,DO都會輸出下一位數據,一共八位數據。
    6.最後傳輸完成後一定要把CS拉高,不然你讀完的數據,就會出現有數據變動然後數據變爲0,再也不能測數據。
    代碼如下:
#ifndef  __ADC0832__H
#define  __ADC0832__H


#include "stm32f10x.h"

#define AD_CLOCK							RCC_APB2Periph_GPIOB
#define AD_GPIO_PORT						GPIOB
#define AD_CS_PIN							GPIO_Pin_0
#define AD_CLK_PIN							GPIO_Pin_1
#define AD_DO_PIN							GPIO_Pin_3
#define AD_DI_PIN							GPIO_Pin_2

#define ADDO_READ()							GPIO_ReadInputDataBit(AD_GPIO_PORT,AD_DO_PIN)

#define ADCLK0								GPIO_ResetBits(AD_GPIO_PORT,AD_CLK_PIN)
#define ADCLK1								GPIO_SetBits(AD_GPIO_PORT,AD_CLK_PIN)
#define ADCS0								GPIO_ResetBits(AD_GPIO_PORT,AD_CS_PIN)
#define ADCS1								GPIO_SetBits(AD_GPIO_PORT,AD_CS_PIN)
#define ADDO0								GPIO_ResetBits(AD_GPIO_PORT,AD_DO_PIN)
#define ADDO1								GPIO_SetBits(AD_GPIO_PORT,AD_DO_PIN)
#define ADDI0								GPIO_ResetBits(AD_GPIO_PORT,AD_DI_PIN)
#define ADDI1								GPIO_SetBits(AD_GPIO_PORT,AD_DI_PIN)

void DELAY_Us(void);
void ADC0832_Config(void);
void ADC0832_start(void);
uint8_t ADC0832_read(void);


#endif
/*-----------------------------ADC0832引腳初始化---------------------------------*/
void ADC0832_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(AD_CLOCK,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin=AD_CS_PIN|AD_CLK_PIN|AD_DI_PIN;
	GPIO_Init(AD_GPIO_PORT,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin=AD_DO_PIN;
	GPIO_Init(AD_GPIO_PORT,&GPIO_InitStruct);

}



/*--------------------------初始化ADC0832---------------------------*/

void ADC0832_start(void)
{
	ADCS0;//片選信號置零,芯片使能
	ADDO0;//ADDO爲高阻態
	DELAY_Us();
	DELAY_Us();
	
	ADCLK0;
	DELAY_Us();
	DELAY_Us();
	ADDI1;//第一個脈衝下降前,DI必須爲1
	/************起始信號*************/
	ADCLK1;//第一個脈衝上升沿
	DELAY_Us();
	DELAY_Us();
	ADCLK0;//第一個脈衝下降沿
	DELAY_Us();
	DELAY_Us();

	/**********通道選擇**************/
	ADDI1;
	ADCLK1;//第二個脈衝上升沿
	DELAY_Us();
	DELAY_Us();
	ADCLK0;//第二個脈衝下降沿
	DELAY_Us();
	DELAY_Us();
	ADDI0;//選擇通道0
	ADCLK1;//第三個脈衝上升沿
	DELAY_Us();
	DELAY_Us();
	ADCLK0;//第三個脈衝下降沿
	DELAY_Us();
	DELAY_Us();
}

/*-----------------------啓動ADC0832進行轉換-------------------------------*/

uint8_t ADC0832_read(void)
{
	uint8_t temp=0;
	uint16_t i;
	ADC0832_start();
	ADDI0;//DI轉換成高阻態
	ADDO1;//使DO脫離高阻態
/*通道選擇結束開始讀取轉換後的二進制數*/
	ADCLK1;//第四個脈衝上升沿
	DELAY_Us();
	ADCLK0;//ADCLK=0;//第四個脈衝下降沿,開始讀數,一下進行判斷和處理,共8次
	DELAY_Us();
	for(i=0;i<8;i++)
	{
		ADCLK1;
		DELAY_Us();
		ADCLK0;
		
		
		if(ADDO_READ()==1)
		{
			temp |=0x01;
		}
		else
		{
			temp &=0xfe;
		}
		temp=temp<<1;
		DELAY_Us();

	}
	ADCS1;
	ADC_date=temp;
	return ADC_date;
}
  • 其他的就是普通的控制I/O 沒什麼特別,這樣就完成了,PM2.5報警器

實驗效果如下圖
在這裏插入圖片描述

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