这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【原创】STC89C52简易散热系统--from棚

共2条 1/1 1 跳转至

【原创】STC89C52简易散热系统--from棚

工程师
2025-01-19 11:58:32     打赏

图片1.png

思路:通过DS18B20测量温度,与设定值进行比较,温度高于设定值启动直流电机风扇降温。低于设定温度时电机停止。

主要模块:DS18B20温度传感器、直流电机驱动、onewire通信协议、定时器扫描按键。

重点为DS18B20的读写,和onewire通信协议的使用,定时器扫描按键。

一. onewire通信协议的使用

 

1.onewire不同的时序结构

1) 初始化时序

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平

时间至少 480us(该时间的时间范围可以从 480 960 微妙),以产生复位脉

冲。接着主机释放总线,外部的上拉电阻将单总线拉高,延时 1560 us,并进

入接收模式。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,若

为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要

480 微妙。初始化时序图如下: 

图片2.png

2)写时序

写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2

独立的写时序之间至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总

线。写 1 时序:主机输出低电平,延时 2us,然后释放总线,延时 60us。写 0

时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。写时序图如下:

图片3.png

3)读时序

单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出

读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少

需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时

序都由主机发起,至少拉低总线 1us。主机在读时序期间必须释放总线,并且在

时序起始后的 15us 之内采样总线状态。读时序图如下:

典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us

图片4.png

#include <REGX52.H>

#include "INTRINS.H"

sbit DQ=P3^7;

unsigned char OneWire_Init()  //开始指令

{

char i,Reception;

EA=0;

DQ=1;

DQ=0;

_nop_();i = 247;while (--i);  //延时

DQ=1;

_nop_();i = 32;while (--i);

Reception=DQ;

_nop_();i = 247;while (--i);

EA=1;

return Reception;

}

 

void Send_Bit(unsigned char Bit)  //发送一位

{

unsigned char i;

EA=0;

DQ=1;

DQ=0;

_nop_();i = 4;while (--i);

DQ=Bit;

_nop_();i = 24;while (--i);

DQ=1;

EA=1;

}

 

unsigned char Receive_Bit()  //接收一位

{

unsigned char Bit,i;

EA=0;

DQ=1;

DQ=0;

i = 2;while (--i);

DQ=1;

i = 2;while (--i);

Bit=DQ;

_nop_();

i = 24;while (--i);

EA=1;

return Bit;

}

 

void OneWire_SendByte(unsigned char Byte)  //发送一个字节

{

unsigned char i;

for(i=0;i<8;i++)

{

Send_Bit(Byte&(0x01<<i));

}

}

unsigned char OneWire_ReceiveByte()  //接收一个字节

{

unsigned char Byte=0x00,i;

for(i=0;i<8;i++)

{

if(Receive_Bit())Byte|=(0x01<<i);

}


return Byte;

}

 

DS18B20温度传感器

图片5.png

图片6.png

#include <REGX52.H>

#include "OneWire.H"

 

#define SKIP_ROM    0xCC     //跳过ROM

#define Conver  0x44     // 温度更新

#define ReadT_T  0xBE     //读取温度

 

void ConverT()  //温度转换(更新温度)

{

OneWire_Init();

OneWire_SendByte(SKIP_ROM);

OneWire_SendByte(Conver);

}

 

float ReadT()  //读取温度

{

unsigned char TLSB,TMSB;

int Temp;

float T;

OneWire_Init();

OneWire_SendByte(SKIP_ROM);

OneWire_SendByte(ReadT_T);

//将数据合并并转化为浮点数

TLSB=OneWire_ReceiveByte();

TMSB=OneWire_ReceiveByte();

Temp=(TMSB<<8)|TLSB;

T=Temp/16.0;

return T;

}

三、定时器扫描按键

 

通过中断在相同间隔时间内对按下的按键进行扫描消抖,再通过判断两次扫描的结果判断上升沿来确定按键是否按下。

#include <REGX52.H>

 

unsigned char Key_KeyNumber;

 

unsigned char Key(void)

{

    unsigned char Temp = 0;

    Temp = Key_KeyNumber;    // 将全局变量Key_KeyNumber的值赋给Temp,以便后续返回该值

    Key_KeyNumber = 0;      // Key_KeyNumber清零,为下一次记录按键相关情况做准备

    return Temp;                                                                                                

}

 

unsigned char Key_GetState() // 函数Key_GetState用于检测按键的当前状态,根据P3端口特定引脚的电平情况来确定按下的按键对应的编号

{

    unsigned char KeyNumber = 0;    // 定义一个无符号字符型变量KeyNumber,用于存储检测到的按键编号,初始化为0

    if (P3_1 == 0) { KeyNumber = 1; }

    if (P3_0 == 0) { KeyNumber = 2; }

    if (P3_2 == 0) { KeyNumber = 3; }

    if (P3_3 == 0) { KeyNumber = 4; }

    return KeyNumber;

}

 

void Key_Loop(void)     //通过判断定时器中断每段扫描后的电平变化,来判断按键是否被按下

