Forum: Mikrocontroller und Digitale Elektronik µC Programm tut nicht, was es soll


von Bernd P. (bernte)


Lesenswert?

Hey ihr lieben!

Ich habe folgendes Problem. Ein Motor drückt mir zwei um pi/2 
verschobene in der Anzahl zur Drehazahl proportionale Rechtecksignale 
durchs Kabel, welche ich mit dem attiny45 auslese.

Die Platine ist denkbar ungünstig geroutet, daher folgende 
Anschlussbelegung:

PB5/Reset <- Rechteck 1 (reset ist per fuse natürlich disabled)
PB4 <- Rechteck 2
PB2 -> CLK
PB1 -> DATA
PB0 -> LOAD

Im Debugger läuft alles perfekt, leider nicht in echt. Die 
Ansteuerroutine des DAC scheint zu laufen, jedenfalls werden die 2047 
aus dem Timer Overflow korrekt aufgebraten. Die gesamte Prozedur ist aus 
er Wiki hier. Allerdings krieg ich nur irgendwelche sprunghaften 
Signale, wenn ich ganz langsam drehe. Vielleicht ist der ClockDevide 
1024 auch zu viel und deshalb zähl ich über das Ziel hinaus? Könnte aber 
eigentlich nicht sein, da die Taktfrequenz bei 20MHz durch einen 
externen Oszillator liegt. Jetzt mal das Programm:

-----------------------------------------------------------------
main.c
-----------------------------------------------------------------

#include <avr/io.h>

#include "ltc1257.h"
#include "avr/interrupt.h"

/* Prototypes: */

static unsigned int counter;

int main(void);
void interruptinit(void);
void ioinit(void);

int main(void)
{

  ioinit();
  counter = 2047;

  while(1)
  {
    ;
  }

  /* NEVEREACHED */
  return 0;
}

void ioinit(void)
{
  /* IO setup: */
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB4) | (0 << PB5); 
/* LTC1257 pins (output) */
  PORTB = (1 << PB4) | (1 << PB5);
  /* Low-level init of DAC: */
  ltc1257_ll_init();

  /* init interrupts */
  interruptinit();
}

void interruptinit(void)
{
  GTCCR = (1 << TSM) | (1 << PSR0);
  TCCR0B = (1 << CS02) | (0 << CS01) | (1 << CS00); //Clock devide by 
1024 0 0 0 stoppt timer
  TIMSK = (1 << TOIE0); //Overflow Interrupt Counter 0
  GIMSK = (1 << PCIE); //pin change interrupt
  PCMSK = (1 << PCINT4); //interrupt pin 4 changes;

  sei();

  GTCCR = 0 << TSM; //loszählen
}

ISR(PCINT0_vect)
{
  if (bit_is_set(PINB, 4) == bit_is_set(PINB, 5)) counter++;
  else counter--; //zählen Richtungsabhängig
}


ISR (TIMER0_OVF_vect)
{
  cli();
  TCCR0B = (0 << CS02) | (0 << CS01) | (0 << CS00);
  PCMSK = (0 << PCINT4);
  ltc1257_ll_write(counter);
  counter = 2047;
  TCNT0 = 0;
  TCCR0B = (1 << CS02) | (0 << CS01) | (1 << CS00);
  PCMSK = (1 << PCINT4);
  sei();
}

-------------------------------------------------------------
ltc1257.h
-------------------------------------------------------------
/*
 * ltc1257.h
 *
 * Created: 28.06.2011 22:20:50
 *  Author: Berni
 */

#ifndef LTC1257_H_
#define LTC1257_H_

/*
 * Low level access routines to the LTC1257 DAC device.
 */

/*
 * Port, where LTC1257 is connected to:
 * PORTC/PINC
 */

#define DACOUT    PORTB
#define DACIN    PINB

/*
 * Port configuration:
 *
 * Port pin  LTC1257
 * --------------------
 * PB0    LOAD
 * PB1    DATA
 * PB2    CLK
 *
 */

#define DACCLK(LEVEL)  DACOUT = (LEVEL) ? (DACIN | _BV(PB2)):(DACIN & 
~_BV(PB2))
#define DACDATA(LEVEL)  DACOUT = (LEVEL) ? (DACIN | _BV(PB1)):(DACIN & 
~_BV(PB1))
#define DACLOAD(LEVEL)  DACOUT = (LEVEL) ? (DACIN | _BV(PB0)):(DACIN & 
~_BV(PB0))

#define LATCHTIMING  0x01        /* spend some time to the latch  */

#define LEV_LOW    0
#define LEV_HIGH  1

void ltc1257_ll_init(void);
inline void ltc1257_ll_write(unsigned int);

