STM32 f407 溫濕度采集報警


軟件

keil5

實現

1.使用stm32f407中的DS18B20傳感器采集空氣溫度
2.使用stm32f407中的DHT11傳感器采集空氣的溫度和濕度
3.顯示到stm32f407的LCD液晶顯示器上
4.當溫度超過30℃時,led燈 和 電磁繼電器控制的燈閃爍,蜂鳴器持續響
5.當溫度低於30℃時,一切恢復

效果

效果

源碼

main.c

#include "led.h"
#include "button.h"
#include "buzzer.h"
#include "delay.h"
#include "lcd.h"
#include "ds18b20.h"
#include "dht11.h"

#define WAR_T 30

int main(void)    {	
	int yan;
	char buf[10];
	char dht[5];
	delay_init();
	LCD_Init();
	buzzer_init();
	//320 * 240
	DS18B20_Init();
	dht_init();
	LCD_Clear(0x01CF);
	BRUSH_COLOR = WHITE;
	BACK_COLOR = 0x1f << 11;
	//BACK_COLOR = BLACK;
	//LCD_DisplayString(30, 50, 24, (u8 *)" 0.0 ");
	LCD_DisplayMyname(10,200);		//Ãû×Ö
	LCD_Draw_Rectangle(1, 1, 318, 238);
	LCD_Draw_Line( 110,1 ,110 ,160 );
	LCD_Draw_Line( 220,1 ,220 ,160 );
	LCD_Draw_Line( 1,120 ,220 ,120 );
	LCD_Draw_Line( 1,160 ,318 ,160 );
	
	LCD_DisplayString(10, 70, 16, (u8 *)"PM2.5 ug/m3");
	LCD_DisplayString(125, 70, 16, (u8 *)"HCHO mg/m3");
	LCD_DisplayString(260, 170, 24, (u8 *)"TIME");
	LCD_DisplayString(220, 200, 24, (u8 *)"12 : 00");
	LCD_DisplayString(30, 175, 24, (u8 *)"WELCOME !");
	
	LCD_DisplayTu1(225,20);
	LCD_DisplayTu2(225,100);
	
	//for(yan=0xF800;yan<=0xFFE0;yan++);
	LCD_Draw_Rectangle(10, 90, 90, 100);
	LCD_Draw_Rectangle(125, 90, 210, 100);
	LCD_Fill_onecolor(10, 95, 90, 100,yan);
	LCD_Fill_onecolor(125, 95, 210, 100,yan);
	
	while(1)	{
		int i;
		get_temperature(buf);
		LCD_DisplayString(225, 50, 24, (u8 *)buf);
		LCD_DisplayOTherChar(295,50,0,24);//溫度符號
		dht_get_data(dht);
		LCD_DisplayNum(285, 100, dht[0], 2, 24, 0);
		LCD_DisplayNum(285, 20, dht[2], 2, 24, 0);
		//if( buf[1] >= '0'+2 && buf[2] >= 9+'0')

		delay_ms(500);
	}
}

led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f4xx_conf.h"

/*
	LED0	PE3
	LED1	PE4
	LED2	PG9
	GPIO管腳輸出高電壓時燈滅 低電壓時亮
	1.對於GPIO管腳打開時鍾
*/

#define GPIOE_MODER		(*(volatile unsigned int *)(GPIOE_BASE + 0x00))
#define GPIOE_OTYPER	(*(volatile unsigned int *)(GPIOE_BASE + 0x04))
#define GPIOE_OSPEEDR	(*(volatile unsigned int *)(GPIOE_BASE + 0x08))
#define GPIOE_PUPDR		(*(volatile unsigned int *)(GPIOE_BASE + 0x0C))
#define GPIOE_ODR		(*(volatile unsigned int *)(GPIOE_BASE + 0x14))

#define GPIOG_MODER	(*(volatile unsigned int *)(GPIOG_BASE + 0x00))
#define GPIOG_OTYPER	(*(volatile unsigned int *)(GPIOG_BASE + 0x04))
#define GPIOG_OSPEEDR	(*(volatile unsigned int *)(GPIOG_BASE + 0x08))
#define GPIOG_PUPDR		(*(volatile unsigned int *)(GPIOG_BASE + 0x0C))
#define GPIOG_ODR		(*(volatile unsigned int *)(GPIOG_BASE + 0x14))

extern void led_init(void);
extern void led_on(int no);
extern void led_off(int no);
#endif

led.c

#include "led.h"
#include "bitband.h"

void led_init(void)    {
	GPIO_InitTypeDef LED;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG, ENABLE);
	
	LED.GPIO_Mode = GPIO_Mode_OUT;
	LED.GPIO_OType = GPIO_OType_PP;
	LED.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
	LED.GPIO_PuPd = GPIO_PuPd_NOPULL;
	LED.GPIO_Speed = GPIO_Fast_Speed;
	
	GPIO_Init(GPIOE, &LED);
	LED.GPIO_Pin = GPIO_Pin_9;
	GPIO_Init(GPIOG, &LED);
	GPIO_SetBits(GPIOE, GPIO_Pin_3 | GPIO_Pin_4);
	GPIO_SetBits(GPIOG, GPIO_Pin_9);
}

void led_on(int no)    {
	switch(no)	{
		case 0 :
			PGOut(9) = 0;
			break;
		case 1 :
			PEOut(4) = 0;
			break;
		case 2 :
			PEOut(3) = 0;
			break;
		default:
			break;
	}
}

void led_off(int no)    {
	switch(no)	{
		case 0 :
			PGOut(9) = 1;
			break;
		case 1 :
			PEOut(4) = 1;
			break;
		case 2 :
			PEOut(3) = 1;
			break;
		default:
			break;
	}
}

button.h

#ifndef __BUTTON_H
#define __BUTTON_H

#include "stm32f4xx_conf.h"

extern void button_init(void);
extern int button_state(int);

#endif

button.c

#include "button.h"
#include "bitband.h"
// PF9 PF8 PF7 PE6
//按鍵按下是1 抬起是0
void button_init(void)    {
	GPIO_InitTypeDef BUTTON;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF, ENABLE);
	
	BUTTON.GPIO_Mode = GPIO_Mode_IN;
	BUTTON.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
	BUTTON.GPIO_PuPd = GPIO_PuPd_NOPULL;
	
	GPIO_Init(GPIOF, &BUTTON);
	
	BUTTON.GPIO_Pin = GPIO_Pin_6;
	GPIO_Init(GPIOE, &BUTTON);
}

int button_state(int no)    {
	int ret;
	
	switch(no)	{
		case 0 : 
			ret = PFIn(9);
			break;
		case 1 :
			ret = PFIn(8);
			break;
		case 2 :
			ret = PFIn(7);
			break;
		case 3 :
			ret = PEIn(6);
			break;
		default:
			ret = 1;
			break;
	}	return !ret;
}

buzzer.h

#ifndef __BUZZER_H
#define __BUZZER_H

#include "stm32f4xx_conf.h"

extern void buzzer_init(void);
extern void buzzer_on(void);
extern void buzzer_off(void);

#endif

buzzer.c

