⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 charger.c

📁 基于AVR制作的电话语音录制系统
💻 C
📖 第 1 页 / 共 2 页
字号:
        c=pgm_read_byte(p++);
        if (!c) break;
        xmit(c);
    }
}

/* This function transmits a byte in 'c' over the serial channel. It stores
   the byte in the transmit FIFO and sets the transmission counters if
   appropriate. Actual transmission happens in the Timer0 interrupt service
   routine */

void xmit(unsigned char c)
{
    // Find out what the next tail index will be, accounting for circularity
    unsigned char next_tail=txtail+1;
	if (next_tail==TXFIFOSIZE) next_tail=0;
    // If the FIFO is full, return with no action, discarding the byte
	if (next_tail==txhead) return; 
    // Insert byte into the transmit FIFO and update tail index
	fifo[txtail]=c; txtail=next_tail;
    // Start a new transmission cycle if we're not already doing so
	if (!xmitbit) {
	    xmitbit=1; xmitbyte=fifo[txhead++];
		if (txhead==TXFIFOSIZE) txhead=0;
	}
}

void do_charge_control(void)
{
	// Sense the current battery voltage. Since we do this at the very beggining
	// of the RTC clock cycle, we know for sure that the PWM is off and we're
	// sensing the battery voltage and not the charger voltage.
	voltage=get_battery_voltage();
	// This is a trick to have the average accumulator and counter in the same
	// integer. The current accumulated average is in bits 31..8 and the average
	// counter is in bits 7..0.
	avg_accum+=((unsigned long)voltage<<8)|1;
	// If we don't have main voltage (or, more precisely, the main voltage is
	// less than 10.2V), we won't charge the battery, period, no  matter what 
	// the charging logic says
    unsigned short mains_voltage=get_mains_voltage();
	if (mains_voltage<650 || quell_charging) {
        set_duty_cycle(0);
        disable_charger();
		//disable_battery_pwm();
		//DDRD |= _BV(PD7);
		//PORTD |= _BV(PD7);
        if (charging_state!=BatteryNotCharging) {
            charging_state=BatteryNotCharging;        
#ifdef BATT_DEBUG				
            xmit_timestamp();
            xmit_pstr(" LOW MAINS (");
            xmit_u8as4d(mains_voltage);
            xmit_pstr("): MOVING TO 'NOT CHARGING'\r\n");
#endif
        }
    } else {
	    if (charging_state==BatteryNotCharging) {
		    charging_state=BatteryInitialSense;
            xmit_timestamp();
            xmit_pstr(" STARTING UP: MOVING TO 'INITIAL SENSE'\r\n");
        }
	}
	// If we had 256 samples accumulated already, let's take some action
	if (!(avg_accum&0xFF)) {
	    short voltage=avg_accum>>13;              // Compute average
		avg_accum=0;                               // Zero average accumulator
		max_battery_charge_time--;
#ifdef BATT_DEBUG				
        xmit_timestamp();
        xmit_pstr(" V=");
        xmit_k1_u8as5dot2f(voltage);
        xmit_crlf();
#endif
		switch (charging_state) {
		    case BatteryNotCharging:
#ifdef BATT_DEBUG				
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" NOT CHARGING: ");
					if (quell_charging)
					    xmit_pstr("DISABLED BY SOFTWARE");
					else
					    xmit_pstr("NO MAIN POWER\r\n");
#endif
			    break;
		    case BatteryInitialSense:
			    // If we're below 2 volts, the battery is almost certainly
				// disconnected, so we have nothing to charge. We also don't
				// charge if the battery voltage is beyond levels only found
				// during fast charge
			    if (voltage<1088 || voltage>4592) {
                    set_duty_cycle(0);
                    disable_charger();
				    //disable_battery_pwm();
					//DDRD |= _BV(PD7);
					//PORTD |= _BV(PD7);
					charging_state=BatteryInitialSense;
#ifdef BATT_DEBUG					
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" INITIAL SENSE: "
					    "VOLTAGE OUT OF RANGE\r\n");
#endif
					break;
				}
				// If we're above 8 volts, the battery is still in very good
				// shape and maybe didn't even had the time to cool down from
				// the last charge, so let's switch to trickle. Otherwise,
				// start a soft charge to get things started
			    if (voltage>4256) {
				    charging_state=BatteryTrickleCharging;
					//OCR2=245; // 4% Duty cycle
                    set_duty_cycle(4); // 4% duty cycle
#ifdef BATT_DEBUG					
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" INITIAL SENSE: "
					    "MOVING TO 'TRICKLE CHARGE'\r\n");
#endif
					// Come back to this state ~5 min before each hour starts
					// so we can recheck the voltage and decide what to do
					max_battery_charge_time=13;
				} else {
				    charging_state=BatterySoftCharging;
					//OCR2=128;   // 50% Duty cycle
                    set_duty_cycle(50); // 50% duty cycle
#ifdef BATT_DEBUG					
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" INITIAL SENSE: "
					    "MOVING TO 'SOFT CHARGE'\r\n");
