Forum: Mikrocontroller und Digitale Elektronik MEGA8 ADC Interrupt beeinflusst TWI Interrupt


von Harry_13 (Gast)


Lesenswert?

Hallo, ich habe aktuell als kleines Projekt ein per i2c steuerbares 
Display inklusive Tastenfeld. Das Tastenfeld wird mittels 
Widerstandsmatrix und ADC eingelesen. Mein Problem ist allerdings dass 
der ADC zu schnell zu sein scheint, wenn ich nämlich nicht 50ms delay in 
meine Hauptschleife integriere, habe ich keinen Zugriff mehr per I2C.
Und wenn ich den ADC ohne Interrupt einlese also das Bit (1<<ADIE) nicht 
setze, dann stürzt er mir ab sobald ich eine Spannung am ADC anlegen 
habe. Wisst ihr weiter?
Vielen Dank für eure Zeit
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/pgmspace.h>
5
#include <avr/eeprom.h>
6
#include "twislave.h"
7
#include "twislave.c"
8
#include "lcd-routines.h"
9
#include "lcd-routines.c"
10
#include <util/delay.h>
11
#ifndef F_CPU
12
#define F_CPU 8000000UL
13
#endif
14
15
//###################### Slave-Adresse
16
#define SLAVE_ADRESSE 0x50                 // Slave-Adresse
17
18
//###################### Macros
19
#define uniq(LOW,HEIGHT)  ((HEIGHT << 8)|LOW)      // 2x 8Bit   --> 16Bit
20
#define LOW_BYTE(x)          (x & 0xff)          // 16Bit   --> 8Bit
21
#define HIGH_BYTE(x)         ((x >> 8) & 0xff)      // 16Bit   --> 8Bit
22
23
24
#define sbi(ADDRESS,BIT)   ((ADDRESS) |= (1<<(BIT)))  // set Bit
25
#define cbi(ADDRESS,BIT)   ((ADDRESS) &= ~(1<<(BIT)))  // clear Bit
26
#define  toggle(ADDRESS,BIT)  ((ADDRESS) ^= (1<<BIT))    // Bit umschalten
27
28
#define  bis(ADDRESS,BIT)  (ADDRESS & (1<<BIT))    // bit is set?
29
#define  bic(ADDRESS,BIT)  (!(ADDRESS & (1<<BIT)))    // bit is clear?
30
#define PORT_ON(port,pin) port |= (1<<pin)
31
#define PORT_OFF(port,pin) port &= ~(1<<pin)
32
33
//###################### Variablen
34
  uint16_t   Variable=2345;        //Z‰hler
35
  uint16_t  buffer;
36
  uint16_t  low, hight;