#include "buzzer.h"
#include "bitband.h"
//pd7
void buzzer_init(void)    {
	GPIO_InitTypeDef BUZZER;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	
	BUZZER.GPIO_Mode = GPIO_Mode_OUT;
	BUZZER.GPIO_OType = GPIO_OType_PP;
	BUZZER.GPIO_Pin = GPIO_Pin_7;
	BUZZER.GPIO_PuPd = GPIO_PuPd_NOPULL;
	BUZZER.GPIO_Speed = GPIO_Fast_Speed;
	
	GPIO_Init(GPIOD, &BUZZER);
	GPIO_ResetBits(GPIOD, GPIO_Pin_7);
}

void buzzer_on(void)    {
	PDOut(7) = 1;
}

void buzzer_off(void)    {
	PDOut(7) = 0;
}

delay.h

#ifndef __DELAY_H
#define __DELAY_H 			   
#include "stm32f4xx.h" 

typedef uint32_t  u32;
typedef uint16_t  u16;
typedef uint8_t   u8;

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

//GPIO
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     
//GPIO
#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
#define PAOut(n)   BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAIn(n)    BIT_ADDR(GPIOA_IDR_Addr,n) 

#define PBOut(n)   BIT_ADDR(GPIOB_ODR_Addr,n) 
#define PBIn(n)    BIT_ADDR(GPIOB_IDR_Addr,n) 

#define PCOut(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  
#define PCIn(n)    BIT_ADDR(GPIOC_IDR_Addr,n) 

#define PDOut(n)   BIT_ADDR(GPIOD_ODR_Addr,n) 
#define PDIn(n)    BIT_ADDR(GPIOD_IDR_Addr,n) 

#define PEOut(n)   BIT_ADDR(GPIOE_ODR_Addr,n) 
#define PEIn(n)    BIT_ADDR(GPIOE_IDR_Addr,n) 

#define PFOut(n)   BIT_ADDR(GPIOF_ODR_Addr,n) 
#define PFIn(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  

#define PGOut(n)   BIT_ADDR(GPIOG_ODR_Addr,n) 
#define PGIn(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  

#define PHOut(n)   BIT_ADDR(GPIOH_ODR_Addr,n) 
#define PHIn(n)    BIT_ADDR(GPIOH_IDR_Addr,n) 

#define PIOut(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  
#define PIIn(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  

#define SYSCLK 168    //調用系統時鍾
	
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif

delay.c

#include "delay.h"

//利用系統定時,編寫的延時函數
static u8  fac_us=0; //us延時倍乘數			   
static u16 fac_ms=0; //ms延時倍乘數,在ucos下,代表每個街拍的ms數

/****************************************************************************
* 名稱: delay_init()
*功能:延時函數初始化
* 入口參數:無
* 返回參數:無
****************************************************************************/
void delay_init()    {
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	fac_us=SYSCLK/8;
	fac_ms=(u16)fac_us*1000; //每個ms需要的systick時鍾數
}								    

/****************************************************************************
* 名稱: void delay_us(u32 nus)
* 功能:延時nus
* 入口參數:要延時的微秒數
* 返回參數:無
* 說明:nus的值 不要大於798915us
****************************************************************************/
void delay_us(u32 nus)    {		
	u32 midtime;	    	 
	SysTick->LOAD=nus*fac_us; //時間加載		 
	SysTick->VAL=0x00;        //清空計數器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //開始倒數
	do	{
		midtime=SysTick->CTRL;
	}
	while((midtime&0x01)&&!(midtime&(1<<16)));//等待時間到達 
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //關閉計數器
	SysTick->VAL =0X00;       //清空計數器 
}
/****************************************************************************
* 名稱: void delay_xms(u16 nms)
* 功能:延時nms
* 入口參數:要延時的毫秒數
* 返回參數:無
* 說明:SysTick->LOAD為24位寄存器,所以,最大延時為:nms<=0xffffff*8*1000/SYSCLK
            對168M條件下nms<=798ms 
****************************************************************************/
void delay_xms(u16 nms)    {	 		  	  
	u32 midtime;		   
	SysTick->LOAD=(u32)nms*fac_ms;//時間加載(SysTick->LOAD為24bit)
	SysTick->VAL =0x00;           //清空計數器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //開始倒數 
	do	{
		midtime=SysTick->CTRL;
	}
	while((midtime&0x01)&&!(midtime&(1<<16)));//等待時間到達 
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //關閉計數器
	SysTick->VAL =0X00;       //清空計數器 	    
} 
/****************************************************************************
* 名稱: void delay_ms(u16 nms)
* 功能:延時nms
* 入口參數:要延時的毫秒數
* 返回參數:無
* 說明:nms:0~65535
****************************************************************************/
void delay_ms(u16 nms)    {	 	 
	u8 repeat=nms/540;	//這里用540,是考慮到某些地方可能超頻使用
					        //比如超頻到248M的時候,delay_xms最大智能延時541ms左右了
	u16 remain=nms%540;
	while(repeat)	{
		delay_xms(540);
		repeat--;
	}
	if(remain)delay_xms(remain);
} 

lcd.h

#ifndef __LCD_H
#define __LCD_H		
#include "delay.h"	 
#include "stdlib.h" 
 
//LCD驅動重要參數集
extern  u16  lcd_id;         //LCD ID
extern  u8   dir_flag;       //橫屏還是豎屏控制:0,豎屏;1,橫屏	
extern  u16  lcd_width;      //LCD寬度
extern  u16  lcd_height;     //LCD高度
extern  u16	 write_gramcmd;	 //寫gram指令
extern	u16  setxcmd;		     //設置x坐標指令
extern	u16  setycmd;		     //設置y坐標指令	 

//LCD的畫筆顏色和背景色  
extern u16  BRUSH_COLOR;//默認紅色
extern u16  BACK_COLOR; //背景顏色 默認為白色
 
//-----------------LCD背光端口定義---------------- 
#define	LCD_BACK PDOut(3)//PFout(10)  //LCD背光    	PF10 	    

//根據硬件電路圖可以看靠我們使用NOR/SRAM的Bank1.sector4,地址位 HADDR[27,26]=11
//A12作為數據命令區分線
//因為我們使用的是16位的數據高度,所以要注意設置時STM32內部會右移一位對齊	    
#define  CMD_BASE        ((u32)(0x6C000000 | 0x00000000))
#define  DATA_BASE       ((u32)(0x6C000000 | 0x00002000))

#define LCD_CMD       ( * (volatile u16 *) CMD_BASE )
#define LCD_DATA      ( * (volatile u16 *) DATA_BASE)
	 
//掃描方向定義
#define L2R_U2D  0 //從左到右 從上到下
#define L2R_D2U  1 //從左到右 從下到上
#define R2L_U2D  2 //從右到左 從上到下
#define R2L_D2U  3 //從右到左 從下到上

#define U2D_L2R  4 //從上到下 從左到右
#define U2D_R2L  5 //從上到下 從右到左
#define D2U_L2R  6 //從下到上 從左到右
#define D2U_R2L  7 //從下到上 從右到左

#define INIT_SCAN_DIR  R2L_U2D   //設置初始化掃描方向

