基于Atmega16的LM35温度传感器Proteus仿真:负温度显示异常求助
基于Atmega16的LM35温度传感器Proteus仿真:负温度显示异常求助
看起来你已经把正温度的显示逻辑跑通了,唯独卡在负温度显示上——明明手动模拟负温度时能正常显示,但真实采样时只会出0.0℃对吧?我帮你梳理下核心问题,再给你调整后的完整代码方案。
核心问题分析
1. 偏置电压的软件处理缺失
你提到硬件上加了2.5V偏置电路来测负温度,但代码里完全没做对应的处理!LM35本身是单极性输出(0℃对应0V,正温度输出正电压),加2.5V偏置后,0℃对应2.5V,-25℃对应0V,25℃对应5V。但你原来的代码直接把ADC采样的电压除以0.01转温度,相当于把2.5V当成25℃,完全没减去偏置,所以真实采样负温度时,得到的是25℃以下的正数,自然显示不出负号。
2. LCD显示逻辑可简化
原来的代码手动判断正负号再拼接字符串,其实sprintf可以自动处理负号,没必要额外取反处理,这点可以简化。
调整后的完整代码
我标注了所有修改的地方(// MODIFIED 注释):
#include <mega16.h> #include <delay.h> #include <alcd.h> #include <stdio.h> #define ADC_VREF_TYPE ((0<<REFS1)|(1<<REFS0)|(0<<ADLAR)) const unsigned char seg_patterns[11] = { 0xC0, // 0 0xF9, // 1 0xA4, // 2 0xB0, // 3 0x99, // 4 0x92, // 5 0x82, // 6 0xF8, // 7 0x80, // 8 0x90, // 9 0xBF // Minus sign '-' }; volatile unsigned char display_digit = 0; volatile unsigned char digits[4] = {0xFF, 0xFF, 0xFF, 0xFF}; volatile unsigned char decimal_points[4] = {0, 0, 1, 0}; interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0 = 240; PORTB &= ~0xF0; if (digits[display_digit] != 0xFF) { PORTC = seg_patterns[digits[display_digit]]; if (decimal_points[display_digit]) PORTC &= ~0x80; } else { PORTC = 0xFF; } PORTB |= (1 << (display_digit + 4)); display_digit = (display_digit + 1) % 4; } unsigned int read_adc(unsigned char ch) { ADMUX = ch | ADC_VREF_TYPE; delay_us(10); ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)); return ADCW; } void update_display(float temp) { int temp_int; unsigned char is_negative = 0; // Check if temperature is negative if (temp < 0) { is_negative = 1; temp_int = (int)((-temp) * 10); // Make positive for digit extraction } else { temp_int = (int)(temp * 10); } // For negative numbers: -26.0 should show as "-26.0" // digits[0] = minus, digits[1] = 2, digits[2] = 6, digits[3] = 0 if (is_negative) { digits[0] = 10; // Minus sign if (temp_int >= 100) { // Two digits before decimal (e.g., -26.0) digits[1] = (temp_int / 100) % 10; // Tens digit digits[2] = (temp_int / 10) % 10; // Units digit digits[3] = temp_int % 10; // Decimal digit } else { // One digit before decimal (e.g., -5.2) digits[1] = 0xFF; // Blank digits[2] = (temp_int / 10) % 10; // Units digit digits[3] = temp_int % 10; // Decimal digit } } else { // Positive numbers if (temp_int >= 1000) { // Three digits (e.g., 125.4) digits[0] = (temp_int / 1000) % 10; digits[1] = (temp_int / 100) % 10; digits[2] = (temp_int / 10) % 10; digits[3] = temp_int % 10; } else if (temp_int >= 100) { // Two digits (e.g., 25.5) digits[0] = 0xFF; // Blank digits[1] = (temp_int / 100) % 10; digits[2] = (temp_int / 10) % 10; digits[3] = temp_int % 10; } else { // One digit (e.g., 5.2) digits[0] = 0xFF; // Blank digits[1] = 0xFF; // Blank digits[2] = (temp_int / 10) % 10; // Units digit digits[3] = temp_int % 10; // Decimal digit } } // Set decimal point position (after digit 2) decimal_points[0] = 0; decimal_points[1] = 0; decimal_points[2] = 1; // Decimal point here decimal_points[3] = 0; } void main(void) { DDRB = 0xF1; DDRC = 0xFF; PORTC = 0xFF; TCCR0 = (1 << CS01); TIMSK |= (1 << TOIE0); TCNT0 = 240; ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); lcd_init(16); #asm("sei") lcd_clear(); // Test counter for simulating different temperatures int test_counter = 0; while (1) { unsigned int adc_value = read_adc(0); float voltage = (adc_value * 5.0) / 1024.0; // MODIFIED: 减去2.5V偏置电压,转换为真实温度 float temp = (voltage - 2.5) / 0.01; // LM35 output 10mV per °C (with 2.5V bias) // TEMPORARY: Simulate negative temperatures for testing // Remove this section once you confirm negative display works if (test_counter < 10) { temp = -26.5; // Test negative temperature } else if (test_counter < 20) { temp = -5.2; // Test single digit negative } else if (test_counter < 30) { temp = 25.5; // Test positive temperature } else { test_counter = 0; // Reset counter } test_counter++; // END OF TEST SECTION char lcd_text[16]; // MODIFIED: 直接用sprintf自动处理负号,简化代码 sprintf(lcd_text, "Temp: %.1fC", temp); lcd_clear(); lcd_puts(lcd_text); update_display(temp); delay_ms(500); } }
测试与验证步骤
- 先保留测试代码段,手动设置负温度,确认7段码和LCD都能正确显示负号与数值;
- 移除测试代码,在Proteus中搭建好LM35+2.5V偏置的电路,调整仿真温度到负数区间,检查ADC采样后的温度转换是否正确;
- 确认硬件位选(PORTB高四位)与段选(PORTC)的连线和代码逻辑完全对应,避免接线错误导致显示异常。
内容来源于stack exchange




