Forum: Mikrocontroller und Digitale Elektronik RGB-LED Ansteuerung mittels PWM in AVR Studio 4 (C-Programmieren)


von Maxx (Gast)


Lesenswert?

Guten Tag liebe Gemeinde,

ich habe ein Problem: ich habe relativ wenig Ahnung von Programmierung, 
daher fällt mir das sehr schwer und einen richtigen Ansatz habe ich auch 
nicht gefunden. Ich bin mir auch nicht sicher, ob sowas ähnliches schon 
mal Thema war im Forum, ich hab vieles Ähnliches gefunden, aber richtig 
schlau wurde ich daraus nicht. Bin was Programmieren angeht wirklich ein 
Noob.

Für ein kleineres Projekt an der Uni ist meine Aufgabe, eine 
RGB-LED-Ansteuerung per Pulsweitenmodulation zu realisieren. Als 
Mikrocontroller verwenden wir einen Atmega 328, nebenbei arbeiten wir 
mit AVR Studio 4 und einem AVR Dragon. Für das Projekt soll der ADC des 
uC verschiedene "Potentiometerstellungen" einlesen und diesen 
verschiedene Werte zuordnen( welche dann für die "Stärke" der 3 Farben 
stehen, soweit ich das verstanden habe).

Ich hab mich schon viele Nachmittage rangesetzt, aber es mangelt mir 
einfach an theoretischem Verständnis dafür.
Deshalb bitte ich euch um Hilfe.

Ich danke im Voraus! :)

LG Max

: Verschoben durch User
von yesitsme (Gast)


Lesenswert?

Bist du schon über den Punk "Ich lasse eine LED im Sekundentakt blinken" 
hinaus?

von Maxx (Gast)


Lesenswert?

wir haben dafür im Unterricht schon COdes geschrieben.. verstanden habe 
ich diese aber dennoch nicht. Leider.

von yesitsme (Gast)


Lesenswert?

Woran haperts beim Verstehen?

Hast du mal einen einfachen Beispielcode?

von Maxx (Gast)


Lesenswert?

es hapert an allem ehrlich gesagt. ich komme mit Programmierung einfach 
nicht zurecht

und Beispielcodes habe ich, aber nur für Blinken oder so.
also nichts wirklich hilfreiches.

ich kann auch nicht lesen, was in solchen Codes steht, weil ich es 
einfach nicht begreife.

Wenn du sagst was für ein Code für den Ansatz nützlich wäre könnte ich 
ihn reinstellen :)

von google (Gast)


Lesenswert?

Maxx schrieb:
> ich kann auch nicht lesen, was in solchen Codes steht, weil ich es
> einfach nicht begreife.

Die Angst davor lähmt Dich. Such Dir einen Leidensgenossen und fangt 
einfach an mit den Beispielcodes. Diese dann variieren, Effekte 
bestaunen. Dann verlierst Du die Angst davor.

von Roland F. (rhf)


Lesenswert?

Hallo Maxx,

> ich kann auch nicht lesen, was in solchen Codes steht, weil ich es
> einfach nicht begreife.

Zeige mal ein Beispiel.

rhf

von google (Gast)


Lesenswert?

google schrieb:
> Diese dann variieren, Effekte
> bestaunen.

Hab grad gesehen, dass man mit dem Dragon debuggen kann. Also das auch 
nutzen, gucken, was mit dem Code passiert.

Vor allem: ANFANGEN, nicht theoretisch erwägen ...

von Maxx (Gast)


Lesenswert?

das ist leider wahr, die Angst davor lähmt mich wirklich..

und der Fakt, dass es so ein halbwegs anspruchsvolles Projekt(in meinen 
Augen) ist wirkt nicht gerade motivierender auf mich.

Codes kann ich euch leider morgen ab 10:00 erst schicken. Ich hoffe ihr 
könnt mir dann helfen.
Hab dann den ganzen Tag Zeit, vielleicht ihr ja auch. :) wäre super 
lieb.

Bis dahin gucke ich weiter, versuche, was zu verstehen.

vielleicht könnt ihr mir ja einen ungefähren Aufbau meines Codes liefer, 
a la anfangen mit Variablendeklaration, einer Funktion zum einlesen des 
Potis, eine Funktion, die diese Werte verarbeitet, dann die Funktion, 
die für das Erzeugen einer PWM zuständig ist, wessen Signal dann an die 
R,G,B- Elemente der LED's weitergegeben wird, usw..

Ich verstehe komischerweise genau, was dort passieren soll, wie es 
angeschlossen wird, was gemacht werden muss, nur hab ich halt sobald es 
um's Programmieren geht, wirklich keine Vorstellung, wie ich das 
anzustellen habe.

