You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于8051的高温报警系统温度显示异常问题求助

Proteus 8截图

问题描述

我基于8051开发了高温报警系统,代码中用adc*2计算LM35传感器的温度值,但只能显示偶数温度(如28℃、30℃),无法呈现奇数温度(29℃、31℃)。需要实现温度数值连续平滑变化,无跳变或舍入误差。

原代码

//Code for HIGH TEMPERATURE ALERT SYSTEM using 8051

#include<reg51.h> // Includes 8051 microcontroller definitions

// Function declarations
void delay(unsigned int i); // Generates a delay for LCD enable pulse
void lcd_cmd(unsigned char a); // Sends a command to the LCD
void lcd_data(unsigned char b); // Sends data (characters) to the LCD
void lcd_init(void); // Initializes the LCD
void lcd_str(unsigned char *str); // Displays a string on the LCD
void hex2ascii(unsigned char value); // Converts hex value to ASCII for display

// Pin and port definitions
sbit rs = P2^0; // Register select pin for LCD
sbit en = P2^1; // Enable pin for LCD
sfr ldata = 0xb0; // Data port for LCD (Port 3)
sbit rd = P2^2; // Read pin for ADC
sbit wr = P2^3; // Write pin for ADC
sbit intr = P2^4; // Interrupt pin from ADC
sfr adc = 0x90; // ADC data from Port 1
sbit buz = P2^5; // Buzzer control pin

// Main function
void main ()
{
    // LCD welcome message
    lcd_init(); // Initialize LCD
    buz = 0; // Ensure the buzzer is off at the start
    lcd_str("    WELCOME    "); // Display first line of welcome message
    lcd_cmd(0xc0); // Move to the second line
    lcd_str("   TO PROJECT   "); // Display second line of welcome message
    delay(65000); // Delay for display
    lcd_cmd(0x01); // Clear the display
    
    // Display project title
    lcd_cmd(0x81); // Position the cursor
    lcd_str("  TEMPERATURE  "); // Display project title
    lcd_cmd(0xc2); // Move to the second line
    lcd_str("   ALERT   "); // Display 'ALERT' text
    delay(65000); // Delay for display
    lcd_cmd(0x01); // Clear display
    
    // Display temperature label
    lcd_cmd(0x80); // Move cursor to first line, start position
    lcd_str("  Temp ="); // Display 'Temp =' text
    lcd_cmd(0x8b); // Move cursor to show temperature in degrees
    lcd_data((char)223); // Display degree symbol
    lcd_str("C"); // Display 'C' for Celsius

    // Infinite loop to continuously monitor temperature
    while(1)
    {   
        // ADC conversion process
        rd = 1; // Set read high
        wr = 0; // Start conversion by setting write low
        delay(100); // Wait for conversion
        wr = 1; // Set write high
        while(intr == 1); // Wait until conversion finishes (interrupt flag low)
        delay(100); // Small delay
        rd = 0; // Set read low to fetch ADC result

        // Display temperature value
        lcd_cmd(0x89); // Set cursor position to display temperature value
        hex2ascii(adc*2); // Convert ADC value to ASCII and display
        
        // High-temperature alert condition
        if(adc*2 > 0x1d) // Check if temperature exceeds threshold (29°C)
        {
            // Display alert message and activate buzzer
            lcd_cmd(0xC0); // Move cursor to second line
            lcd_str("HIGH TEMP ALERT!"); // Display high temp alert message
            buz = 1; // Turn buzzer on
        }
        else
        {
            // Clear alert message and turn off buzzer
            lcd_cmd(0xC0); // Move cursor to second line
            lcd_str("                "); // Clear the alert message
            buz = 0; // Turn buzzer off
        }
        intr = 1; // Ready for next ADC conversion
    }
}

// Function to convert hex value to ASCII and display on LCD
void hex2ascii(unsigned char value) 
{
    unsigned char x, d1, d2, d3;
    x = value / 10; // Extract tens digit
    d3 = value % 10; // Extract ones digit
    d2 = x % 10; // Extract tens digit
    d1 = x / 10; // Extract hundreds digit
    //lcd_data(d1 + 0x30); // Display hundreds digit (ASCII)
    lcd_data(d2 + 0x30); // Display tens digit (ASCII)
    lcd_data(d3 + 0x30); // Display ones digit (ASCII)
}

// LCD initialization function
void lcd_init()
{
    lcd_cmd(0x38); // Initialize LCD for 8-bit mode
    lcd_cmd(0x0c); // Display on, cursor off
    lcd_cmd(0x01); // Clear display
    lcd_cmd(0x80); // Set cursor to beginning of first line
}

// Delay function
void delay(unsigned int i)
{
    unsigned int j;
    for(j = 0; j < i; j++); // Simple loop for delay
}

// Function to send command to LCD
void lcd_cmd(unsigned char a)
{
    rs = 0; // Set for command mode
    ldata = a; // Load command to data port
    en = 1; // Enable LCD
    delay(5); // Small delay
    en = 0; // Disable LCD
    delay(5); // Small delay
}

// Function to send data (characters) to LCD
void lcd_data(unsigned char b)
{
    rs = 1; // Set for data mode
    ldata = b; // Load data to data port
    en = 1; // Enable LCD
    delay(5); // Small delay
    en = 0; // Disable LCD
    delay(5); // Small delay
}

// Function to display string on LCD
void lcd_str(unsigned char *str)
{
    while(*str) // Loop until the end of the string
    {
        lcd_data(*str++); // Send each character to the LCD
    }
}

问题原因

LM35输出为10mV/℃,若使用8位ADC(参考电压5V),分辨率约为19.53mV。原代码adc*2相当于用39.06mV对应1℃,直接舍去了小数部分,导致每次ADC值变化1时,温度只能跳变2℃,无法显示奇数温度。

解决方法

方式1:显示整数温度(含奇偶)

通过精确计算+四舍五入,把ADC值转换为实际温度的整数形式:

  1. 修改主函数中温度计算和显示的代码:
// 替换原有的hex2ascii(adc*2); 行
unsigned int temp = (adc * 500) / 256; // 计算得到xx.x℃的整数形式(如295代表29.5℃)
temp = (temp + 5) / 10; // 四舍五入到整数温度
hex2ascii(temp);
  1. 修改报警条件:
// 替换原有的if(adc*2 > 0x1d)行
unsigned int temp_threshold = 290; // 29℃对应290
unsigned int temp = (adc * 500) / 256;
if(temp > temp_threshold)

方式2:显示一位小数(更平滑)

若LCD空间允许,显示一位小数可实现更细腻的温度变化:

  1. 添加带小数的ASCII转换函数:
void hex2ascii_with_decimal(unsigned int value) 
{
    unsigned char d1, d2, d3;
    d1 = value / 100; // 十位
    d2 = (value / 10) % 10; // 个位
    d3 = value % 10; // 小数位
    lcd_data(d1 + 0x30);
    lcd_data(d2 + 0x30);
    lcd_data('.');
    lcd_data(d3 + 0x30);
}
  1. 修改主函数中的温度显示代码:
unsigned int temp = (adc * 500) / 256; // 得到xx.x的整数形式
lcd_cmd(0x89);
hex2ascii_with_decimal(temp);
  1. 调整温度标签的位置:
// 替换原有的温度标签代码
lcd_cmd(0x80);
lcd_str("  Temp =");
lcd_cmd(0x8d); // 调整温度符号的位置
lcd_data((char)223);
lcd_str("C");

关键逻辑说明

8位ADC的温度计算公式:温度(℃) = (ADC值 × 参考电压) ÷ (256 × 0.01),其中0.01对应LM35的10mV/℃输出。四舍五入处理能确保温度接近整数时,正确显示奇偶数值。

内容的提问来源于stack exchange,提问作者Pavan Freak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:35:54