37
/* Byte */
38
uint16_t brightness EEMEM;
39
/* Byte */
40
uint16_t contrast EEMEM;
41
//### PORTS
42
43
//################################################################################################### Initialisierung
44
void Initialisierung(void)
45
  {
46
          cli();
47
    char text [2];
48
    lcd_init();
49
50
    //### TWI
51
  init_twi_slave(SLAVE_ADRESSE);      //TWI als Slave mit Adresse slaveadr starten
52
53
    // Die Ausgabemarke in die 2te Zeile setzen
54
        lcd_setcursor( 0, 1 );
55
    lcd_string(">Booting...");
56
    lcd_setcursor( 0, 2 );
57
        itoa (SLAVE_ADRESSE,text,16);
58
    lcd_string("I2C Adress=0x");
59
        lcd_string(text);
60
        for (int Index=0; Index<85; ++Index) {
61
            rxbuffer[Index] = 0x20;
62
        }
63
        rxbuffer[81]=0xFF;
64
        rxbuffer[82]=0xFF;
65
        rxbuffer[83]=0xFF;
66
        rxbuffer[84]=0xFF;
67
          sei();
68
}
69
//update LCD
70
void lcd_update(void){
71
    cli();
72
    for (int o=1;o<=4; o++)
73
    for (int i=1; i<=20; i++){
74
        lcd_setcursor( i-1, o );
75
        lcd_data(rxbuffer[i+((o-1)*20)]);
76
    }
77
    sei();
78
}
79
//################################################################################################### Hauptprogramm
80
ISR(ADC_vect)
81
{
82
char text[5];
83
itoa (ADC,text,16);
84
lcd_setcursor( 0,4 );
85
lcd_string(text);
86
}
87
int main(void)
88
{
89
    int adc_count=0;
90
    
91
    DDRC &= ~(1 << PC0);
92
    PORTC &= ~(1 << PC0);
93
    Initialisierung();
94
    DDRB = (1 << DDB1) | (1 << DDB2);
95
    OCR1A = eeprom_read_word(&brightness); // PWM einstellen,
96
    OCR1B = eeprom_read_word(&contrast);
97
    ICR1 = 1000;  // TOP-wert
98
    
99
    TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // 2-Kanal "non-inverting"
100
    TCCR1B = (1<<WGM13)|(1<<WGM12) | (1<<CS11);
101
    
102
    //Initialize ADC
103
    ADMUX = (1<<REFS0);               // Set Reference to AVCC and input to ADC0
104
    ADCSRA =(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADIE)| (1<<ADPS0);    // Fadc=Fcpu/prescaler=8000000/128=62.5kHz
105
    // Fadc should be between 50kHz and 200kHz
106
    // Enable ADC conversion complete interrupt
107
                          // Set the I-bit in SREG
108
    
109
    ADCSRA |= (1<<ADSC);              // Start the first conversion
110
111
112
    char text[2];
113
    while(1)
114
    {
115
116
        for (int Index=0; Index<85; ++Index) {
117
            txbuffer[Index] = rxbuffer[Index];
118
        }
119
  
120
        uint16_t brightness_i2c=0;
121
        uint16_t contrast_i2c=0;
122
  
123
        brightness_i2c=(rxbuffer[81]<<8)|(rxbuffer[82]);
124
        contrast_i2c=(rxbuffer[83]<<8)|(rxbuffer[84]);
125
126
       
127
        if (rxbuffer[0]==1){
128
                     lcd_update();
129
            rxbuffer[0]=4;
130
        }else if(brightness_i2c!=eeprom_read_word(&brightness) && brightness_i2c!=0xFFFF){
131
        eeprom_write_word(&brightness,brightness_i2c);
132
            OCR1A = eeprom_read_word(&brightness);
133
     
134
        }else if (contrast_i2c!=eeprom_read_word(&contrast) && contrast_i2c!=0xFFFF){
135
            eeprom_write_word(&contrast,contrast_i2c);
136
            OCR1B = eeprom_read_word(&contrast);
137
          
138
        }else{
139
            for (uint8_t i=0; i<10; i++) _delay_ms(10);
140
      
141
        }
142
        ADCSRA |= (1<<ADSC);
143
144
  } //end.while
145
} //end.main

von Arc N. (arc)


Lesenswert?

Mega8 hat afair kein Hardware-I2C also dürfte das per Software 
(timingkritisch) gemacht werden und da der ADC-Interrupt 
höchstwahrscheinlich viel zu lange braucht (itoa + LCD-Routinen, 
letztere womöglich noch mit Delays) wird das die I2C-Übertragung aus dem 
Takt bringen.
Lösung: Im ADC-Interrupt nur ein (volatile) Flag (adcReady o.ä.) setzen 
und das ADC-Ergebnis kopieren und die Ausgabe und Umwandlung in der Main 
machen, wenn das Flag gesetzt ist.

von Harry_13 (Gast)


Lesenswert?

Der hat doch TWI/I2C laut Datenblatt oder was verstehe ich da falsch?
http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_summary.pdf 
(S165)

von Mitlesa (Gast)


Lesenswert?

8 Mhz / 800 ergibt eine Interrupt-Rate von 10KHz oder 1/10usec.

Die Ausgabe eines LCD Zeichens dauert typischerweise (grob
geschätzt) 1..10usec.

Das bedeuted dass der Prozessor aus den Interrupts (wo er auf
das LCD schreibt) kaum mehr herauskommt um was anderes zu tun.

von Harry_13 (Gast)


Lesenswert?

Okay ja das klingt logisch :), kann ich irgendwie den ADC ohne Interrupt 
auslesen? Das wäre mir das liebste, so oft benötige ich den ja nicht...

von Stefan F. (Gast)


Lesenswert?

Sicher, er setzt ja ein Flag, wenn die Messung beendet ist. Das liest du 
in der Hauptschleife aus.

von Harry_13 (Gast)


Lesenswert?

Ja das mache ich ja Normalerweise so:
initialisierung:
1
  ADCSRA =(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)| (1<<ADPS0);
1
  ADCSRA |= (1<<ADSC); // Start conversion
2
    while (ADCSRA & (1<<ADSC)); // wait for conversion to complete
3
    adc_value = ADCW; //Store ADC value
aber wieso wird genau dann, mit Interrupt disabled, immer mit Spannung 
am ADC mein Controller resetted?

von Mitlesa (Gast)


Lesenswert?

Harry_13 schrieb:
> aber wieso wird genau dann, mit Interrupt disabled, immer mit Spannung
> am ADC mein Controller resetted?

Da musst du schon den ganzen Code zeigen der dieses Verhalten
provoziert. Am Lesen des ADCs wird es wohl nicht liegen ....
.... vielleicht auch noch die Schaltung (zeigen) ....

von Arc N. (arc)


Lesenswert?

Harry_13 schrieb:
> Der hat doch TWI/I2C laut Datenblatt oder was verstehe ich da falsch?
> 
http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_summary.pdf
> (S165)

Dann hatte ich das falsch im Kopf. Ändert aber nichts daran, dass die 
Zeit im Interrupt zu lang ist und währenddessen die anderen Interrupts 
zu lange blockiert sind.

von Amateur (Gast)


Lesenswert?

Zugegeben ich bin etwas provokativ.

Weißt Du, was Du ausgibst?

Wenn ich Deine lcd_update()-Funktion richtig verstehe, so schreibst Du 
immer das ganze Display voll.

Ist das würglich nötig?

Mit der Geschwindigkeit?

Ist die Ausgabe schneller als die Zufuhr von neuen Werten, so ist 
definitiv irgendwas in die Hose gegangen.

Es gibt immer die Möglichkeit, Teile oder, wenn Du keine Ahnung hast, 
ganze Zeilen zu aktualisieren.

Hast Du Dich mal mit der maximalen "Hinguckfrequenz" beschäftigt? Damit 
meine ich die maximale Frequenz, mit der das Auge Änderungen erkennt und 
das in 4 Zeilen...

von Mitlesa (Gast)


Lesenswert?

Harry_13 schrieb:
> aber wieso wird genau dann, mit Interrupt disabled, immer mit Spannung
> am ADC mein Controller resetted?

Mal so ins Blaue geraten:

Du konfigurierst den ADC so dass beim Lesen ein Interrupt ausgelöst
wird den du nicht als ISR auch bedienst. Der unbediente Interrupt
lässt den Prozessor in den Reset springen.

von Harry_13 (Gast)


Lesenswert?

Bei genau diesem Code passiert folgendes, solange der Eingang vom ADC 
auf GND ist ist alles gut, sobald aber irgendeine Spannung anliegt, wird 
das Display geleert, ( zeigt nichts mehr an) und per I2C ist er auch 
nicht mehr Ansprechbar, nach einem RESET funktionierts dann wieder. 
Fehler in der Beschaltung könnte man doch ausschliessen, da es ja mit 
Interrupts einliest? AVCC und AREF liegen halt auf 5V GND wurde mit GND 
verbunden. Das LCD hängt mit 4 Bit an PortD, An OC1A hängt per Pwm und 
Transistor die Hintergundbeleuchtung an OC1B hängt die Kontrastspannung 
mit 100uF Kondensator an Masse. Die Betriebsspannung ist stabilisiert 
und Zusätzlich mit einem Glättungskondensator (330uF) versehen. der I2C 
Bus ist mit PullUps versehen und wird mit einem Level Shifter auf 3.3 V 
für einen Raspi geshiftet. Ich zeichne morgen aber gerne noch nen 
Schaltplan :)
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/pgmspace.h>
5
#include <avr/eeprom.h>
6
#include "twislave.h"
7
#include "twislave.c"
8
#include "lcd-routines.h"
9
#include "lcd-routines.c"
10
#include <util/delay.h>
11
#ifndef F_CPU
12
#define F_CPU 8000000UL
13
#endif
14
15
//###################### Slave-Adresse
16
#define SLAVE_ADRESSE 0x50                 // Slave-Adresse
17
18
//###################### Macros
19
#define uniq(LOW,HEIGHT)  ((HEIGHT << 8)|LOW)      // 2x 8Bit   --> 16Bit
20
#define LOW_BYTE(x)          (x & 0xff)          // 16Bit   --> 8Bit
21
#define HIGH_BYTE(x)         ((x >> 8) & 0xff)      // 16Bit   --> 8Bit
22
23
24
#define sbi(ADDRESS,BIT)   ((ADDRESS) |= (1<<(BIT)))  // set Bit
25
#define cbi(ADDRESS,BIT)   ((ADDRESS) &= ~(1<<(BIT)))  // clear Bit
26
#define  toggle(ADDRESS,BIT)  ((ADDRESS) ^= (1<<BIT))    // Bit umschalten
27
28
#define  bis(ADDRESS,BIT)  (ADDRESS & (1<<BIT))    // bit is set?
29
#define  bic(ADDRESS,BIT)  (!(ADDRESS & (1<<BIT)))    // bit is clear?
30
#define PORT_ON(port,pin) port |= (1<<pin)
31
#define PORT_OFF(port,pin) port &= ~(1<<pin)
32
33
//###################### Variablen
34
  uint16_t   Variable=2345;        //Z‰hler
35
  uint16_t  buffer;
36
  uint16_t  low, hight;
37
/* Byte */
38
uint16_t brightness EEMEM;
39
/* Byte */
40
uint16_t contrast EEMEM;
41
//### PORTS
42
43
//################################################################################################### Initialisierung
44
void Initialisierung(void)
45
  {
46
          cli();
47
    char text [2];
48
    lcd_init();
49
50
    //### TWI
51
  init_twi_slave(SLAVE_ADRESSE);      //TWI als Slave mit Adresse slaveadr starten
52
53
    // Die Ausgabemarke in die 2te Zeile setzen
54
        lcd_setcursor( 0, 1 );
55
    lcd_string(">Booting...");
56
    lcd_setcursor( 0, 2 );
57
        itoa (SLAVE_ADRESSE,text,16);
58
    lcd_string("I2C Adress=0x");
59
        lcd_string(text);
60
        for (int Index=0; Index<85; ++Index) {
61
            rxbuffer[Index] = 0x20;
62
        }
63
        rxbuffer[81]=0xFF;
64
        rxbuffer[82]=0xFF;
65
        rxbuffer[83]=0xFF;
66
        rxbuffer[84]=0xFF;
67
          sei();
68
}
69
//update LCD
70
void lcd_update(void){
71
    for (int o=1;o<=4; o++)
72
    for (int i=1; i<=20; i++){
73
        lcd_setcursor( i-1, o );
74
        lcd_data(rxbuffer[i+((o-1)*20)]);
75
    }
76
}
77
int main(void)
78
{
79
DDRC &= ~(1 << PC0);
80
PORTC &= ~(1 << PC0);
81
Initialisierung();
82
DDRB = (1 << DDB1) | (1 << DDB2);
83
OCR1A = eeprom_read_word(&brightness); // PWM einstellen,
84
OCR1B = eeprom_read_word(&contrast);
85
ICR1 = 1000;  // TOP-wert
86
87
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // 2-Kanal "non-inverting"
88
TCCR1B = (1<<WGM13)|(1<<WGM12) | (1<<CS11);
89
90
//Initialize ADC
91
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0)| (1<<ADPS1);
92
 ADMUX = (1<<REFS0);  
93
unsigned int adc_value=0; // Variable to hold ADC result
94
95
char text[4];
96
while(1)
97
{
98
    ADCSRA |= (1<<ADSC); // Start conversion
99
    while (ADCSRA & (1<<ADSC)); // wait for conversion to complete
100
    adc_value = ADCW; //Store ADC value
101
    itoa (adc_value,text,16);
102
    lcd_setcursor( 0,4 );
103
    lcd_string(text);
104
    for (int Index=0; Index<85; ++Index) {
105
        txbuffer[Index] = rxbuffer[Index];
106
    }
107
    uint16_t brightness_i2c=0;
108
    uint16_t contrast_i2c=0;
109
110
    brightness_i2c=(rxbuffer[81]<<8)|(rxbuffer[82]);
111
    contrast_i2c=(rxbuffer[83]<<8)|(rxbuffer[84]);
112
    if (rxbuffer[0]==1){
113
                 lcd_update();
114
        rxbuffer[0]=4;
115
    }else if(brightness_i2c!=eeprom_read_word(&brightness) && brightness_i2c!=0xFFFF){
116
    eeprom_write_word(&brightness,brightness_i2c);
117
        OCR1A = eeprom_read_word(&brightness);
118
119
    }else if (contrast_i2c!=eeprom_read_word(&contrast) && contrast_i2c!=0xFFFF){
120
        eeprom_write_word(&contrast,contrast_i2c);
121
        OCR1B = eeprom_read_word(&contrast);
122
123
    }else{
124
    }
125
126
} 
127
}