//顏色值定義
#define WHITE        0xFFFF
#define BLACK        0x0000	  
#define BLUE         0x001F 
#define GREEN        0x07E0
#define BRED         0XF81F
#define GRED 			   0XFFE0
#define GBLUE			   0X07FF
#define BROWN 			 0XBC40  
#define BRRED 			 0XFC07  
#define GRAY  			 0X8430  
#define RED          0xF800
#define MAGENTA      0xF81F
#define CYAN         0x7FFF
#define YELLOW       0xFFE0
#define DARKBLUE      	 0X01CF	//深藍
#define LIGHTBLUE      	 0X7D7C	//淺藍
#define GRAYBLUE       	 0X5458 //灰藍
#define JBS        for(JBS=RED;JBS<=DARKBLUE;JBS++)

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_Value);
u16 LCD_ReadReg(u16 LCD_Reg);
void LCD_WriteRAM_Prepare(void);

void LCD_Init(void);//初始化
void LCD_DisplayOn(void);//開顯示
void LCD_DisplayOff(void);//關顯示
void LCD_Clear(u16 Color);//清屏
void LCD_SetCursor(u16 Xpos, u16 Ypos);						//設置光標
void LCD_DrawPoint(u16 x,u16 y);									//畫點
void LCD_Color_DrawPoint(u16 x,u16 y,u16 color);	//顏色畫點
u16  LCD_GetPoint(u16 x,u16 y); 								  //讀點

void LCD_AUTOScan_Dir(u8 dir);					 
void LCD_Display_Dir(u8 dir);						 
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height); 	

void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);	//畫圖
void LCD_Draw_Line(u16 x1, u16 y1, u16 x2, u16 y2);//畫線
void LCD_Draw_Rectangle(u16 x1, u16 y1, u16 x2, u16 y2);		   	//畫矩形
void LCD_Fill_onecolor(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);		//填充單個顏色
void LCD_Draw_Picture(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);		//填充指定顏色
void LCD_DisplayChar(u16 x,u16 y,u8 word,u8 size);						      //顯示一個字符
void LCD_DisplayOTherChar(u16 x,u16 y,u8 word,u8 size);							//顯示除ASCII之外的字符
void LCD_DisplayNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);				//顯示 數字
void LCD_DisplayNum_color(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode,u16 brushcolor,u16 backcolor); //顯示自定義數字
void LCD_DisplayString(u16 x,u16 y,u8 size,u8 *p);		           //顯示一個12/16/24字體字符串
void LCD_DisplayString_color(u16 x,u16 y,u8 size,u8 *p,u16 brushcolor,u16 backcolor); //顯示一個12/16/24字體自定義顏色的字符串
	  	   							
void LCD_DisplayMyname(u16 x,u16 y);
void LCD_DisplayTu1(u16 x,u16 y);
void LCD_DisplayTu2(u16 x,u16 y);

#endif  

lcd.c

#include "lcd.h"
#include "cfont.h"    	 
				 
//初始化LCD的畫筆顏色和背景色	   
u16 BRUSH_COLOR=BLACK;	//畫筆顏色
u16 BACK_COLOR=WHITE;  //背景色

//管理LCD驅動重要參數
  u16  lcd_id;          //LCD ID
  u16  lcd_width;       //LCD的寬度
  u16  lcd_height;      //LCD的高度
  u16 write_gramcmd=0X2C;
  u16 read_gramcmd = 0x2E;
  u16 setxcmd=0X2A;
  u16 setycmd=0X2B;
	  
/****************************************************************************
* 名稱: void LCD_WriteReg(u16 LCD_Reg, u16 LCD_Value)
* 功能:LCD寫寄存器
* 入口參數:LCD_Reg: 寄存器地址
*              LCD_RegValue: 要寫入的數據
****************************************************************************/				   
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_Value)    {	
	LCD_CMD = LCD_Reg;		 //寫入要寫的寄存器序號
	LCD_DATA = LCD_Value;  //向寄存器寫入的數據	    		 
}
/****************************************************************************
* 名稱: u16 LCD_ReadReg(u16 LCD_Reg)
* 功能:LCD讀寄存器
* 入口參數:LCD Reg:寄存器地址
* 返回參數:督導該寄存器序號里的值     
****************************************************************************/	
u16 LCD_ReadReg(u16 LCD_Reg)    {										   
	LCD_CMD=LCD_Reg;		//寫入要讀的寄存器序號
	delay_us(5);		  
	return LCD_DATA;		//返回讀到的值
}   
//開始寫GRAM
void LCD_WriteRAM_Prepare(void)    {
 	LCD_CMD=write_gramcmd;	  
}
//lcd延時函數
void lcdm_delay(u8 i)    {
	while(i--);
}

//LCD開啟顯示
void LCD_DisplayOn(void)    {					   
		   LCD_CMD=0x29;
}	

//LCD關閉顯示
void LCD_DisplayOff(void)    {	
		   LCD_CMD=0x28;
}   
/****************************************************************************
*名稱: void LCD_SetCursor(u16 Xaddr, u16 Yaddr)
* 功能:設置光標位置
* 入口參數:x:x坐標      y:y坐標    
****************************************************************************/
void LCD_SetCursor(u16 Xaddr, u16 Yaddr)    {	     
		LCD_CMD=setxcmd; 
		LCD_DATA=(Xaddr>>8); 
		LCD_DATA=(Xaddr&0XFF);	 
		LCD_CMD=setycmd; 
		LCD_DATA=(Yaddr>>8); 
		LCD_DATA=(Yaddr&0XFF);
} 
/****************************************************************************
* 名稱: void LCD_AUTOScan_Dir(u8 dir)
* 功能:設置LCD的自動掃描方向
* 入口參數:dir:掃描方向  
****************************************************************************/  	   
void LCD_AUTOScan_Dir(u8 dir)    {
	u16 regval=0;
	u16 dirreg=0; 

	switch(dir)    {
		case L2R_U2D://從左到右 從上到下 
			regval|=(0<<7)|(0<<6)|(0<<5); break;
		case L2R_D2U://從左到右 從下到上
			regval|=(1<<7)|(0<<6)|(0<<5); break;
		case R2L_U2D://從右到左 從上到下
			regval|=(0<<7)|(1<<6)|(0<<5); break;
		case R2L_D2U://從右到左 從下到上
			regval|=(1<<7)|(1<<6)|(0<<5); break;	 
		case U2D_L2R://從上到下 從左到右
			regval|=(0<<7)|(0<<6)|(1<<5); break;
		case U2D_R2L://從上到下 從右到左
			regval|=(0<<7)|(1<<6)|(1<<5); break;
		case D2U_L2R://從下到上 從左到右
			regval|=(1<<7)|(0<<6)|(1<<5);break;
		case D2U_R2L://從下到上 從右到左
			regval|=(1<<7)|(1<<6)|(1<<5); break;	 
	}

	//設置掃描方法
	dirreg=0X36;  
	regval|=0X08;		
	LCD_WriteReg(dirreg,regval);
	
	LCD_CMD=setxcmd; //x的最小值
	LCD_DATA=0;
	LCD_DATA=0;//x的最大值
	LCD_DATA=(lcd_width-1)>>8;
	LCD_DATA=(lcd_width-1)&0XFF;
	LCD_CMD=setycmd; //y的最小值
	LCD_DATA=0;
	LCD_DATA=0;//y的最大值
	LCD_DATA=(lcd_height-1)>>8;
	LCD_DATA=(lcd_height-1)&0XFF;  
}
/****************************************************************************
* 名稱: void LCD_Display_Dir(u8 dir)
* 功能:這只LCD顯示方向
* 入口參數:dir: 0,豎屏  1,橫屏
****************************************************************************/
void LCD_Display_Dir(u8 dir)    { 
	switch (dir) {
		case L2R_U2D:
		case L2R_D2U:
		case R2L_U2D:
		case R2L_D2U:
			//先左右后上下的是豎屏
			lcd_width=240;
			lcd_height=320;	
			break;
		default:
			//先上下后左右的是橫屏顯示
			lcd_width=320;
			lcd_height=240;
			break;
	}
	
	LCD_AUTOScan_Dir(dir);	//設置掃描方向
}	

