16.01.2019, 02:21 AM
(Dieser Beitrag wurde zuletzt bearbeitet: 16.01.2019, 02:28 AM von voltwide.)
(16.01.2019, 02:12 AM)alfsch schrieb: >Damit wäre Stromsparen im sleep modus also nicht möglich....
hä? sleep hat < 1uA....was willst da genau noch "sparen" ??
Nö, es ging ja darum die PLL zu nutzen - und die wird aber schon im standby Modus deaktiviert.
Den progagierten Stromverbrauch erreiche ich ja darüber dass der uP die meiste Zeit im standby-Mode verweilt.
Echter power-down nach WDT-TimeOut ist eine andere Baustelle.
Code:
/* A Very Basic USB/LiIon-Battery-Powered Audio Sine-Wave Test Generator
created: 2014-01-21
update: 2019-01-07a
author: VoltWide
target ATTINY25-20
clock frequency ............... 8Mhz/1 internal
fuses uncheck CLKDIV8
check untouch EEPROM
hfuse readout, bitEna=0 11010111b
WDTON = bit4 disabled=safety level1
prototype data
output function pwm sine
max output level, peak-peak >90% of Vsupply
pwm sample rate 8MHz/512 = 16khz
output frequencies/THD 15Hz/0.48%
30Hz/0.33%
60Hz/0.31%
125Hz/0.52%
250Hz/0.6%
500Hz/0.92%
1000Hz/0.63%
power supply 2.7~5.5V: USB, 3V-LiBatt, 2~3xAA..
power consumption active, no load, 2*ADC/17+17ms, LED 5V*2.68mA, 4V*2.05mA, 3V*1.41mA
power consumption sleep-idle, cli, max prr, PORTB=0 3V*0.7mA
Atmel specs page 166
power consumption idle @8MHz 5V*1.2mA
power consumption ref1.1.....................................2.7V*15uA
cpu load irq on/off 7.4us/56.4us
eof battery charge threshold = watchdog disable 4V
UVLO shut down threshold disabled
shut down current consumption <1uA
DIP8/SOIC8 multilevel-pinning:
pin1 PB5 PCINT5 /RESET ADC0 dW
pin2 PB3 PCINT3 XTAL1 CLKI /OC1B ADC3
pin3 PB4 PCINT4 XTAL2 CLKO OC1B ADC2
pin4 GND
pin5 PB0 MOSI DI SDA AIN0 OC0A /OC1A AREF PCINT0
pin6 PB1 MISO DO AIN1 OC0B OC1A PCINT1
pin7 PB2 SCK USCK SCL ADC1 T0 INT0 PCINT2
pin8 VCC
*/
#include <stdlib.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
const __flash char SineTab[] = { // 8bit sinewave lookup table
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
};
const __flash uint16_t FqTab[] = {
//64,128,256,512,1024,2048,4096,8192,16384,32768
63,126,250,526,1047,2089,4188 //2018-12-27 customized!!
};
const int8_t FrequIdxMax = 6; //2018-12-27
// i/o mapping
#define pin1 (1<<PB5)
#define pin2 (1<<PB3)
#define pin3 (1<<PB4)
#define pin5 (1<<PB0)
#define pin6 (1<<PB1)
#define pin7 (1<<PB2)
#define OutSine pin6
#define OutChargeReq pin5
#define OutPoti pin7
#define InVcc pin2
#define InPoti pin3
//input divider Rhi/Rlo=10k/2k2 Cin=0 Vref=1V1 VBattMin=3V VBattMax=4V:
//Vin(max,min) = 0.72/0.54V
//ADCin(maxs,min) =167/125
#define VBattMax 167
#define VBattHyst 5
#define EmptyBattCountDown 200
//!!! 2count/sec:
#define WDTirqCountDown 3600
//++++++++ global vars
volatile uint16_t Phase16,PhaseOfs16,WDTirqCount; // 2019-01-06
uint8_t PotiResult,VccResult,EmptyBattcount,FrequIdx,EnaGetVcc,LoopCount; //2018-12-27
//++++++++ Initialisation
void Boot(void){
//Timer
GTCCR = (1<<TSM) | (1<<PSR0); // timer0: reset pre-scaler
TCCR0A = (1<<COM0B1) | (1<<COM0B0) | (1<<WGM00); // 2018-12-27 output pin6 only
TCCR0B = ( 1<<CS00 ); // clk=cpuclk/1
TCNT0 = 0; // clear counter
OCR0A = 0; // clear pwm output compare register A
OCR0B = 0; // clear pwm output compare register B
TIMSK = (1<<TOIE0); // timer0-irq on counter overflow
GTCCR = 0; // start counter(s)
//Ports
MCUCR |= (1<<PUD); // 2018-12-26 pullup,sleep=off, sleepmode=idle
DDRB = OutSine | OutChargeReq | OutPoti; // 2018-12-26 output ports
PINB = -1; // 2018-12-26 power reduction of dig input buffers
DIDR0 = (1<<ADC0D) | (1<<ADC1D) | (1<<ADC2D) | (1<<ADC3D); // 2018-12-26 dig inputs=off
//ADC
ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<MUX0) | (1<<MUX1); // 2018-12-27 adcref=1V1, result left adj, in=ADC3/PB3/pin2
ACSR = (1<<ACD); // 2018-12-26 comp=off
ADCSRA = 0; // 2018-12-26 ADCen,ADCstart,ADCtrig,ADCirq=off, adcclk=cpuclk/2
ADCSRB = 0; // 2018-12-26 unipolar, polarity=tru,free running
//Misc
PRR = (1<<PRTIM1) | (1<<PRUSI) | (1<<PRADC); // power timer1,usi,adc=off
PhaseOfs16 = FqTab[FrequIdx];
Phase16 = 0;
LoopCount=-1; // 2018-12-27!!
WDTirqCount = WDTirqCountDown; // 2019-01-06
EnaGetVcc=1; // 2019-01-06
sei();
}
void ShutDown(void) {
cli(); // 2018-12-26
ADCSRA = 0; // 2018-12-26 dis ADC???
TCCR0A = 0; // 2018-12-27 disconn sine port from timer, PRIOR! to powersave
MCUSR = 0; // 2019-01-06 clear WDRF
WDTCR |= (1<<WDCE) | (1<<WDE); // 2019-01-06
WDTCR = 0; // 2019-01-06 clear WDE
ADMUX = 0; // 2019-01-06 disable ref1V1
PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRUSI) | (1<<PRADC); // 2018-12-26 power timer0+1,usi,adc=off
PORTB = 0; // 2018-12-26 LED=off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // 2018-12-26
sleep_enable(); // 2018-12-26
sleep_cpu(); // shut down
}
ISR(WDT_vect){ // ca 2x/s: autoclears WDIE, must be set again to avoid wdt-reset
sleep_disable(); // wakeup!
WDTirqCount--; // 2019-01-07 shutdown not here, but in main loop
WDTCR |= (1<<WDIE); // continue wdt irq, not wdt reset
}
void WDTon(void) { // 2019-01-06 p.45, safety level 1
WDTCR = (1<<WDIE) | (1<<WDE) | (1<<WDP2) | (1<<WDP0); // Watchdog timer 0.5sec ticker
MCUSR |= (1<<WDRF); // 2019-01-07 overrides WDE
}
void WDToff(void) { // 2019-01-06 p.45, safety level 1, timed sequence:
MCUSR = 0; // c.code example 8.4.2: clear WDRF
WDTCR |= (1<<WDCE) | (1<<WDE);
WDTCR = 0; // clear WDE
}
ISR(TIM0_OVF_vect) { // DDS-irq: output next sound sample
uint8_t Voltage,Phase8; //2019-01-06
Phase16 += PhaseOfs16; //16bit phase pointer
Phase8 = Phase16 >> 8; // 8bit table index
Voltage = (SineTab[Phase8]); // drive h-bridge:
OCR0B = Voltage; // 2018-12-27 sinewave true output
}
void GetPoti (void) {
ADCSRA |= (1<<ADEN) | (1<<ADSC); // 2018-12-26 start ad-conversion fsample=clk/2 adcirq=off
while (0 == (ADCSRA & (1<<ADIF))); // A/D-conversion
ADCSRA |= (1<<ADIF); // 2019-01-07
PotiResult = ADCH; // bit9..2 , 8bit result
ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<MUX0) | (1<<MUX1); // 2018-12-27 ref-1V1 early turn-on, ADC3=PB3
}
void GetVcc (void) {
ADCSRA |= (1<<ADEN) | (1<<ADSC); //2019-01-06 start adc fsample=clk/2 adcirq=off
while (0 == (ADCSRA & (1<<ADIF))); //
ADCSRA |= (1<<ADIF); // 2019-01-07
VccResult = ADCH; // bit9..2 , 8bit result
ADMUX = (1<<ADLAR) | (1<<MUX1); // 2019-01-06 ref-1V1 early turn-off!!!
if (VccResult>=VBattMax){
WDToff(); // 2019-01-06 WDT=off
WDTirqCount = WDTirqCountDown; // 2019-01-06
}
if (VccResult<=(VBattMax-VBattHyst)) {
WDTon(); // 2019-01-06 hysteresis!! WDT=on
}
}
void GetFrequ (void) { // 2018-12-26
FrequIdx = PotiResult>>5; // 2018-12-26
if (FrequIdx>FrequIdxMax) FrequIdx=FrequIdxMax; // 2018-12-27
PhaseOfs16 = FqTab[FrequIdx]; // 2018-12-26
}
//++++++++ Main Program
int main(void) {
Boot();
for (;;) {
while (LoopCount!=0) { // 2019-01-06 skip main loops
LoopCount--;
sleep_cpu(); // 2019-01-06 power down
}; // skip main program
PRR &= ~(1<<PRADC); // 2018-12-27 ADC-power-reduction=off
PORTB |= OutPoti; // 2019-01-06 tpulse=0
if ( EnaGetVcc) { // 1.pass: battery monitor first for max ref1V1 setup time
GetVcc();
EnaGetVcc=0;
}
else { // 2.pass
GetPoti();
GetFrequ();
LoopCount=-1; // 2019-01-06 done, skip main loops
EnaGetVcc=1; // 2019-01-06
PORTB &= ~OutPoti; // 2019-01-06 disconnect Vcc from poti
} // 2019-01-06 tpulse=21.6us/16.2ms
if (WDTirqCount==0) ShutDown(); // 2019-01-06
PRR = (1<<PRTIM1) | (1<<PRUSI) | (1<<PRADC); // 2019-01-06 power timer1,usi,adc=off
set_sleep_mode(SLEEP_MODE_IDLE); // 2019-01-06 cpu & i/o clocks active
sleep_enable();
sleep_cpu(); // 2019-01-06 power down
}
}
...mit der Lizenz zum Löten!