Forum: Mikrocontroller und Digitale Elektronik Code von Atmel Mega8 auf ATtiny13


von Andy (Gast)


Lesenswert?

Hallo wollte mal fragen wie ich den Code umschreiben muss dass er auf 
einem ATtiny 13 läuft hab jetzt viel rumprobiert und wäre für eine 
Lösung sehr dankbar. Funktion: Eine Led blinkt und wird über einen Poti 
geregelt.

#define F_CPU 3686400
#include <avr\io.h>
#include <inttypes.h>
#include <avr\interrupt.h>
//---------------------------------------------------------------------- 
----
unsigned char timer_value;
ISR (TIMER0_OVF_vect)
{
  PORTB = ~ PORTB;    // Flankenwechsel für Tonfrequenz
  TCNT0 = timer_value;
}

ISR(ADC_vect)
{
  int adc_value;
  adc_value=ADC;
  timer_value=char(adc_value/5);
  sbi  (ADCSRA,6);      // restart ADC
}

void adcInit()
{
  ADMUX=0;
  ADCSRA=0xDD;      //0b11011101, ADC-Clock, ADC ON, INT ON
}

void timer0Init()
{
  timer_value=0xFF;
  TCCR0=0x05;
  TIMSK=0x01;
}

void portsInit()
{
  sbi(DDRB,0);      //OUT Summer
  sbi(DDRB,1);      //OUT LED
}

main()
{
  //Initialisierung
    portsInit();      // PortB als Ausgang initialisieren
    timer0Init();      // Timer Interrupt initialisieren
    adcInit();
    sei();                  // enable interrupts
  do { } while(true);    // mainloop
}

von Karl H. (kbuchegg)


Lesenswert?

Die Lösung besteht darin, dass du dir
* das Datenblatt zum Mega8
* das Datenblatt zum Tiny13
besorgst und das Programm zunächst analysierst. Du nimmst das Datenblatt 
zum Mega8 und gehst das Programm durch, bis du verstanden hast, was da 
alles genau abgeht. Die Details, was die ganzen Registerzuweigungen 
machen, holst du dir aus dem Datenblatt zum Mega8

Nachdem der Istzustand damit erhoben ist, werden die Datenblätter 
verglichen, ob alles was auf dem Mega8 benutzt wurde, auch in dieser 
Form auf dem Tiny13 verfügbar ist.

Das meiste davon wird identisch sein, aber kleinere Abweichungen wird es 
geben.

Und dann wird das Programm vom Mega auf den Tiny übertragen, wobei die 
Erkentnisse aus dem Datenblattvergleich einfliessen.


Auch auf die Pinbelegung nicht vergessen.
Während der Mega8 3 Ports hat, hat der Tiny nur einen: Alles, auch der 
ADC, ist am PortB.
In der ISR wird daher das hier
  PORTB = ~ PORTB;    // Flankenwechsel für Tonfrequenz
nicht so schlau sein.

von Andy (Gast)


Lesenswert?

Ja
hab soweit alles verglichen. Die LED brennt zwar aber der Timer scheint 
nicht zu funktionieren. Wie wird das  PORTB = ~ PORTB;  gelöst 
vielleicht liegt es auch daran dass es nicht geht.

von Karl H. (kbuchegg)


Lesenswert?

Sorry.
Aber ich geh jetzt nicht her und drösle das hier

  ADCSRA=0xDD;      //0b11011101, ADC-Clock, ADC ON, INT ON

  TCCR0=0x05;
  TIMSK=0x01;

dahingehend auf, welche Bits da wirklich gesetzt sind.

> Wie wird das  PORTB = ~ PORTB;

Indem man nur die Bits toggelt, die auch tatsächlich benutzt werden?
An denen also Summer und LED hängen.

Durch diesen Rundumschlag schaltest du auf dem ADC Pin ständig den 
Pullup Widerstand ein/aus. Der ADC wird so alles mögliche messen, nur 
nicht das, was du willst.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Andy schrieb:

> Ja
> hab soweit alles verglichen. Die LED brennt zwar aber der Timer scheint
> nicht zu funktionieren.

Hast du auch daran gedacht, die Taktraten zu vergleichen?

Wenn der Atmega8 langsamer taktet als der Attiny13 kann es passieren, 
dass das Blinken zu schnell für deine Augen wird und du nur noch 
Dauerleuchten siehst.