{

    static unsigned char NowState, LastState;    // NowState用于记录按键的当前状态,LastState用于记录按键的上一次状态

    // 静态变量在函数多次调用之间能保持其值,便于对比前后状态变化

    LastState = NowState;    // 将当前状态赋值给上一次状态变量LastState,用于记录之前的状态

    NowState = Key_GetState();    // 获取当前按键的状态并赋值给NowState变量

    if (LastState == 1 && NowState == 0)

    {

        Key_KeyNumber = 1;

    }                                                                                                                                         

 

    if (LastState == 2 && NowState == 0)

    {

        Key_KeyNumber = 2;

    }

 

    if (LastState == 3 && NowState == 0)

    {

        Key_KeyNumber = 3;

    }

 

    if (LastState == 4 && NowState == 0)

    {

        Key_KeyNumber = 4;

    }

}

四、主函数

 

#include <REGX52.H>

#include "LCD1602.H"

#include "Timer0.H"

#include "DS18B20.H"

#include "Delay.H"

#include "Key.H"

 

sbit Motor = P1^0;// 定义电机控制引脚

float T;// 用于存储温度值

char STD = 28;// 存储设定温度值,为28

char KeyNum;// 用于存储按键的键值

 

// 函数功能:在LCD1602上显示当前温度值

// 具体步骤包括进行温度转换、适当延时后读取温度值,然后根据温度正负情况进行相应的显示处理

// 同时也会在LCD上显示设定温度值相关的符号和数值

 

void Show_Temperature()

{

    ConverT();                           // 调用温度转换函数,启动DS18B20进行温度转换

    Delay(300);                          // 延时300毫秒,等待温度转换完成(这个延时时间根据实际情况调整,确保转换完成)

    T = ReadT();                         // 读取温度传感器DS18B20转换后的温度值,并存储到变量T

    if (T < 0)                           // 如果温度值小于0

    {

        LCD_ShowChar(2, 10, '-');        // LCD1602的第2行第10列显示负号'-'

        T = -T;                          // 将温度值取绝对值,方便后续显示处理(因为显示时一般正数处理更统一)

    }

    else

    {

        LCD_ShowChar(2, 10, '+');       // LCD1602的第2行第10列显示正号'+'

    }

    LCD_ShowChar(2, 14, '.');

    LCD_ShowNum(2, 11, T, 3);

    LCD_ShowNum(2, 15, (unsigned long)(T * 100) % 100, 2);    // LCD1602的第2行第15列开始显示温度值的小数部分(乘以100取余得到两位小数对应的整数)

    if (STD >= 0)                       // 如果设定温度STD大于等于0

    {

        LCD_ShowChar(2, 5, '+');        // LCD1602的第2行第5列显示正号'+'

    }

    if (STD < 0)                        // 如果设定温度STD小于0

    {

        LCD_ShowChar(2, 5, '-');        // LCD1602的第2行第5列显示负号'-'

    }

    if (STD >= 0)                       // 如果设定温度STD大于等于0

    {

        LCD_ShowNum(2, 6, STD, 2);      // LCD1602的第2行第6列开始显示设定温度的整数部分,保留2位有效数字

    }

    else

    {

        LCD_ShowNum(2, 6, -STD, 2);     // LCD1602的第2行第6列开始显示设定温度的绝对值,保留2位有效数字(因为是负数情况)

    }

}

 

//////////////////////////////////////////////////////////////////////////////////////////////////////

void main()

{

//初始化

    Motor = 0;

    ConverT();

    Delay(1000);

    LCD_Init();

    Timer0_Init();

    LCD_ShowString(2, 8, "T:");

    LCD_ShowString(2, 1, "STD:");

    LCD_ShowString(1, 1, "T Control:");


    while (1)

    {

        KeyNum = Key();                     // 检测控制电机开关

        if (STD < T)

            Motor = 1;

        else

            Motor = 0;

        if (KeyNum)                         // 如果有按键按下(即KeyNum不为0

        {

            if (KeyNum == 1)                // 如果按下的是按键K1

            {

                STD++;                      // 设定温度值加1,然后对125取余(防止超出温度合理范围)

                STD %= 125;

            }

            if (KeyNum == 2)                // 如果按下的是按键K2

            {

                STD--;                  // 设定温度值减1

                if (STD < -54)              // 如果设定温度值小于 -54,则将其重置为0(同样是范围限定处理)

                    STD = 0;

            }

        }

        Show_Temperature();        // 调用函数显示当前温度和设定温度相关信息到LCD1602

    }

}

//////////////////////////////////////////////////////////////////////////////////////////////////////

void Routine() interrupt 1  //用于扫描按键

{

    // 用于计数定时器中断的次数

    int T0Count;

    TL0 = 0xCD;

    TH0 = 0xD4;

    T0Count++;

    if (T0Count > 20)

    {

        // 将计数变量清零,重新开始计数

        T0Count = 0;

        // 调用按键扫描循环函数

        Key_Loop();

    }

}



助工
2025-01-19 13:45:54     打赏
2楼

上个示波器看看波形呀!


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]