von Harry_13 (Gast)


Lesenswert?

Amateur schrieb:
> Wenn ich Deine lcd_update()-Funktion richtig verstehe, so schreibst Du
> immer das ganze Display voll.
>
> Ist das würglich nötig?
>
> Mit der Geschwindigkeit?


Nein, die LCD_Update wird nur aufgerufen wenn mit I2C alle Daten 
angekommen sind und in Rx_buffer[0] eine 1 steht, die wird nach dem 
Update gelöscht. somit kann ich in aller ruhe Daten in den Speicher 
laden und diese dann auf einen Rutsch aufs LCD schreiben lassen.

von Karl H. (kbuchegg)


Lesenswert?

Amateur schrieb:

> Wenn ich Deine lcd_update()-Funktion richtig verstehe, so schreibst Du
> immer das ganze Display voll.

Und dann das ganze auch noch unter Interrupt Sperre
1
void lcd_update(void){
2
    cli();
3
    for (int o=1;o<=4; o++)
4
    for (int i=1; i<=20; i++){
5
        lcd_setcursor( i-1, o );
6
        lcd_data(rxbuffer[i+((o-1)*20)]);
7
    }
8
    sei();
9
}

Den Cursor nach jedem Zeichen immer neu zu setzen braucht auch kein 
Mensch. Jede einigermassen vernünftige LCD Library wird nach der Ausgabe 
eines Zeichens den Cursor ganz für sich alleine um 1 Zeichen weiter 
setzen.

Zum Thema Interrupt Sperre:
Da die I2C Routinen offensichtlich über Interrupts funktionieren 
(funktionieren müssen), ist es ganz fies, wenn du für eine derart lange 
Zeit die Interrupts abstellst. In dieser Zeit wird dein TWI Interface 
nämlich lahm gelegt.

Ganz abgesehen davon, dass es vollkommmen ausreichen würde, wenn in der 
Hauptschleife immer nur ein einziges Zeichen aus deinem 
Bildschirmspeicher aufs LCD übertragen wird. Nur dann eben reihum immer 
das jeweils nächste, so dass sich dein LCD dann eben über einen Zeitraum 
von 20*4 = 80 Durchläufen durch die Hauptschleife aktualisiert. Das ist 
immer noch schnell genug, so dass kein Mensch bemerken wird, dass das 
nicht in einem Rutsch sondern nach und nach geschieht.

Alles in allem: das ist mal wieder alles mit der heissen Nadel 
zusammengestrickt und dann noch dazu mit wenig Sachkentniss.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

1
char text[4];
2
while(1)
3
{
4
    ADCSRA |= (1<<ADSC); // Start conversion
5
    while (ADCSRA & (1<<ADSC)); // wait for conversion to complete
6
    adc_value = ADCW; //Store ADC value
7
    itoa (adc_value,text,16);

Da der größte Wert, den du vom ADC kriegen kannst, 1024 ist, ist ein 
text[4] um 1 Stelle zu klein.
-> du nudelst dir irgendwas im Speicher nieder.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

unsigned int adc_value=0; // Variable to hold ADC result

char text[4];
while(1)
{
    ADCSRA |= (1<<ADSC); // Start conversion
    while (ADCSRA & (1<<ADSC)); // wait for conversion to complete
    adc_value = ADCW; //Store ADC value
    itoa (adc_value,text,16);


itoa ist die falsche Funktion für einen unsigned int.
das i in itoa steht für int. Den hast du aber nicht. Du hast einen 
unsigned int. Die richtige Funktion dafür ist utoa.

Und mach dir um Himmels willen Hilfsfunktionen!
Einen int oder unsigned int auf einem LCD ausgeben braucht man alle Nase 
lang. Das ist wirklich keine Raketentechnik sich dafür eine lcd_puti 
bzw. lcd_putu Funktion zu schreiben.
1
void lcd_puti( int wert )
2
{
3
  char txt[7];
4
5
  itoa( wert, txt, 10 );
6
  lcd_string( txt );
7
}
8
9
void lcd_putu( unsigned int wert )
10
{
11
  char txt[7];
12
13
  utoa( wert, txt, 10 );
14
  lcd_string( txt );
15
}

fertig. Die Funktionen kommen zu deinen LCD Funktionen mit dazu und in 
Zukunft passiert dir so was nicht mehr, dass dein Ausgabearray zu klein 
ist.

: Bearbeitet durch User
von Mitlesa (Gast)


Lesenswert?

Karl H. schrieb:
> Da der größte Wert, den du vom ADC kriegen kannst, 1024 ist

1023?  (-->0x3FF)

von Amateur (Gast)


Lesenswert?

>Nein, die LCD_Update wird nur aufgerufen wenn mit I2C alle Daten...

Meine Frage bezog sich hauptsächlich darauf, ob es sinnvoll ist immer 
das GANZE Display zu aktualisieren. Da gibt’s nämlich - versteckt - jede 
Menge an delay.

Nicht vergessen: Egal ob Du nur alle paar Sekunden, oder im 
Mikrosekundenrhythmus, einen Funktionsblock aufrufst. Ist dieser, 
zeitlich, zu lang ist er zeitlich zu lang.

von Karl H. (kbuchegg)


Lesenswert?

Mitlesa schrieb:
> Karl H. schrieb:
>> Da der größte Wert, den du vom ADC kriegen kannst, 1024 ist
>
> 1023?  (-->0x3FF)

Ja ok. Danke
Das Array ist trotzdem zu klein

von Harry_13 (Gast)


Lesenswert?

Amateur schrieb:
> Meine Frage bezog sich hauptsächlich darauf, ob es sinnvoll ist immer
> das GANZE Display zu aktualisieren. Da gibt’s nämlich - versteckt - jede
> Menge an delay.

Da gebe ich dir recht, das muss ich noch ändern. Ein größerer Buffer 
hilft auf nichts, trotzdem hängt er wieder... Die Interrupt Sperre war 
aktuell nur testweise drinnen, da mir zuvor der ADC interrupt immer die 
Display Aktualisierung unterbrochen hat, und somit zum teil nur halb 
geschrieben wurde.

von asdf (Gast)


Lesenswert?

Harry_13 schrieb:
> Okay ja das klingt logisch :), kann ich irgendwie den ADC ohne Interrupt
> auslesen? Das wäre mir das liebste, so oft benötige ich den ja nicht...

Und warum nicht umgekehrt? ADC im Interrupt auslesen, aber mit dem LCD 
in der Hauptschleife kommunizieren?

von Karl H. (kbuchegg)


Lesenswert?

asdf schrieb:
> Harry_13 schrieb:
>> Okay ja das klingt logisch :), kann ich irgendwie den ADC ohne Interrupt
>> auslesen? Das wäre mir das liebste, so oft benötige ich den ja nicht...
>
> Und warum nicht umgekehrt? ADC im Interrupt auslesen, aber mit dem LCD
> in der Hauptschleife kommunizieren?

Im Prinzip muss es egal sein.
Ob mit oder ohne Interrupt, da darf nichts abschmieren.

von Amateur (Gast)


Lesenswert?

Noch zwei Fragen:

Woher kommt rxbuffer. Immerhin 80 Zeichen.

Meckern Deine Include-Dateien nicht, wenn Du die Frequenz nachher 
festlegst?

Soweit mir bekannt benötigt zumindest delay.h diese Angabe...

von Karl H. (kbuchegg)


Lesenswert?

Harry_13 schrieb:

> aktuell nur testweise drinnen, da mir zuvor der ADC interrupt immer die
> Display Aktualisierung unterbrochen hat, und somit zum teil nur halb
> geschrieben wurde.

Na ja gut.
Das war sowieso Quatsch.

Dein LCD ist nun mal eine Shared Resource und damit gibt es nur eine 
Stelle, die darauf zugreifen darf. Entweder die Hauptschleife oder 1 
ISR. Aber nicht beide gleichzeitig, denn sonst kommen sich die ins 
Gehege.

von Karl H. (kbuchegg)


Lesenswert?

Hast du schon mal probiert, was pasiert wenn du nur den ADC am laufen 
hast
1
int main(void)
2
{
3
  DDRB = (1 << DDB1) | (1 << DDB2);
4
  OCR1A = eeprom_read_word(&brightness); // PWM einstellen,
5
  OCR1B = eeprom_read_word(&contrast);
6
  ICR1 = 1000;  // TOP-wert
7
8
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // 2-Kanal "non-inverting"
9
  TCCR1B = (1<<WGM13)|(1<<WGM12) | (1<<CS11);
10
11
  lcd_init();
12
13
  //Initialize ADC
14
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0)| (1<<ADPS1);
15
  ADMUX = (1<<REFS0);  
