打印
[程序源码]

51单片机温度控制风扇源代码

[复制链接]
1471|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ZSQ9161|  楼主 | 2020-11-12 11:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include"stc12c5a60s2.h"
#include <intrins.h>
#include<stdio.h>  


#define ADC_POWER  0x80
#define ADC_FLAG   0x10
#define ADC_START  0x08
#define CMD_IDLE 0     //IAP等待
#define CMD_READ 1     //读flash
#define CMD_PROGRAM  2   //写入
#define CMD_ERASE 3    //擦除
#define IAP_EN 0x83
#define iap_ADDRESS 0x0000           //地址


#define uchar unsigned char
#define uint unsigned int
#define LCD1602_DATAPINS P0

sfr PCAPWM0  =  0xf2;  //定义寄存器PCAPWM0
sfr PCAPWM1  =  0xf3;  //定义寄存器PCAPWM1

sbit LCD1602_E=P1^2;          //定义lcd1602的使能端
sbit LCD1602_RW=P1^1;        //定义lcd1602的写操作端
sbit LCD1602_RS=P1^0;        //定义lcd1602的发送命令端
sbit DSPORT=P2^7;  //温度传感器读写端
sbit LED0 = P2^3;       
sbit LED1 = P2^4;
sbit jia_key=P2^0;//加速按钮
sbit key1 = P2^1; //控制温度调节按键1、2
sbit key2 = P2^2;
sbit key_sw = P3^7;//温控与键控切换开关

uint a=0;
uint b=0;
uint c=0;
uint tem_1=27;
uint tem_2=30;
uchar num=0;


//使硬件或软件操作停止
void iap_IDLE()
  {
      IAP_CONTR=0;  //禁止IAP读写擦除
      IAP_CMD=0;  //等待
      IAP_TRIG=0;  //命令未触发
      IAP_ADDRH=0x80;  //高位数据地址
      IAP_ADDRL=0;     //低位
  }

//从数据里面读取数据
uchar iap_READ(uint addr)
   {  
     uchar datas;
           IAP_CONTR=IAP_EN; //控制允许位
         IAP_CMD=CMD_READ;   //写入读命令
         IAP_ADDRL=addr;  //自定义地址
         IAP_ADDRH=addr>>8;
         IAP_TRIG=0x5a;  //命令有效
         IAP_TRIG=0xa5;
           _nop_();
           datas=IAP_DATA;
            iap_IDLE();
         return datas;  //返回读出的数据
   }


//写一个比特ISP写到某个地方
void iap_PROGRAM(uint addr,uchar datas)
   {
      IAP_CONTR=IAP_EN;
      IAP_CMD=CMD_PROGRAM;
      IAP_ADDRL=addr;
      IAP_ADDRH=addr>>8;
      IAP_DATA=datas;
      IAP_TRIG=0x5a;
      IAP_TRIG=0xa5;
         _nop_();
         iap_IDLE();
     }

//擦掉某个区域
void iap_ERASE(uint addr)
   {
      IAP_CONTR=IAP_EN;
      IAP_CMD=CMD_ERASE;
      IAP_ADDRL=addr;
      IAP_ADDRH=addr>>8;
      IAP_TRIG=0x5a;
      IAP_TRIG=0xa5;
      _nop_();
      iap_IDLE();
   }


       
/******************************************************************************
* 函 数 名         : Delay1ms
* 函数功能                   : 延时函数
******************************************************************************/
void Delay1ms(uint y)  //粗略延时1ms
{
        uint x;
        for( ; y>0; y--)
        {
                for(x=440; x>0; x--);
        }
}

void delay1ms(void)   //误差 0us
{
    unsigned char a,b;
    for(b=129;b>0;b--)
        for(a=45;a>0;a--);
}

void delay1us(uint x)   //误差 0us
{
    unsigned char a,b;
    for(b=x;b>0;b--)
        for(a=3;a>0;a--);
}

/******************************************************************************
* 函 数 名         : Ds18b20Init
* 函数功能                   : 初始化
* 输    入         : 无
* 输    出         : 初始化成功返回1,失败返回0
******************************************************************************/
void LcdWriteCom(uchar com)          //写入命令
{
        LCD1602_E = 0;     //使能
        LCD1602_RS = 0;           //选择发送命令
        LCD1602_RW = 0;           //选择写入
       
        LCD1602_DATAPINS = com;     //放入命令
        Delay1ms(1);                //等待数据稳定

        LCD1602_E = 1;                  //写入时序
        Delay1ms(5);          //保持时间
        LCD1602_E = 0;
}

void LcdWriteData(uchar dat)                        //写入数据
{
        LCD1602_E = 0;        //使能清零
        LCD1602_RS = 1;        //选择输入数据
        LCD1602_RW = 0;        //选择写入

        LCD1602_DATAPINS = dat; //写入数据
        Delay1ms(1);

        LCD1602_E = 1;   //写入时序
        Delay1ms(5);   //保持时间
        LCD1602_E = 0;
}

void LcdInit()                                                  //LCD初始化子程序
{
        LcdWriteCom(0x38);  //开显示
        LcdWriteCom(0x0c);  //开显示不显示光标
        LcdWriteCom(0x06);  //写一个指针加1
        LcdWriteCom(0x01);  //清屏
        LcdWriteCom(0x80);  //设置数据指针起点
}

uchar Ds18b20Init()
{
        uchar i;
        DSPORT = 0;                         //将总线拉低480us~960us
        delay1us(642);        //延时642us
        DSPORT = 1;                        //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
        i = 0;
        while(DSPORT)        //等待DS18B20拉低总线
        {
                i++;
                if(i>5)//等待>5MS
                {
                        return 0;//初始化失败
                }
                delay1ms( );       
        }
        return 1;//初始化成功
}

/******************************************************************************
* 函 数 名         : Ds18b20WriteByte
* 函数功能                   : 向18B20写入一个字节
******************************************************************************/
void Ds18b20WriteByte(uchar dat)
{
        uint j;
        for(j=0; j<8; j++)
        {
                DSPORT = 0;                  //每写入一位数据之前先把总线拉低1us
                delay1us(1);              
                DSPORT = dat & 0x01;  //然后写入一个数据,从最低位开始       
                delay1us(68); //延时68us,持续时间最少60us
                DSPORT = 1;        //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
                dat >>= 1;
        }
}

/*******************************************************************************
* 函 数 名         : Ds18b20ReadByte
* 函数功能                   : 读取一个字节
******************************************************************************/
uchar Ds18b20ReadByte()
{
        uchar byte, bi;
        uint  j;       
        for(j=8; j>0; j--)
        {
                DSPORT = 0;//先将总线拉低1us
            delay1us(1);
                DSPORT = 1;//然后释放总线
                delay1us(6);          //延时6us等待数据稳定
                bi = DSPORT;         //读取数据,从最低位开始读取
                /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
                byte = (byte >> 1) | (bi << 7);                                                  
                delay1us(45);
        }                               
        return byte;
}
/*****************************************************************************
* 函 数 名         : Ds18b20ChangTemp
* 函数功能                   : 让18b20开始转换温度
******************************************************************************/
void  Ds18b20ChangTemp()
{
        Ds18b20Init();
        delay1ms( );
        Ds18b20WriteByte(0xcc);                //跳过ROM操作命令                 
        Ds18b20WriteByte(0x44);            //温度转换命令  
}

/***************************************************************************
* 函 数 名         : Ds18b20ReadTempCom
* 函数功能                   : 发送读取温度命令
****************************************************************************/
void  Ds18b20ReadTempCom()
{       
        Ds18b20Init();
        delay1ms( );
        Ds18b20WriteByte(0xcc);         //跳过ROM操作命令
        Ds18b20WriteByte(0xbe);         //发送读取温度命令
}
/***************************************************************************
* 函 数 名         : Ds18b20ReadTemp
* 函数功能                   : 读取温度
****************************************************************************/
int Ds18b20ReadTemp()
{
        int temp = 0;
        uchar tmh, tml;
        Ds18b20ChangTemp();                                 //先写入转换命令
        Ds18b20ReadTempCom();                        //然后等待转换完后发送读取温度命令
        tml = Ds18b20ReadByte();                //读取温度值共16位,先读低字节
        tmh = Ds18b20ReadByte();                //再读高字节
        temp = tmh;
        temp <<= 8;
        temp |= tml;
        return temp;
}
/*****************************************************************************
* 函数名         : LcdDisplay()
* 函数功能                   : LCD显示读取到的温度
*****************************************************************************/
void LcdDisplay(int temp)          //lcd显示                                 
{
          unsigned char datas[] = {0, 0, 0, 0, 0}; //定义数组         
        float tp;  
        if(temp< 0)                                //当温度值为负数
          {
                  LcdWriteCom(0x80);                //写地址 80表示初始地址
            LcdWriteData('-');                  //显示负
                //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
                temp=temp-1;          
                temp=~temp;
                tp=temp;
                temp=tp*0.0625*100+0.5;       
                //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
                //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
                //算加上0.5,还是在小数点后面。
          }
        else
          {                       
                  LcdWriteCom(0x80);                //写地址 80表示初始地址
            LcdWriteData('+');                 //显示正
                tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
                //如果温度是正的那么,那么正数的原码就是补码它本身
                temp=tp*0.0625*100+0.5;       
                //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
                //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
                //算加上0.5,还是在小数点后面。
        }
        datas[0] = temp / 10000;
        datas[1] = temp % 10000 / 1000;
        datas[2] = temp % 1000 / 100;
        datas[3] = temp % 100 / 10;
        datas[4] = temp % 10;

        a = datas[0];        //a,b,c的作用是取温度的整数,进行温控
        b = datas[1];
        c = datas[2];

        LcdWriteCom(0x82);                  //写地址  
        LcdWriteData('0'+datas[0]); //百位
       
        LcdWriteCom(0x83);                 //写地址  
        LcdWriteData('0'+datas[1]); //十位

        LcdWriteCom(0x84);                //写地址
        LcdWriteData('0'+datas[2]); //个位

        LcdWriteCom(0x85);                //写地址  
        LcdWriteData('.');                 //显示 '.'

        LcdWriteCom(0x86);                 //写地址  
        LcdWriteData('0'+datas[3]); //显示小数点  

        LcdWriteCom(0x87);                 //写地址  
        LcdWriteData('0'+datas[4]); //显示小数   
                  
}
/*********************************************
  温度控制电机输出占空比函数
***********************************************/
void control (void)
{
        if((a*100+b*10+c)< tem_1)
            {
              CCAP0H = CCAP0L = 0xff;         //PWM0 口输出 0%占空比
                  LED0 = 0;
                  LED1 = 0;      
            }
         else if (tem_1 <= (a*100+b*10+c)&&(a*100+b*10+c)<tem_2 )
            {
                  CCAP0H = CCAP0L = 0xB3;         //PWM0 口输出30%占空比
                  LED0 = 1;
                  LED1 = 0;
            }                 
        else if (tem_2 <= (a*100+b*10+c))
           {
                  CCAP0H = CCAP0L = 0x1a;         //PWM0 口输出90%占空比
                  LED0 = 1;
                  LED1 = 1;
           }               
}

/******************************************************************************
* 函数名         : keyscan
* 函数功能                 : 键盘扫描
******************************************************************************/
void keyscan1 ()
{
  if (0 == key1)   //温度下限调整按键
  {
    Delay1ms(20);
        if (0 == key1)
         {
                   tem_1++;
                if(31 == tem_1)
                  tem_1 = 17;
                while(!key1);
         }
  }

  if (0 == key2)   //温度上限调整按键
  {
    Delay1ms(20);
        if (0 == key2)
         {
                   tem_2++;
                if(44 == tem_2)
                  tem_2 = 23;
                while(!key2 );
         }
  }
  
  if(tem_1 == tem_2) tem_2++; //防止两个温度范围一样

  if(tem_2 < tem_1)   //防止温度上限比温度下限低
  {  
    tem_2=tem_1+1;
  }           
}

void  keyscan2 ()
{     
  if(jia_key==0)   //加速按键
        {
                Delay1ms(20);;
                if(jia_key==0)
                {
                        num++;
                        if(num==3)
                                num=0;
                        while(jia_key==0);
                }
        }
}
/*********************************************
  电机输出档位选择函数
***********************************************/
void dangwei()
{
        switch(num)
        {
         case 0:
                     CCAP0H = CCAP0L = 0xff;         //PWM0 口输出 0%占空比
                 LED0 = 0;
                 LED1 = 0;
                 break;
        case 1:
                    CCAP0H = CCAP0L = 0x67;         //PWM0 口输出60%占空比
                    LED0 = 1;
                    LED1 = 0;
                    break;
        case 2:
                CCAP0H = CCAP0L = 0x1a;         //PWM0 口输出90%占空比
                    LED0 = 1;
                    LED1 = 1;
                    break;
        }
}

/****************************************************************************
* 函数名         : displayx ()
* 函数功能                   : LCD显示读取到的键盘的数值
*****************************************************************************/
void display1 (int p)
{
   unsigned char datas[] = {0, 0};           

   datas[0] = p / 10;
   datas[1] = p % 10;

        LcdWriteCom(0x8b);                     
        LcdWriteData('0'+datas[0]);  
       
        LcdWriteCom(0x8c);                    
        LcdWriteData('0'+datas[1]);  
}

void display2 (int t)
{
   unsigned char datas[] = {0, 0};           

   datas[0] = t / 10;
   datas[1] = t % 10;

        LcdWriteCom(0x8e);                     
        LcdWriteData('0'+datas[0]);   
       
        LcdWriteCom(0x8f);                  
        LcdWriteData('0'+datas[1]);  
}

/*********************************************
  电机输出寄存器初始化函数
***********************************************/
void init_dianji()
{
    CCON = 0;                       //初始化 PCA控制寄存器
                                    //PCA计数器停止运行
                                    //清除CF标志位
                                    //清除所有中断标志位
    CL = 0;                         //重置PCA的16位计数器
    CH = 0;
    CMOD = 0x02;                    //设置 PCA 计数器时钟源为 Fosc/2
                                    //禁止PCA 计数器溢出中断   
    CCAPM0 = 0x42;                  //PCA模块0工作在8位PWM模式并且没有PCA中断
    CR = 1;                         //PCA 计数器开始运行
}


/****************************************************************************
* 函数名         : main
* 函数功能                   : 主函数
*****************************************************************************/
void main()
{

        LED0=0;
        LED1=0;
        CCAP0H = CCAP0L = 0xff;

        P1M1 = 0x00;
        P1M0 = 0x08; //把P1.3口定义为强推挽输出,驱动电机

        P2M1 = 0x00;
        P2M0 = 0x18; //把P2.3和P2.4定义为强推挽输出,驱动LED

        LcdInit();                         //初始化LCD1602
        init_dianji();      //电机PWM驱动初始化
        while(1)
        {
           if(1 == key_sw)  //温控模式
          {       
                LcdWriteCom(0x88);        //写地址 88
            LcdWriteData('C');
                LcdDisplay(Ds18b20ReadTemp());        //温度读取显示       
            control ();  //温度控制电机占空比
                keyscan1 (); //键盘扫描
                display1 (tem_1);  //控制温度数字显示
                display2 (tem_2);
                }

          if(0 == key_sw)  //键控模式
          {
                LcdWriteCom(0xc2);         
            LcdWriteData('D');
                LcdWriteCom(0xc3);         
            LcdWriteData('W');
                LcdWriteCom(0xc4);         
            LcdWriteData(':');

                dangwei(); //键控电机档位选择       
                keyscan2 ();         //键盘扫描               
               
                LcdWriteCom(0xc5);         
            LcdWriteData('0'+num);         //显示按键档位
          }
        }
}

使用特权

评论回复

相关帖子

沙发
LcwSwust| | 2020-11-12 12:14 | 只看该作者
本帖最后由 LcwSwust 于 2020-11-12 12:20 编辑

uint a=0;
uint b=0;
uint c=0;
这个差评;
另外,其实可以每个温度对应一个速度,三个档太少了。
可以像台灯那样无极调速。

使用特权

评论回复
板凳
zwsam| | 2022-7-30 16:19 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

4

帖子

0

粉丝