PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM Attiny25



walterk
01.01.2011, 21:56
Hallo!

Seit einigen Tagen versuche ich, auf einem Attiny25 auf Lochraster eine PWM mit dem Timer0 zu erstellen.

Auf einem Atmega32, mit einem anderem selbsterstellen Quellcode und dem RN Control1.4, klappt es, der Tastgrad ist mit dem Oszi schön zu sehen.

Die Lochrasterplatine mit dem Attiny25 funktioniert ebenfalls. Einen zweiten Kontroller habe ich bereits in der Platine mit gleichem Ergebnis ausprobiert.
Den Quellcode habe ich gemäß Datenblatt erstellt.

Was kann ich noch beachten?

Walter



#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>





int main (void){

DDRB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB4);
TCCR0A = (1<<WGM00) | (1<<COM0A0) | (1<<COM0A1);
TCCR0B = (1<<WGM02) | (1<<CS02) | (1<<CS00);

OCR0A = 100;

while(1){

}
}

TobiKa
01.01.2011, 23:18
Wie bitte?!
Mit dem Atmega32 funktionierts und mit dem ATtiny auf der Lochraster ebenfalls? Na dann ist doch alles Prima.

walterk
02.01.2011, 08:28
Hallo TobiKa!

Sorry, Missverständnis, zurück an den Start:

Mein Vorhaben:
Ein Gleichstromverbraucher soll durch einen einzelnen PWM-Kanal gesteuert werden.

Der Weg dorthin:
Den ersten Versuchsaufbau habe ich mit einem Atmega32 erstellt, funktioniert. Für einen einzelnen PWM-Kanal wäre der Atmega32 überdimensioniert. Nun will ich dafür den wesentlich kleineren Attiny25 einsetzen.

Der gepostete, nichtfunktionierene Code ist vom Attiny25.

Auf der Lochrasterplatine des Attiny25 habe ich bereits ein anderes Programm für einen Attiny25 erfolgreich raufkopiert. Die Hardware (Platine) des Attiny ist ok.

Die Frage:
Der gepostete Code erzeugt keine PWM. Was habe ich übersehen?

radbruch
02.01.2011, 09:17
Hallo

Interrupts nicht freigegeben?


DDRB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB4);
// PWM, PhaseCorrect, OCRA ist Top!
TCCR0A = (1<<WGM00);
TCCR0B = (1<<WGM02);
// Set OC0A on Compare Match when up-counting. Clear OC0A on
// Compare Match when down-counting.
// OC0A ist PB0 (Pin5)
TCCR0A |= (1<<COM0A0) | (1<<COM0A1);
// Prescaler /1024 (8MHz/1024/512=15,29Hz)
TCCR0B |= (1<<CS02) | (1<<CS00);

OCR0A = 127;
OCRA = 255; // ?
sei();


Gruß

mic

TobiKa
02.01.2011, 09:19
Sicher das du die richtigen Regeister benutzt? Wo hast du das Beispiel her?

walterk
02.01.2011, 12:06
Danke für eure Antworten.

Interrupts habe ich enabled und das sei() im Code gelassen. Interrupts waren jedoch für PWM nicht erforderlich. Die entsprechenden includes kopiere ich einfach weiter, was der Präprozessor nicht braucht, wirft er raus.

Die Register Description des Timer0 vom Attiny25 liegt ausgedruckt beim PC und war die Grundlage für das Programm. Um eine PWM zu erzeugen, sind IMHO CompareOutputMode, ClockSelect und WaveformGenerationMode zu setzen.

Für den Atmega32 reichen diese Angaben, für den Attiny25 offensichtlich nicht.

Gäbe es sonst noch etwas zu beachten?

mfg
Walter

TobiKa
02.01.2011, 12:25
Mal von vorne, welche Frequenz möchtest du? Welche Art von PWM?...?



TCCR0A = (1<<COM0A1) | (1<<WGM01) | (1<<WGM00);
TCNT0 = 0;
OCR0A = 128; //50%
TCCR0B = (1<<CS02);

radbruch
02.01.2011, 12:27
Das mit den Interrupts war natürlich Quatsch, sorry.

WGM2 und WGM0 gesetzt ist PhaseCorrectPWM mit OCRA als Top!

avion23
02.01.2011, 12:47
Schau dir nochmal an, bis wohin dein Timer zählt. Entweder den Top Wert auf 0xff ändern oder OCR0C verwenden.

walterk
02.01.2011, 14:30
Als Last ist vorerst ein Elektromagnet vorgesehen, welcher an 24 - 48V mit ~0,34H und ~24Ohm die PWM glattbügeln wird. Um die Endstufe mit der Freilaufdiode nicht unnötig mit Schaltvorgängen zu belasten, ist eine möglichst niedrige PWM Frequenz angestrebt.

WGM02 und WGM00 ergibt PhasenCorrect mit OCRA als Top.
CS02 und CS00 ergibt einen Prescaler von 1024.
Die Auswirkung COM0Ax (Signalinvertierung) ist mir derzeit noch gleichgültig.

Bei der Verwendung von OCRA als Registername im Quellcode wirft ARV-Studio die Fehlermeldung: undeclared - first use in this function.

Der Timer0 des Attiny hat zwei PWM-Kanäle, deren Taktverhältnis mit den OutputCompareRegistern OCR0A und OCR0B definiert werden.

Danke für weitere Antworten.

Walter

radbruch
02.01.2011, 15:36
Hallo

Auch das Datenblatt scheint das Register OCRA nicht zu kennen. In der Beschreibung des Modi (Seite 76) heist es:


TOP is defined as 0xFF when WGM2:0 = 1, and OCR0A when WGM2:0 = 5.

In der Mode-Tabelle auf Seite 82 steht aber bei Mode 5 eindeutig Top=OCRA.