/****************************************************************************
* 名稱: u16 LCD_GetPoint(u16 x,u16 y)
* 讀取某點的顏色值
* 入口參數:x:x坐標   y:y坐標
* 返回參數:此點的顏色
****************************************************************************/
u16 LCD_GetPoint(u16 x,u16 y)    {
 	vu16 r=0,g=0,b=0;

	if(x>=lcd_width||y>=lcd_height)
		return 0;	 //超過了范圍 直接返回	   
	LCD_SetCursor(x,y);	    
	LCD_CMD = read_gramcmd;   //9341 發送讀GRAM指令	 				 
	if(LCD_DATA)
		r=0;						
	lcdm_delay(2);	  
 	r=LCD_DATA;  		  						 //實際坐標顏色
	
	lcdm_delay(2);	  
	b=LCD_DATA; 
	g=r&0XFF;		 //對於9341第一次讀取的是RG的值 R在前 G在后 個占8位
	g<<=8;

	return (((r>>11)<<11)|((g>>10)<<5)|(b>>11)); //ILI9341需要公式轉換一下}	

/****************************************************************************
* 名稱: void LCD_DrawPoint(u16 x,u16 y)
* 功能:畫點(在該點寫入畫筆的顏色)
* 入口參數:x:x坐標   y:y坐標
* 返回參數:無
* 說明 RUSH_COLOR:此點的顏色值
****************************************************************************/
void LCD_DrawPoint(u16 x,u16 y)    {
	LCD_SetCursor(x,y);		    //設置光標位置 
	LCD_WriteRAM_Prepare();	  //開始寫入GRAM
	LCD_DATA=BRUSH_COLOR; 
}
/****************************************************************************
* 名稱: void LCD_Color_DrawPoint(u16 x,u16 y,u16 color)
* 功能:在設置的坐標除畫相應顏色(在該點寫入自定義顏色)
* 入口參數:x:x坐標  y:y坐標
            color 此點的顏色值
*說明:color:寫入此點的顏色值   UCGUI調用該函數
****************************************************************************/
void LCD_Color_DrawPoint(u16 x,u16 y,u16 color)    {	       
		LCD_CMD=setxcmd; 
		LCD_DATA=(x>>8); 
		LCD_DATA=(x&0XFF);	 
		LCD_CMD=setycmd; 
		LCD_DATA=(y>>8); 
		LCD_DATA=(y&0XFF);
		
	  LCD_CMD=write_gramcmd; 
	  LCD_DATA=color; 
}	 
/****************************************************************************
* 名稱: void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
* 功能:設置窗口,最后並設置畫點坐標到窗口左上角(sx,sy)
*入口參數:sx,sy:窗口起始坐標(左上角)     width,height:窗口寬度和高度
*說明:窗口大小width*height.
****************************************************************************/
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height)    {   
	width=sx+width-1;
	height=sy+height-1;
	LCD_CMD=setxcmd; 
	LCD_DATA=(sx>>8); 
	LCD_DATA=(sx&0XFF);	 
	LCD_DATA=(width>>8); 
	LCD_DATA=(width&0XFF);  
	LCD_CMD=setycmd; 
	LCD_DATA=(sy>>8); 
	LCD_DATA=(sy&0XFF); 
	LCD_DATA=(height>>8); 
	LCD_DATA=(height&0XFF); 
} 

