找回密码
 立即注册
查看: 48|回复: 1

写了一个电子温度计程序,一次点亮成功,喜欢的同学拿去用。

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2026-04-08 08:28:01
已绑定手机

10

主题

4

回帖

80

积分

注册会员

积分
80
发表于 5 天前 | 显示全部楼层 |阅读模式
写了一个电子温度计程序,一次点亮成功,喜欢的同学拿去用。程序还可以扩展,下个帖子扩展几个功能,支持的坛友点赞关注一下!
STC32G DS18B20温度测量与数码管显示程序
  硬件:
    MCU: STC32G12K128
   温度传感器: DS18B20
    显示: 4位共阴数码管
引脚连接:
    DS18B20数据线: P1.7
   数码管段选A-H: P2.0-P2.7
   数码管位选1-4: P3.0-P3.3


#include "STC32G.h"
#include <intrins.h>

/*============================================================================
* 引脚定义
============================================================================*/
// DS18B20数据引脚定义
sbit DS18B20_DQ = P1^7;  // DS18B20数据线

// 数码管段选引脚定义 (P2端口)
sbit SEG_A = P2^0;  // 数码管A段
sbit SEG_B = P2^1;  // 数码管B段
sbit SEG_C = P2^2;  // 数码管C段
sbit SEG_D = P2^3;  // 数码管D段
sbit SEG_E = P2^4;  // 数码管E段
sbit SEG_F = P2^5;  // 数码管F段
sbit SEG_G = P2^6;  // 数码管G段
sbit SEG_DP = P2^7; // 数码管小数点

// 数码管位选引脚定义 (P3端口)
sbit DIG1 = P3^0;  // 第1位数码管
sbit DIG2 = P3^1;  // 第2位数码管
sbit DIG3 = P3^2;  // 第3位数码管
sbit DIG4 = P3^3;  // 第4位数码管

/*============================================================================
* 常量定义
============================================================================*/
// 数码管编码表 (共阴极,0-9,带特殊字符)
// 格式:DP G F E D C B A
unsigned char code SEG_CODE[] = {
    0x3F,  // 0: 00111111
    0x06,  // 1: 00000110
    0x5B,  // 2: 01011011
    0x4F,  // 3: 01001111
    0x66,  // 4: 01100110
    0x6D,  // 5: 01101101
    0x7D,  // 6: 01111101
    0x07,  // 7: 00000110
    0x7F,  // 8: 01111111
    0x6F,  // 9: 01101111
    0x40,  // -: 01000000 (负号)
    0x00,  // 空: 00000000
    0x39,  // C: 00111001
    0x76,  // H: 01110110
    0x00   // 灭: 00000000
};

// 数码管位选控制码
unsigned char code DIGIT_CODE[] = {
    0xFE,  // 11111110 - 第1位
    0xFD,  // 11111101 - 第2位
    0xFB,  // 11111011 - 第3位
    0xF7   // 11110111 - 第4位
};

/*============================================================================
* 全局变量
============================================================================*/
unsigned int temp_value;      // 温度值(放大10倍,如25.5度存储为255)
signed char temp_sign = 1;    // 温度符号:1为正,-1为负
unsigned char display_flag = 0;  // 显示更新标志
unsigned int time_count = 0;  // 时间计数器

// 显示缓冲区(存放4位数码管要显示的数字)
unsigned char display_buf[4] = {0, 0, 0, 0};
unsigned char dot_position = 0;  // 小数点位置(0:无小数点,1:第1位,2:第2位,3:第3位)

/*============================================================================
* 延时函数
============================================================================*/

/**
* @brief 微秒级延时
* @param us 微秒数
*/
void Delay_us(unsigned int us)
{
    while(us--)
    {
        _nop_(); _nop_(); _nop_(); _nop_();
        _nop_(); _nop_(); _nop_(); _nop_();
    }
}

/**
* @brief 毫秒级延时
* @param ms 毫秒数
*/
void Delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for(i = 0; i < ms; i++)
    {
        for(j = 0; j < 1140; j++)
        {
            _nop_();
        }
    }
}

/*============================================================================
* 系统初始化函数
============================================================================*/

/**
* @brief GPIO引脚初始化
*/
void GPIO_Init(void)
{
    // P2端口配置为推挽输出(数码管段选)
    P2M0 = 0xFF;  // 设置为推挽输出模式
    P2M1 = 0x00;
    P2 = 0x00;    // 初始输出低电平,关闭所有段
   
    // P3.0-P3.3配置为推挽输出(数码管位选)
    P3M0 = 0x0F;  // P3.0-P3.3推挽输出
    P3M1 = 0x00;
    P3 |= 0x0F;   // 初始输出高电平,关闭所有位
   
    // P1.7配置为准双向口(DS18B20)
    P1M0 &= ~0x80;
    P1M1 &= ~0x80;
    P1 |= 0x80;   // 初始输出高电平
   
    // 其他端口保持默认
    P0M0 = 0x00;
    P0M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
}

