C: Frage zu If / Else Abfrage

Folienkondensator

Neues Mitglied
28. Mai 2012
89
0
0
Sprachen
  1. ANSI C
  2. Assembler
Hallo
Ich hab letztens mal versucht ein Blibklicht mit C zu basteln. Das hat auch gut funktioniert. Dann dacht ich mir ich bau nen Start Taster mit ein und fange mit der Blinkerei an sobald der Taster gedrückt ist. wenn man ihn los lässt hört es auf zu blinken. Ich hab ewig lange rum gegooglet und gesucht (teils funktionierende Programme einfach ins AVRstudio 5 rein koppiert. jedes mal das selbe Problem, das Programm tut so als wär garkein Taster eingebaut.

hier mal ein Beispielprogramm. es sollte eigendlich die LEDs einschalten sobald der Taster auf pinb,0 gedrückt ist. wenn der Taster nicht gedrückt ist sollen die LEDs wider aus gehen. Funktioniert aber nicht :cray:
hat jemand ne Erklärung wiso?

-> in welches Forum muss man eigendlich Fragen zur programmierung selbst rein schreiben. gibz da was spezielles oder kann man wild durch die Gegend posten? ^^
Gruß

Code:
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 1000000

int main(void)
{
	
	DDRD = 0b11111111;
	DDRB = 0b00000000;
	
    while(1)
    {
		if (PINB0 >=0)
		{
		PORTD = 0b11111111;
		}
		else
		{
		PORTD = 0b00000000;
		}
	}
	return 0;
}
 
Hallo,

wenn du dir nicht sicher bist, wo das Thema am besten rein passt, dann wähle einfach das Forum Software.

Bezüglich der Abfrage eines Portpins, du hast in deiner if-Bedingung nur Konstanten, das geht so nicht.

Verwende folgenden Code:

Code:
if (PINB & (1<<PB0))
{
  // Zustand high
} else {
  // Zustand low
}

Dirk :ciao:
 
Hi

@ Dirk
Hat funktioniert. Alles blinkt wie es soll. Danke^^
-> Wens interessiert, hier das fertige Blinkprogramm mit Start Taster.
gruß

Code:
#include <avr/io.h>				//Includedatei für Chip laden
#include <util/delay.h>			//Wartezeiten Katalog
#define F_CPU 1000000			//Definiere Chiptakt von 1 Mhz

int main(void)
{
	
	DDRD = 0b11111111;			//DDRD auf Ausgang schalten
	DDRB = 0b00000000;			// DDRB auf EIngang schalten
	
    while(1)					// Schleife starten
    {
		if (PINB & (1<<PB0))		//Ist PINB,0 = 1? Wenn ja:
		{
		PORTD = 0b11111111; _delay_ms(500);		// Alle LEDs einschalten und 500ms pause
		PORTD = 0b00000000; _delay_ms(500);		// Alle LEDs ausschalten und 500 ms Pause
		}
		else                       // Ist PINB,0 =1? Wenn nein:
		{
		PORTD = 0b00000000;			// Alle LEDs ausschalten
		}
	}	//Sprung zurück zu while(1)
return 0;
}
 
Hi,

sehr schön, dass es funktioniert.

Eine kurze Anmerkung noch von mir. Versuch so wenig wie möglich die Methode "_delayXX" zu verwenden. Der Punkt ist der, dass Du damit die MCU "schlafen" schickst, sprich sie kann während dessen nichts machen. Wenn Du dann eine USART-ISR hast, kann es passieren, dass Dir npaar Zeichen durch die Lappen gehen. Versuch an der Stelle lieber Timer zu verwenden.

Grüße
Heinrich
 
Hi

Meist du damit Timer auf 0 setzen, und dann den nächsten Schritt erst ausführen lassen wenn der Timer eine bestimmte Stelle erreicht hat?
Gruß
 
Ja, genau so.

Du lässt den Timer eine Variable hochzählen und in der Main-Schleife pollst Du die Variable. Wenn sie einen Wert erreicht, lässt Du eine Methode ausführen.

So kannst Du Zeitscheiben definieren, sagen wir mal, alle 100ms, alle 200ms, alle 500ms und so weiter. Musst nur aufpassen, dass sie sich nicht in die Quere kommen.

Grüße
Heinrich
 
Hallo,

im Detail geht das etwa so ...

Du benötigst an verschiedenen Stellen eine Verzögerung von 200ms, von 100ms und von 20ms.

Nun könntest du zB einen Timer mit 5ms Intervall laufen lassen.

Dann nimmst du eine Variable die in diesem Intervall von der Interruptserviceroutine vom Timerüberlauf hochgezählt wird. Also alle 5ms plus Eins.

Bei der 20ms Verzögerung wartest du so lange bis die Variable den Stand 4 erreicht (4x 5ms = 20ms).
Bei der 100ms Verzögerung wartest du bis 20 (20x 5ms = 100ms)
und bei 200ms wartest du bis 40.

Wenn du das warten bis zum richtigen Variablenstand allerdings in einer Schleife machst, dann wirst du nur die Möglichkeit haben in dieser Zeit auf andere Interrupts zu reagieren. Du mußt dieses Warten also so geschickt in die Routinen einarbeiten das das Programm in den anderen Bereichen weiterarbeiten kann und nur wenn der Variablenstand erreicht ist diesen Bereich dann weiter ausführt. Ist eigentlich garnicht so kompliziert wie es sich anhört. Es ist lediglich ein wenig nachdenken erforderlich.

Gruß
Dino
 
Hi
Das mit dem Timer hat super funktioniert. ;)
Und jetzt mal ne allgemeine Frage zu AVR Studio 5.1.208
Kann es sein dass bei dem programm der Compiler irgendwie nicht ganz ausgereift ist wenn man C benutzt? Wenn ich folgenden code auf einen ATmega 8 schreibe (Soll bewirken dass 16 Kanäle mit PWM beschaltet werden) Ich hab das programm hunderte male durchgeschaut und umgebaut. egal wie ich die PWMs mache, es ist immer der selbe Fehler. Die einzelnen LEDs an den Kanälen (ganz kleine LEDs die fast nichts brauchen) leuchten im großen und ganzen etwa gleich hell. (so solls auch sein) NUR PC3 ist immer auf Low und PC0 immer auf High. wenn ich aber im programm diese Ports direkt entweder dauer an oder dauer aus schalte funktioniert es. kann es sein dass diese Ports einfach keine schnellen Schaltvorgänge aushalten oder sowas. (ist bei allen MEGA8 die ich hier rum liegen hab das selbe. Lustig ist nur dass dieses grausame Verhalten auch bei einem MEGA16 auftritt.
Hat jemand dieses problem schon mal gehabt?

Gruß

Code:
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

uint8_t Zahler;

		
//Konfiguartion
//******************************************************

uint8_t		A1 = 50;	// Kanal 1 in %
uint8_t		A2 = 50;	// Kanel 2 in %
uint8_t		A3 = 50;	// Kanal 3 in %
uint8_t		A4 = 50;	// Kanel 4 in %
uint8_t		A5 = 50;	// Kanel 5 in %
uint8_t		A6 = 50;	// Kanel 6 in %
uint8_t		A7 = 50;	// Kanal 7 in %
uint8_t		A8 = 50;	// Kanal 8 in %
uint8_t		A9 = 50;	// Kanal 9 in %
uint8_t		A10 = 50;	// Kanal 10 in %
uint8_t		A11 = 50;	// Kanal 11 in %
uint8_t		A12 = 50;	// Kanal 12 in %
uint8_t		A13 = 50;	// Kanal 13 in %
uint8_t		A14 = 50;	// Kanal 14 in %
uint8_t		A15 = 50;	// Kanal 15 in %
uint8_t		A16 = 50;	// Kanal 16 in %

uint8_t		A = 100;	// Auflösung in Schritte

//******************************************************

uint8_t 	Phase = 0;
uint8_t		Aufloesung;				

uint8_t		Kanal_1;	 
uint8_t		Kanal_2;		 
uint8_t		Kanal_3;		
uint8_t		Kanal_4;		
uint8_t		Kanal_5;		
uint8_t		Kanal_6;		
uint8_t		Kanal_7;		
uint8_t		Kanal_8;
uint8_t		Kanal_9;
uint8_t		Kanal_10;
uint8_t		Kanal_11;
uint8_t		Kanal_12;
uint8_t		Kanal_13;
uint8_t		Kanal_14;
uint8_t		Kanal_15;
uint8_t		Kanal_16;




	
int main(void)
{	
DDRC = 0b11111111;	// DDRC Auf Ausgang schalten
DDRB = 0b11111111;	// DDRB Auf Ausgang schalten
DDRD = 0b11111111;	// DDRD Auf Ausgang schalten

//Timer Init
//*********************************************************
TCCR0 |=(1<<CS02) | (0<<CS01) | (1<<CS00);		// Prescaler Einstellen
TIMSK |= (1<<TOIE0);							// Timer Overflow erlauben
sei();											// Interrupts freigeben



//PWM Zyklus		
//*********************************************************
	while (1)
	{

		Aufloesung = A;
		Kanal_1=A1;
		Kanal_2=A2;
		Kanal_3=A3;
		Kanal_4=A4;
		Kanal_5=A5;
		Kanal_6=A6;
		Kanal_7=A7;
		Kanal_8=A8;
		Kanal_9=A9;
		Kanal_10=A10;
		Kanal_11=A11;
		Kanal_12=A12;
		Kanal_13=A13;
		Kanal_14=A14;
		Kanal_15=A15;
		Kanal_16=A16;
		
	
	
		PORTB = 0b00000000;
		PORTC = 0b00000000;
		PORTD = (0<<PD0);
		PORTD = (0<<PD1);
		PORTD = (0<<PD2);
		PORTD = (0<<PD3);
		PORTD = (0<<PD4);
		// PD 5 wird ausgelassen wegen Blinkimpuls
		PORTD = (0<<PD6);
		PORTD = (0<<PD7);
		
		
		
		
	
		while(Aufloesung>=1)
		{			
//			while (Zahler == 0)
//			{
//			}
			
			Zahler = 0;				//Timer Interrupt zurück setzen
			Aufloesung--;
				
				
			if (Kanal_1 >= Phase)	// CH1
			{PORTD = (1<<PD4);}
			else
			{PORTD = (0<<PD4);}
		
			if (Kanal_2 >= Phase)	// CH2
			{PORTD = (1<<PD3);}
			else
			{PORTD = (0<<PD3);}
		
			if (Kanal_3 >= Phase)	// CH3
			{PORTD = (1<<PD2);}
			else
			{PORTD = (0<<PD2);}
			
			if (Kanal_4 >= Phase)	// CH4
			{PORTD = (1<<PD1);}
			else
			{PORTD = (0<<PD1);}
			
			if (Kanal_5 >= Phase)	// CH5
			{PORTD = (1<<PD0);}
			else
			{PORTD = (0<<PD0);}
				
			if (Kanal_6 >= Phase)	// CH6
			{PORTC = (1<<PC5);}
			else
			{PORTC = (0<<PC5);}
				
			if (Kanal_7 >= Phase)	// CH7
			{PORTC = (1<<PC4);}
			else
			{PORTC = (0<<PC4);}
				
			if (Kanal_8 >= Phase)	// CH8
			{PORTC = (1<<PC3);}
			else
			{PORTC = (0<<PC3);}
				
			if (Kanal_9 >= Phase)	// CH9
			{PORTC = (1<<PC2);}
			else
			{PORTC = (0<<PC2);}
				
			if (Kanal_10 >= Phase)	// CH10
			{PORTC = (1<<PC1);}
			else
			{PORTC = (0<<PC1);}
				
			if (Kanal_11 >= Phase)	// Ch11
			{PORTC = (1<<PC0);}
			else
			{PORTC = (0<<PC0);}
				
			if (Kanal_12 >= Phase)	// CH12
			{PORTB = (1<<PB2);}
			else
			{PORTB = (0<<PB2);}
				
			if (Kanal_13 >= Phase)	// Ch13
			{PORTB = (1<<PB1);}
			else
			{PORTB = (0<<PB1);}
				
			if (Kanal_14 >= Phase)	// CH14
			{PORTB = (1<<PB0);}
			else
			{PORTB = (0<<PB0);}
				
			if (Kanal_15 >= Phase)	// CH15
			{PORTD = (1<<PD7);}
			else
			{PORTD = (0<<PD7);}
				
			if (Kanal_16 >= Phase)	// CH16
			{PORTD = (1<<PD6);}
			else
			{PORTD = (0<<PD6);}
			
			Kanal_1 --; Kanal_2 --;  Kanal_3 --;  Kanal_4 --;  Kanal_5 --;  Kanal_6 --;  Kanal_7 --;  Kanal_8 --;
			Kanal_9 --; Kanal_10 --; Kanal_11 --; Kanal_12 --; Kanal_13 --; Kanal_14 --; Kanal_15 --; Kanal_16 --;
						
		}	        
    }
	
return 0;
}


ISR (TIMER0_OVF_vect)
{
	Zahler++;
}
 
Hallo,

Die einzelnen LEDs an den Kanälen (ganz kleine LEDs die fast nichts brauchen) leuchten im großen und ganzen etwa gleich hell. (so solls auch sein) NUR PC3 ist immer auf Low und PC0 immer auf High.
...
kann es sein dass diese Ports einfach keine schnellen Schaltvorgänge aushalten oder sowas. (ist bei allen MEGA8 die ich hier rum liegen hab das selbe. Lustig ist nur dass dieses grausame Verhalten auch bei einem MEGA16 auftritt.
Hat jemand dieses problem schon mal gehabt?
also dafür das ich C eigentlich nicht kann ... Die Programmstruktur ist ja in etwa überall ähnlich.

Du machst also Soft-PWM und läßt den Rampenzähler über nen Timer erhöhen. So im Überblick würde ich mal sagen das da alles soweit OK aussieht. Wenn da jetzt wegen Copy-Paste zwischen den ganzen Kanälen jetzt nicht nen Schreibfehler reingekommen ist den ich auch übersehen habe sollte es soweit klappen.

Also der Port C hat beim Mega8 die ADC-Eingänge mit drauf. Beim Mega16 ist es der Port A. Diese Pins werden also über AVcc versorgt. Das muß man beachten. Wenn man also keinen ADC benötigt der genau arbeitet dann sollte man AVcc ohne Drossel direkt an Vcc legen um mehr Strom zur Verfügung zu stellen. Das hat aber nichts mit deinem Phänomen zu tun.

Also normalerweise sind alle Pins gleichwertig und können problemlos 10mA an eine LED liefern. Da würde ich mir erstmal keine Gedanken machen. Bei mir war sowas mal weil ich nen blöden Schreibfehler bei der Portinitialisierung drin hatte. Da waren die Pins noch auf Eingang geschaltet und die LEDs liefen über die internen PullUps :rolleyes:

Wenn das identische Problem selbst bei nem Mega16 auftritt würde ich eher an einen Fehler im Programm denken der evtl jetzt noch übersehen wurde. Vor allem weil du zwei verschiedene Megas zum Test verwendet hast.

Gruß
Dino
 
Kann es sein dass bei dem programm der Compiler irgendwie nicht ganz ausgereift ist wenn man C benutzt?

Nein, der C-Compiler ist ausgereift.


So ganz versehe ich deinen Code leider nicht.

Hier mal was mir aufgefallen ist:

(1) In den If-Abfragen verwendest du einen Vergleich mit der Variable uint8_t Phase. Phase ist immer Null, die Variable ändert sich nie.

(2) Dekrement von uint8_t Aufloesung und uint8_t Kanal_n ist im Moment zeitlich nicht kontrolliert, der Zeitpunkt wann dekrementiert wird, wird eigentlich nur durch die Code-Laufzeit innerhalb der while-Schleife vorgegeben.

(3) Folgende Zuweisung bewirken alle das selbe, sie kopieren eine Null in das Register:

Code:
PORTD = (0<<PD0); 
PORTD = (0<<PD1); 
PORTD = (0<<PD2); 
PORTD = (0<<PD3); 
PORTD = (0<<PD4);

Dies verwendest du auch wenn die if-Bedingungen unwahr sind.
Du möchtest sicherlich das einzelne Bit löschen. Das geht zum Beispiel so: PORTD &= ~(1<<PD0)

Solch eine Zuweisung setzt ausschließlich das eine Bit im Register, alle anderen Bitpositionen werden gelöscht:
Code:
PORTD = (1<<PD1);
Du möchtest sicherlich das eine Bit setzen ohne die anderen Bits zu ändern. Das geht zum Beispiel so: PORTD |= (1<<PD1)

Vielleicht hilft dir hiervon ja etwas weiter.

Dirk :ciao:
 
Hi

Jetzt Mit den neuen Befehlen von Dirk funktionierts endlich so wie es soll. (paar kleinere fehler noch ausgebessert)
Das Phänomen AVCC (sihe oberen Beitrag von Dino) ist aber auch nicht zu verachten. Wenn man so eine Software PWM benutzt und diese auf PORTA liegt sollte man unbedingt AVCC anschließen. sonst hat man gegenüber der anderen Ports schnell mal 0,5V weniger an Spannung anliegen. ;)
Gruß
 
Hallo,

Das Phänomen AVCC (sihe oberen Beitrag von Dino) ist aber auch nicht zu verachten. Wenn man so eine Software PWM benutzt und diese auf PORTA liegt sollte man unbedingt AVCC anschließen. sonst hat man gegenüber der anderen Ports schnell mal 0,5V weniger an Spannung anliegen. ;)
ich würde eher sagen ... dann hast du da garnix anliegen weil du den Teil des Prozessors überhaupt nicht versorgt hast. Das wäre so als wenn du bei nem Haus bei der ersten Etage die Sicherung rausdrehst. Der Rest hat dann trotzdem noch Licht :p

Wenn du AVcc nicht beschaltest, dann haben die IO-Schaltungen der Pins wo die ADC-Eingänge draufliegen und auch der Chipbereich mit dem ADC überhaupt keine Versorgung. Sie haben nicht weniger sondern garnix.

Ich möchte nicht wissen wo dann im Controller die Ausgleichsströme langfließen :rolleyes:

Da wird im Datenblatt aber extra drauf hingewiesen.

Gruß
Dino
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)