Ich weiß, das ist peinlich, vor allem, wenn man sich stundenlang damit 
beschäftigt und es trotzdem nicht begreift...

von google (Gast)


Lesenswert?

Maxx schrieb:
> vielleicht könnt ihr mir ja einen ungefähren Aufbau meines Codes liefer,
> a la anfangen mit Variablendeklaration, einer Funktion zum einlesen des
> Potis, eine Funktion, die diese Werte verarbeitet, dann die Funktion,
> die für das Erzeugen einer PWM zuständig ist, wessen Signal dann an die
> R,G,B- Elemente der LED's weitergegeben wird, usw..

Du hast doch ausreichend Beispielcodes ... sollen wir Deine Arbeit 
machen?

von Maxx (Gast)


Lesenswert?

nein sollt ihr nicht. ich komme nur halt erst morgen an die Codes ran 
und hoffe, dass ihr mir dann helfen könnt.

ich will halt nur heute irgendwas für das Projekt machen, direkt daran 
arbeiten kann ich aber erst morgen

von Robert S. (bimbo385)


Lesenswert?

Hey Maxx,

ich bin seit noch nicht so langer Zeit mit meinem E-Technik Studium 
fertig und ich erinnere mich noch ziemlich gut an einige Kommilitonen, 
die mit Programmierung überhaupt nicht klargekommen sind. Ist halt nicht 
unbedingt jedermanns Sache.

Ich kann dir nur den Rat geben; such dir einen Kommilitonen der ein 
Händchen dafür hat und lass dir von dem auf die Sprünge helfen. Hilfe 
aus der Ferne ist ziemlich mühselig und jemand der dir deine Arbeit 
macht, findest du hier bestimmt nicht (ist ja auch nicht Sinn des 
Studiums).

Also ich verstehe die Aufgabenstellung wie folgt: 3 Potis an 3 
ADC-Eingängen (Port A) und 3 LEDs an 3 PWM-Ausgängen (ggf. über 
Transistor/MOSFET/Treiber-IC).
Was ich dir als Eckpunkte aber gerne gegen den Kopf werfe, ist wie ich 
dein Programm ganz grob aufbauen würde:

Initialisierung (einmal am Programmanfang):
1. Ein- und Ausgänge konfigurieren (DDR Register)
2. ADC konfigurieren (Register siehe Datenblatt)
3. Timer als Dual-Slope PWM konfigurieren, welche Timer du dafür nimmst, 
hängt davon ab, an welchen Pins deine LEDs angeschlossen sind. 8-Bit 
Modus beim 16-Bit Timer wird wahrscheinlich reichen.

Programmablauf in Endlosschleife:
1. ADC Kanal 1 auswählen
2. AD-Wandlung starten
3. Warten bis Wandlung abgeschlossen ist
4. Ergebnis der Wandlung abholen und um 2 Bits kürzen (10 Bit auf 8 Bit)
5. 8-Bit Ergebnis in das Compareregister des Timers für die 1. LED 
schreiben
-> Schritte 1 bis 5 jetzt auch noch für Kanal 2 und 3 Wiederholen


Das ist es im Prinzip schon. Kann man mit Spaghetticode machen, schöner 
wird es wenn du die 3 Schritte der Initialisierung in einzelne 
Funktionen steckst. Punkt 1 bis 3 der Endlosschleife würde ich auch in 
eine Funktion verpacken, die den ADC-Wert als uint16_t zurückgibt und 
den Kanal als uint8_t Parameter bekommt. Wenn du für 5. dann auch noch 
eine kleine Funktion mit Wert und Kanal als Parameter schreibst, kannst 
du die 3 Kanäle in einer for-Schleife abhandeln und musst nicht den 
gleichen Code 3-mal schreiben.

Mfg Bimbo385

von Robert S. (bimbo385)


Lesenswert?

Was du heute schon machen solltest ist, dir im Datenblatt die Kapitel 
und Registerbeschreibungen vom ADC und den Timern durchzulesen, das hält 
sich in Grenzen.

Druck dir die Kapitel am besten aus und schreib dir in die 
Registerbeschreibungen schon mal rein, wie die Bits für deinen 
Anwendungsfall sein müssen. Geh alle Bits einmal durch, dann hast du 
eigentlich auch verstanden wie der ADC und die Timer funktionieren.

Wenn du dann die Registerwerte, die du raus hast, hier postest, findest 
sich vielleicht auch jemand, der dazu einen Kommentar abgibt ;-)

Mfg Bimbo385

von Maxx (Gast)


Lesenswert?

Danke!! ich werde mich damit beschäftigen, ich hoffe, dass das was wird!

einiges habe ich noch nicht ganz verstanden, kannst du vielleicht auf 
folgende Dinge nochmal näher eingehen:

Bimbo 3. schrieb:
> 3. Timer als Dual-Slope PWM konfigurieren, welche Timer du dafür nimmst,
> hängt davon ab, an welchen Pins deine LEDs angeschlossen sind. 8-Bit
> Modus beim 16-Bit Timer wird wahrscheinlich reichen.

was bedeutet DUal-Slope und wie lege ich einen Timer fest? ich hab immer 
nur was von Timer1 gelesen


Bimbo 3. schrieb:
> 1. ADC Kanal 1 auswählen

- wie "wähle" ich den denn "aus" also mit welcher Funktion wird das 
gemacht?

Bimbo 3. schrieb:
> 2. AD-Wandlung starten

- wie starte ich die mit welcher Funktion?

Bimbo 3. schrieb:
> 4. Ergebnis der Wandlung abholen und um 2 Bits kürzen (10 Bit auf 8 Bit)

- wie kürze ich das? einfach die Variable minus 2 rechnen?

Bimbo 3. schrieb:
> 5. 8-Bit Ergebnis in das Compareregister des Timers für die 1. LED
> schreiben

- auch bitte erläutern, kann mir darunter leider nix vorstellen :/


tut mir wirklich leid, mir fehlt da wirklich jegliches Verständnis fürs 
Programmieren.. es fällt mir super schwer, mich da reinzuversetzen.

Danke jedenfalls! bis auf die Punkte habe ich alles, denke ich, gut 
verstanden! das hat schon mal viel geholfen!!

von Dieter F. (Gast)


Lesenswert?


von Robert S. (bimbo385)


Lesenswert?

Oha, da scheinen dir ja jegliche Grundlagen zu fehlen, das ist nichts 
was ich mit 3 Sätzen aufklären könnte. Arbeite dich erstmal durch die 
Tutorials, Link steht ja schon da.

Die Timer (Der ATmega328 hat 3 davon) sind wie z.B. der ADC Teile des 
µControllers, welche auf dem Chip neben der eigentlichen ALU vorhanden 
sind und teils unabhängig arbeiten. Bei allen µP die ich kenne ist es 
so, dass solche Komponenten durch Konfigurationsregister eingestellt 
werden und dann mehr oder weniger automatisch etwas tun. Das Ergebnis 
kann man dann aus Statusregistern oder "Ergebnisregistern" auslesen. 
Außerdem kann man auch Interrupts auslösen lassen, aber das vergiss 
erstmal wieder.

Für den Timer0 musst du jetzt z.B. die Register TCCR0A und TCCR0B 
(Timer/Counter Control Register A/B) schreiben. Darin gibt es Bits die 
bestimmen was der Timer/Counter tun soll. Also hoch oder runterzählen, 
mit welchem Takt und ob daraus z.B. ein PWM-Signal generiert werden 
soll. Welche Bits was machen Steht im Datenblatt des ATmega328 auf S. 
105 und folgende.

Hier mal eine init-Funktion es einem meiner Programme (Ist für einen 
ATmega2560) bei der ich mehrere Timer konfiguriere, nur das du mal 
siehst wie das aussehen kann. Zu meiner Schande habe ich hier binäre 
Zahlen in die Register geschrieben, sodass man zwangsläufig ins 
Datenblatt schauen muss um die Bedeutung zu erkennen.
1
// This function initializes the timers TC1 & TC4 for 25.000 kHz PWM.
2
// TC2 to an other PWM frequency (>20 kHz), TC5 for period measuring and TC 3 for tick generation
3
void timer_init()
4
{
5
  // Three timers for PWM generation.
6
  TCCR1A = 0b10101000;      // clear up, set down, phase and frequency correct PWM
7
  ICR1 = (320 -1);        // 16MHz / (2*320) = 25kHz
8
                  // maximum is 319 so 0 - 319 are allowed values  
9
  TCCR1B = 0b00010001;      // WGM: 8, 16 MHz
10
  
11
  
12
  TCCR4A = 0b10101000;      // clear up, set down, phase and frequency correct PWM
13
  ICR4 = (320 -1);        // 16MHz / (2*320) = 25kHz
14
                  // maximum is 319 so 0 - 319 are allowed values  
15
  TCCR4B = 0b00010001;      // WGM: 8, 16 MHz
16
  
17
  
18
  TCCR2A = 0b10100001;      // clear up, set down, phase correct PWM
19
                  // 16MHz / (2*256) = 31.25kHz
20
                  // maximum is 255 so 0 - 255 are allowed values
21
  TCCR2B = 0b00000001;      // WGM: 8, 16 MHz
22
  
23
  
24
    
25
  // TC5 for period measuring
26
  TCCR5A = 0b00000000;      // no output compare WGM: normal
27
  TCCR5B = 0b10000100;      // input noise cancel, falling edge, prescaler = 256
28
  TIMSK5 = 0b00100001;      // input capture and overflow interrupt enabled
29
  
30
  EICRA = 0b10100000;        // INT2 and INT3 to falling edge
31
  EICRB = 0b00001010;        // INT4 and INT5 to falling edge
32
  EIMSK = 0b00111100;        // INT2-5 enable
33
  
34
  
35
  // TC3 for 100 ms trigger
36
  TCCR3A = 0b00000000;      // no output compare WGM: 12 CTC at ICR3
37
  OCR3A = 6249;          // 16MHz / (256*6250) = 10Hz
38
  TCCR3B = 0b00001100;      // prescaler = 256
39
  TIMSK3 = 0b00000010;      // overflow interrupt enabled    
40
}

von Maxx (Gast)


Lesenswert?

Guten Tag, Max hier

danke erstmal für den hilfreichen Text! Ich hoffe, dass es mir 
weiterhilft!
So ganz eine Vorstellung was ich dann im finalen Source Code schreiben 
soll habe ich aber dennoch nicht.
Ich verstehe aber zumindest, was dort geschehen soll.

Ich könnte jetzt sogar einige Codes schicken, von denen ich aber den 
richtigen Effekt nicht wirklich kenne. Vielleicht kannst du/ könnt ihr 
mir ja dann einiges zum Verständnis erläutern!

MfG Max :)

von Roland F. (rhf)


Lesenswert?

Hallo Maxx,

> Ich könnte jetzt sogar einige Codes schicken, von denen ich aber den
> richtigen Effekt nicht wirklich kenne. Vielleicht kannst du/ könnt ihr
> mir ja dann einiges zum Verständnis erläutern!

Du erzählst uns jetzt seit zwei Tagen das du das alles nicht verstehst, 
zeigst aber nicht was du nicht verstehst. Wie soll man dir da helfen?

Zeige endlich mal was du an Quellcodes hast und was du daran nicht 
verstehst.

rhf

von Maxx (Gast)


Lesenswert?

Hey, hier nun endlich ein Code, tut mir leid, ich war doch mehr im 
Stress als erwartet.

dieser Code hier ist zB für mein Projekt relativ gut geeignet, den habe 
ich jedoch nicht selbst erstellt, sondern selbst gefunden.
an dem würde ich mich orientieren, wenn ich ihn verstehen würde.

ich habe auch noch einzelne Codes für einzelne Module wie zB pwm.c, aber 
erstmal dachte ich, schicke ich diesen, weil der viele Übereinstimmungen 
mit meinem Projekt hat.
Ich würde euch ja auch selbstgemachte Codes schicken, aber die wären 
dann von mehr Fehlern geprägt.


'OC0A = PD.6 = Pin 12 - RGB LED_1 R
'OC0B = PD.5 = Pin 11 - RGB LED_2 R
'OC1A = PB.1 = Pin 15 - RGB LED_1 G
'OC1B = PB.2 = Pin 16 - RGB LED_2 G
'OC2A = PB.3 = Pin 17 - RGB LED_1 B
'OC2B = PD.3 = Pin 5  - RGB LED_1 B

'ADC0 = PC.0 = Pin 23
'ADC1 = PC.1 = Pin 24
'ADC2 = PC.2 = Pin 25
'ADC3 = PC.3 = Pin 26
'ADC4 = PC.4 = Pin 27
'ADC5 = PC.5 = Pin 28

$regfile = "m88adef.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

'$PROG &HFF,&HE2,&HDF,&HF9' generated. Take care that the chip supports 
all fuse bytes.

Ddrb = &B11111111                                           'PortB = 
Ausgang
Portb = &B00000000                                          'und auf low 
gesetzt

Ddrc = &B00000000                                           'PortC = 
Eingang
Portc = &B00000000                                          'und auf low 
gesetzt

Ddrd = &B11111111                                           'PortD = 
Ausgang
Portd = &B00000000                                          'und auf low 
gesetzt


Rot_pwm1 Alias Ocr0a                                        'PWM-Output: 
Pin 12
Rot_pwm2 Alias Ocr0b                                        'PWM-Output: 
Pin 11
Gruen_pwm1 Alias Ocr1al                                     'PWM-Output: 
Pin 15
Gruen_pwm2 Alias Ocr1bl                                     'PWM-Output: 
Pin 16
Blau_pwm1 Alias Ocr2a                                       'PWM-Output: 
Pin 17
Blau_pwm2 Alias Ocr2b                                       'PWM-Output: 
Pin 05

Dim Adc0 As Byte
Dim Adc1 As Byte
Dim Adc2 As Byte
Dim Adc3 As Byte
Dim Adc4 As Byte
Dim Adc5 As Byte