#endif
					// Arm a timer to stop the full charging process at
					// most 63 256-second cycles (i.e., around 4h28min) later
					max_battery_charge_time=63;
				}
				//DDRD |= _BV(PD7);
				//enable_battery_pwm();
#ifdef BATT_DEBUG					
				xmit_timestamp();
				xmit_pstr(" INITIAL SENSE: "
				    "DONE\r\n");
#endif
			    break;
			case BatteryTrickleCharging:
			    // If enough time has passed, give the battery a
				// rest and let the initial state decide what to do
                if (!max_battery_charge_time) {
				    charging_state=BatteryInitialSense;
                    set_duty_cycle(0);
                    disable_charger();
					//disable_battery_pwm();
					//DDRD |= _BV(PD7);
					//PORTD |= _BV(PD7);
#ifdef BATT_DEBUG					
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" TRICKLE: "
					    "MOVING TO 'NO CHARGING'\r\n");
#endif
				}
				break;
			case BatterySoftCharging:
			    // After one cycle of soft charge, let's go to fast
				// charging. The soft charge thing helps to eliminate
				// false peaks that may confuse the full charge mode
				// negative delta-V (that is, voltage drop) -based
				// termination algorithm.
				//OCR2=5;  // 98% duty cycle 
                set_duty_cycle(98); // 98% duty cycle
				charging_state=BatteryFastCharging;
#ifdef BATT_DEBUG					
				xmit_crlf();	
				xmit_timestamp();
				xmit_pstr(" SOFT: "
				    "MOVING TO 'FAST CHARGING'\r\n");
#endif
			    break;
			case BatteryFastCharging:
			    // We finish the fast charge process if either we
				// spent the absolute maximum time or if the voltage
				// has decreased since our last measurement -- If the
				// battery is in use (i.e., we have no main power), this
				// is because it is being discharged, so our charging
				// attempts are moot. If we do have main power, the
				// voltage drop is because we've hit the maximum battery
				// capacity, so we should stop.
                if (!max_battery_charge_time || last_voltage>voltage) {
				    charging_state=BatteryInitialSense;
                    set_duty_cycle(0);
                    disable_charger();
					//disable_battery_pwm();
					//DDRD |= _BV(PD7);
					//PORTD |= _BV(PD7);
#ifdef BATT_DEBUG					
                    xmit_crlf();	
                    xmit_timestamp();
					xmit_pstr(" FAST: "
					    "MOVING TO 'NO CHARGING'\r\n");
#endif
				}
				last_voltage=voltage;
				break;			
		}
    }
}

/* Select ADC channel 'ch' and takes a voltage reading. Used indirectly
   through the get_battery_voltage() and get_mains_voltage() macros. */

unsigned short getVoltage(unsigned char ch)
{
	adc_set_channel(ch);
	adc_start();
	while (adc_busy());
    return adc_value();
}

/* Timer0 Output Compare Interrupt Service Routine: this is called
   BAUD_RATE*PHASE times per second to serially transmitting bits -- a
   software UART, in fact. (Actually, a software UAT, because it's transmit
   only. The PHASE thing is a relic from an earlier version that did have a
   receiver. It is not really needed for the transmitter but since it doesn't
   hurt, I opted for leaving it there).
   
   Besides, the routine updates the clock each second and also controls the
   timing of the battery charger enable bit -- like a slow PWM.
   
*/

SIGNAL(SIG_OUTPUT_COMPARE0A)
{
    // --- Software UART for serial reception and transmission

    phase=cnt++&PHASE_MASK;
    
    // Serial transmission: if it's time to transmit a bit and
    // we do have something to transmit, let's do it!
	if (!phase) {
        if (xmitbit) {
            if (xmitbit==1) {                      // Start bit
                    xmit0();
                    xmitbit++;
            } else if (xmitbit==10) {              // Stop bit
                    xmit1();
                if (txhead==txtail) 
                    xmitbit=0;
                else {
                    xmitbit=1;
                    xmitbyte=fifo[txhead++];
                    if (txhead==TXFIFOSIZE) txhead=0;
                }
            } else {                                // Data bits
                if (xmitbyte&1) {
                    xmit1();
                } else {
                    xmit0();
                }
                xmitbyte>>=1; xmitbit++;
            }
        }
        if (++gcount==BAUD_RATE) {
            // 1Hz ticker for updating the clock and resseting the
            // charger control
            gcount=0;
            if (seconds==59) {
                seconds=0;
                if (minutes==59) {
                    minutes=0;
                    if (hours==23) {
                        hours=0;
                    } else hours++;
                } else minutes++;
            } else seconds++;
            has_new_second=TRUE;
            if (duty_cycle>0) 
                disable_charger();
        }
        // Enables the charger at some point within the 1Hz cycle
        if (gcount==duty_cycle) {
            enable_charger();
        }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -