《基于STC89C52及红外遥控的测温智能电风扇:免费开源51单片机个人课程设计》

51单片机个人课程设计–基于stc89c52及红外遥控的测温智能电风扇
个人学校的课程设计-智能电风扇,包含proteus原理图与源代码。
代码部分由我个人写的也有普中实验中的代码块。
3.1 硬件设计
主要器件:

  1. 单片机 AT89C52
  2. 红外接收 HS0038
  3. LCD1602
  4. 温度测量 DS18B20
  5. 驱动集成芯片 L298N
  6. 导线及各类电阻
  7. 红外遥控器
    功能设计:
    本智能风扇采用 stc89c52 为芯片,使用 lcd1602 作为信息输出设备,配
    备有红外遥控器,同时使用 DS18B02 作为温度收集元件,而使用 L298N 芯片
    来实现 pwm 控制电机不同转速。图 1 智能风扇仿真
    DS18B20图 3 DS18B20 温度测量模块
    DS18B20dq 为数据传输线。
    (3) HS0038 红外接收模块
    PROTEUS 中无 HS0038 元件,所以无仿真图,实物连接时连接 P3^2。
    HS0038 红外接收通过接收红外信号,信号经过芯片处理后即可判别选择不同功
    能。
    (4) L298N 电机驱动模块
    图 4 L298N 直流电机模块
    3.2 软件设计
    本程序设计采用多个头文件形式,使得程序结构层次分明,逻辑清晰,在
    后续的开发改进升级维护时更加容易。
    本程序分为多个功能程序单独文件编写调用形式,在很大程度上减少了主
    程序长度,代码逻辑清晰分明,程序分为多个模块,包含了 lcd1602 显示程序,
    temp 测温模块,红外遥控模块,及各个模块的初始化程序。在主程序中包含了
    一些定义与对各个模块函数的调用,以及风扇驱动与状态判断程序。
    (1) .红外接收模块:
    此模块使用了红外接收头 HS0038 作为硬件功能部分, 在主要程序上其连接
    P3^2 即 INT0 引脚,设定为下降沿触发,在接收到红外信号后进入中断程序,
    在中断程序中通过判断 P3^2 上电平持续时间来得到所需要的信息。在这里不得
    不提到红外协议中的 NEC 协议。载波 38khz 包含了逻辑 0 与逻辑 1。
    逻辑 1 共计 2.25ms 先是持续 0.56ms 的低电平然后是 1.69ms 的高电平。
    逻辑 0 共计 1.12ms,先为 0.56ms 的低电平然后是 0.56ms 的高电平。
    NEC 协议格式:
    P3.6
    P3.7 5 IN1
    7 IN2
    6 ENA
    OUT1 2
    OUT2 3
    11 ENB OUT3 13
    OUT4 14
    10 IN3
    12 IN4
    1 SENSA
    15 SENSB GND
    8
    VS
    4
    VCC
    9 U2
    L298
    +88.8图 5 红外 NEC 协议
    首先发送 9ms 的起始码然后是 4.5ms 的低电平,然后是 8 位用户码之后是
    8 位用户码的反码(主要用于校验是否出错) 然后是 8 位数据码之后是 8 位数
    据码的反码。需要注意的是数据从低位开始发送选择右移接收方式。
    (1) .红外接收程序;
    Ired.c 文件包含了红外接收的各种函数及中断程序
    /*******************************************************************************
  • 函 数 名 : ired_init
  • 函数功能 : 红外端口初始化函数,外部中断 0 配置
  • 输 入 : 无
  • 输 出 : 无
    /
    void ired_init(void)
    {
    IT0=1; //下降沿触发
    EX0=1; //打开中断 0 允许
    EA=1; //打开总中断
    IRED=1; //初始化端口
    }
    void ired() interrupt 0 //外部中断 0 服务函数
    {
    u8 ired_high_time=0;
    u16 time_cnt=0;
    u8 i=0,j=0;
    if(IRED0){
    time_cnt=1000;
    while((!IRED)&&(time_cnt))//等待引导信号 9ms 低电平结束,若超过 10ms 强制退

    {
    delay_10us(1);//延时约 10us
    time_cnt–;
    if(time_cnt
    0)return;
    }
    if(IRED)//引导信号 9ms 低电平已过,进入 4.5ms 高电平
    {
    time_cnt=500;
    while(IRED&&time_cnt)//等待引导信号 4.5ms 高电平结束,若超过 5ms 强制
    退出
    {
    delay_10us(1);
    time_cnt–;
    if(time_cnt0)return;
    }
    for(i=0;i<4;i++)//循环 4 次,读取 4 个字节数据
    {
    for(j=0;j<8;j++)//循环 8 次读取每位数据即一个字节
    {
    time_cnt=600;
    while((IRED
    0)&&time_cnt)//等待数据 1 或 0 前面的 0.56ms 结束,
    若超过 6ms 强制退出
    {
    delay_10us(1);
    time_cnt–;
    if(time_cnt==0)return;}
    time_cnt=20;
    while(IRED)//等待数据 1 或 0 后面的高电平结束,若超过 2ms 强制
    退出
    {
    delay_10us(10);//约 0.1ms
    ired_high_time++;
    if(ired_high_time>20)return;
    }
    gired_data[i]>>=1;//先读取的为低位,然后是高位
    if(ired_high_time>=8)//如果高电平时间大于 0.8ms,数据则为 1,
    否则为 0
    gired_data[i]|=0x80;
    ired_high_time=0;//重新清零,等待下一次计算时间
    }
    }
    }
    if(gired_data[2]!=~gired_data[3])//校验控制码与反码,错误则返回
    {
    for(i=0;i<4;i++)
    gired_data[i]=0;
    return;
    }
    }
    }
    (2) .lcd1602 显示模块;
    此功能模块硬件选择 lcd1602 作为硬件部分在硬件部分上 vo 位额外使用滑动变阻器使得能够
    自由调整亮度,软件部分包含了写命令与写字符部分,以次来实现写入字符与命令等。
    Lcdplus.c 文件包含 lcd1602 的各种函数包括写命令和写入字符功能等。
    #include"lcdplus.h"void Lcd1602_Delay1ms(int c) //误差 0us
    {
    u8 a,b;
    for (; c>0; c–)
    {
    for (b=199;b>0;b–)
    {
    for(a=1;a>0;a–);
    }
    }
    }
    void init()
    {
    wc51r(0x38);
    wc51r(0x0c);
    wc51r(0x06);
    }
    void fbusy()
    {
    P2=0Xff;RS=0;RW=1;
    E=0;
    E=1;
    while(P0&0X80){E=0;E=1;}
    }
    void wc51r(u8 j)
    {
    fbusy();
    E=0;RS=0;RW=0;
    E=1;P0=j;
    Lcd1602_Delay1ms(2);E=0;}
    void wc51ddr(u8 j)
    {
    fbusy();
    E=0;RS=1;RW=0;Lcd1602_Delay1ms(2);
    E=1;P0=j;E=0;
    }
    ( 3) .温度检测程序部分:
    硬件采用 DS18b20 进行温度的采集处理。 软件部分有初始化,写
    数据等函数, 对于各个函数在函数前有队函数的说明。 模块包含两个
    文件 temp.H 与 temp.C 文件
    temp.h 此文件包含了 temp.c 所需的各种宏定义等。
    /
  • 函数名 : Ds18b20Init
  • 函数功能 : 初始化
  • 输入 : 无
  • 输出 : 初始化成功返回 1,失败返回 0
    /
    unsigned char Ds18b20Init()
    {
    unsigned int i;
    DSPORT=0; //将总线拉低 480us~960us
    i=70;
    while(i–);//延时 642us
    DSPORT=1; //然后拉高总线,如果 DS18B20 做出反应会将在 15us~60us 后总线
    拉低
    i=0;
    while(DSPORT) //等待 DS18B20 拉低总线
    {i++;
    if(i>5000)//等待>5MS
    return 0;//初始化失败
    }
    return 1;//初始化成功
    }
    /
  • 函数名 : Ds18b20WriteByte
  • 函数功能 : 向 18B20 写入一个字节
  • 输入 : com
  • 输出 : 无
    /
    void Ds18b20WriteByte(unsigned char dat)
    {
    unsigned int i,j;
    for(j=0;j<8;j++)
    {
    DSPORT=0; //每写入一位数据之前先把总线拉低 1us
    i++;
    DSPORT=dat&0x01; //然后写入一个数据,从最低位开始
    i=6;
    while(i–); //延时 68us,持续时间最少 60us
    DSPORT=1; //然后释放总线,至少 1us 给总线恢复时间才能接着写入第二个数值
    dat>>=1;
    }
    }/
  • 函数名 : Ds18b20ReadByte
  • 函数功能 : 读取一个字节
  • 输入 : com
  • 输出 : 无
    **/
    unsigned char Ds18b20ReadByte()
    {
    unsigned char byte,bi;
    unsigned int i,j;
    for(j=8;j>0;j–)
    {
    DSPORT=0;//先将总线拉低 1us
    i++;
    DSPORT=1;//然后释放总线
    i++;
    i++;//延时 6us 等待数据稳定
    bi=DSPORT; //读取数据,从最低位开始读取
    /将 byte 左移一位,然后与上右移 7 位后的 bi,注意移动之后移掉那位补 0。 /
    byte=(byte>>1)|(bi<<7);
    i=4; //读取完之后等待 48us 再接着读取下一个数
    while(i–);
    }
    return byte;
    }
    /
  • 函数名 : Ds18b20ChangTemp
  • 函数功能 : 让 18b20 开始转换温度
  • 输入 : com
  • 输出 : 无*******************************************************************************/
    void Ds18b20ChangTemp()
    {
    Ds18b20Init();
    Delay1ms(1);
    Ds18b20WriteByte(0xcc); //跳过 ROM 操作命令
    Ds18b20WriteByte(0x44); //温度转换命令
    }
    /*******************************************************************************
  • 函数名 : Ds18b20ReadTempCom
  • 函数功能 : 发送读取温度命令
  • 输入 : com
  • 输出 : 无
    /
    void Ds18b20ReadTempCom()
    {
    Ds18b20Init();
    Delay1ms(1);
    Ds18b20WriteByte(0xcc); //跳过 ROM 操作命令
    Ds18b20WriteByte(0xbe); //发送读取温度命令
    }
    /
  • 函数名 : Ds18b20ReadTemp
  • 函数功能 : 读取温度
  • 输入 : com
  • 输出 : 无*******************************************************************************/
    short Ds18b20ReadTemp()
    {
    unsigned char temp=0;
    unsigned char tmh,tml;
    short tem;
    Ds18b20ChangTemp(); //先写入转换命令
    Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令
    tml=Ds18b20ReadByte(); //读取温度值共 16 位,先读低字节
    tmh=Ds18b20ReadByte(); //再读高字节
    if(tmh>7)
    {
    tmh=~tmh;
    tml=~tml;
    temp=0;//温度为负
    }
    else
    {
    temp=1;//温度为正
    }
    tem=tmh; //获得高八位
    tem<<=8;
    tem|=tml;//获得底八位
    tem=(double)tem*0.625;//转换 放大 10 倍 精度 0.1
    if(temp)
    return tem; //返回温度值
    elsereturn -tem;
    }
    ( 4) 主程序部分:
    程序运行的主体部分,调用以上各文件中函数实现智能电风扇的功能。
    遥控器开关数据码: 44 开关启动 40 43 加数 46 47 减数 按下 eq07 后 设置定时时间按对应数字键。
    程序主体:
    #include “reg52.h”
    #include “public.h”
    #include “ired.h”
    #include “lcdplus.h”
    #include “temp.h”
    sbit PWM=P3^6;
    sbit PWM2=P3^7;
    unsigned char time;
    double count=0;
    int eq1;
    u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
    u8 lcdnum[10]={‘0’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’};
    u8 p={’ ‘};
    u8 E1,E2,E3,EQ;
    u8 blueh ;u8 bluel;
    u8 blue1,blue2,blue3;
    int red1,red2,red3;
    sbit led=P2^0;
    static unsigned char time1,time2,time3,time4;
    unsigned char num = 0;
    void delay(u8 c) //误差 0us 1ms 延时;{
    for (; c>0; c–);
    }
    u8 temp_buf[5];
    void Temp_DataPros()
    {
    short temp;
    temp=Ds18b20ReadTemp();
    if(temp<0)
    {
    temp=-temp;
    }
    temp_buf[0]=temp/100+0x30;
    temp_buf[1]=temp%100/10+0x30;
    temp_buf[2]=’.’;
    temp_buf[3]=temp%100%10+0x30;
    temp_buf[4]=’\0’; //显示检测的温度 xx.x
    }
    void tmtime() interrupt 1
    {
    TH0=0X3C;
    TL0=0XB0;
    num++;
    if(num20)
    {num = 0;
    time4=time4-1;if(IRED
    1)
    if(time40)
    {time4=9;time3=time3-1;
    if(time3
    0){time3=6;time2=time2-
    1;if(time2==0){time2=9;time1=time1-1;}}
    }
    }
    }
    *******************************************************************************/
  • 函数名 : time0()
  • 函数功能 : 电机转速 pwm 控制
  • 输入 : 无
  • 输出 : 无
    *******************************************************************************/
    void time0() interrupt 3
    {
    TR1=0; //设置定时器初值期间,关闭定时器
    TH1=(65536-10000)/256;
    TL1=(65536-10000)%256;
    TR1=1;
    PWM2=0;
    time++;
    if(time<count) //count 为占空比
    {
    PWM=1;
    //输出高电平
    }
    else
    PWM=0;if(time>=100)
    {
    time=0;
    }
    }
    *******************************************************************************/
  • 函数名 : fengshan()
  • 函数功能 : 红外遥控控制
  • 输入 : 无
  • 输出 : 无
    *******************************************************************************/
    void fengshan ()
    {
    unsigned char a;
    unsigned char b;
    a=gsmg_code[gired_data[2]/16];//将控制码高 4 位转换为段码
    b=gsmg_code[gired_data[2]%16];//将控制码低 4 位转换为段码
    switch(a)
    {
    case 0x66:
    {a=0x00;
    switch(b)
    {
    case 0x3f: //档位减小
    {
    red1=red1-1;b=0x00;count=count-10;
    gired_data[2]=0;
    if(red1<0){
    red1=0;count=0;
    }
    }break;
    case 0x7d: //时间减少
    {time2=time2-1;b=0x00;if(time20)
    {time2=9;time1=time1-1;}
    gired_data[2]=0;
    }break;
    case 0x4f: //档位加大
    {
    red1=red1+1;b=0x00;
    gired_data[2]=0;count=count+10;
    if(red1>9)
    {red1=0;count=0;
    }
    }break;
    case 0x07: //时间曾大
    { time2=time2+1;b=0x00;
    if(time2>=9){time2=0;time1=time1+1;}
    gired_data[2]=0;
    } break;
    case 0x6d: //风扇开关
    { TR1=~TR1;gired_data[2]=0;
    }break;
    case 0x66: //定时开关 默认关默认时间 10 分钟
    { TR0=~TR0;gired_data[2]=0;
    } break;}
    }break;
    case 0x3f:
    {
    if(b
    0x07)
    {
    E1=’ ';E2=‘O’,E3=‘N’;
    gired_data[2]=0;
    eq1=1;
    }
    if(b==0x39)
    {
    E1=‘O’;E2=‘F’,E3=‘F’; eq1=0;
    }
    } break;
    }
    }
    *******************************************************************************/
  • 函数名 : main
  • 函数功能 : 主函数
  • 输入 : 无
  • 输出 : 无
    *******************************************************************************/
    void main()
    {
    ired_init();//红外初始化
    P2=0X00;
    SP=0X50;
    init();blue1=blue2=blue3=0;//比分初始化
    time1=0,time2=9,time3=5;time4=9;
    EA=1;TMOD=0X01;TR0=1;ET0=1;
    TH0=0X3C;
    TL0=0XB0;
    P2=0X00;
    Ds18b20Init();
    TH1=(65536-100)/256;
    TL1=(65536-100)%256;
    ET1=1;
    TR1=0;//默认风扇开
    E1=‘O’;E2=‘F’,E3=‘F’;
    while(1)
    { TR1=0;
    Ds18b20ReadTempCom();
    Temp_DataPros();
    fengshan ();
    wc51r(0x80);
    wc51ddr(‘T’);wc51ddr(‘E’);wc51ddr(‘M’);wc51ddr(‘P’);wc51ddr(’:’);wc51ddr(
    temp_buf[0]);wc51ddr(temp_buf[1]);wc51ddr(temp_buf[2]);wc51ddr(temp_buf[3]);wc
    51ddr§; wc51ddr§;wc51ddr§;wc51ddr(‘K’);wc51ddr(lcdnum[red1]);
    wc51ddr§;wc51ddr§;
    wc51r(0xc0);wc51ddr(‘t’);wc51ddr(‘i’);wc51ddr(‘m’);wc51ddr(‘e’);wc51ddr(l
    cdnum[time1]);wc51ddr(lcdnum[time2]);wc51ddr(’:’);wc51ddr(lcdnum[time3]);wc51d
    dr(lcdnum[time4]);
    wc51ddr§;wc51ddr(‘E’);wc51ddr(‘Q’);wc51ddr§;wc51ddr(E1);wc51ddr(E2);wc51dd
    r(E3);
    if(eq11){TR1=1;
    if(temp_buf[0]
    ‘2’||temp_buf[0]‘3’||temp_buf[0]‘4’||temp_buf[0]‘5’
    ||temp_buf[0]
    ‘6’||temp_buf[0]‘7’||temp_buf[0]‘8’||temp_buf[0]‘9’)
    if(temp_buf[1]
    ‘5’||temp_buf[1]‘6’||temp_buf[1]‘7’||temp_buf[1]‘8’
    ||temp_buf[1]
    ‘9’)
    {red1=red1+1;count=count+10;
    if(red1>=9)
    red1=9;count=90;}
    else
    red1=count=0;
    }
    else
    TR1=1;
    } }
  • proteus仿真图:

    完整代码:

    包含多个头文件,各位在复现时可创建新文件然后复制代码即可。

    1 完整代码
    文件 main.C
    //44 开关启动 40 43 加数 46 47 减数 按下 eq07 后 设置定时时间按对应数字键。
    #include "reg52.h"
    #include "public.h"
    #include "ired.h"
    #include "lcdplus.h"
    #include "temp.h"
    sbit PWM=P3^6;
    sbit PWM2=P3^7;
    unsigned char time;
    double count=0;
    int eq1;
    u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
    u8 lcdnum[10]={'0','1','2','3','4','5','6','7','8','9'};
    u8 p={' '};
    u8 E1,E2,E3,EQ;
    u8 blueh ;u8 bluel;
    u8 blue1,blue2,blue3;
    int red1,red2,red3;
    sbit led=P2^0;static unsigned char time1,time2,time3,time4;
    unsigned char num = 0;
    void delay(u8 c) //误差 0us 1ms 延时;
    {
    for (; c>0; c--);
    }
    u8 temp_buf[5];
    void Temp_DataPros()
    {
    short temp;
    temp=Ds18b20ReadTemp();
    if(temp<0)
    {
    temp=-temp;
    }
    temp_buf[0]=temp/100+0x30;
    temp_buf[1]=temp%100/10+0x30;
    temp_buf[2]='.';
    temp_buf[3]=temp%100%10+0x30;
    temp_buf[4]='\0'; //显示检测的温度 xx.x
    }
    void tmtime() interrupt 1
    {
    TH0=0X3C;
    TL0=0XB0;num++;
    if(num==20)
    {
    num = 0;
    time4=time4-1;if(IRED==1)
    if(time4==0)
    {time4=9;time3=time3-1;
    if(time3==0){time3=6;time2=time2-1;if(time2==0){time2=9;time1=time1-1;}}
    }
    }
    }
    void time0() interrupt 3
    {
    TR1=0; //设置定时器初值期间,关闭定时器
    TH1=(65536-10000)/256;
    TL1=(65536-10000)%256;
    TR1=1;
    PWM2=0;
    time++;
    if(time<count) //count 为占空比
    {
    PWM=1;
    //输出高电平
    }
    else
    PWM=0;
    if(time>=100)
    {
    time=0;
    }}
    void fengshan ()
    {
    unsigned char a;
    unsigned char b;
    a=gsmg_code[gired_data[2]/16];//将控制码高 4 位转换为数码管段码
    b=gsmg_code[gired_data[2]%16];//将控制码低 4 位转换为数码管段码
    switch(a)
    {
    case 0x66:
    {a=0x00;
    switch(b)
    {
    case 0x3f: //档位减小
    {
    red1=red1-1;b=0x00;count=count-10;
    gired_data[2]=0;
    if(red1<0)
    {
    red1=0;count=0;
    }
    }break;
    case 0x7d: //时间减少
    {time2=time2-1;b=0x00;if(time2==0)
    {time2=9;time1=time1-1;}
    gired_data[2]=0;
    }break;case 0x4f: //档位加大
    {
    red1=red1+1;b=0x00;
    gired_data[2]=0;count=count+10;
    if(red1>9)
    {red1=0;count=0;
    }
    }break;
    case 0x07: //时间曾大
    { time2=time2+1;b=0x00;
    if(time2>=9){time2=0;time1=time1+1;}
    gired_data[2]=0;
    } break;
    case 0x6d: //风扇开关
    { TR1=~TR1;gired_data[2]=0;
    }break;
    case 0x66: //定时开关 默认关默认时间 10 分钟
    { TR0=~TR0;gired_data[2]=0;
    } break;
    }
    }break;
    case 0x3f:
    {
    if(b==0x07)
    {
    E1=' ';E2='O',E3='N';
    gired_data[2]=0;
    eq1=1;}
    if(b==0x39)
    {
    E1='O';E2='F',E3='F'; eq1=0;
    }
    } break;
    }
    }
    void main()
    {
    ired_init();//红外初始化
    P2=0X00;
    SP=0X50;
    init();
    blue1=blue2=blue3=0;//比分初始化
    time1=0,time2=9,time3=5;time4=9;
    EA=1;TMOD=0X01;TR0=1;ET0=1;
    TH0=0X3C;
    TL0=0XB0;
    P2=0X00;
    Ds18b20Init();
    TH1=(65536-100)/256;
    TL1=(65536-100)%256;
    ET1=1;
    TR1=0;//默认风扇开
    E1='O';E2='F',E3='F';
    while(1){ TR1=0;
    Ds18b20ReadTempCom();
    Temp_DataPros();
    fengshan ();
    wc51r(0x80);
    wc51ddr('T');wc51ddr('E');wc51ddr('M');wc51ddr('P');wc51ddr(':');wc51ddr(temp_buf[0]);w
    c51ddr(temp_buf[1]);wc51ddr(temp_buf[2]);wc51ddr(temp_buf[3]);wc51ddr(p);
    wc51ddr(p);wc51ddr(p);wc51ddr('K');wc51ddr(lcdnum[red1]); wc51ddr(p);wc51ddr(p);
    wc51r(0xc0);wc51ddr('t');wc51ddr('i');wc51ddr('m');wc51ddr('e');wc51ddr(lcdnum[time1]);
    wc51ddr(lcdnum[time2]);wc51ddr(':');wc51ddr(lcdnum[time3]);wc51ddr(lcdnum[time4]);
    wc51ddr(p);wc51ddr('E');wc51ddr('Q');wc51ddr(p);wc51ddr(E1);wc51ddr(E2);wc51ddr(E3);
    if(eq1==1)
    {TR1=1;
    if(temp_buf[0]=='2'||temp_buf[0]=='3'||temp_buf[0]=='4'||temp_buf[0]=='5'||temp_buf[0]=
    ='6'||temp_buf[0]=='7'||temp_buf[0]=='8'||temp_buf[0]=='9')
    if(temp_buf[1]=='5'||temp_buf[1]=='6'||temp_buf[1]=='7'||temp_buf[1]=='8'||temp_buf[1]=
    ='9')
    {red1=red1+1;count=count+10;
    if(red1>=9)
    red1=9;count=90;}
    else
    red1=count=0;
    }
    else
    TR1=1;
    }}
    *******************************************************************************/
    *******************************************************************************/
    PUBLIC.H 文件
    #ifndef _public_H
    #define _public_H
    #include "reg52.h"
    typedef unsigned int u16; //对系统默认数据类型进行重定义
    typedef unsigned char u8;
    typedef unsigned long u32;
    void delay_10us(u16 ten_us);
    void delay_ms(u16 ms);
    #endif
    PUBLIC.C 文件
    #include "public.h"
    /*******************************************************************************
    * 函 数 名 : delay_10us
    * 函数功能 : 延时函数, ten_us=1 时,大约延时 10us
    * 输 入 : ten_us
    * 输 出 : 无
    *******************************************************************************/
    void delay_10us(u16 ten_us)
    {
    while(ten_us--);
    }
    /*******************************************************************************
    * 函 数 名 : delay_ms
    * 函数功能 : ms 延时函数, ms=1 时,大约延时 1ms
    * 输 入 : ms: ms 延时时间
    * 输 出 : 无
    *******************************************************************************/
    void delay_ms(u16 ms)
    {
    u16 i,j;
    for(i=ms;i>0;i--)
    for(j=110;j>0;j--);
    }*******************************************************************************/
    *******************************************************************************/
    Ired.c 文件
    #include "ired.h"
    u8 gired_data[4];//存储 4 个字节接收码(地址码+地址反码+控制码+控制反码)
    /*******************************************************************************
    * 函 数 名 : ired_init
    * 函数功能 : 红外端口初始化函数,外部中断 0 配置
    * 输 入 : 无
    * 输 出 : 无
    *******************************************************************************/
    void ired_init(void)
    {
    IT0=1; //下降沿触发
    EX0=1; //打开中断 0 允许
    EA=1; //打开总中断
    IRED=1; //初始化端口
    }
    void ired() interrupt 0 //外部中断 0 服务函数
    {
    u8 ired_high_time=0;
    u16 time_cnt=0;
    u8 i=0,j=0;
    if(IRED==0)
    {
    time_cnt=1000;
    while((!IRED)&&(time_cnt))//等待引导信号 9ms 低电平结束,若超过 10ms 强制退
    出
    {
    delay_10us(1);//延时约 10us
    time_cnt--;
    if(time_cnt==0)return;
    }
    if(IRED)//引导信号 9ms 低电平已过,进入 4.5ms 高电平
    {
    time_cnt=500;
    while(IRED&&time_cnt)//等待引导信号 4.5ms 高电平结束,若超过 5ms 强制
    退出
    {delay_10us(1);
    time_cnt--;
    if(time_cnt==0)return;
    }
    for(i=0;i<4;i++)//循环 4 次,读取 4 个字节数据
    {
    for(j=0;j<8;j++)//循环 8 次读取每位数据即一个字节
    {
    time_cnt=600;
    while((IRED==0)&&time_cnt)//等待数据 1 或 0 前面的 0.56ms 结束,
    若超过 6ms 强制退出
    {
    delay_10us(1);
    time_cnt--;
    if(time_cnt==0)return;
    }
    time_cnt=20;
    while(IRED)//等待数据 1 或 0 后面的高电平结束,若超过 2ms 强制
    退出
    {
    delay_10us(10);//约 0.1ms
    ired_high_time++;
    if(ired_high_time>20)return;
    }
    gired_data[i]>>=1;//先读取的为低位,然后是高位
    if(ired_high_time>=8)//如果高电平时间大于 0.8ms,数据则为 1,否
    则为 0
    gired_data[i]|=0x80;
    ired_high_time=0;//重新清零,等待下一次计算时间
    }
    }
    }
    if(gired_data[2]!=~gired_data[3])//校验控制码与反码,错误则返回
    {
    for(i=0;i<4;i++)
    gired_data[i]=0;
    return;
    }
    }
    }
    *******************************************************************************/
    *******************************************************************************/
    Ired.h 文件#ifndef _ired_H
    #define _ired_H
    #include "public.h"
    //管脚定义
    sbit IRED=P3^2;
    //声明变量
    extern u8 gired_data[4];
    //函数声明
    void ired_init(void);
    #endif
    Lcdplus.H 文件
    #ifndef _lcdplus_H
    #define _lcdplus_H
    #include "public.h"
    sbit RS = P2^6;
    sbit RW = P2^5;
    sbit E = P2^7;
    void init(void);
    void wc51r(u8 i);
    void wc51ddr(u8 i);
    void fbust(void);
    void Lcd1602_Delay1ms(u8 c);
    #endif
    *******************************************************************************/
    *******************************************************************************/
    Lcdplus.C 文件
    #include"lcdplus.h"
    void Lcd1602_Delay1ms(int c) //误差 0us
    {
    u8 a,b;
    for (; c>0; c--)
    {
    for (b=199;b>0;b--)
    {
    for(a=1;a>0;a--);
    }}
    }
    void init()
    {
    wc51r(0x38);
    wc51r(0x0c);
    wc51r(0x06);
    }
    void fbusy()
    {
    P2=0Xff;RS=0;RW=1;
    E=0;
    E=1;
    while(P0&0X80){E=0;E=1;}
    }
    void wc51r(u8 j)
    {
    fbusy();
    E=0;RS=0;RW=0;
    E=1;P0=j;
    Lcd1602_Delay1ms(2);E=0;
    }
    void wc51ddr(u8 j)
    {
    fbusy();
    E=0;RS=1;RW=0;Lcd1602_Delay1ms(2);
    E=1;P0=j;E=0;
    }
    *******************************************************************************/
    *******************************************************************************/
    Temp.c 文件
    #include "temp.h"
    /*******************************************************************************
    * 函数名 : Delay1ms
    * 函数功能 : 延时函数
    * 输入 : 无
    * 输出 : 无
    *******************************************************************************/
    void Delay1ms(unsigned int y)
    {
    unsigned int x;for(y;y>0;y--)
    for(x=110;x>0;x--);
    }
    /*******************************************************************************
    * 函数名 : Ds18b20Init
    * 函数功能 : 初始化
    * 输入 : 无
    * 输出 : 初始化成功返回 1,失败返回 0
    *******************************************************************************/
    unsigned char Ds18b20Init()
    {
    unsigned int i;
    DSPORT=0; //将总线拉低 480us~960us
    i=70;
    while(i--);//延时 642us
    DSPORT=1; //然后拉高总线,如果 DS18B20 做出反应会将在 15us~60us 后
    总线拉低
    i=0;
    while(DSPORT) //等待 DS18B20 拉低总线
    {
    i++;
    if(i>5000)//等待>5MS
    return 0;//初始化失败
    }
    return 1;//初始化成功
    }
    /*******************************************************************************
    * 函数名 : Ds18b20WriteByte
    * 函数功能 : 向 18B20 写入一个字节
    * 输入 : com
    * 输出 : 无
    *******************************************************************************/
    void Ds18b20WriteByte(unsigned char dat)
    {
    unsigned int i,j;
    for(j=0;j<8;j++)
    {
    DSPORT=0; //每写入一位数据之前先把总线拉低 1us
    i++;
    DSPORT=dat&0x01; //然后写入一个数据,从最低位开始
    i=6;while(i--); //延时 68us,持续时间最少 60us
    DSPORT=1; //然后释放总线,至少 1us 给总线恢复时间才能接着写入第二个数
    值
    dat>>=1;
    }
    }
    /*******************************************************************************
    * 函数名 : Ds18b20ReadByte
    * 函数功能 : 读取一个字节
    * 输入 : com
    * 输出 : 无
    *******************************************************************************/
    unsigned char Ds18b20ReadByte()
    {
    unsigned char byte,bi;
    unsigned int i,j;
    for(j=8;j>0;j--)
    {
    DSPORT=0;//先将总线拉低 1us
    i++;
    DSPORT=1;//然后释放总线
    i++;
    i++;//延时 6us 等待数据稳定
    bi=DSPORT; //读取数据,从最低位开始读取
    /*将 byte 左移一位,然后与上右移 7 位后的 bi,注意移动之后移掉那位补 0。 */
    byte=(byte>>1)|(bi<<7);
    i=4; //读取完之后等待 48us 再接着读取下一个数
    while(i--);
    }
    return byte;
    }
    /*******************************************************************************
    * 函数名 : Ds18b20ChangTemp
    * 函数功能 : 让 18b20 开始转换温度
    * 输入 : com
    * 输出 : 无
    *******************************************************************************/
    void Ds18b20ChangTemp()
    {
    Ds18b20Init();
    Delay1ms(1);Ds18b20WriteByte(0xcc); //跳过 ROM 操作命令
    Ds18b20WriteByte(0x44); //温度转换命令
    }
    /*******************************************************************************
    * 函数名 : Ds18b20ReadTempCom
    * 函数功能 : 发送读取温度命令
    * 输入 : com
    * 输出 : 无
    *******************************************************************************/
    void Ds18b20ReadTempCom()
    {
    Ds18b20Init();
    Delay1ms(1);
    Ds18b20WriteByte(0xcc); //跳过 ROM 操作命令
    Ds18b20WriteByte(0xbe); //发送读取温度命令
    }
    /*******************************************************************************
    * 函数名 : Ds18b20ReadTemp
    * 函数功能 : 读取温度
    * 输入 : com
    * 输出 : 无
    *******************************************************************************/
    short Ds18b20ReadTemp()
    {
    unsigned char temp=0;
    unsigned char tmh,tml;
    short tem;
    Ds18b20ChangTemp(); //先写入转换命令
    Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令
    tml=Ds18b20ReadByte(); //读取温度值共 16 位,先读低字节
    tmh=Ds18b20ReadByte(); //再读高字节
    if(tmh>7)
    {
    tmh=~tmh;
    tml=~tml;
    temp=0;//温度为负
    }else
    {
    temp=1;//温度为正
    }
    tem=tmh; //获得高八位
    tem<<=8;
    tem|=tml;//获得底八位
    tem=(double)tem*0.625;//转换 放大 10 倍 精度 0.1
    if(temp)
    return tem; //返回温度值
    else
    return -tem;
    }
    *******************************************************************************/
    *******************************************************************************/
    Temp.h 文件
    #ifndef _temp_H_
    #define _temp_H_
    #include "public.h"
    sbit DSPORT=P1^7;
    void Delay1ms(unsigned int );
    unsigned char Ds18b20Init();
    void Ds18b20WriteByte(unsigned char com);
    unsigned char Ds18b20ReadByte();
    void Ds18b20ChangTemp();
    void Ds18b20ReadTempCom();
    short Ds18b20ReadTemp();
    #endif
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 《基于STC89C52及红外遥控的测温智能电风扇:免费开源51单片机个人课程设计》

    发表评论