Dim Rot_pwm1 As Byte
Dim Rot_pwm2 As Byte
Dim Gruen_pwm1 As Byte
Dim Gruen_pwm2 As Byte
Dim Blau_pwm1 As Byte
Dim Blau_pwm2 As Byte

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc

Config Timer0 = Pwm , Prescale = 1 , Compare A Pwm = Clear Up , Compare 
B Pwm = Clear Up
On Timer0 Timer0_pwm
Enable Timer0

Config Timer1 = Pwm , Prescale = 1 , Pwm = 8 , Compare A Pwm = Clear Up 
, Compare B Pwm = Clear Up
On Timer1 Timer1_pwm
Enable Timer1

Config Timer2 = Pwm , Prescale = 1 , Compare A Pwm = Clear Up , Compare 
B Pwm = Clear Up
On Timer2 Timer2_pwm
Enable Timer2

Enable Interrupts

Config Lcdpin = Pin , Db4 = Portd.0 , Db5 = Portd.1 , Db6 = Portd.2 , 
Db7 = Portd.4 , E = Portb.6 , Rs = Portb.7
Config Lcd = 16 * 2
Cls

Do

Adc0 = Getadc(0)
Adc1 = Getadc(1)
Adc2 = Getadc(2)
Adc3 = Getadc(3)
Adc4 = Getadc(4)
Adc5 = Getadc(5)

Rot_pwm1 = Adc0
Gruen_pwm1 = Adc1
Blau_pwm1 = Adc2
Rot_pwm2 = Adc3
Gruen_pwm2 = Adc4
Blau_pwm2 = Adc5

Locate 1 , 1
Lcd " " ; Rot_pwm1
Locate 1 , 5
Lcd " " ; Gruen_pwm1
Locate 1 , 10
Lcd " " ; Blau_pwm1

Locate 2 , 1
Lcd " " ; Rot_pwm2
Locate 2 , 5
Lcd " " ; Gruen_pwm2
Locate 2 , 10
Lcd " " ; Blau_pwm2

Locate 1 , 1
Lcd " " ; Adc0
Locate 1 , 5
Lcd " " ; Adc1
Locate 1 , 10
Lcd " " ; Adc2

Locate 2 , 1
Lcd " " ; Adc3
Locate 2 , 5
Lcd " " ; Adc4
Locate 2 , 10
Lcd " " ; Adc5


Waitms 500
Cls
Loop
End

Timer0_pwm:
Rot_pwm1 = Adc0
Rot_pwm2 = Adc3
Return

Timer1_pwm:
Gruen_pwm1 = Adc1
Gruen_pwm2 = Adc4
Return

Timer2_pwm:
Blau_pwm1 = Adc2
Blau_pwm2 = Adc5
Return



entnommen von:
https://www.makerconnect.de/index.php?threads/adc-werte-f%C3%BCr-pwm-nutzen-rgb-led-ansteuerung.2860/

von Maxx (Gast)


Lesenswert?

hier eine vorgegebene Datei: pwm.c

/**
 * @brief pwm driver implementation, uses atmega328 timer
 * @author T.K.
 * @note This is a doxygen style comment block
**/


/* avr gcc specific header files for uC I/O etc. */
#include <avr/io.h>

#include "pwm.h"


/**
 * @brief Init all PWM handling specific HW
 * @par none
 */
void PwmInit(void)
{

  TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) 
| (1 << WGM11) | (0 << WGM10);
    TCCR1B = (0 << ICNC1) | (0 << ICES1) | (1 << WGM13) | (1 << WGM12) | 
(0 << CS12) | (1 << CS11) | (0 << CS10);
    TCNT1 = 0;

    OCR1A = 0;
  ICR1 = 0xffff;

  OCR1B = 0;
#if 0
  TCCR1A |= 0x43;
  TCCR1B |= 0x19;
  TCNT1 = 0;
#endif

  DDRB |= 0x04; // PB2 to output

}



/**
 * @brief PWM duty cycle set function
 * @par none
 */
void PwmSetDuty(uint8_t duty)
{
  uint16_t d;

  if (duty == 0)
  {
    PORTB |= 0x04;  // set pin off
    TCCR1B &= ~0x07;  // stop timer
    return;
  }
  if (duty == 100)
  {
    PORTB |= 0x04;  // set pin on
    TCCR1B &= ~0x07;  // stop timer
    return;
  }

  d = (0xffff/100) * duty;
  OCR1B = d;
  TCCR1B |= 0x01;  // (re)start timer
}



/**
 * @brief
 * @par
 * @par
 * @par
 */

von Maxx (Gast)


Lesenswert?

tick.c, obwohl ich mir nicht sicher bin, ob das hilfreich ist

/**
 * @brief one msec tick timer driver implementation, uses atmega328 
timer0
 * @author T.K.
 * @note This is a doxygen style comment block
**/


/* avr gcc specific header files for uC I/O etc. */
#include <avr/io.h>
#include <avr/interrupt.h>

#include "tick.h"


/* reload value for timer0 counting up to MAX (0xff) at 20Mhz/256 for 
1msec */
#define T0_RELOAD_1MSEC    (0xff-78+1)

/* global variables used by isr and applic */
volatile static uint8_t  Keytimer;  /* keys sampling cycle timer */
volatile static uint16_t Sectimer;  /* one second counter (msecs) */

/**
 * @brief timer0 isr, gets called every 1msec
 * @par none
 */
ISR(TIMER0_OVF_vect)
{
  TCNT0 = T0_RELOAD_1MSEC;
  Keytimer++;
  Sectimer++;
}


/**
 * @brief Init all msec tick Timer handling specific HW
 * @par none
 */
void TickInit(void)
{
  /* 1 msec timer 0 init */
  TCCR0B = 0x04;  /* CPU clock/256 prescaler */
  TCNT0 = T0_RELOAD_1MSEC;
  TIMSK0 = 0x01;  /* enable T0 Overflow interrupt */
}

/**
 * @brief Get the actual msecs counter
 * @par none
 */
uint16_t TickGetMsecs(void)
{
    return (Sectimer);
}

/**
 * @brief Set the msecs counter
 * @par new counter value
 */
void TickSetMsecs(uint16_t val)
{
    ISR_DISABLE();
  Sectimer = val;
  ISR_ENABLE();
}

/**
 * @brief Get the actual key debounce msecs counter
 * @par none
 */
uint16_t TickGetKeyMsecs(void)
{
    return (Keytimer);
}

/**
 * @brief Set the key debounce msecs counter
 * @par new counter value
 */
void TickSetKeyMsecs(uint16_t val)
{
    ISR_DISABLE();
  Keytimer = val;
  ISR_ENABLE();
}




/**
 * @brief
 * @par
 * @par
 * @par
 */

von Maxx (Gast)


Lesenswert?

uart.c


/**
 * @brief uart driver implementation
 * @author T.K.
 * @note This is a doxygen style comment block
**/


/* avr gcc specific header files for uC I/O etc. */
#include <avr/io.h>
#include <avr/interrupt.h>


#include "uart.h"

#define UART_RX_BUF_SIZE    16

static volatile uint8_t Rxbuf[UART_RX_BUF_SIZE];
static volatile uint8_t RxRidx; /* read idx from circular RX-Buffer */
static volatile uint8_t RxWidx; /* write idx to circular RX-Buffer */
static volatile uint8_t RxSema;  /* number of chars waiting for read by 
application */



/**
 * @brief UART0 RxD Isr
 * @par none
 */
ISR (USART_RX_vect)
{
    Rxbuf[RxWidx] = UDR0;
    RxWidx++;
    RxWidx &= (UART_RX_BUF_SIZE-1);
    RxSema++;
}



/**
 * @brief Init UART peripheral
 * @par none
 */
void UartInit(void)
{
#ifndef F_CPU
    #define F_CPU 20000000UL  // Systemtakt in Hz - Definition als 
unsigned long beachten
#endif

#define BAUD 9600UL      // gewünschte Baudrate

// Berechnungen durch den C Preprocessor machen lassen ;o)
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = 
kein Fehler.

#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu 
hoch!
#endif
    UBRR0H = UBRR_VAL >> 8;
    UBRR0L = UBRR_VAL & 0xFF;
    UCSR0B = (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0);
    UCSR0C = (1 << UCSZ01)|(1 << UCSZ00); // Asynchron 8N1

    RxRidx = 0;
    RxWidx = 0;
    RxSema = 0;
}


/**
 * @brief Test if UART is free to send next char
 * @par none
 */
uint8_t UartTxAvailable(void)
{
    uint8_t r;

    if ( (UCSR0A & 0x20) > 0 )
        r = 1;
    else
        r = 0;

    return(r);
}

/**
 * @brief Test if a UART has a received char available
 * @par none
 */
uint8_t UartRxAvailable(void)
{
    return(RxSema);
}

/**
 * @brief Send a char by UART
 * @par uint8_t char to be sent
 */
void UartPutc(uint8_t c)
{
    UDR0 = c;
}


/**
 * @brief Send a string by UART
 * @par uint8_t* char to start of string to be sent
 */
void UartPutString(uint8_t* s)
{
  while(*s)
  {
    if (UartTxAvailable())
    {
      UartPutc(*s);
      s++;
    }
  }
}


/**
 * @brief Get a char from UART
 * @par none
 */
uint8_t UartGetc(void)
{
    uint8_t r;

    r = Rxbuf[RxRidx];
    RxRidx++;
    RxRidx &= (UART_RX_BUF_SIZE-1);
  if (RxSema > 0)
    RxSema--;

    return(r);
}


/**
 * @brief
 * @par
 * @par
 * @par
 */

von Maxx (Gast)


Lesenswert?

und eine dazugehörige main.c, die ein Studienkollege erstellt hat:

#include <avr/io.h>
#include <util/delay.h>

#define LED_PORT    PORTC
#define LED_PIN     0
#define LED_off()  LED_PORT&=~_BV(LED_PIN)
#define LED_on() LED_PORT|=_BV(LED_PIN)

int main (void)
{
  DDRC  = 0b10000000;
  while (1)
  {
    LED_on();
    _delay_ms(2);
    LED_off();
    _delay_ms(8);
  }

  return(0);




#include <avr/io.h>
#include <avr/interrupt.h>

#include "key.h"
#include "pwm.h"
#include "tick.h"
#include "uart.h"
#include "string.h"

int main (void)
{
  uint8_t keystate = 0;
  uint8_t str[50];
  uint8_t str2[50];
  uint8_t instr[16];
  uint8_t dutyled = 50;
  uint8_t c;

  TickInit();
  PwmInit();
  UartInit();

  ISR_ENABLE();

  while(1)
  {
    if(TickGetKeyMsecs() >= 300)
    {
            TickSetKeyMsecs(0);

      if(UartRxAvailable())
          {
        for(int i = 0; i < UartRxAvailable();i++)
        {
          str2[i] = UartGetc();
        }

        sprintf((char*) &str[0],"%i\n", UartRxAvailable());
        UartPutString(&str[0]);
          }
    }
  }
}

von Roland F. (rhf)


Lesenswert?

Hallo Maxx,

Mit welcher Proragmmiersprache arbeitet ihr? Der erst Quellcode ist in 
Basic (vermutlich BASCOM), die unteren Quellcodes sind in C geschrieben.

> und eine dazugehörige main.c, die ein Studienkollege erstellt hat:

Das sind aber 2 verschiedene main()-Routinen: einmal der Klassiker zum 
LED-Blinken und unten die main()-Routine für die PWM-Geschichte. Aber 
egal, was verstehst du nicht?

rhf

von Maxx (Gast)


Lesenswert?

Hey Roland!

Wir arbeiten mit C in AVR Studio 4
und da ich mich damit nicht auskenne wusste ich auch nicht, dass der 
erste nicht in C geschrieben war, entschuldigung.

Naja ich verstehe einfach die einzelnen Funktionen nicht, was diese 
bewirken und wie sie das tun.

ich verstehe die Variablendeklarationen
 uint8_t keystate = 0;
  uint8_t str[50];
  uint8_t str2[50];
  uint8_t instr[16];
  uint8_t dutyled = 50;
  uint8_t c;

das danach sind sicherlich aufgerufene Funktionen aus den zugehörigen 
Header-Dateien

die while Schleife ist dann schon schwieriger, die versteh ich nicht so 
wirklich.

soll ich die dazugehörigen header mal reinstellen?

bringt dieser code meinem Projekt überhaupt etwas?

danke für die Hilfe :)

von Roland F. (rhf)


Lesenswert?

Hallo Maxx,

> Wir arbeiten mit C in AVR Studio 4
> und da ich mich damit nicht auskenne wusste ich auch nicht, dass der
> erste nicht in C geschrieben war, entschuldigung.

Du brauchst dich nicht zu entschuldigen. Allerdings hat es keinen Zweck 
mit dir den Code durch zusprechen, wenn du den Unterschied zwischen 
BASIC und C nicht erkennst. Dein Problem ist das du noch nicht mal die 
absoluten Grundlagen verstanden hast und darüber hinaus offensichtlich 
auch dein Werkzeug nicht bedienen kannst. Nicht schlimm, das kann man 
alles lernen.

Ein Forum wie dieses hier kann dir dabei aber nur wenig helfen, weil die 
Kommunikation viel zu umständlich und zeitraubend ist. Ich pflichte 
einem anderen Diskussionsteilnehmer bei und rate dir jemanden zu suchen, 
der mit dir zusammen mal ein paar Grundlagen und Beispiele durch geht.

rhf

von Maxx (Gast)


Lesenswert?

Hey Roland,

ich hab den Unterschied mittlerweile erkannt.

und einige Grundlagen beherrsche ich auch.
Ich hab den ersten Quelltext nur überflogen und da sah er ähnlich aus. 
Jetzt wo ich ihn näher betrachtet habe, erkenne ich aus.

Dennoch weiß ich nicht mal, wie ich bei meinem Projekt anfangen soll...

ich finde, dass das Forum mir aber trotzdem viel weitergeholfen hat!Ich 
hab' dadurch bereits eine viel größere Vorstellung davon, wie ich mein 
Projekt zu gestalten habe.

Also vielleicht kannst du mir ja mal sagen, welche Funktionen ich 
brauche, um mein Projekt so zu realisieren, wie ich muss?
Vielleicht auch mit kurzer Beschreibung?

Der gute Bimbo385 hat mir ja schon geholfen, einen groben Aufbau des 
Programms zu haben.

von Roland F. (rhf)


Lesenswert?

Hallo Maxx,

> Dennoch weiß ich nicht mal, wie ich bei meinem Projekt anfangen soll...

Ja, das merkt man.
Du musst dich zuerst mit der Programmiersprache vertraut machen. Vorher 
brauchst du mit deinem Projekt gar nicht anfangen. Kauf dir ein Buch zu 
C, installiere dir ein C-Entwicklungssystem, was einfaches wie z.B. LCC:

http://www.cs.virginia.edu/~lcc-win32/

und programmiere die Beispiel im Lehrbuch nach. Das hört sich jetzt erst 
mal nach viel Vorarbeit an und das ist es auch. Aber es führt kein Weg 
daran vorbei.
Erst wenn du in C eine gewisse Sicherheit erlangt hast, solltest du mit 
dem einfachsten Beispiel auf dem AVR-Kontroler beginnen (das ist das 
LED-Blink-Programm deiner ersten main()-Funktion). Wenn das läuft, weißt 
du das deine AVR-Entwicklungsumgebung (also AVR Studio 4) funktioniert.

> Also vielleicht kannst du mir ja mal sagen, welche Funktionen ich
> brauche, um mein Projekt so zu realisieren, wie ich muss?

Du musst deine Aufgabe in ganz einfache Teilaufgaben zerlegen:
Als erstes würde ich ein Programm schreiben, das mittels des AD-Wandlers 
einen Potentiometerwert einliest und z.B. über die serielle 
Schnittstelle (UART) ausgibt (damit man sieht ob die Werte plausibel 
sind). Das erweiterst du dann so, das 3 Potis ausgelesen und angezeigt 
werden.

Dann würde ich eine Funktion schreiben, die ein PWM-Signal ausgibt und 
mit diesem Signal erst mal nur eine einfache LED ansteuern. Funktioniert 
das, erweiterst du das auf 3 LEDs, so das du dann mit deinen 3 Potis (je 
eins für R, G und B) diese 3 LEDs in der Helligkeit steuern kannst.

Eine ganz wichtige Hilfe ist

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

und

https://www.mikrocontroller.net/articles/AVR-Tutorial

Da steht im Prinzip (ADC-, UART- und PWM-Programmierung) alles drin, was 
du zum Lösen deiner Aufgabe wissen musst.

rhf

von Robert S. (bimbo385)


Lesenswert?

Moin Maxx, bin wieder da, musste mal ein bisschen Rennauto fahren die 
letzten Tage ;-)

Also wenn ich dich dich richtig verstehe fehlen dir schon die Grundlagen 
zur C-Programmierung (while-Schleife). Die Programmiersprache C ist 
grundsätzlich erstmal unabhängig von dem zu programmierendem System/µC. 
Du solltest eigentlich wenn du im Studium an so einem Projekt sitzt, 
vorher irgendeine Grundlagenvorlesung C-Programmierung gehabt haben, in 
der so Sachen wie Schleifen, Deklarationen, Funktionen, 
Typendefinitionen, Strukturen, Arrays und Pointer usw. erklärt werden.
Ich gebe gerne zu, dass auch ich nicht jede Syntax immer im Kopf habe 
und ich hier und da noch mal nachschlagen muss. Aber du solltest das 
alles zumindest schon mal gehört und auch verstanden haben.
Man kann sich natürlich C auch beim µC Programmieren beibringen. 
Einfacher geht es aber erstmal die Sprache auf einem normalen Computer 
zu lernen, auf dem man dann auch die Standardausgabe printf usw. einfach 
benutzen kann, einfache Möglichkeiten zum Debuggen hat und sich auch 
keine Gedanken über Speicher und Performance machen muss. Ein aktuelles 
Notebook/PC hat davon einfach genug (zumindest für das was wir jetzt 
machen wollen).
Ich persönlich benutze zum Testen von Programmschnipseln und Algorithmen 
gerne den Onlineservice von 
https://www.tutorialspoint.com/compile_c_online.php dort kann man 
einfach loslegen und der verwendete GCC Compiler ist dem AVR-GCC auch 
ziemlich ähnlich.

Wenn du mit C soweit vertraut bist, solltest du mit dem bereits 
verlinkten AVR-Tutorial weitermachen. Dann sollte mit den bereits 
gegebenen Tipps der Rest relativ einfach sein.

Frohes Schaffen,
Bimbo385

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.