Aus RN-Wissen.de
Version vom 18. April 2010, 14:56 Uhr von Manni2k (Diskussion | Beiträge) (Abschnitte hinzugefügt / modifiziert (-> strukturierter jetzt))

Wechseln zu: Navigation, Suche
Laderegler Test Tueftler Seite

C99-Standard

Das Programm erzeugt beim kompilieren mit AVRStudio 4.13.528 Fehler bei den For-Schleifen. Das rührt daher, dass in rncontrol.h Variablen in C++-Manier in den for-Anweisung selbst deklariert werden.

Bsp.:

void sound(uint8_t hoehe, uint16_t laenge)
{
	for(uint16_t i=0; i<laenge*15; i=i+(2*hoehe))
	{
	setportdon(7);
	_delay_ms(hoehe);
	setportdoff(7);
	_delay_ms(hoehe);
	}
}

Fehler:

"error: 'for' loop initial declaration used outside C99 mode"

Werde das jetzt an den relevanten Stellen so ändern :

void sound(uint8_t hoehe, uint16_t laenge)
{
        uint16_t i;
	for(i=0; i<laenge*15; i=i+(2*hoehe))
	{
	setportdon(7);
	_delay_ms(hoehe);
	setportdoff(7);
	_delay_ms(hoehe);
	}
}

Wäre schön, wenn es dann zur Sicherheit mal jemand testen könnte.

Habe zur Sicherheit bei allen Änderungen mal

"initial declaration error" fix

eingefügt.

EDIT von Manni2k: Ich habe in den Anmerkungen zum C-Demoprogramm mal den Hinweis eingebaut, dass man dem AVR-Compiler den C99-Standard mitteilen muss. Ich denke, dass dies besser ist, als das Programm auf den alten Standard hin umzubauen.


Tastenabfrage

Zum letzten Abschnitt: Stimmt!

Mir ist aufgefallen, dass das Basic Beispieltestprogramm für die Tastenabfrage am Porta.7 den Pull-Up Widerstand verwendet, um bei nicht gedrückter Taste einen definierten Spannungspegel am AD Wandlereingang zu haben (+5V)


...

Config Adc = Single , Prescaler = Auto        'Für Tastenabfrage und Spannungsmessung 

Config Pina.7 = Input                         'Für Tastenabfrage 
Porta.7 = 1                                   'Pullup Widerstand ein 

...

Dies ist im C-Programm nicht so realisiert und der Pin hängt bei nicht gedrückter Taste in der Luft, was möglicher Weise zu dem im C-Programm beschriebenen Effekt führt


.....

setportaon(7);		//Ohne das hier "flackern" die Werte aus irgend einem Grund -> es werden
                        // mitunter Tasten erkannt, die gar nicht gedrückt wurden oder das 
                        //Programm bleibt für einige Sekunden "hängen"
waitms(1);
setportaoff(7);
....


Meine Lösung:


.........

/*### Hauptschleife ###*/

