//آند مشترک #include #include #include #define F_CPU 8000000UL #include //------------------------------- پایه‌ها #define DISPLAY_PORT PORTD #define SEGMENT_PORT PORTB #define SAMPLE_SIZE 30 #define ADC_BITS 10 #define VREF 4.987f #define R1 470000.0 #define R2 14347.0 #define Led_yellow PC1 #define Led_green PC2 #define Led_red PC3 #define relay PD2 #define TEST_DISPLAY_DURATION_MS 5000 //------------------------------- سگمنت‌ها uint8_t digits[17] = { 0x18,0xDB,0x94,0xD0,0x53,0x70,0x30,0xDA,0x10,0x50, 0xf5,0x13,0x3F,0xf7,0x3D,0xb1,0x19 // 16 = - }; //------------------------------- متغیرها volatile uint16_t adc_value = 0; volatile uint16_t adc_samples[SAMPLE_SIZE]; volatile uint8_t adc_index = 0; float voltage_threshold_low = 180.0; float voltage_threshold_high = 250.0; int var = 1; // 1=مجاز، 2=پایین، 3=بالا volatile uint16_t countdown_seconds = 180; volatile uint8_t timer_active = 0; volatile uint8_t timer_display_mode = 0; volatile uint8_t blink_flag = 0; volatile uint8_t overflow_counter = 0; //------------------------------- ADC void read_analog() { ADMUX = (1 << REFS0) | (1 << MUX2); // ADC4 ADCSRA |= (1 << ADSC); } //------------------------------- نمایش void display_adc_value(int val_in) { uint8_t digits_array[3]; switch (var) { case 1: digits_array[0] = val_in % 10; val_in /= 10; digits_array[1] = val_in % 10; val_in /= 10; digits_array[2] = val_in % 10; break; case 2: // -lo digits_array[0] = 15; digits_array[1] = 14; digits_array[2] = 13; break; case 3: // -hi digits_array[0] = 12; digits_array[1] = 11; digits_array[2] = 13; break; default: digits_array[0] = digits_array[1] = digits_array[2] = 16; break; } for (uint8_t i = 0; i < 3; i++) { SEGMENT_PORT = digits[digits_array[i]]; DISPLAY_PORT |= (1 << (i + 5)); _delay_ms(2); DISPLAY_PORT &= ~(1 << (i + 5)); } } //------------------------------- بیشترین نمونه ADC uint16_t get_max_sample() { uint16_t max_sample = adc_samples[0]; for (uint8_t i = 1; i < SAMPLE_SIZE; i++) { if (adc_samples[i] > max_sample) max_sample = adc_samples[i]; } return max_sample; } //------------------------------- راه‌اندازی void setup() { DDRD = 0xFF; DDRB = 0xFF; DDRC = (1 << Led_red) | (1 << Led_yellow) | (1 << Led_green); DDRD |= (1 << relay); ADMUX = (1 << REFS0) | (1 << MUX2); ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS0); ADCSRA |= (1 << ADSC); OCR1A = 249; TCCR1B = (1 << WGM12) | (1 << CS12); TIMSK |= (1 << OCIE1A); TCCR0 = (1 << CS02) | (1 << CS00); TIMSK |= (1 << TOIE0); } //------------------------------- TIMER1: شروع ADC ISR(TIMER1_COMPA_vect) { read_analog(); } //------------------------------- TIMER0: تایمر 1 ثانیه و چشمک‌زن ISR(TIMER0_OVF_vect) { overflow_counter++; if (overflow_counter >= 31) { overflow_counter = 0; if (timer_active && var == 1) { if (countdown_seconds > 0) { countdown_seconds--; blink_flag ^= 1; if (blink_flag) PORTC |= (1 << Led_green); else PORTC &= ~(1 << Led_green); } if (countdown_seconds == 0) { timer_active = 0; timer_display_mode = 0; PORTC |= (1 << Led_green); // سبز ثابت } } } } //------------------------------- ADC Interrupt ISR(ADC_vect) { adc_samples[adc_index++] = ADC; if (adc_index >= SAMPLE_SIZE) adc_index = 0; adc_value = get_max_sample(); float adc_voltage = ((adc_value * VREF) / (1 << ADC_BITS)) * 2; float rms_voltage = (((adc_voltage * R2 * 1.01) + 0.5) / sqrt(R1 * R1 + R2 * R2)) * 1000; if (rms_voltage > voltage_threshold_high) { PORTC |= (1 << Led_red); PORTC &= ~(1 << Led_yellow | 1 << Led_green); PORTD &= ~(1 << relay); var = 3; timer_active = 0; countdown_seconds = 180; } else if (rms_voltage < voltage_threshold_low) { PORTC |= (1 << Led_yellow); PORTC &= ~(1 << Led_red | 1 << Led_green); PORTD &= ~(1 << relay); var = 2; timer_active = 0; countdown_seconds = 180; } else if (rms_voltage > (voltage_threshold_low + 5) && rms_voltage < (voltage_threshold_high - 5)) { PORTC &= ~(1 << Led_red | 1 << Led_yellow); var = 1; if (!timer_active && countdown_seconds == 180) { timer_active = 1; timer_display_mode = 1; } } // روشن شدن رله فقط بعد از پایان تایمر if (var == 1 && countdown_seconds == 0) { PORTD |= (1 << relay); } else { PORTD &= ~(1 << relay); } // --- نمایش: دقیقه.ثانیه --- if (var == 1 && timer_active && timer_display_mode) { uint8_t min = countdown_seconds / 60; uint8_t sec = countdown_seconds % 60; int display_val = min * 100 + sec; // دقیقه.ثانیه display_adc_value(display_val); } else { display_adc_value((int)rms_voltage); } } //------------------------------- تست ولتاژ (5 ثانیه) void self_test_voltage_display() { uint16_t elapsed = 0; while (elapsed < TEST_DISPLAY_DURATION_MS) { ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)); adc_samples[adc_index++] = ADC; if (adc_index >= SAMPLE_SIZE) adc_index = 0; uint32_t sum_sq = 0; for (uint8_t i = 0; i < SAMPLE_SIZE; i++) { sum_sq += (uint32_t)adc_samples[i] * adc_samples[i]; } float mean = (float)sum_sq / SAMPLE_SIZE; float adc_rms = sqrt(mean) * VREF / (1 << ADC_BITS); adc_rms *= 2.0; float rms_voltage = (adc_rms * R2) / sqrt(R1 * R1 + R2 * R2) * 1000.0; uint16_t val = (uint16_t)((rms_voltage * 1.01) + 0.5); uint8_t arr[3]; arr[0] = val % 10; arr[1] = (val / 10) % 10; arr[2] = (val / 100) % 10; for (uint8_t i = 0; i < 3; i++) { SEGMENT_PORT = digits[arr[i]]; DISPLAY_PORT |= (1 << (i + 5)); _delay_ms(2); DISPLAY_PORT &= ~(1 << (i + 5)); } elapsed += 6; } } //------------------------------- self_test: رقص + ولتاژ void self_test() { // --- فاز 1: رقص LED و سگمنت --- for (uint8_t i = 0; i < 1; i++) { PORTC |= (1 << Led_red) | (1 << Led_yellow) | (1 << Led_green); PORTD |= (1 << relay); _delay_ms(200); PORTC &= ~((1 << Led_red) | (1 << Led_yellow) | (1 << Led_green)); PORTD &= ~(1 << relay); _delay_ms(200); } // نمایش اعداد 0 تا 9 روی هر رقم سون‌سگمنت for (uint8_t num = 0; num < 10; num++) { for (uint8_t i = 0; i < 3; i++) { SEGMENT_PORT = digits[num]; DISPLAY_PORT |= (1 << (i + 5)); _delay_ms(80); DISPLAY_PORT &= ~(1 << (i + 5)); } _delay_ms(120); } // پاکسازی PORTC &= ~((1 << Led_red) | (1 << Led_yellow) | (1 << Led_green)); PORTD &= ~(1 << relay); SEGMENT_PORT = 0xFF; DISPLAY_PORT = 0x00; self_test_voltage_display(); } //------------------------------- main int main() { setup(); self_test(); // تست اولیه sei(); while (1) { // همه کارها در وقفه صورت می‌گیرد } }