/*
 * Low level initialisation routine for LTC1257.
 */

void ltc1257_ll_init(void)
{
  /* Initial port/pin state */
  DACCLK(LEV_LOW);        /* clock pin low -> idle  */
  DACLOAD(LEV_HIGH);        /* load pin high -> idle  */
}

/*
 * Low level write routine for LTC1257.
 * Awaits data in unsigned integer format
 * 12 bits masked (0x800 masks the data's MSB)
 */

void ltc1257_ll_write(unsigned int data)
{
  volatile unsigned char bitctr = 0;

  for(bitctr = 0; bitctr < 0x0C; bitctr++)
  {
    DACDATA(data & 0x800);      /* output MSB (bits [11..0]!)    */
    data <<= 1;        /* shift next bit to MSB    */
    DACCLK(LEV_HIGH);      /* rising edge -> load bit    */
    DACCLK(LEV_LOW);      /* -> await rising edge      */
  }

  DACCLK(LEV_LOW);        /* clock pin low -> idle    */

  for (bitctr = 0; bitctr < LATCHTIMING; bitctr++)
    ;

  DACLOAD(LEV_LOW);        /* load pulled low -> output    */
  DACLOAD(LEV_HIGH);        /* load pulled high -> idle    */
}

#endif /* LTC1257_H_ */

------------------------------------------------------

Falls ihr eine Idee habt, woran das liegen könnte, nur her damit. Danke 
für die Mühen und liebe Grüße
Bernd

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Vorab:
Funktionen haben in Header-Dateien nichts zu suchen.

Vorab, die zweite:
In einer Interruptroutine sind alle weiteren Interrupts sowieso 
geblockt. Deshalb ist das unnötig:
ISR (TIMER0_OVF_vect)
{
  cli();
  :
  sei();
}

Bernd P. schrieb:
> Ein Motor drückt mir zwei um pi/2 verschobene in der Anzahl
> zur Drehazahl proportionale Rechtecksignale durchs Kabel,
> welche ich mit dem attiny45 auslese.
> ISR(PCINT0_vect)
> {
>   if (bit_is_set(PINB, 4) == bit_is_set(PINB, 5)) counter++;
>   else counter--; //zählen Richtungsabhängig
> }
Eine Encoderauswertung sieht normalerweise anders aus...

Was soll denn der Code machen?
Den Drehgeber auswerten und dann auf den DAC schreiben?

von Bernd P. (bernte)


Lesenswert?

Hey!

Danke schonmal für diese Info. Ja, der Drehgeber wird ausgelesen und der 
DAC gefüttert.

Viele Grüße
Bernd

von Bernd P. (bernte)


Lesenswert?

Hey!

Das Problem lag scheinbar in der

ISR(PCINT0_vect)
{
  if (bit_is_set(PINB, 4) == bit_is_set(PINB, 5)) counter++;
  else counter--; //zählen Richtungsabhängig
}

Einfach nur hochzählen klappt. Die bit_is_set() hat nich funktioniert. 
Jemand ne Idee, warum? Ansonsten kann das Problem als gelöst angesehen 
werden.

Viele Grüße
Bernd

von Sam .. (sam1994)


Lesenswert?

Bernd P. schrieb:
> ISR(PCINT0_vect)
> {
>   if (bit_is_set(PINB, 4) == bit_is_set(PINB, 5)) counter++;
>   else counter--; //zählen Richtungsabhängig
> }
>
> Einfach nur hochzählen klappt. Die bit_is_set() hat nich funktioniert.
> Jemand ne Idee, warum? Ansonsten kann das Problem als gelöst angesehen
> werden.

Ich habe eine Vermutung:

bit_ist_set sieht wahrscheinlich so aus:

#define bit_is_set(a,b) ((a) & (1 << (b))

Dieses Makro gibt ungleich 0 zurück wenn das bit gesetzt ist, aber 
trotzdem keinen festen Wert.

Das sollte funktionieren:
1
if(bit_is_set(PINB, 4) && bit_is_set(PINB, 5))

von J.-u. G. (juwe)


Lesenswert?

Samuel K. schrieb:
> Dieses Makro gibt ungleich 0 zurück wenn das bit gesetzt ist, aber
> trotzdem keinen festen Wert.

Nicht fest, aber definiert. Zitat avr-gcc-tutorial:
1
bit_is_set (<Register>,<Bitnummer>)
>Die Funktion bit_is_set prüft, ob ein Bit gesetzt ist. Wenn das Bit gesetzt
>ist, wird ein Wert ungleich 0 zurückgegeben. Genau genommen ist der
>Rückgabewert die Wertigkeit des abgefragten Bits, also 1 für Bit0, 2 für
>Bit1, 4 für Bit2 etc.

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.