/**
* @brief 定时器0初始化(用于数码管扫描)
*/
void Timer0_Init(void)
{
    AUXR &= 0x7F;     // 定时器时钟12T模式
    TMOD &= 0xF0;     // 设置定时器模式
    TMOD |= 0x01;     // 定时器0模式1,16位定时器
   
    TL0 = 0x00;       // 设置定时初值
    TH0 = 0xEE;       // 1ms定时(12MHz晶振)
   
    TF0 = 0;          // 清除TF0标志
    TR0 = 1;          // 定时器0开始计时
   
    ET0 = 1;          // 允许定时器0中断
    EA = 1;           // 开总中断
}

/*============================================================================
* DS18B20驱动程序
============================================================================*/

/**
* @brief DS18B20初始化
* @return 0:初始化失败 1:初始化成功
*/
unsigned char DS18B20_Init(void)
{
    unsigned char flag = 0;
   
    // 主机拉低总线480-960us
    DS18B20_DQ = 0;
    Delay_us(600);
    DS18B20_DQ = 1;
   
    // 释放总线,等待15-60us
    Delay_us(30);
   
    // 检测从机响应脉冲
    if(DS18B20_DQ == 0)
    {
        flag = 1;  // DS18B20存在
    }
    else
    {
        flag = 0;  // DS18B20不存在
    }
   
    // 等待从机释放总线
    while(!DS18B20_DQ);
   
    return flag;
}

/**
* @brief DS18B20写一个字节
* @param dat 要写入的数据
*/
void DS18B20_WriteByte(unsigned char dat)
{
    unsigned char i;
   
    for(i = 0; i < 8; i++)
    {
        // 开始写时序
        DS18B20_DQ = 0;
        _nop_(); _nop_();  // 延时约2us
        
        // 写入1位数据
        DS18B20_DQ = dat & 0x01;
        Delay_us(60);      // 保持60us
        
        // 释放总线
        DS18B20_DQ = 1;
        _nop_(); _nop_();  // 延时约2us
        
        // 准备下一位
        dat >>= 1;
    }
   
    // 写入完成后延时
    Delay_us(2);
}

/**
* @brief DS18B20读一个字节
* @return 读取到的数据
*/
unsigned char DS18B20_ReadByte(void)
{
    unsigned char i, dat = 0;
   
    for(i = 0; i < 8; i++)
    {
        // 主机拉低总线开始读时序
        DS18B20_DQ = 0;
        _nop_(); _nop_();  // 延时约2us
        
        // 释放总线
        DS18B20_DQ = 1;
        _nop_(); _nop_();  // 延时约2us
        
        // 读取数据
        dat >>= 1;
        if(DS18B20_DQ)
        {
            dat |= 0x80;
        }
        
        // 保持读时序
        Delay_us(60);
        
        // 释放总线等待下一位
        DS18B20_DQ = 1;
    }
   
    return dat;
}

/**
* @brief 读取温度值
* @return 温度值(实际值×10,如25.5返回255)
*/
signed int DS18B20_Read_Temperature(void)
{
    unsigned char tempL, tempH;
    signed int temp_value;
    float temperature;
   
    // 初始化DS18B20
    if(DS18B20_Init() == 0)
    {
        return 0x7FFF;  // 读取失败,返回特殊值
    }
   
    // 跳过ROM指令
    DS18B20_WriteByte(0xCC);
   
    // 启动温度转换
    DS18B20_WriteByte(0x44);
   
    // 延时等待转换完成(最大750ms)
    Delay_ms(750);
   
    // 重新初始化DS18B20
    if(DS18B20_Init() == 0)
    {
        return 0x7FFF;  // 读取失败
    }
   
    // 跳过ROM指令
    DS18B20_WriteByte(0xCC);
   
    // 读取温度寄存器指令
    DS18B20_WriteByte(0xBE);
   
    // 读取温度值(低字节、高字节)
    tempL = DS18B20_ReadByte();
    tempH = DS18B20_ReadByte();
   
    // 合成16位温度值
    temp_value = tempH;
    temp_value <<= 8;
    temp_value |= tempL;
   
    // 判断温度正负
    if(temp_value & 0xF800)  // 高5位为1表示负数
    {
        temp_sign = -1;  // 负温度
        temp_value = ~temp_value + 1;  // 取补码
    }
    else
    {
        temp_sign = 1;   // 正温度
    }
   
    // 计算实际温度值(保留1位小数)
    temperature = temp_value * 0.0625;
    temp_value = (signed int)(temperature * 10);
   
    return temp_value;
}

/*============================================================================
* 数码管显示函数
============================================================================*/

/**
* @brief 设置显示缓冲区
* @param value 要显示的值(实际值×10)
* @param sign 符号:1为正,-1为负
*/
void Set_Display_Buffer(signed int value, signed char sign)
{
    unsigned int abs_value;
   
    // 取绝对值
    if(value < 0)
    {
        abs_value = -value;
    }
    else
    {
        abs_value = value;
    }
   
    // 分离各位数字
    display_buf[0] = abs_value % 10;          // 十分位(小数第一位)
    display_buf[1] = (abs_value / 10) % 10;   // 个位
    display_buf[2] = (abs_value / 100) % 10;  // 十位
    display_buf[3] = (abs_value / 1000) % 10; // 百位
   
    // 设置小数点位置(在个位后)
    dot_position = 1;
   
    // 符号处理
    if(sign < 0)
    {
        // 负号显示在最高位
        display_buf[3] = 10;  // 显示"-"
    }
    else
    {
        // 正数,如果百位为0则不显示
        if(display_buf[3] == 0)
        {
            display_buf[3] = 11;  // 不显示
            
            // 如果十位也为0则不显示
            if(display_buf[2] == 0)
            {
                display_buf[2] = 11;  // 不显示
            }
        }
    }
}

/**
* @brief 数码管扫描显示函数(定时器中断调用)
*/
void Display_Scan(void)
{
    static unsigned char digit = 0;  // 当前显示的位
    unsigned char seg_data;
   
    // 关闭所有数码管(消隐)
    DIG1 = 1;
    DIG2 = 1;
    DIG3 = 1;
    DIG4 = 1;
   
    // 获取当前位要显示的数字编码
    seg_data = SEG_CODE[display_buf[digit]];
   
    // 如果需要显示小数点
    if(dot_position == digit)
    {
        seg_data |= 0x80;  // 点亮小数点
    }
   
    // 设置段选数据
    P2 = seg_data;
   
    // 选择要显示的位
    switch(digit)
    {
        case 0: DIG1 = 0; break;  // 第1位(个位/十分位)
        case 1: DIG2 = 0; break;  // 第2位(十位/个位)
        case 2: DIG3 = 0; break;  // 第3位(百位/十位)
        case 3: DIG4 = 0; break;  // 第4位(符号/百位)
    }
   
    // 切换到下一位
    digit++;
    if(digit >= 4)
    {
        digit = 0;
    }
}

/*============================================================================
* 定时器0中断服务函数
============================================================================*/
void Timer0_ISR(void) interrupt 1
{
    static unsigned int temp_count = 0;
    static unsigned int display_count = 0;
   
    // 重装定时器初值(1ms)
    TL0 = 0x00;
    TH0 = 0xEE;
   
    // 数码管扫描(每1ms扫描1位)
    Display_Scan();
   
    // 温度读取计数(每500ms读取一次温度)
    if(temp_count++ >= 500)
    {
        temp_count = 0;
        display_flag = 1;  // 设置温度读取标志
    }
   
    // 显示刷新计数
    if(display_count++ >= 1000)
    {
        display_count = 0;
        // 可以在这里添加其他定时任务
    }
}

/*============================================================================
* 主函数
============================================================================*/
void main(void)
{
    signed int current_temp = 0;
    signed int last_temp = 0;
   
    // 系统初始化
    GPIO_Init();      // GPIO引脚初始化
    Timer0_Init();    // 定时器0初始化
   
    // 初始显示"----"
    display_buf[0] = 10;  // "-"
    display_buf[1] = 10;  // "-"
    display_buf[2] = 10;  // "-"
    display_buf[3] = 10;  // "-"
    dot_position = 0;     // 无小数点
   
    // 首次温度读取
    current_temp = DS18B20_Read_Temperature();
    if(current_temp != 0x7FFF)
    {
        Set_Display_Buffer(current_temp, temp_sign);
    }
   
    // 主循环
    while(1)
    {
        // 检查是否需要读取温度
        if(display_flag)
        {
            display_flag = 0;  // 清除标志
            
            // 读取温度
            current_temp = DS18B20_Read_Temperature();
            
            // 如果读取成功,更新显示
            if(current_temp != 0x7FFF)
            {
                // 温度有变化才更新显示,避免闪烁
                if(current_temp != last_temp)
                {
                    last_temp = current_temp;
                    Set_Display_Buffer(current_temp, temp_sign);
                }
            }
            else
            {
                // 读取失败,显示错误
                display_buf[0] = 13;  // "H"
                display_buf[1] = 12;  // "C"
                display_buf[2] = 10;  // "-"
                display_buf[3] = 10;  // "-"
                dot_position = 0;
            }
        }
        
        // 可以在这里添加其他任务
        // 如按键检测、报警处理等
    }
}





1.jpg
2.jpg
3.jpg
4.jpg
5.jpg
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2026-04-08 08:28:01
已绑定手机

10

主题

4

回帖

80

积分

注册会员

积分
80
发表于 5 天前 | 显示全部楼层
温度和买的显示一样
8.jpg
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-4-8 16:33 , Processed in 0.110269 second(s), 49 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表