int main(void)
{

	/*###Initialisierungsphase###*/

	//Pins bzw. Ports als Ein-/Ausgänge konfigurieren

	//Initialisierungen
	
	setportdoff(7);	//Speaker aus
	
	init_USART();	//USART konfigurieren

	DDRA = 0x00;	//00000000 -> alle Analogports als Eingänge
    	
        SFIOR &= ~(1<<PUD);     // Pull-UP enable (nicht unbedingt nötig, aber zur Klarheit!)
        PORTA |= (1<<PA7);    // internen Pull-Up an PA7 aktivieren 

......

Dann muss die Buttonabfrage wegen des Pull-Up Widerstandes entsprechend angepasst werden, denn er liegt nun parallel zu dem 10k Widerstand + 1 bis 4 1k Widerständen (je nach gedrückter Taste). Dann stimmen die Ergebnisse der AD Wandlung auch mit dem des Basic-Programms überein und können direkt übernommen werden



...

/*### Buttonabfrage ###*/

uint8_t button(void)
{
	uint8_t taste = 0; 	//Variable für Nummer des Tasters
	uint16_t analog7 = adcwert(7);	//Wert des Ports

//-----------auskommentieren, sonst wird der int. Pull Up Widerstand wieder abgeschaltet!
	
//	setportaon(7);		
//	waitms(1);
//	setportaoff(7);

/ Die folgende Zeile ist nur zur Überprüfung aller gelesenen Werte und kann auskommentiert werden
	utoa(analog7, wort, 10),sendUSART("ADC-Wert=");sendUSART(wort);sendUSART("\r\n");

	//Abfrage des gedrückten Tasters - um Störungen zu vermeiden wurden
        //die Bereiche sehr eng gefasst, sollten bei Bedarf an jedes Board extra angepasst werden.
	if((analog7>=400) && (analog7<=450)) {taste = 1;utoa(analog7, wort, 10),sendUSART("Wert=");sendUSART(wort);}
	else if((analog7>=330) && (analog7<=380)) {taste = 2;utoa(analog7, wort, 10),sendUSART("ADC-Wert=");sendUSART(wort);}
	else if((analog7>=260) && (analog7<=305)) {taste = 3;utoa(analog7, wort, 10),sendUSART("ADC-Wert=");sendUSART(wort);}
	else if((analog7>=180) && (analog7<=230)) {taste = 4;utoa(analog7, wort, 10),sendUSART("ADC-Wert=");sendUSART(wort);}
	else if((analog7>=90) && (analog7<=130)) {taste = 5;utoa(analog7, wort, 10),sendUSART("ADC-Wert=");sendUSART(wort);}
	else {}
	
	return taste;
}




Hier mal die bei mir gemessenen AD Werte: (in der letzten Tabellenspalte wurde der interne Pull Up Widerstand (PW) durch einen externen 22k Widerstand ersetzt!)

Taste ohne PW mit internem PW mit ext. PW (22k)
1 341 408 432
2 272 340 363
3 204 268 286
4 135 190 202
5 67 106 106

Korrektur der Soundausgabe

Hallo,

ich bin zwar grad erst in die Mikrocontrollerwelt eingestiegen, habe aber gleich mal einen Verbesserungsvorschlag für das Demoprogramm:

Die Soundausgabe hat bei mir nicht wirklich funktioniert (RN-Control mit 16 MHz). Es lag einerseits daran, dass die waitms()-Funktion nicht die korrekte Anzahl an Millisekunden gewartet hat und andererseits hat auch die sound()-Funktion nur komische Töne erzeugt. Unter diesem Link (Registrierung nötig) kann man sich eine alternative delay.h herunterladen (delay_x.h). Diese stellt Delays bis auf einen Taktzyklus genau dar und ist Compileroptimierungsunabhängig. Damit habe ich eine neue sound()-Funktion geschrieben, der als Argumente die Frequenz in Hertz und die Dauer in 1/10-Sekunden übergeben wird.

void sound(uint16_t frequenz, uint16_t dauer)
{
	uint32_t cycles;
	uint16_t holdtime;
	cycles=frequenz*dauer/2;
	holdtime=1000000/frequenz;
	
	for (uint16_t i = 0; i<(cycles/10); i++)
	{
		setportdon(7);
		_delay_us(holdtime);
		setportdoff(7);
		_delay_us(holdtime);
	}
}

Natürlich vorher die delay_x.h ins \util-Verzeichnis packen und die include Anweisung entsprechend anpassen.

Das ganze lässt sich sicher noch optimieren. Probierts mal aus, bei mir hats hervorragend geklappt. Wenn das ganze bugfrei ist, dann würd ichs (wenn das genehm ist) im Hauptartikel entsprechend umschreiben.

EDIT von Manni2k: Hat bei mit leider auch nicht funktioniert. Du rufst "_delay_us" auch mit einer Nicht-Konstanten auf, was laut avr-libc doku zu fehlerhaften Delays führt.

Korrektur der Soundausgabe 2

Ich habe mich mal rangemacht, das Sound-Problem zu lösen und bin am Ende zu einer kurzen, schlanken und effizienten Lösung gekommen, die darin besteht, lediglich die Zeilen in der sound()-Funktion mit "_delay_ms(hoehe);" durch "_delay_loop_2(hoehe<<7);" zu ersetzen. Die Problematik bestand u.a. darin, dass laut avr-libc doku _delay_ms und _delay_us nur mit zur Compilerzeit konstanten Werten aufgerufen werden dürfen. Die ist bei den delay_basic-Funktionen _delay_loop_1 und _delay_loop_2 ander. Wie diese Funktionen genau funktionieren steht in der avr-libc doku (hier). Die Multiplikation von hoehe mit der Konstanten 128 (hoehe<<7) wurde experimentell bestimmt und lässt sich durch (hoehe<<7) effizient berechnen.

Weiteres dazu unter folgendem Thread: Thread: Sound-Probleme mit dem Demoprogramm in C + kurze Fragen

Optimierungen

Ich bin zwiar kein wirklicher C Spezi, aber da sind einige Teile nicht gut gelöst. Einen Teil könnte der Compiler eventuell automatisch optinmieren, GCC tuts aber noch nicht überall.

Bei der ADWandlerroutine solle man statt wert = wert / 4; besser "wert >> 2" nutzen, ist nicht so übersichtlich, aber die Division wird so vermieden.

Viele der ganz kurzen Funktionen (z.B. Bit in Ports setzen) sollte man wenigstes als inline deklarieren. Besser wäre es da mit #define zu arbeiten.


LiFePO4 Speicher Test