/****************************************************************************
* 名稱: void LCD_Clear(u16 color)
* 功能:清屏函數
* 入口參數:color: 要清屏的填充色
****************************************************************************/
void LCD_Clear(u16 color)    {
	u32 i=0;      
	u32 pointnum=0;
	
	pointnum=lcd_width*lcd_height; 	 //得到LCD總點數
	LCD_SetCursor(0x00,0x00);	       //設置光標位置
	LCD_WriteRAM_Prepare();     		 //開始寫入GRAM	 	  
	for(i=0;i<pointnum;i++)	{
		LCD_DATA=color;	   
	}
} 
/****************************************************************************
* 名稱: void LCD_Fill_onecolor(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
*功能:在指定的區域內填充單個顏色
* 入口參數:(sx,sy),(ex,ey):填充矩形對角坐標    color:要填充的顏色
*說明:區域大小為:(ex-sx+1)*(ey-sy+1) 
****************************************************************************/
void LCD_Fill_onecolor(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)    {          
	u16 i,j;
	u16 nlen=0;

		nlen=ex-sx+1;	 
		for(i=sy;i<=ey;i++)    {
		 	LCD_SetCursor(sx,i);      				  //設置光標位置 
			LCD_WriteRAM_Prepare();     			  //開始寫入GRAM	  
			for(j=0;j<nlen;j++)LCD_DATA=color;	//設置光標位置 	    
		}
} 
/****************************************************************************
* 名稱: void LCD_Draw_Picture(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
* 功能:在指定區域內畫入圖片
* 入口參數:(sx,sy),(ex,ey):填充矩形對角坐標     color:要填充的圖片像素顏色數組
*說明:區域大小為:(ex-sx+1)*(ey-sy+1)
****************************************************************************/
void LCD_Draw_Picture(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)    {  
	u16 height,width;
	u16 i,j;
	width=ex-sx+1; 			    //得到圖片的寬度
	height=ey-sy+1;			    //得到圖片的高度
 	for(i=0;i<height;i++)    	{
 		LCD_SetCursor(sx,sy+i);   	//設置光標位置
		LCD_WriteRAM_Prepare();     //開始寫入GRAM
		for(j=0;j<width;j++)LCD_DATA=color[i*height+j];//寫入顏色值
	}	  
}  
/****************************************************************************
* 名稱: void LCD_Draw_Line(u16 x1, u16 y1, u16 x2, u16 y2)
* 功能:畫線
* 入口參數:x1,y1:起點坐標    x2,y2:終點坐標
* 說明:有三種情況的畫線,水平線、垂直線與斜線(畫線、划矩形與畫圓參考網上代碼)
************************2****************************************************/  
void LCD_Draw_Line(u16 x1, u16 y1, u16 x2, u16 y2)    {
	u16 i; 
	int xm1=0,ym2=0,model_x,model_y,model,  mcx,mcy,mRow,mCol;  

	model_x=x2-x1;                  //計算直線的模 畫線坐標增量
	model_y=y2-y1; 
	mRow=x1; 
	mCol=y1; 
	if(model_x>0)mcx=1;       
	else if(model_x==0)mcx=0;      //垂直線
	else {mcx=-1;model_x=-model_x;} 
	if(model_y>0)mcy=1; 
	else if(model_y==0)mcy=0;      //水平線
	else{mcy=-1;model_y=-model_y;} 
	if( model_x>model_y)model=model_x;  
	else model=model_y; 
	for(i=0;i<=model+1;i++ )       //畫線輸出
	{  
		LCD_DrawPoint(mRow,mCol);     
		xm1+=model_x ; 
		ym2+=model_y ; 
		if(xm1>model)     { 
			xm1-=model; 
			mRow+=mcx; 
		} 
		if(ym2>model)     { 
			ym2-=model; 
			mCol+=mcy; 
		} 
	}  
}
/****************************************************************************
* 名稱: void LCD_Draw_Rectangle(u16 x1, u16 y1, u16 x2, u16 y2)
* 功能:畫矩形  
* 入口參數:(x1,y1),(x2,y2):矩形的對角坐標
****************************************************************************/
void LCD_Draw_Rectangle(u16 x1, u16 y1, u16 x2, u16 y2)    {
	LCD_Draw_Line(x1,y1,x2,y1);
	LCD_Draw_Line(x1,y1,x1,y2);
	LCD_Draw_Line(x1,y2,x2,y2);
	LCD_Draw_Line(x2,y1,x2,y2);
}
/****************************************************************************
* 名稱: void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)
*功能:字指定位置畫一個指定大小的圓
* 入口參數:(x,y):中心點      r :半徑
****************************************************************************/
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)    {
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判斷下個點位置的標志
	while(a<=b)	{
		LCD_DrawPoint(x0+a,y0-b);             
 		LCD_DrawPoint(x0+b,y0-a);                    
		LCD_DrawPoint(x0+b,y0+a);                       
		LCD_DrawPoint(x0+a,y0+b);             
		LCD_DrawPoint(x0-a,y0+b);             
 		LCD_DrawPoint(x0-b,y0+a);             
		LCD_DrawPoint(x0-a,y0-b);                      
  	LCD_DrawPoint(x0-b,y0-a);               	         
		a++;	
		if(di<0)di +=4*a+6;	  //使用Bresenham算法畫圓
		else	{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
} 

/****************************************************************************
* 名稱: void LCD_DisplayChar(u16 x,u16 y,u8 num,u8 size)
* 功能:在指定位置顯示一個字符
* 入口參數:x,y:起始坐標
            word:要顯示的字符:abcdefg1234567890...
            size:字體大小 12/16/24
*說明:取字模參考網上取字模方式,改字模取模方向為先從上到下,再從左到右
****************************************************************************/
void LCD_DisplayChar(u16 x,u16 y,u8 word,u8 size)    {  							  
  u8  bytenum,bytedata, a,b;
	u16 ymid=y;   			     
	 
	if(size==12) bytenum=12;        // 判斷各個字體子啊字庫數組中占的字節數
	else if(size==16) bytenum=16;
	else if(size==24) bytenum=36;
	else return;
	
	word=word-' ';  //得到偏移后的值 因為空格之前的字符沒在font.h中的數組里面
	    for(b=0;b<bytenum;b++)    {   
					if(size==12)bytedata=char_1206[word][b]; 	 	  //調用1206字體
					else if(size==16)bytedata=char_1608[word][b];	//調用1608字體
					else if(size==24)bytedata=char_2412[word][b];	//調用2412字體
					else return;								                  //沒有的字符數組 沒字符字庫
					for(a=0;a<8;a++)	{			    
						if(bytedata&0x80)LCD_Color_DrawPoint(x,y,BRUSH_COLOR);
						else LCD_Color_DrawPoint(x,y,BACK_COLOR);
						bytedata<<=1;
						y++;
						if(y>=lcd_height)return;		//超區域 退出函數
						if((y-ymid)==size)	{
							y=ymid;
							x++;
							if(x>=lcd_width)return;	  //超區域 退出函數
							break;
						}
		      }   	 
	    }       	 	  
}   

/****************************************************************************
* 名稱: void LCD_DisplayOtherChar(u16 x,u16 y,u8 num,u8 size)
* 功能:在指定位置顯示一個除ASCII之外的字符
* 入口參數:x,y:起始坐標     word:要顯示的字符    0:攝氏度標志   size:字體大小 12/16/24
* 說明:取字模參考網上 該字模取模方向為先從上到下 再從左到右
****************************************************************************/
void LCD_DisplayOTherChar(u16 x,u16 y,u8 word,u8 size)    {  							  
  u8  bytenum,bytedata, a,b;
	u16 ymid=y;   			     
	 
	if(size==12) bytenum=24;        // 判斷各個字體子啊字庫數組中占的字節數
	else if(size==16) bytenum=32;
	else if(size==24) bytenum=72;
	else return;

	for(b=0;b<bytenum;b++)    	{   
			if(size==12)bytedata=otherChar_1212[word][b]; 	 	  //調用1212字體
			else if(size==16)bytedata=otherChar_1616[word][b];	//調用1616字體
			else if(size==24)bytedata=otherChar_2424[word][b];	//調用2424字體
			else return;								                  		  //沒有的字符數組,沒字符字庫
		
			for(a=0;a<8;a++)    {			    
				if(bytedata&0x80)LCD_Color_DrawPoint(x,y,BRUSH_COLOR);
				else LCD_Color_DrawPoint(x,y,BACK_COLOR);
				bytedata<<=1;
				y++;
				if(y>=lcd_height)return;		//超區域 退出函數
				if((y-ymid)==size)    {
					y=ymid;
					x++;
					if(x>=lcd_width)return;	  //超區域 退出函數
					break;
				}
			}   	 
	}       	 	  
}   
//m^n函數
//返回值:m^n次方
u32 LCD_Pow(u8 m,u8 n)    {
	u32 mid=1;	 
	while(n--)mid*=m;    
	return mid;
}
/****************************************************************************
* 名稱: : void LCD_DisplayNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
* 功能: 在指定位置顯示一串數字
* 入口參數:x,y:起始坐標
            num:數值(0~999999999);	 
            len:長度(即要顯示的位數)
            size:字體大小
            mode: 0:高位為0 不顯示
                  1:高位為0顯示0
****************************************************************************/
void LCD_DisplayNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)    {  
	u8 t,numtemp;
	u8 end0=0;						   
	for(t=0;t<len;t++)    	{
		numtemp=(num/LCD_Pow(10,len-t-1))%10;
		if(end0==0&&t<(len-1))	{
			if(numtemp==0)    {
				if(mode)LCD_DisplayChar(x+(size/2)*t,y,'0',size);  
				else LCD_DisplayChar(x+(size/2)*t,y,' ',size);  
 				continue;
			}else end0=1; 	 
		}
	 	LCD_DisplayChar(x+(size/2)*t,y,numtemp+'0',size); 
	}
} 
/****************************************************************************
* 名稱: void LCD_DisplayNum_color(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
* 功能:在指定位置顯示一串自定義顏色的數字
* 入口參數: x,y:起始坐標
            num:數值(0~999999999);	 
            len:長度(即要顯示的位數)
            size:字體大小
            mode: 0:高位為0 不顯示     1:高位為0顯示0
            brushcolor:自定義畫筆顏色
            backcolor:自定義背景顏色
****************************************************************************/
void LCD_DisplayNum_color(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode,u16 brushcolor,u16 backcolor)    {
 u16 bh_color,bk_color;
	
 	bh_color=BRUSH_COLOR;  //暫存畫筆顏色
	bk_color=BACK_COLOR;   //暫存背景顏色
	
	BRUSH_COLOR=brushcolor;
	BACK_COLOR=backcolor;
	
	LCD_DisplayNum(x,y,num,len,size,mode);
	
	BRUSH_COLOR=bh_color;   //不改變系統顏色
	BACK_COLOR=bk_color;
}
/****************************************************************************
* 名稱: void LCD_DisplayString(u16 x,u16 y,u8 size,u8 *p)
* 功能:顯示字符串
* 入口參數:x,y:起始坐標
*           size:字體大小    *p:字符串起始地址
****************************************************************************/	  
void LCD_DisplayString(u16 x,u16 y,u8 size,u8 *p)    {
	
    while((*p<='~')&&(*p>=' ')) //判斷是不是非法字符!  {       
        LCD_DisplayChar(x,y,*p,size);
        x+=size/2;
			  if(x>=lcd_width) break;
        p++;
    }  
}
/****************************************************************************
*名稱: : void LCD_DisplayString(u16 x,u16 y,u8 size,u8 *p)
* 功能: 顯示自定義字符串
* 入口參數:x,y:起始坐標
*           width,height:區域大小
*           size:字體大小
*           *p:字符串起始地址	
*           brushcolor:自定義畫筆顏色
*           backcolor:自定義背景顏色
****************************************************************************/	  
void LCD_DisplayString_color(u16 x,u16 y,u8 size,u8 *p,u16 brushcolor,u16 backcolor)    {
   u16 bh_color,bk_color;
	
 	bh_color=BRUSH_COLOR;  //暫存畫筆顏色
	bk_color=BACK_COLOR;   //暫存背景顏色
	
	BRUSH_COLOR=brushcolor;
	BACK_COLOR=backcolor;
	
	LCD_DisplayString(x,y,size,p);
	
	BRUSH_COLOR=bh_color;   //不改變系統顏色
	BACK_COLOR=bk_color;
}