Wenn das zutrifft, gibt es mehrere Wege, dem abzuhelfen. Ein Weg wäre, 
den Hardware PRESCALER des Timers zu erhöhen. Das wäre eine Änderung in 
der kryptischen Zeile TCCR0=0x05;

Ich würde mich auch im ersten Schritt nur auf den Timer und die LED 
konzentrieren und erst wenn das steht, den ADC verwenden. Für den ersten 
Schritt würde ich die Zeile

  timer_value=char(adc_value/5);

mal durch

  timer_value=char(/*adc_value*/ 511/5);

ersetzen. Die 511 sind willkürlich gewählt (Mittelwert des 10-Bit 
ADC-Bereichs 0..1023).

Es muss auch heissen (s. Tutorial):
volatile unsigned char timer_value;
Das ist schon ein Bug im Atmega8 Programm.

von Andy (Gast)


Lesenswert?

Hab jetzt alles mögliche ausprobiert bekomme es aber nicht zum laufen, 
die Led leuchtet nur. Ich weiß nicht mehr weiter.

#define F_CPU 3686400
#include <avr\io.h>
#include <inttypes.h>
#include <avr\interrupt.h>
//---------------------------------------------------------------------- 
----
volatile unsigned char timer_value;
ISR (TIM0_OVF_vect)
{    // Flankenwechsel für Tonfrequenz
  PORTB = ~ 0b000010;
  TCCR0A= timer_value;
}

ISR(ADC_vect)
{
  int adc_value;
  adc_value=ADC;
  timer_value=char(/*adc_value*/511/5);
  sbi  (ADCSRA,6);      // restart ADC
}

void adcInit()
{

  ADMUX=0x42;   // Port, Referenzspannung und Auflösung
     ADCSRA=0xE5;   // Modus, Interrupt und Start
}

void timer0Init()
{
  timer_value=0xFF;
  TIMSK0=0x01;
  TCCR0A=0x15;


}

void portsInit()
{
  sbi(DDRB,1);      //OUT LED
}

main()
{
  //Initialisierung
    portsInit();      // PortB als Ausgang initialisieren
    timer0Init();      // Timer Interrupt initialisieren
    adcInit();
    sei();                  // enable interrupts
  do { } while(true);    // mainloop
}

von Karl H. (kbuchegg)


Lesenswert?

Was soll den das hier sein
1
  PORTB = ~ 0b000010;

http://www.mikrocontroller.net/articles/Bitmanipulation
1
PORTB = PORTB ^ ( 0b00000010 );

Es wäre gut, wenn du dir für die LED ein #define machst, damit du den 
Mischmasch aus direkter Bitmanipulation und cbi/sbi bereinigen kannst. 
Einige deiner Problem sind durch die ungeschickte Schreibweise 
hausgemacht.
1
#define F_CPU 3686400
2
#include <avr\io.h>
3
#include <inttypes.h>
4
#include <avr\interrupt.h>
5
//--------------------------------------------------------------------------
6
volatile unsigned char timer_value;
7
8
#define LED_PIN  PB1
9
10
ISR (TIM0_OVF_vect)
11
{
12
  PORTB = PORTB ^ ( 1<<LED_PIN );
13
  TCCR0A = timer_value;
14
}
15
16
ISR(ADC_vect)
17
{
18
  int adc_value;
19
20
  adc_value = ADC;
21
  timer_value = char(/*adc_value*/511/5);
22
  ADCSRA |= (1<<ADSC);      // restart ADC
23
}
24
25
void adcInit()
26
{
27
  ADMUX  = 0x42;   // Port, Referenzspannung und Auflösung
28
  ADCSRA = 0xE5;   // Modus, Interrupt und Start
29
}
30
31
void timer0Init()
32
{
33
  timer_value = 0xFF;
34
  TIMSK0 = 0x01;
35
  TCCR0A = 0x15;
36
}
37
38
void portsInit()
39
{
40
  DDRB |= (1<<LED_PIN);
41
}
42
43
main()
44
{
45
  //Initialisierung
46
  portsInit();      // PortB als Ausgang initialisieren
47
  timer0Init();      // Timer Interrupt initialisieren
48
  adcInit();
49
  sei();                  // enable interrupts
50
51
  do { } while(true);    // mainloop
52
}

von Andy (Gast)


Lesenswert?

Erstmal danke für die Tipps und hilfe.
Aber der Effekt ist immernoch der gleiche. Die Led blinkt einfach nicht.

von Karl H. (kbuchegg)


Lesenswert?

Und die Fehler und Warnungen, die der Compiler wirft, stören dich nicht 
weiter. Oder wie?

von Karl H. (kbuchegg)


Lesenswert?

Ausserdem weist du dem Timer an keiner Stelle einen Vorteiler zu. Der 
Timer läuft ganz einfach nicht!

Drösel endlich diesen Unsinn hier
  TIMSK0 = 0x01;
  TCCR0A = 0x15;
in eine vernünftige Bit-Schreibweise auf!
Dann wirst du sehen, dass kein CS Bit gesetzt wird
(Hauptsächlich deshalb, weil die CS Bits beim Tiny13 im Register TCCR0B 
beheimatet sind)

von Andy (Gast)


Lesenswert?

Also der Compiler bringt keine Fehlermeldung.
Und wie soll ich die Bits setzen dass ich einen Effekt sehe.

von Karl H. (kbuchegg)


Lesenswert?

Andy schrieb:
> Also der Compiler bringt keine Fehlermeldung.

Nicht?

ALso das hier
1
timer_value=char(/*adc_value*/511/5);
ist kein gültiges C. Es wäre allerdings gültiges C++.
Genauso wie es in C (wohl aber in C++) kein 'true' gibt.

> Und wie soll ich die Bits setzen dass ich einen Effekt sehe.
Schau endlich ins verd... Datenblatt, lies den Abschnitt über Timer und 
such dir raus, welche Bits in welchen Registern
* es gibt
* zu setzen sind, damit der Timer einen Vorteiler bekommt.

Sorry.
Aber du wirst nicht drumherum kommen, die Beschreibung zu studieren 
anstatt blindlings einfach nur draufloszuprogrammierern und mit der 
Stange im Nebel zu stochern. Jetzt hab ich dir ohnehin schon den Weg bis 
zum zuständigen Register gezeigt. Durch die letzte Tür musst du schon 
alleine gehen.

(Und Hinweis: Im Simulator vom AVR-Studio kann man sein Programm 
wunderbar simulieren. Wenn man das tut, dann erkennt man das der Timer 
gar nicht tickt, weil er keinen Vorteiler hat)

von ich (Gast)


Lesenswert?

also ich würde statt

> TIMSK0 = 0x01;

das so schreiben TIMSK = (1<<TOIE0); (damit du siehst, welche Bits du 
genau setzst)

außerdem der Register TIMSK0 heißt bei ATmega8 TIMSK (oder sehe ich da 
was falsch?)

von Andy (Gast)


Lesenswert?

TCCR0B = 0x05;
ist das nicht der Vorteiler?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>   TCCR0A = timer_value;

Ich denke, du willst NICHT das Konfigurationsregister des Timers mit 
dem ADC Wert füllen. Ich könnte mir vorstellen, dass du den Timerzähler 
TCNT0 manipulieren willst.

>   TCCR0A = 0x15;

Datenblatt:
11.9.1 TCCR0A – Timer/Counter Control Register A

             Bit 7       6      5      4 3 2     1     0
             COM0A1 COM0A0 COM0B1 COM0B0 – – WGM01 WGM00
Deine
Einstellung  0      0      0      1      0 1     0     1

Da stimmt was nicht; Bit 2 ist undefiniert. Ich würde einfach den Normal 
Modus (Tabelle 11-8) benutzen ohne Hardwareausgabe.

TCCR0A = 0;

Der Prescaler wird mit TCCR0B gesetzt. Das fehlt in void timer0Init() 
völlig. Da läuft nix, da No clock source (Timer/Counter stopped).

11.9.2 TCCR0B – Timer/Counter Control Register B

         Bit 7     6 5 4     3    2    1    0
         FOC0A FOC0B – – WGM02 CS02 CS01 CS00

Table 11-9. Clock Select Bit Description
CS02 CS01 CS00 Description
   0    0    0 No clock source (Timer/Counter stopped)
   0    0    1 clkI/O/(No prescaling)
   0    1    0 clkI/O/8 (From prescaler)
   0    1    1 clkI/O/64 (From prescaler)
   1    0    0 clkI/O/256 (From prescaler)
   1    0    1 clkI/O/1024 (From prescaler)
   1    1    0 External clock source on T0 pin. Clock on falling edge.
   1    1    1 External clock source on T0 pin. Clock on rising edge.

>  TIMSK0 = 0x01;

11.9.6 TIMSK0 – Timer/Counter Interrupt Mask Register
Bit 7 6 5 4      3      2     1 0
    – – – – OCIE0B OCIE0A TOIE0 -

Die 0x01 sind also auch falsch. Der Attiny13 kommt nie in die 
ISR(TIM0_OVF_vect), sondern resettet sich beim Auftreten des Interrupts.

Also
1
void timer0Init()
2
{
3
  timer_value = 0xFF;
4
5
  TIMSK0 = (1<<TOIE0);
6
  TCCR0A = 0;
7
  TCCR0B = (1<<CS02) | (1<<CS00); // Prescaler 1024
8
}

Der Attiny13 läuft ab Werk mit

Table 6-4. Internal Calibrated RC Oscillator Operating Modes
CKSEL1..0 Nominal Frequency
10(1)     9.6 MHz                 (1) = Werkseinstellung

Beim größten(!) Prescaler 1024 wird die ISR(TIM0_OVF_vect) 
9600000/1024/256 = 36,6 mal pro Sekunde aufgerufen (oder häufiger (!) 
wenn TCNT0 auf timer_value > 0 gesetzt wird). Das Auge löst das nicht 
mehr als Blinken auf, sondern als Dauerleuchten.

Ändere die ISR mal in:
1
ISR (TIM0_OVF_vect)
2
{
3
  static uint8_t sw_prescaler = 10;
4
5
  if ( --sw_prescaler == 0 )
6
  {
7
    sw_prescaler = 10
8
    PORTB = PORTB ^ ( 1<<LED_PIN );
9
    TCNT0 = timer_value;
10
  }
11
}

um die Taktrate des Attiny13 zusätzlich um 10 zu teilen.

von ich (Gast)


Lesenswert?

Hallo Jungs,
verstehe ich richtig, du verwendest den Timer/Counter0 von ATmega8? (Im 
Datenblatt sehe ich aber keine >>TCCR0A und >>TCCR0B Register für den 
Timer/Counter0)

von ich (Gast)


Lesenswert?

> ISR (TIM0_OVF_vect)

muss doch so heißen ISR(TIMER0_OVF_vect)

von Andy (Gast)


Lesenswert?

Hi
nein das erste Programm war auf einem Mega8 und hat funktioniert. Jetzt 
will ich es auf einem ATtiny13 haben.
Es geht aber immer noch nicht die Led blinkt nicht sondern leuchtet nur 
ich glaub ich gebs jetzt auf.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ich schrieb:

>> ISR (TIM0_OVF_vect)
>
> muss doch so heißen ISR(TIMER0_OVF_vect)

Guter Hinweis! Kann sein, aber ich habe das aktuelle Attiny13 
Includefile des WinAVR nicht vor mir um nachzusehen.

von Karl H. (kbuchegg)


Lesenswert?

ich schrieb:
>> ISR (TIM0_OVF_vect)
>
> muss doch so heißen ISR(TIMER0_OVF_vect)

Hat mich auch verblüfft.
Aber stimmt schon so. Hab im Include File nachgesehen.

von ich (Gast)


Lesenswert?

das erste ist doch richtig, ich dachte es geht um den ATmega8 (und das 
war mein Fehler)

von Karl H. (kbuchegg)


Lesenswert?

Andy schrieb:

> ich glaub ich gebs jetzt auf.

Arbeite einfach sorgfältig!

Es ist ein Irrtum zu glauben, man kann ein Programm so mir nichts, dir 
nichts von Prozessor A auf Prozessor B transferieren.

Man muss sich jedes Bit in jedem Konfigurationsregister ansehen, ob es 
auf der Zielarchitektur auch wirklich wieder an derselben Stelle ist.

Benutzt man die Schreibweise ala

    TCCRA0 = 0x15;

dann ist dieser Vorgang doppelt hart und man schaffts sich nur unnötig 
selbst Stress.

Ausserdem: Nicht böse sein.
Aber wenn du das Mega8 Programm ganz einfach mit Datenblatthilfe neu 
geschrieben hättest (*), wärst du schon 3mal fertig.

(*) Also:
Überlegen welchen Timermodus ich haben möchte bzw. brauche. Datenblatt 
nehmen und die entsprechenden Register und Bits raussuchen und in einer 
vernünftigen Form hinschreiben.

von Andy (Gast)


Lesenswert?

Ok dank dir werd nochmal alles nachschauen und es neu vesuchen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.