Gruß

mic

walterk
02.01.2011, 19:04
Hallo zusammen!

Danke für die Postings!

Die Attinys25 sind bereits wieder in der Transportverpackung und der Atmega32 ist in Gebrauch.

Das Datenblatt des Attiny25 ist nicht das einzige mit Ungereimtheiten:

http://www.datasheetcatalog.com/datasheets_pdf/B/D/1/7/BD179.shtml

Der maximale Basisstrom des BD179 wird hier sowohl mit 1 als auch mit 7 Ampere angegeben, dies bei einem maximalen Kollektorstrom von 3 Ampere. Die 7 A habe ich nicht getestet.

mfg
Walter

TobiKa
02.01.2011, 19:16
Hi

Der Strom wird im Datanblatt auch noch von anderen Faktoren abhängig gemacht.

Zum Controller:
Mit dem ATtiny25 scheinst nicht nur du probleme zu haben. Ich selber habe nie einen benutzt, wird auch nicht passieren...
Aber bevor es jetzt ein ATmega32 ist, benutz doch nen ATmega8, der wäre nicht so extrem überdimensioniert und PWM ist damit auch sehr einfach umzusetzen.

walterk
03.01.2011, 09:45
Danke für den Tipp.

Hatte mit dem Attiny25 u.a. vor, im Frühjahr eine Solarlüftungssteuerung mit 3x Analogeingang und 2x PWM-Ausgang zu bauen.

Nun wird es wahrscheinlich dafür ein Attiny24 mit 14 Pins werden.

Die Sache mit dem Elektromagneten werde ich mit dem überdimensionieren Atmega32 weiterverfolgen und gegen Ende einen passenden Kontroller lt. Dateblatt auswählen.

021aet04
03.01.2011, 13:26
Ich habe bei einem Attiny 45 auch Probleme (ist der gleiche nur mit mehr Flash). Wollte nur einen Analogwert einlesen und damit den PWM Kanal ansteuern. hat nicht funktioniert bis ich beim Analogkanal den Prescaler geändert habe. Zuerst habe ich den Prescaler so belassen (der Prescaler sollte laut DB 2 betragen). Jetzt habe ich den Prescaler auf 16. Das Komische daran war, dass er immer in die Interruptroutine eingestiegen ist, aber die PWM hat sich nicht geändert. Hier habe ich das Programm. Funktioniert auf einem Attiny 45.


#include <avr/interrupt.h>
#include <util/delay.h>

volatile unsigned int adc_value, adc_min, i;

ISR(ADC_vect)
{
adc_value = ADCH;
PORTB ^= (1<<PB1);
}

int main(void)
{
PORTB |= (1<<PB3)|(1<<PB4);

DDRB |= (1<<PB0)|(1<<PB1);

ADMUX = (1<<REFS1)|(1<<ADLAR)|(1<<MUX0);

ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2);

TCCR0A |= (1<<WGM00)|(1<<WGM01)|(1<<COM0A1)|(1<<COM0A0);

TCCR0B |= (1<<CS02);

sei();

while(1)
{
ADCSRA |= (1<<ADSC);
adc_value = 255 - adc_value;
OCR0A = adc_value;
_delay_ms(100);
}
}


MfG Hannes

avion23
03.01.2011, 16:19
Ich habe keine Probleme mit dem attiny25. Sowohl mit timer0 als auch mit timer1.

Welchen Sinn hat eine CTC mode mit OCR0A als top und PWM? Genau, keinen.

void initTimer1(void){
//cs13:cs10 = 0010 for 125kHz
//cs13:cs10 = 0001 for 250kHz
//TCCR1 |= (1<<CTC1); // Clear timer/counter on compare match
TCCR1 |= (1<<PWM1A); // Pulse width modulator A enable
TCCR1 |= (1<<COM1A1); // comparator A mode select, 01 here
//TCCR1 |= (1<<COM1A0);

//TCCR1 |= (1<<CS13); // clock select, prescaler
//TCCR1 |= (1<<CS12); // 125kHz
TCCR1 |= (1<<CS11);
//TCCR1 |= (1<<CS10);

GTCCR = 0;
GTCCR |= (1<<PWM1B); // enable PWM B
GTCCR |= (1<<COM1B1); // comparator B mode select
//GTTCR |= (1<<COM1B0); // 10 = clear on compare match
//GTTCR |= (1<<FOC1B); // force output compare match
//GTTCR |= (1<<FOC1A); // force output compare match
//GTTCR |= (1<<PSR1); // Reset the prescaler

OCR1A = 0;
OCR1B = 0;
OCR1C = 255; // maximum value for pwm
//TIMSK |= (1<<OCIE1A); // Output compare match a interrupt enable
PLLCSR |= (1<<PLLE); // enable PLL before enabling it as source for timer1
_delay_us(1); // wait 100us for pll to stabilize
PLLCSR |= (1<<LSM); // low speed mode

// lock detection
// Blocks until lock is detected, i.e. PLOCK = 1
while(!(PLLCSR & (1<<PLOCK)))
;

PLLCSR |= (1<<PCKE); // enable PLL as timer1 clock source

// init dead times
//DTPS1 |= (1<<DTPS11); // dead time prescaler
//DTPS1 |= (1<<DTPS10); // 00 = 1, 11 = 8
/*
// amount of dead cycles coded in binary
DT1A |= (1<<DT1AH3);
DT1A |= (1<<DT1AH2);
DT1A |= (1<<DT1AH1);
DT1A |= (1<<DT1AH0);
DT1A |= (1<<DT1AL3);
DT1A |= (1<<DT1AL2);
DT1A |= (1<<DT1AL1);
DT1A |= (1<<DT1AL0);
*/
}