//配置FSMC可變靜態存儲控制器
void LCD_FSMC_Config()    {
	GPIO_InitTypeDef  GPIO_InitStructure;
	FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
  FSMC_NORSRAMTimingInitTypeDef  readWriteTiming; 
	FSMC_NORSRAMTimingInitTypeDef  writeTiming;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOG, ENABLE);//使能PD PE PF PG時鍾
  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);//使能FSMC時鍾
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;        //PF10 推挽輸出 控制背光
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     //普通輸出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉
  GPIO_Init(GPIOD, &GPIO_InitStructure);            //初始化 //
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //復用輸出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉
  GPIO_Init(GPIOD, &GPIO_InitStructure);            //初始化
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //復用輸出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉­
  GPIO_Init(GPIOE, &GPIO_InitStructure);            //初始化 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;         //PG2,FSMC_A12
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //¸´ÓÃÊä³ö
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //ÍÆÍìÊä³ö
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //ÉÏÀ­
  GPIO_Init(GPIOG, &GPIO_InitStructure);            //³õʼ»¯  

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;        //PG12
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //復用輸出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉­­
  GPIO_Init(GPIOG, &GPIO_InitStructure);            //初始化

  GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);//PD0,AF12
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);//PD1,AF12
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC); 
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC); 
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);//PD15,AF12
 
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC); //PE7,AF12
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);//PE15,AF12
 
  GPIO_PinAFConfig(GPIOG,GPIO_PinSource2,GPIO_AF_FSMC);//PF12,AF12
  GPIO_PinAFConfig(GPIOG,GPIO_PinSource12,GPIO_AF_FSMC);

  readWriteTiming.FSMC_AddressSetupTime = 0XF;	 //地址建立時間(ADDSET)為16個HCLK 1/168M=6ns*16=96ns	> 90
  readWriteTiming.FSMC_AddressHoldTime = 0x00;	 //地址保持時間(ADDHLD)模式A未用到
  readWriteTiming.FSMC_DataSetupTime = 60;			 //數據存儲時間為60個HCLK	=6*60=360ns > 255
  readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
  readWriteTiming.FSMC_CLKDivision = 0x00;
  readWriteTiming.FSMC_DataLatency = 0x00;
  readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;	 //模式A 
    
	writeTiming.FSMC_AddressSetupTime = 3;	   //地址建立時間(ADDSET)為3個HCLK =18ns > 15
  writeTiming.FSMC_AddressHoldTime = 0x00;	 //地址保持時間(ADDHLD) 模式A不使用
  writeTiming.FSMC_DataSetupTime = 2;		     //數據保存時間為6ns*3個HCLK=18ns > 15
  writeTiming.FSMC_BusTurnAroundDuration = 0x00;
  writeTiming.FSMC_CLKDivision = 0x00;
  writeTiming.FSMC_DataLatency = 0x00;
  writeTiming.FSMC_AccessMode = FSMC_AccessMode_A;	 //模式A 

  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;//   使用E4,也就對應BTCR[6],[7]
  FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; // 不復用數據地址
  FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM;  //SRAM   
  FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存儲器數據寬度為16bit   
  FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable; 
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
	FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable; 
  FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;   
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;  
  FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;	//存儲器寫使能
  FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;   
  FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable; // 讀寫使用不同的時序
  FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; 
  FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming; //讀寫時序
  FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &writeTiming;  //寫時序
  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  //初始化FSMC配置
  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);  // 使能BANK1 
				 
  delay_ms(50); // delay 50 ms 
}
//初始化lcd
void LCD_Init(void)    { 			
		LCD_FSMC_Config();
		
 		//嘗試9341 ID的讀取		
		LCD_CMD=0XD3;				   
		lcd_id=LCD_DATA;	//dummy read 	
 		lcd_id=LCD_DATA; 	//讀到0X00
  	        lcd_id=LCD_DATA;   	//讀取93								   
 		lcd_id<<=8;
		lcd_id|=LCD_DATA;  	//讀取41 
	
		LCD_CMD=0xCF;  
		LCD_DATA=0x00;
		LCD_DATA=0xC1; 
		LCD_DATA=0X30; 
		LCD_CMD=0xED;  
		LCD_DATA=0x64; 
		LCD_DATA=0x03; 
		LCD_DATA=0X12; 
		LCD_DATA=0X81; 
		LCD_CMD=0xE8;  
		LCD_DATA=0x85; 
		LCD_DATA=0x10; 
		LCD_DATA=0x7A; 
		LCD_CMD=0xCB;  
		LCD_DATA=0x39; 
		LCD_DATA=0x2C; 
		LCD_DATA=0x00; 
		LCD_DATA=0x34; 
		LCD_DATA=0x02; 
		LCD_CMD=0xF7;  
		LCD_DATA=0x20; 
		LCD_CMD=0xEA;  
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_CMD=0xC0;    //Power control 
		LCD_DATA=0x1B;   //VRH[5:0] 
		LCD_CMD=0xC1;    //Power control 
		LCD_DATA=0x01;   //SAP[2:0];BT[3:0] 
		LCD_CMD=0xC5;    //VCM control 
		LCD_DATA=0x30; 	 //3F
		LCD_DATA=0x30; 	 //3C
		LCD_CMD=0xC7;    //VCM control2 
		LCD_DATA=0XB7; 
		LCD_CMD=0x36;    // Memory Access Control 
		LCD_DATA=0x48; 
		LCD_CMD=0x3A;   
		LCD_DATA=0x55; 
		LCD_CMD=0xB1;   
		LCD_DATA=0x00;   
		LCD_DATA=0x1A; 
		LCD_CMD=0xB6;    // Display Function Control 
		LCD_DATA=0x0A; 
		LCD_DATA=0xA2; 
		LCD_CMD=0xF2;    // 3Gamma Function Disable 
		LCD_DATA=0x00; 
		LCD_CMD=0x26;    //Gamma curve selected 
		LCD_DATA=0x01; 
		LCD_CMD=0xE0;    //Set Gamma 
		LCD_DATA=0x0F; 
		LCD_DATA=0x2A; 
		LCD_DATA=0x28; 
		LCD_DATA=0x08; 
		LCD_DATA=0x0E; 
		LCD_DATA=0x08; 
		LCD_DATA=0x54; 
		LCD_DATA=0XA9; 
		LCD_DATA=0x43; 
		LCD_DATA=0x0A; 
		LCD_DATA=0x0F; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 		 
		LCD_CMD=0XE1;    //Set Gamma 
		LCD_DATA=0x00; 
		LCD_DATA=0x15; 
		LCD_DATA=0x17; 
		LCD_DATA=0x07; 
		LCD_DATA=0x11; 
		LCD_DATA=0x06; 
		LCD_DATA=0x2B; 
		LCD_DATA=0x56; 
		LCD_DATA=0x3C; 
		LCD_DATA=0x05; 
		LCD_DATA=0x10; 
		LCD_DATA=0x0F; 
		LCD_DATA=0x3F; 
		LCD_DATA=0x3F; 
		LCD_DATA=0x0F; 
		LCD_CMD=0x2B; 
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0x01;
		LCD_DATA=0x3f;
		LCD_CMD=0x2A; 
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0xef;	 
		LCD_CMD=0x11; //Exit Sleep
		delay_ms(120);
		LCD_CMD=0x29; //display on	
		
		LCD_Display_Dir(U2D_R2L);		 //初始化為 橫屏
		LCD_BACK=1;			   //點亮背光
		LCD_Clear(WHITE);
}

