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

问题描述
我基于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值转换为实际温度的整数形式:
- 修改主函数中温度计算和显示的代码:
// 替换原有的hex2ascii(adc*2); 行 unsigned int temp = (adc * 500) / 256; // 计算得到xx.x℃的整数形式(如295代表29.5℃) temp = (temp + 5) / 10; // 四舍五入到整数温度 hex2ascii(temp);
- 修改报警条件:
// 替换原有的if(adc*2 > 0x1d)行 unsigned int temp_threshold = 290; // 29℃对应290 unsigned int temp = (adc * 500) / 256; if(temp > temp_threshold)
方式2:显示一位小数(更平滑)
若LCD空间允许,显示一位小数可实现更细腻的温度变化:
- 添加带小数的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); }
- 修改主函数中的温度显示代码:
unsigned int temp = (adc * 500) / 256; // 得到xx.x的整数形式 lcd_cmd(0x89); hex2ascii_with_decimal(temp);
- 调整温度标签的位置:
// 替换原有的温度标签代码 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
相关产品推荐
相关产品推荐

