PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LEDs mit Poti zuschalten über µC



frankensteins-freund
23.11.2012, 18:07
hallo,

Ich habe folgendes projekt:

Ich würde gerne mit einem Poti zwei LEDs schalten. Ligt der Messwert des Microcontrollers unter 1V Leuchtet nur LED1. Ligt der Messwert über 1V soll zusätzlich eine LED2 eingeschalten werden. Da ich aber ein relativ Blutiger Anfänger bin Weis ich nicht, wie ich des ADC (Analog-Digital Converter) aktivieren und auslesen Soll. Ich würde es gerne mit einer einfachen IF- Else Anweisung schreiben. Meine versuche das Programm selbst zu konstruieren mit google & co sind leider gescheitert :(

Nun die Technischen Sachen:
- Sprache: C
- Atmega16
- ADC läuft auf 10 Bit
- Sensoranschluss auf PA1
- LED 1+2 an PD5, PD6

Ich weis, dass ich jetzt von niemendem erwarten kann, dass er mir ein ganzes Programm schreibt und erklärt. Aber kann mir jemand auf ähnliche Projekte im web einen Link schicken oder mir vielleicht einen gedankenstoß in sachen ADC aktivierung und auslesung geben?

MfG
Michael

oberallgeier
23.11.2012, 18:48
... mit einem Poti ... schalten ... wie ... ADC ... aktivieren und auslesen ...Na das mit dem if-else ist ja erst dann möglich, wenn der ADC "am Laufen" ist. Hier ein paar Schnippsel zu nem funktionierenden Programm für nen mega1284 - das sollte mit nem m16 wohl 1:1 laufen (hab ich aber nicht wirklich geprüft).

Hier der Code. Die ----Sequenzen bedeuten ne Art Schnittkante und führen mittenrein in verschiedene Module. Die globalen Deklarationen sind weggelassen - wird Dir aber sicher trotzdem helfen. Das Poti hängt am PA5 - wie im Kommentar/Code beschrieben. Du kannst vermutlich für Deine Zwecke mit einem wesentlich "langsamer" wirkenden prescaler für den ADC-Takt arbeiten. Für Dich ist im Prinzip nur der Befehl
ADC_ist = ADC;
wichtig, den Rest brauchst Du aber, damit der Befehl überhaupt wirkt. Und mit dem gewonnen Wert ADC_ist kannst Du dann Deine LEDs schalten. In der Luxusausführung könntest Du noch den ADC_ist-Wert in tatsächliche Spannung umrechnen. Das solltest Du dann aber wohl selbst lösen = hinkriegen.


Initialisierungen etc im main:
----------------------------------------------
// ================================================== =
// ####>>>> Initialisierung der Anschlüsse für R5M auf mega1284: <<<<####
// PB0 1 A E 40 PA0
// Relais Blink/Warnl. PB1 2 A E 39 PA1
// PB2 3 A E 38 PA2
// PB3 4 A E 37 PA3
// PB4 5 A EU 36 PA4
// MOSI, PB5 6 A E 35 PA5, ADC Batterie_2-Test (Test, Poti)
// MISO, PB6 7 AU E 34 PA6, ADC Batterie_1-Test !!RNCntrl!!
// SCK, PB7 8 A E 33 PA7
// /RESET 9 32 AREF ref Vccaktuell (?)
----------------------------------------------
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ports+Pins als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
// A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
// - - - - - - - - - - - - - - - -
DDRA = 0b00000000; // siehe aktuell oben
PORTA = 0b00010000; // PA5 = ADC-Eingang Poti
//
----------------------------------------------
// - - - - - - - - - - - - - - - -
adcpnr = 5; // Vorwahl ADC Portnummer
ADC_init_10_irupt(); // Init. ADC, 10 Bit, Interrupt, auf Kanal adc_pnr ~gpd~
// - - - - - - - - - - - - - - -
----------------------------------------------
// ================================================== ============================ =
// === Initialisierung fuer ADC mega1284 MIT Interrupt free running
// === ADC5/PA5 auf 10 Bit, fertige Wandlung ###>>> löst Interrupt aus
void ADC_init_10_irupt(void) // Initialisiere ADC, Kanal5, 10 Bit, MIT Interrupt
{ //
if (adcpnr > 7) adcpnr = 5; // Defaultwert adcpnr
ADMUX |= (1<<REFS0); // Referenzspannung ist AVcc S 258
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // Prescaler = clock/128 S 261
ADCSRA |= (1<<ADATE); // Auto Triggering Enable S 245 + 260
// es wird bei clock 20 Mhz mit ca. 80 µs getriggert
ADCSRA |= (1<<ADIE); // ADC Interrupt Enable doc S 260
ADCSRA |= (1<<ADEN); // ADC Enable
ADCSRA |= (1<<ADSC); // starte gleich die erste Wandlung
} //
// ================================================== ============================ =
// ================================================== ============================ =
// === Nicht unterbrechbare ISR für ADC
// Routine übernimmt ADC-Wert
ISR(ADC_vect) // VECTOR 25, Adr $0030
{ //
adc5_tmp = ADC; // Hole Wert
// Anmerkung für Forum - 23. Nov. 2012, 19:34 Dieser Wert wird "anderswo gefragt
} //
// ================================================== ============================ =
----------------------------------------------
Auswertung des ADC, hier im main, sozusagen etwas unter dem Schnippsel ganz oben
Anmerkung: mit diesem Schnippsel wird im späteren Zielsystem mit Akku
die aktuelle Spannung abgefragt. Hier nur ne Funktionskontrolle, die
nur den (konstanten) Wert durch Netzteil und Poti/Spannungsteiler nennt
==================
// - - - - - - - - - - - - - - -
uart_puts ("\tUbattADC5-Minimalwert : "); // Melde ADC5-MinimalWert
itoa(ADC5MM, wortadc, 10); // aktueller ADC-Abschaltwert
sendUSART(wortadc); // ... ausgeben
uart_puts ("\r\n\tUbattADC5 Messwert : "); // Melde ADC-5-Istwert
cli(); ADC_ist = ADC; sei(); // hole aktuellen ADC5-wert
itoa(ADC_ist, wortadc, 10); // aktueller ADC-Abschaltwert
sendUSART(wortadc); // ... ausgeben
uart_puts ("\r\n"); // Melde aktuellen ADC-Istwert
//
// ================================================== ============================ =

Viel Erfolg.

frankensteins-freund
27.11.2012, 19:48
Hallo,
Also ich habe nun ein Paar Versuche gemacht und dabei ist mir aufgefallen, dass selbst wenn ich den text von oben 1:1 in mein geany schreibe, geany alles rot unterstreicht und die konvertierung verweigert. Ligt das an geany??

MfG
Michael

Hubert.G
27.11.2012, 21:27
Kann der geany (weiss nur das es ein Editor ist) für den AVR kompilieren?
Ich nehme mal an das er mit dem Code einfach nichts anfangen kann.

frankensteins-freund
28.11.2012, 15:30
Hallo,

Ja das Kompilieren funktionierte bisher mit meinen einfachen if-else programmen immer unter geany. sollte ich mal einen anderen editor verwenden? falls ja, was wird empfohlen?

MfG
Michael

Zameer
28.11.2012, 15:50
Mit Geany kannst auch für die µC's compilen, man muss halt dafür'n paar Einstellungen zurechtbasteln und des avr-gcc draufhaben.

frankensteins-freund
20.12.2012, 17:13
Hallo,

Also ich habe mich in den letzten Tagen dann nochmal an das Projekt gesetzt und nun kann ich erfolge vermerken:

#include "avr/io.h"
#include "util/delay.h"
#include "stdlib.h"
#include "avr/interrupt.h"
#include "stdio.h"

int main (void) {

DDRD = 0xff; //DDRD alle Pins Ausgang
ADMUX = 0x40; // Avcc=Referenz--> AVCC geschalten wie
// im datenblatt seite 196, abbildung 96, Rechtsbündig, PC0 gewählt
ADCSRA = 0x83; // ADC eingeschaltet, Taktung/8

while(1)
{
ADCSRA |= (1<<ADSC); // start conversion

if(ADCW<=200)
{
PORTD |= (1<<PD5);
PORTD &= ~(1<<PD6);
}
else
{
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD5);
}
}
return 0;
}

