标题:
基于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 //系统频率
#define BAUD 9600 //串口波特率
#define TM (65536 - (FOSC/4/BAUD))
/*LCD1602*/
#define LCD_Set 0x38 //显示初始化: 16*2显示,5*7点阵,8位数
#define LCD_Clear 0x01 //清屏
#define LCD_Display 0x0C //显示功能设置:开显示,不显示光标,光标不闪烁
#define LCD_Mode 0x06 //设置光标状态:读一个字符光标加1
#define LCD_1 0x80 //第一行起始地址
#define LCD_2 (0x80+0x40) //第二行起始地址
/*EEPROM*/
#define CMD_IDLE 0 //空闲模式
#define CMD_READ 1 //IAP字节读命令
#define CMD_PROGRAM 2 //IAP字节编程命令
#define CMD_ERASE 3 //IAP扇区擦除命令
//#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_();
}
/*写控制命令函数*LCD1602*/
void Write_Command(u8 Comm)
{
RS=0;
RW=0;
P0=Comm;
E=1;
delay_ms(1);
E=0;
}
/*写数据函数*/
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]);
}
}
//复位DHT11
void DHT11_Rst(void)
{
DHT11_Data=0; //拉低Data
delay_ms(20); //至少18ms
DHT11_Data=1; //Data=1
delay_30us();
}
//等待DHT11的回应
//返回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读取一个字节
//返回值:读到的数据
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读取一次数据
//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位数据
{
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;// 无按键按下
}
/*----------------------------
关闭IAP
----------------------------*/
void IapIdle()
{
IAP_CONTR = 0; //关闭IAP功能
IAP_CMD = 0; //清除命令寄存器
IAP_TRIG = 0; //清除触发寄存器
IAP_ADDRH = 0x80; //将地址设置到非IAP区域
IAP_ADDRL = 0;
}
/*----------------------------
从ISP/IAP/EEPROM区域读取一字节
----------------------------*/
u8 IapReadByte(u16 addr)
{
u8 dat; //数据缓冲区
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_READ; //设置IAP命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_(); //等待ISP/IAP/EEPROM操作完成
dat = IAP_DATA; //读ISP/IAP/EEPROM数据
IapIdle(); //关闭IAP功能
return dat; //返回
}
/*----------------------------
写一字节数据到ISP/IAP/EEPROM区域
----------------------------*/
void IapProgramByte(u16 addr, u8 dat)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_PROGRAM; //设置IAP命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_DATA = dat; //写ISP/IAP/EEPROM数据
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_(); //等待ISP/IAP/EEPROM操作完成
IapIdle();
}
/*----------------------------
扇区擦除
----------------------------*/
void IapEraseSector(u16 addr)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_ERASE; //设置IAP命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(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; //复位PCA寄存器
CH = 0;
CMOD = 0x02; //设置PCA时钟源SYSCLK/2
PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
CCAPM0 = 0x42; //允许比较器功能、脉宽调节输出
CR = 1; //PCA定时器开始工作
}
/*风扇转动*/
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))//小于下限则停止转动
{
// 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; //设置波特率重装值
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);
}
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1