標題:
基于stc15單片機的只能藍牙溫控風扇程序
[打印本頁]
作者:
mm520..
時間:
2021-6-25 15:46
標題:
基于stc15單片機的只能藍牙溫控風扇程序
#include <stc15.h>
#include <string.h>
#include <stdio.h>
#include <intrins.h>
#define u8 unsigned char
#define u16 unsigned int
/*串口*/
#define FOSC 12000000L //系統(tǒng)頻率
#define BAUD 9600 //串口波特率
#define TM (65536 - (FOSC/4/BAUD))
/*LCD1602*/
#define LCD_Set 0x38 //顯示初始化: 16*2顯示,5*7點陣,8位數(shù)
#define LCD_Clear 0x01 //清屏
#define LCD_Display 0x0C //顯示功能設(shè)置:開顯示,不顯示光標,光標不閃爍
#define LCD_Mode 0x06 //設(shè)置光標狀態(tài):讀一個字符光標加1
#define LCD_1 0x80 //第一行起始地址
#define LCD_2 (0x80+0x40) //第二行起始地址
/*EEPROM*/
#define CMD_IDLE 0 //空閑模式
#define CMD_READ 1 //IAP字節(jié)讀命令
#define CMD_PROGRAM 2 //IAP字節(jié)編程命令
#define CMD_ERASE 3 //IAP扇區(qū)擦除命令
//#define ENABLE_IAP 0x80 //if SYSCLK<30MHz
//#define ENABLE_IAP 0x81 //if SYSCLK<24MHz
#define ENABLE_IAP 0x82 //if SYSCLK<20MHz
//#define ENABLE_IAP 0x83 //if SYSCLK<12MHz
//#define ENABLE_IAP 0x84 //if SYSCLK<6MHz
//#define ENABLE_IAP 0x85 //if SYSCLK<3MHz
//#define ENABLE_IAP 0x86 //if SYSCLK<2MHz
//#define ENABLE_IAP 0x87 //if SYSCLK<1MHz
#define ENABLE_IAP 0x82
#define KEY1_PRES 1
#define KEY2_PRES 2
#define KEY3_PRES 3
#define KEY4_PRES 4
sbit KEY1=P3^2;
sbit KEY2=P3^3;
sbit KEY3=P3^4;
sbit KEY4=P3^5;
u8 TEMP_String[10];
u8 HUMI_String[10];
u8 TH_String[4];
u8 TL_String[4];
sbit DHT11_Data=P1^0;
sbit RS=P2^5;
sbit RW=P2^6;
sbit E=P2^7;
sbit IN1=P1^1;
sbit IN2=P1^2;
sbit ENA=P1^3;
sbit LED=P4^5;
sbit Buzz=P5^5;
u16 TH=30;
u16 TL=15;
u8 Flag=0;
float temperature;
void GPIO(void)
{
P0M0=0;
P0M1=0;
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P3M0=0;
P3M1=0;
P4M0=0;
P4M1=0;
P5M0=0;
P5M1=0;
}
void delay_ms(u16 ms)
{
u16 i,j;
for(i=0;i<ms;i++)
for(j=0;j<1147;j++); //在12MHz時,1ms
}
void delay_30us(void)
{
u16 i;
for(i=0;i<20;i++)
_nop_();
}
/*寫控制命令函數(shù)*LCD1602*/
void Write_Command(u8 Comm)
{
RS=0;
RW=0;
P0=Comm;
E=1;
delay_ms(1);
E=0;
}
/*寫數(shù)據(jù)函數(shù)*/
void Write_Data(u8 Data)
{
RS=1;
RW=0;
P0=Data;
E=1;
delay_ms(1);
E=0;
}
/*LCD1602初始化*/
void LCD1602_Init(void)
{
Write_Command(LCD_Set);
Write_Command(LCD_Display);
Write_Command(LCD_Mode);
Write_Command(LCD_Clear);
delay_ms(5);
}
/*LCD1602在某行某列顯示一個字符*/
void LCD1602_Print_Char(u8 line,u8 Addr,u8 Data)
{
if(line)
{
Write_Command(LCD_2+Addr);
Write_Data(Data);
}
else
{
Write_Command(LCD_1+Addr);
Write_Data(Data);
}
}
/*LCD1602在某行顯示一串字符*/
void LCD1602_Print_String(u8 line,u8 *table)
{
u8 i;
if(line)
{
Write_Command(LCD_2);
}
else
{
Write_Command(LCD_1);
}
for(i=0;i<16;i++)
{
Write_Data(table[i]);
}
}
//復(fù)位DHT11
void DHT11_Rst(void)
{
DHT11_Data=0; //拉低Data
delay_ms(20); //至少18ms
DHT11_Data=1; //Data=1
delay_30us();
}
//等待DHT11的回應(yīng)
//返回1:未檢測到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
while (DHT11_Data&&retry<100)//DHT11會拉低40~80us
{
retry++;
}
if(retry>=100)return 1;
else retry=0;
while (!DHT11_Data&&retry<100)//DHT11拉低后會再次提高40~80us
{
retry++;
}
if(retry>=100)return 1;
return 0;
}
//從DHT11讀取一個位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_Data&&retry<100)//等待變成低電平
{
retry++;
}
retry=0;
while(!DHT11_Data&&retry<100)//等待變成高電平
{
retry++;
}
delay_30us();
if(DHT11_Data)return 1;
else return 0;
}
//從DHT11讀取一個字節(jié)
//返回值:讀到的數(shù)據(jù)
u8 DHT11_Read_Byte(void)
{
u8 i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
}
//從DHT11讀取一次數(shù)據(jù)
//temp:溫度值(范圍:0~50°)
//humi:濕度值(范圍:20%~90%)
//返回值:0,正常;1,讀取失敗
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
{
u8 buf[5];
u8 i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//讀取40位數(shù)據(jù)
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=buf[0];
*temp=buf[2];
}
}
else return 1;
return 0;
}
//初始化DHT11的IO口 DQ 同時檢測DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
DHT11_Rst();
return DHT11_Check();
}
void OtoC2(u8 value,u8 String[ ])
{
String[0]=value/10+0x30;
String[1]=value%10+0x30;
}
void String_Join2bit(u8 Long_String [],u8 Short_String[],u8 Position)
{
u8 i;
for(i=0;i<2;i++)
Long_String[Position+i]=Short_String[i];
}
/*按鍵掃描程序*/
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按鍵松開標志
if(mode)key_up=1; //支持連按
if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
{
delay_ms (10);//去抖動
key_up=0;
if(KEY1==0)
return KEY1_PRES;
else if(KEY2==0)
return KEY2_PRES;
else if(KEY3==0)
return KEY3_PRES;
else if(KEY4==0)
return KEY4_PRES;
}
else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)
key_up=1;
return 0;// 無按鍵按下
}
/*----------------------------
關(guān)閉IAP
----------------------------*/
void IapIdle()
{
IAP_CONTR = 0; //關(guān)閉IAP功能
IAP_CMD = 0; //清除命令寄存器
IAP_TRIG = 0; //清除觸發(fā)寄存器
IAP_ADDRH = 0x80; //將地址設(shè)置到非IAP區(qū)域
IAP_ADDRL = 0;
}
/*----------------------------
從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
----------------------------*/
u8 IapReadByte(u16 addr)
{
u8 dat; //數(shù)據(jù)緩沖區(qū)
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_READ; //設(shè)置IAP命令
IAP_ADDRL = addr; //設(shè)置IAP低地址
IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
_nop_(); //等待ISP/IAP/EEPROM操作完成
dat = IAP_DATA; //讀ISP/IAP/EEPROM數(shù)據(jù)
IapIdle(); //關(guān)閉IAP功能
return dat; //返回
}
/*----------------------------
寫一字節(jié)數(shù)據(jù)到ISP/IAP/EEPROM區(qū)域
----------------------------*/
void IapProgramByte(u16 addr, u8 dat)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_PROGRAM; //設(shè)置IAP命令
IAP_ADDRL = addr; //設(shè)置IAP低地址
IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
IAP_DATA = dat; //寫ISP/IAP/EEPROM數(shù)據(jù)
IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
_nop_(); //等待ISP/IAP/EEPROM操作完成
IapIdle();
}
/*----------------------------
扇區(qū)擦除
----------------------------*/
void IapEraseSector(u16 addr)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_ERASE; //設(shè)置IAP命令
IAP_ADDRL = addr; //設(shè)置IAP低地址
IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
_nop_(); //等待ISP/IAP/EEPROM操作完成
IapIdle();
}
/*PWM初始化*/
void PWM_Init(void)
{
P_SW1 &= ~(1<<4|1<<5); //在P1.0、P1.1輸出
CCON = 0; //初始化PCA寄存器
CL = 0; //復(fù)位PCA寄存器
CH = 0;
CMOD = 0x02; //設(shè)置PCA時鐘源SYSCLK/2
PCA_PWM0 = 0x00; //PCA模塊0工作于8位PWM
CCAP0H = CCAP0L = 0x00; //PWM0的占空比為100%
CCAPM0 = 0x42; //允許比較器功能、脈寬調(diào)節(jié)輸出
CR = 1; //PCA定時器開始工作
}
/*風扇轉(zhuǎn)動*/
void zhuan(float temperature)
{
u8 i;
if((temperature>TH)&&(Flag==0)) //如果溫度大于上限,則報警20次,并且使用全力風速
{// IN1=1;
IN2=0;
for(i=0;i<20;i++)
{
LED=0;
Buzz=0;
delay_ms (100);
LED=1;
Buzz=1;
delay_ms (100);
}
CCAP0H = CCAP0L = 0x00; //PWM0的占空比為100%
Flag=1;
}
else if((TL<temperature)&&(temperature<TH))//大于下限,小于上限則為中速風力
{
// IN1=~IN1;
IN2=0;
LED=1;
Buzz=1;
CCAP0H = CCAP0L = 0x80;//PWM0的占空比為50%
Flag=0;
}
else if((temperature<TL)&&(Flag==0))//小于下限則停止轉(zhuǎn)動
{
// IN1=1;
IN2=0;
for(i=0;i<20;i++)
{
LED=0;
Buzz=0;
delay_ms (100);
LED=1;
Buzz=1;
delay_ms (100);
}
CCAP0H = CCAP0L = 0xFF; //PWM0的占空比為0%
Flag=1;
}
}
/*串口中斷程序*/
void Uart1_INT() interrupt 4 using 1//使用藍牙遙控;
{
u8 Ch;
if (RI)
{
RI = 0; //清除RI位
Ch= SBUF; //將接收到的字符保存
switch (Ch)
{
case '1':
{
TH++;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case '2':
{
TH--;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case '3':
{
TL++;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case '4':
{
TL--;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case '5':
{
IN2=0;
CCAP0H = CCAP0L = 0x00; //PWM0的占空比為100%
break;
}
case '6':
{
IN1=1;
IN2=1;
break;
}
case 'G':
{
IN2=0;
CCAP0H = CCAP0L = 0x40; //PWM0的占空比為75%
break;
}
case 'K':
{
IN2=0;
CCAP0H = CCAP0L = 0xC0; //PWM0的占空比為25%
break;
}
}
}
}
/*串口初始化*/
void UART1_Init(void)
{
SCON = 0x50; //方式1,8位UART,波特率可變
AUXR |= 1<<2|1<<0; //定時器2為1T模式,UART1使用T2
// TMOD = 0x00; //定時器1為模式0(16位自動重載)
T2L = TM; //設(shè)置波特率重裝值
T2H = TM>>8;
AUXR |= 1<<4; //定時器2啟動
ES = 1; //使能串口中斷
EA = 1;
}
int main(void)
{
u8 t=0;
u8 temperature=0;
u8 humidity=0;
// u8 TH_EEPROM_Value,TL_EEPROM_Value; 定義EEPROM溫度上下限變量
u8 String1[]="T: C H: %Rn ";
u8 String2[]="TL: ,TH: ";
u8 Stirng_Error[ ]=" DHT11 Error! ";
GPIO();
PWM_Init();
UART1_Init();
LCD1602_Init();
TH=IapReadByte(0); //讀取EEPROM
TL=IapReadByte(1);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
while(DHT11_Init())
LCD1602_Print_String(0,Stirng_Error);
while(1)
{ t=KEY_Scan(0); //得到鍵值
switch(t)
{
case KEY1_PRES:
{
TH++;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case KEY2_PRES:
{
TH--;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case KEY3_PRES:
{
TL++;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
case KEY4_PRES:
{
TL--;
IapEraseSector(0);
IapProgramByte(0,TH); //寫EEPROM上限
IapProgramByte(1,TL); //寫EEPROM下限
break;
}
}
DHT11_Read_Data(&temperature,&humidity) ;
OtoC2(temperature,TEMP_String);
String_Join2bit(String1,TEMP_String,2);
OtoC2(humidity,HUMI_String);
String_Join2bit(String1,HUMI_String,10);
OtoC2(TH,TH_String);
String_Join2bit(String2,TH_String,11);
OtoC2(TL,TL_String);
String_Join2bit(String2,TL_String,3);
LCD1602_Print_String(0,String1);
LCD1602_Print_String(1,String2);
zhuan(temperature);
}
}
復(fù)制代碼
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1