void LCD_DisplayMyname(u16 x,u16 y)    {  							  
  u8  bytenum,bytedata, a,b;
	u16 ymid=y;   			     
	 
	bytenum = sizeof(gao);//
	
	for(b=0;b<bytenum;b++)    	{   
		bytedata=gao[b]; 	 	  //調用1206字體
													                  //沒有的字符數組 沒字符字庫
		for(a=0;a<8;a++)	{			    
			if(bytedata&0x80)LCD_Color_DrawPoint(x,y,RED);
			else LCD_Color_DrawPoint(x,y,YELLOW);
			bytedata<<=1;
			y++;
			if(y>=lcd_height)return;		//超區域 退出函數
			if((y-ymid)==32)	{
				y=ymid;
				x++;
				if(x>=lcd_width)return;	  //超區域 退出函數
				break;
			}
		}   	 
	}
}   

void LCD_DisplayTu1(u16 x,u16 y)    {
	u8  bytenum,bytedata, a,b;
	u16 ymid=y;   			     
	 
	bytenum = sizeof(biao1);//
	
	for(b=0;b<bytenum;b++)    	{   
		bytedata=biao1[b]; 	 	  //調用1206字體
													                  //沒有的字符數組 沒字符字庫
		for(a=0;a<8;a++)	{			    
			if(bytedata&0x80)LCD_Color_DrawPoint(x,y,WHITE);
			else LCD_Color_DrawPoint(x,y,BLUE);
			bytedata<<=1;
			y++;
			if(y>=lcd_height)return;		//超區域 退出函數
			if((y-ymid)==32)	{
				y=ymid;
				x++;
				if(x>=lcd_width)return;	  //超區域 退出函數
				break;
			}
		}   	 
	}
}

void LCD_DisplayTu2(u16 x,u16 y)    {
	u8  bytenum,bytedata, a,b;
	u16 ymid=y;   			     
	 
	bytenum = sizeof(biao2);//
	
	for(b=0;b<bytenum;b++)    	{   
		bytedata=biao2[b]; 	 	  //調用1206字體
													                  //沒有的字符數組 沒字符字庫
		for(a=0;a<8;a++)	{			    
			if(bytedata&0x80)LCD_Color_DrawPoint(x,y,WHITE);
			else LCD_Color_DrawPoint(x,y,BLUE);
			bytedata<<=1;
			y++;
			if(y>=lcd_height)return;		//超區域 退出函數
			if((y-ymid)==32)	{
				y=ymid;
				x++;
				if(x>=lcd_width)return;	  //超區域 退出函數
				break;
			}
		}   	 
	}	
}

cfont.h

#ifndef __CFONT_H
#define __CFONT_H 
//字庫均來源於網絡工具生成  此處略
//攝氏度符號
const unsigned char otherChar_1212[1][24] = {{0x00,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0xC0,0x11,0x80,0x00,0x00}};

const unsigned char otherChar_1616[1][32] = {{0x00,0x00,0x30,0x00,0x48,0x00,0x30,0x00,0x00,0x00,0x03,0xF0,0x0E,0x18,0x08,0x0C,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x0C,0x0C,0x38,0x00,0x00,0x00,0x00}};

ds18b20.h

#ifndef S3C_DS_H
#define S3C_DS_H

extern void DS18B20_Init(void);
extern void get_temperature(char *buf);

#endif

ds18b20.c

#include "stm32f4xx.h"
#include "ds18b20.h"
#include "delay.h"

extern void gpio_out_state(int);
extern int gpio_input_state(void);

int  DS1820_Reset(void);                //DS1820 復位 
void DS1820_WriteData(char wData);    	//寫數據到 DS1820 

/********************************************************** 
 *DS1820 復位及存在檢測(通過存在脈沖可以判斷 DS1820 是否損壞) 
 *函數名稱:DS1820_Reset() 
 *說明:函數返回一個位標量(0 或 1)flag=0 存在,反之 flag=1 不存在 
 **********************************************************/ 
int DS1820_Reset(void)     { 
	int flag;         

	gpio_out_state(0);
	//延時 480 微秒,產生復位脈沖 
	delay_us(480);
	gpio_out_state(1);
	//延時 80 微秒對總線采樣 
	delay_us(80);
	flag = gpio_input_state();   
	//對數據腳采樣 
	delay_us(400);    //延時 400 微秒等待總線恢復 

	return flag;                //根據 flag 的值可知 DS1820 是否存在或損壞  ,可加聲音告警提示 DS1820 故障 
} 

/********************************************************** 
 *寫數據到 DS1820 
 *函數名稱:DS1820_WriteData() 
 **********************************************************/ 
void DS1820_WriteData(char wData)     { 
	char i; 

	for(i = 8; i > 0; i--)    {
		gpio_out_state(0);                  //拉低總線,產生寫信號 
		delay_us(4);            		//延時 4us 
		gpio_out_state(wData & 0x01); 	//發送 1 位 
		delay_us(60);          		//延時 60us,寫時序至少要 60us 
		gpio_out_state(1);                  //釋放總線,等待總線恢復 
		wData >>= 1;                    //准備下一位數據的傳送 
	} 
} 