//das war ja einfach :)

Ach ja: Ich habe den atmega16 aus versehen geschrottet, indem ich die internen 2,5V referenz eingeschalten habe und ihn extern mit 5V bestromt habe :( deswegen ist dieses Programm für einen Atmega8. beim atmega16 müsste das programm aber eigendlich nahezu gleich aussehen :)

PS: ich habe noch ein Programm geschrieben, wo der controller mehrere messwerte nimmt und dann den durchschnitt errechnet, um messfehler zu verringern. das programm wird demnächst folgen :)

MfG
Michael

BMS
20.12.2012, 17:46
Hallo,
erst mal Glückwunsch, dass es soweit funktioniert ;)
Ich würde noch empfehlen, nach "start conversion" zu warten, bis der AD-Wandler wirklich fertig ist.
Das geht mit

while(ADCSRA & (1<<ADSC)); //Warte bis Wandlung wirklich fertig ist


Wenn du es wiederverwendbar programmieren möchtest, kannst du aus deiner Analog-Wandler-Routine eine Funktion (Methode) machen, die du immer wieder aufrufen kannst.
Grüße, Bernhard

frankensteins-freund
20.12.2012, 20:57
Hallo,

Na diese berichtigung nehme ich gerne an und baue sie noch schnell in mein programm ein:


#include "avr/io.h"
#include "util/delay.h"
#include "stdlib.h"
#include "avr/interrupt.h"
#include "stdio.h"

int main (void) {

DDRD = 0xff; //DDRD alle Pins Ausgang
ADMUX = 0x40; // Avcc=Referenz--> AVCC geschalten wie
// im datenblatt seite 196, abbildung 96, Rechtsbündig, PC0 gewählt
ADCSRA = 0x83; // ADC eingeschaltet, Taktung/8

while(1)
{
ADCSRA |= (1<<ADSC); // start conversion
while(ADCSRA & (1<<ADSC)); //Warte bis Wandlung wirklich fertig ist

if(ADCW<=200)
{
PORTD |= (1<<PD5);
PORTD &= ~(1<<PD6);
}
else
{
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD5);
}
}
return 0;
}





Und wie versprochen noch das programm, das den wert öfters misst und dann mit dem durchschnittswert arbeitet. in meinem Fall wird 30x gemessen und dann der errechnete endwert ausgegeben:


#include "avr/io.h"
#include "util/delay.h"
#include "stdlib.h"
#include "avr/interrupt.h"
#include "stdio.h"

int main (void) {

uint8_t durchlaufzaehler=0; //zählt die durchgänge
uint16_t messwerte=0; //messwerte werden hier abgespeichert
uint16_t endwert=0; //errechneter endwert

DDRD = 0xff; //DDRD alle Pins Ausgang


while(1)
{
for(durchlaufzaehler=0;durchlaufzaehler<30;durchlaufzaehler++) //diese schleife wird 30x durchlaufen
{
ADMUX = 0x40; // Avcc=Referenz--> AVCC geschalten wie
// im datenblatt seite 196, abbildung 96, Rechtsbündig, PC0 gewählt
ADCSRA = 0x83; // ADC eingeschaltet, Taktung/8
ADCSRA |= (1<<ADSC); // start conversion
while(ADCSRA & (1<<ADSC)); //Warte bis Wandlung wirklich fertig ist
messwerte+=ADCW; // aufsummierung der messwerte
}

endwert=messwerte/30; //durchschnitt errechnen

if(endwert<=200)
{
PORTD |= (1<<PD5);
PORTD &= ~(1<<PD6);
}
else
{
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD5);
}
}
return 0;
}


so, ich denke damit kann so mancher anfänger was anfangen :)