16
  unsigned int adc_value=0; // Variable to hold ADC result
17
  char text[7];
18
19
  while(1)
20
  {
21
    ADCSRA |= (1<<ADSC); // Start conversion
22
    while (ADCSRA & (1<<ADSC)); // wait for conversion to complete
23
    adc_value = ADCW; //Store ADC value
24
25
    utoa (adc_value,text,16);
26
    lcd_setcursor( 0,4 );
27
    lcd_string(text);
28
  } 
29
}

Wenn an deiner Hypothese was dran ist, dann müsste es auch hier zu 
Problemen kommen.

: Bearbeitet durch User
von Harry_13 (Gast)


Lesenswert?

Karl H. schrieb:
> Hast du schon mal probiert, was pasiert wenn du nur den ADC am laufen
> hast
Gerade getestet, nur der ADC läuft... Sobald ich jetzt aber I2C 
aktiviere ist dieses dann nicht ansprechbar

von Harry_13 (Gast)


Lesenswert?

Amateur schrieb:
> Woher kommt rxbuffer. Immerhin 80 Zeichen.
>
> Meckern Deine Include-Dateien nicht, wenn Du die Frequenz nachher
> festlegst?
>
> Soweit mir bekannt benötigt zumindest delay.h diese Angabe...

RXBuffer kommt aus der I2C Lib. von Jtronics
http://www.jtronics.de/avr-projekte/library-i2c-twi-slave.html
Die Frequenz übergebe ich zusätzlich im Makefile.

von Karl H. (kbuchegg)


Lesenswert?

Harry_13 schrieb:
> Karl H. schrieb:
>> Hast du schon mal probiert, was pasiert wenn du nur den ADC am laufen
>> hast
> Gerade getestet, nur der ADC läuft... Sobald ich jetzt aber I2C
> aktiviere ist dieses dann nicht ansprechbar

Dann würde ich mir an deiner Stelle die I2C Implementierung mal näher 
ansehen

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Harry_13 schrieb:

> RXBuffer kommt aus der I2C Lib. von Jtronics
> http://www.jtronics.de/avr-projekte/library-i2c-twi-slave.html

Dann ist aber deine Verwendung von 85 im Code keine gute Idee.

Die Größe des zur Verfügung stehenden buffers wird durch 'buffer_size' 
festgelegt.
1
        for (int Index=0; Index < buffer_size; ++Index) {
2
            txbuffer[Index] = rxbuffer[Index];
3
        }

oder gleich mittels memcpy.
Solche doppelt gemoppelt Dinge solltest du dir abgewöhnen. Es gibt nur 
eine einzige Stelle, an der die Buffergröße als Zahlenwert bekannt ist. 
Und das ist hier in twislave.h
1
//#################################### von Benutzer konfigurierbare Einstellung 
2
3
#define buffer_size 20                 //Größe der Buffer in Byte (2..254)

wenn dort bei dir nicht 85 steht, dann liegt hier der Fehler. Aber 
selbst wenn bei dir da 85 eingetragen sein sollte, dann solltest du 
trotzdem überall dieses #define benutzen und nicht direkt in deinem Code 
85 stehen haben. Das sind alles nur Stolpersteine.


> Die Frequenz übergebe ich zusätzlich im Makefile.

Dann nimm sie aus dem Code raus.
Doppelte Angaben verwirren nur.

von Karl H. (kbuchegg)


Lesenswert?

Ich denke, das hier ist falsch
1
    case TW_SR_DATA_ACK:             // 0x80 Slave Receiver,Daten empfangen
2
      data=TWDR;                 // Empfangene Daten auslesen
3
      if (buffer_adr == 0xFF)         // erster Zugriff, Bufferposition setzen
4
        {
5
          if(data<=buffer_size)      // Kontrolle ob gewünschte Adresse im erlaubten bereich

das kann hier nicht <= heissen. Das muss < sein!

(Wenn immer im Zusammenhang mit Array Indizierung irgendwo ein <= 
auftaucht, dann muss man hellhörig werden)

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.