/********************************************************** 
 *DS18B20 初始化 
 *函數名稱:DS1820_WriteData() 
 *說明:本初始化程序可以不要,因為 18B20 在出廠時就被配置為 12 位精度了 
 **********************************************************/ 
void DS18B20_Init(void)  { 
	DS1820_Reset(); 
	DS1820_WriteData(0xCC);    //  跳過 ROM 
	DS1820_WriteData(0x4E);    //  寫暫存器 
	DS1820_WriteData(0x20);    //  往暫存器的第三字節中寫上限值 
	DS1820_WriteData(0x00);    //  往暫存器的第四字節中寫下限值 
	DS1820_WriteData(0x7F);    //  將配置寄存器配置為 12 位精度 

	DS1820_Reset(); 
} 

/********************************************************** 
 *從 DS1820 中讀出數據 
 *函數名稱:DS1820_ReadData() 
 **********************************************************/ 
char DS1820_ReadData(void)     { 
	char i,TmepData = 0; 

	for(i = 8; i > 0; i--)    {
		TmepData >>= 1; 
		gpio_out_state(0);          //拉低總線,產生讀信號 
		delay_us(4);              	//延時 4us 
		gpio_out_state(1);          //釋放總線,准備讀數據 
		delay_us(8);              	//延時 8 微秒讀數據 
		if(gpio_input_state())
			TmepData |= 0x80; 
		delay_us(60);            		//延時 60us 
		gpio_out_state(1);                  //拉高總線,准備下一位數據的讀取. 
	} 
	return TmepData;			//返回讀到的數據 
} 

/********************************************************** 
 *轉換子程序 
 **********************************************************/ 
void tem_to_string(char *buf, char temperature[])    { 
	unsigned char temp_data,temp_data_2; 
	unsigned short TempDec; 		//用來存放 4 位小數 

	temp_data = temperature[1]; 
	temp_data &= 0xf8;    			//取高 4 位 

	if(temp_data == 0xf8)    { 			//判斷是正溫度還是負溫度讀數
						//負溫度讀數求補,取反加 1,判斷低 8 位是否有進位 
		if(temperature[0]==0)    { 		//有進位,高 8 位取反加 1 
			temperature[0]=~temperature[0]+1; 
			temperature[1]=~temperature[1]+1; 
		}else    { 				//沒進位,高 8 位不加 1 
			temperature[0]=~temperature[0]+1; 
			temperature[1]=~temperature[1]; 
		} 
	} 
	//溫度格式  temperature[1]:[xxxxAAAA] AAAA 溫度的高4位
	//溫度格式  temperature[0]:[BBBBCCCC] BBBB 溫度的低4位 CCCC小數(乘以0.0625得到的是溫度)
	temp_data = temperature[1]<<4;      						//取高字節低 4 位(溫度讀數高 4 位),注意此時是 12 位精度 
	temp_data_2 = temperature[0]>>4; 						//取低字節高 4 位(溫度讀數低 4 位),注意此時是 12 位精度 
	temp_data = temp_data | temp_data_2; 					//組合成完整數據 
	
	buf[0] = temp_data / 100 + 0x30;      					//取百位轉換為 ASCII 碼 
	buf[1] = (temp_data % 100) / 10 + 0x30;    			//取十位轉換為 ASCII 碼 
	buf[2] = (temp_data % 100 ) % 10 + 0x30;    		//取個位轉換為 ASCII 碼 
	buf[3] = '.';
#if 0
	1111	= 15;
	2 ^ 3 + 2 ^ 2 + 2 ^ 1 + 2 ^ 0 = 15 
	1111	= (2 ^ 3 + 2 ^ 2 + 2 ^ 1 + 2 ^ 0) * 0.0625	= 15 * 0.0625
	
#endif
	temperature[0] &= 0x0f;                        	//取小數位轉換為 ASCII 碼 
	TempDec = temperature[0] * 625;                	//625=0.0625*10000,表示小數部分,擴大 1 萬倍  ,方便顯示 
	buf[4] = TempDec / 1000 + 0x30;                	//取小數十分位轉換為 ASCII 碼 
	buf[5] = (TempDec % 1000) / 100 + 0x30;      		//取小數百分位轉換為 ASCII 碼 
	buf[6] = ((TempDec % 1000) % 100) / 10 + 0x30;	//取小數千分位轉換為 ASCII 碼 
	buf[7] = ((TempDec % 1000) % 100) % 10 + 0x30;	//取小數萬分位轉換為 ASCII 碼 
	buf[8] = '\0';
}

void get_temperature(char *buf)     { 
	int i; 
	char temperature[2]; //存放溫度數據 

	DS1820_Reset();                  //復位 
	DS1820_WriteData(0xcc); //跳過 ROM 命令 
	DS1820_WriteData(0x44); //溫度轉換命令 
	DS1820_Reset();         //復位 
	DS1820_WriteData(0xcc); //跳過 ROM 命令 
	DS1820_WriteData(0xbe); //讀 DS1820 溫度暫存器命令 
	for (i=0;i<2;i++){ 
		temperature[i] = DS1820_ReadData();    //采集溫度 
	} 
	DS1820_Reset();              //復位,結束讀數據 
	tem_to_string(buf, temperature);
	delay_us(50);
} 

dht11.h

#ifndef __DHT_H
#define __DHT_H

#include "stm32f4xx_conf.h"

extern void dht_init(void);
extern void dht_get_data(char *buf);

#endif

dht11.c

#include "dht11.h"
#include "delay.h"
#include "bitband.h"

void dht_init(void)    {
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
}

void dht_gpio_out(void)    {
	GPIO_InitTypeDef Gpio_Value;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_OUT;
	Gpio_Value.GPIO_OType = GPIO_OType_PP;
	Gpio_Value.GPIO_Pin = GPIO_Pin_4;
	Gpio_Value.GPIO_PuPd = GPIO_PuPd_NOPULL;
	Gpio_Value.GPIO_Speed = GPIO_Fast_Speed;
	
	GPIO_Init(GPIOA, &Gpio_Value);	
}

void dht_gpio_in(void)    {
	GPIO_InitTypeDef Gpio_Value;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_IN;
	Gpio_Value.GPIO_Pin = GPIO_Pin_4;
	Gpio_Value.GPIO_PuPd = GPIO_PuPd_NOPULL;
	Gpio_Value.GPIO_Speed = GPIO_Fast_Speed;
	
	GPIO_Init(GPIOA, &Gpio_Value);	
}

void dht_output_state(int state)    {
	dht_gpio_out();
	if(state)
		PAOut(4) = 1;
	else
		PAOut(4) = 0;
}

int dht_input_state(void)    {
	dht_gpio_in();
	return PAIn(4);
}

void dht_get_data(char *buf)    {
	char i;
	char tmp = 0;
	dht_output_state(0);
	delay_ms(20);
	dht_output_state(1);
	
	while(dht_input_state());
	while(!dht_input_state());
	
	for(i = 0; i < 40; i++)    	{
		while(dht_input_state());
		while(!dht_input_state());
		delay_us(40);
		tmp <<= 1;
		if(dht_input_state())
			tmp |= 1;
		if((i + 1) % 8 == 0)// 7 15 23 31	{
			buf[i / 8] = tmp;
			tmp = 0;
		}
	}
	dht_output_state(1);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM