Forum: Mikrocontroller und Digitale Elektronik LED Fading mir PIC


von Niko (Gast)


Lesenswert?

Hi @ all

ich versuche seit mehreren Wochen ein ganz einfaches Programm zu 
scheiben welches eine LED langsam an und wieder aus faded. Da ich aber 
ein absoluter Newbie in der Welt der uC bin und ich im Internet zumeist 
nur auf unvollständige Forenbeiträge stoße, klappt bis dato nahezu 
garnichts.

Geplant war ein Programm in C zu schreiben welches auf einen PIC12F683 
läuft und mittels PWM die LED dimmt. Als Compiler würde ich gerne den 
CC5X (kostenlos) benutzen.

Ein vernünftiges Beispiel habe ich jedoch nur für einen ATMEL gefunden. 
Da ich mir jedoch schon mehrere PICs + Programmiergerät angeschafft habe 
würde ich dieses Programm gerne für den PIC12F683 umschreiben.

Daher die Frage: Kann mir jemand diesen Code für den PIC umschreiben?
http://www.mikrocontroller.net/articles/LED-Fading

Ich würde mich auch erkenntlich (€) zeigen.

Vielen Dank schonmal im Voraus.

von Lehrmann M. (ubimbo)


Lesenswert?

Servus,
das ist durchaus machbar. Könntest du etwas mehr die Parameter des 
Möglichen defninieren. (Umgebung, Taktquelle, etc.)
Für Software PWM braucht man eine möglichst schnelle Taktquelle.
Welche Gründe habe dich diesen PIC auswählen lassen? Hat nur ein PWM 
Modul - den Rest muss man per Software generieren.
Erzähl mal ein bisschen mehr - dann lässt sich da schon was machen ...

von Stephan S. (uxdx)


Lesenswert?

Der 12F683 hat ein PWM-Modul eingebaut. Damit ist LED-Fading absolut 
easy, Du brauchst die Register PR2, CCPR1L und CCP1CON sowie den Timer2 
mit dem Register T2CON. Nachfolgend ein Snippet aus einem 
Assembler-Programm, darin ist alles aufgeführt, Du musst nur die 
Register belegen und ab geht die Post, in C geht das sogar noch 
einfacher.

Mehr über PWM bei PICs erfährts Du bei 
http://sprut.de/electronic/pic/grund/pwm.htm
1
; Timer 2 für PWM einstellen
2
3
  bank0
4
  clrf   T2CON
5
; bsf    T2CON, T2CKPS1    ; Vorteiler 16:1
6
; bsf    T2CON, T2CKPS0
7
  bsf    T2CON, TMR2ON     ; Timer2 ein
8
9
; Frequenz + duty cycle
10
11
  bank1
12
  movlw  d'128'            ; xxx kHz
13
  movwf  PR2
14
15
  bank0
16
  movlw  d'64'             ; duty cycle: 50% von xxx sind yyy
17
  movwf  CCPR1L
18
19
  movlw  b'00001100'       ; Start, PWM active high
20
  movwf  CCP1CON
21
22
  bank0

bank0 und bank1 sind Makros, welche die Speicherbank einstellen.

von Claus P. (claus_p)


Lesenswert?


von Niko (Gast)


Lesenswert?

Also dann mal von vorne:

@Michael, @all

Ich möchte über diesen PIC mehrere LEDs ansteuern. Diese sollen dabei 
gleichzeitig ein und aus faden, sodass ein PIN des Controlles genügt 
(dieser schällt einen Transistor / kein Software-PWM nötig). Der PIC hat 
dabei nur diese eine Aufgabe. Auf die Rechenlast muss daher nicht 
geachtet werden. Da ich diese Schaltung mehrfach bauen möchte, würde ich 
die Anzahl an Bauteilen gerne möglichst gering halten --> Interner Takt.

Den PICF683 hatte ich nur deshalb gewählt weil er der kleinste und auch 
günstigste PIC mit einem CCP-Modul ist.


@Stephan, @Claus

In dem Beispiel wird ein 'logarithmisches' PWM erzeugt woruch der 
Dimmeffekt für die menschliche Wahrnehmung besser zur Geltung kommt. 
Dies würde ich wenn möglich auch so realisieren.

von Stephan S. (uxdx)


Lesenswert?

> In dem Beispiel wird ein 'logarithmisches' PWM erzeugt woruch der
> Dimmeffekt für die menschliche Wahrnehmung besser zur Geltung kommt.
> Dies würde ich wenn möglich auch so realisieren.

In meinem Beispiel steht die Zahl 64 für einen 50% duty cycle von 128 
(für 25% wären es 32 usw); das habe ich einfach aus einem Programm von 
mir kopiert, um Dir zu zeigen, wie die PWM programmiert wird.

Du kannst ja das PR2-Register mit 255 setzen und das CCPR1L-Register mit 
einer exponetiell abgestuften Zahl von 0 bis 255 setzen, die Du einer 
voher berechneten Tabelle entnimmst. Das musst Du schon selber machen.

von Niko (Gast)


Lesenswert?

Michael, bist du heute da?

von Frank B. (foobar)


Lesenswert?

Was hast du in den mehreren Wochen denn bisher bereits geschafft? Kannst 
bereits mit MPLAB umgehen und den PIC12F683 programmieren und z.B. die 
LED zumindest direkt an- und ausschalten? Ab da kann man dir dann 
weiterhelfen.

von Niko (Gast)


Lesenswert?

Hallo Frank,

ja Ausgänge ein und wieder ausschalten kann ich schon. Was ich bisher 
geschafft habe:

MPLAB + C Colpiler (CC5X) installiert
PIC-Brenner installiert, erste Testprogramme in PIC geladen --> 
funktioniert!
Schaltung entworfen

Jetzt scheitert es nur noch an dem Programm (s. ersten Post)

von Frank B. (foobar)


Angehängte Dateien:

Lesenswert?

Ich habe den Artikel über die PWM-Tastverhältnisberechnung nicht ganz 
verstanden. Die Werte der Excel-Tabelle stimmen nicht mit den Werten des 
Beispielprogramms überein. Scheint vielmehr so, daß das Beispielprogramm 
einfach eine Potenzreihe mit Basis 2 hat, wobei es ein wenig manuell 
angepasst wurde, daß der erste Wert 0 ist und der letzte Wert 65535 (für 
das lange Beispiel).

Bei der angegebenen Formel verstehe ich nicht, was ich für rx und ry 
einsetzen muß. Vielleicht kann mir das aber einer erklären.

Ich habe mal die Excel-Formel in ein kleines Java-Programm übersetzt:
1
public class Log
2
{
3
  public static void main(String args[])
4
  {
5
    double steps = 122;
6
    double max = 1023;
7
    double start = 20;
8
    double base = Math.pow(max / start, 1.0 / (steps - 1));
9
    System.out.println("steps: " + steps);
10
    System.out.println("max: " + max);
11
    System.out.println("start: " + start);
12
    System.out.println("base: " + base);
13
    for (int i = 0; i < steps; i++) {
14
      System.out.print(Math.round(start * Math.pow(base, (double)i)));
15
      System.out.print(", ");
16
      if ((i % 8) == 7) System.out.println("");
17
    }
18
  }
19
}

Das kann man per javac compilieren und per java ausführen (JRE vorher 
installieren und Pfad setzen, oder Eclipse o.ä. installieren). Die 
Ausgabe sieht so aus:
1
steps: 122.0
2
max: 1023.0
3
start: 20.0
4
base: 1.0330532092859641
5
20, 21, 21, 22, 23, 24, 24, 25,
6
26, 27, 28, 29, 30, 31, 32, 33,
7
34, 35, 36, 37, 38, 40, 41, 42,
8
44, 45, 47, 48, 50, 51, 53, 55,
9
57, 58, 60, 62, 64, 67, 69, 71,
10
73, 76, 78, 81, 84, 86, 89, 92,
11
95, 98, 102, 105, 108, 112, 116, 120,
12
124, 128, 132, 136, 141, 145, 150, 155,
13
160, 166, 171, 177, 183, 189, 195, 201,
14
208, 215, 222, 229, 237, 245, 253, 261,
15
270, 279, 288, 297, 307, 317, 328, 339,
16
350, 361, 373, 386, 398, 412, 425, 439,
17
454, 469, 484, 500, 517, 534, 551, 570,
18
589, 608, 628, 649, 670, 692, 715, 739,
19
763, 789, 815, 842, 869, 898, 928, 959,
20
990, 1023,

und kann man direkt als C-Array verwenden.

Ich habe den PIC12F683 nicht, daher konnte ich es nur per MPLAB Logic 
Analyzer testen, aber sollte eigentlich funktionieren:
1
#include <htc.h>
2
#include <stdio.h>
3
#include "limits.h"
4
5
// Chip Konfiguration
6
__CONFIG(
7
  FCMDIS &  // Fail Clock Monitor Enable 
8
  IESODIS &  // Internal External Switch Over 
9
  BORDIS &  // Brown-out detect modes 
10
  UNPROTECT &  // Protection of data block 
11
  UNPROTECT &  // Protection of program code 
12
  MCLRDIS &  // Master clear reset
13
  PWRTEN &  // Power up timer enable 
14
  WDTDIS &  // Watchdog timer enable 
15
  INTIO  // Oscillator configurations: internal, IO-Funktion statt Clkin/Clkout
16
);
17
18
// ist normalerweise in stdint.h enthalten, was der Hi-Tech Compiler aber nicht kennt
19
typedef signed   char         int8_t;
20
typedef unsigned char        uint8_t;
21
typedef signed   int         int16_t;
22
typedef unsigned int        uint16_t;
23
typedef signed   short long  int24_t;  // Microchip specific
24
typedef unsigned short long uint24_t;  // Microchip specific
25
typedef signed   long        int32_t;
26
typedef unsigned long       uint32_t;
27
28
// PWM-Werte
29
static const uint16_t g_pwm[] =
30
{
31
  20, 21, 21, 22, 23, 24, 24, 25,
32
  26, 27, 28, 29, 30, 31, 32, 33,
33
  34, 35, 36, 37, 38, 40, 41, 42,
34
  44, 45, 47, 48, 50, 51, 53, 55,
35
  57, 58, 60, 62, 64, 67, 69, 71,
36
  73, 76, 78, 81, 84, 86, 89, 92,
37
  95, 98, 102, 105, 108, 112, 116, 120,
38
  124, 128, 132, 136, 141, 145, 150, 155,
39
  160, 166, 171, 177, 183, 189, 195, 201,
40
  208, 215, 222, 229, 237, 245, 253, 261,
41
  270, 279, 288, 297, 307, 317, 328, 339,
42
  350, 361, 373, 386, 398, 412, 425, 439,
43
  454, 469, 484, 500, 517, 534, 551, 570,
44
  589, 608, 628, 649, 670, 692, 715, 739,
45
  763, 789, 815, 842, 869, 898, 928, 959,
46
  990, 1023
47
};
48
49
// main Funktion
50
void main(void)
51
{
52
  // Ports initialisieren: alles auf Ausgang
53
  GPIO = 0;
54
  TRISIO = 0;
55
56
  // Oszillator auf 8 MHz einstellen
57
  OSCCON = (1 << 6) | (1 << 5) | (1 << 4) | 1;
58
59
  // Timer0 Counter zurücksetzen
60
  TMR0 = 0;
61
62
  // keine Pullups, Fosc/4 als Taktquelle für Timer0, 1:32 Prescaler:
63
  // ergibt bei 8 MHz also Fosc/4/32/256 = 244 Hz
64
  OPTION = (1 << 7) | (1 << 2);
65
66
  // Period Register von Timer2 auf Maximum
67
  PR2 = 255;
68
69
  // Timer2 on, Prescaler 1
70
  // zusammen mit PR2 ergibt das eine Frequenz von 8 MHz/4/(PR2+1)=4 MHz / 256 = 7812.5 Hz
71
  T2CON = 1 << 2;
72
73
  // keine Interrupts für Timer2
74
  PIE1 = 0;
75
76
  // PWM-Mode für das CCP-Modul aktivieren
77
  CCP1CON = 15;
78
79
  // global interrupt enable, Timer0 overflow enable und Interrupt Flag löschen
80
  INTCON = (1 << 7) | (1 << 5);
81
82
  // der Rest läuft im Interrupt ab
83
  while (1) {
84
  }
85
}
86
87
// Interruptroutine
88
void interrupt timerInterrupt(void)
89
{
90
  // LED mit ca. 1 Hz blinken lassen
91
  static uint8_t counter = 0;
92
  static uint8_t value = 0;
93
  if (counter++ == 122) {
94
    GPIO = value;
95
    value = 255 - value;
96
    counter = 0;
97
  }
98
99
  // Tastverhältnis vom PWM-Ausgang aktualisieren
100
  static uint8_t pwmIndex = 0;
101
  static uint8_t direction = 0;
102
  uint16_t pwm = g_pwm[pwmIndex];
103
  CCPR1L = (pwm >> 2) & 0xff;
104
  CCP1CON = 15 | ((pwm & 3) << 4);
105
106
  // PWM-Index aktualisieren: zählt einmal rauf und dann wieder runter
107
  if (direction) {
108
    if (pwmIndex == sizeof(g_pwm) / sizeof(uint16_t) - 1) {
109
      direction = 0;
110
    } else {
111
      pwmIndex++;
112
    }
113
  } else {
114
    if (pwmIndex == 0) {
115
      direction = 1;
116
    } else {
117
      pwmIndex--;
118
    }
119
  }
120
121
  // Interruptflag zurücksetzen
122
  T0IF = 0;
123
}

Vom Konzept her läuft die ganze Steuerung im Interrupt ab, damit man, 
unabhängig von Programmlaufzeiten für unterschiedliche Code-Pfade, immer 
ein regelmäßiges Update der PWM-Werte hinbekommt. Auf Pin 5 (GP2) sollte 
das PWM-Signal anliegen. Eine LED da dran sollte mit 1 Hz sanft an und 
wieder ausgehen. Alle anderen Pins sollten hart mit 1 Hz blinken.

Resourcenverbrauch:
1
Memory Summary:
2
    Program space        used   1B9h (   441) of   800h words   ( 21.5%)
3
    Data space           used    11h (    17) of    80h bytes   ( 13.3%)
4
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
5
    Configuration bits   used     1h (     1) of     1h word    (100.0%)
6
    ID Location space    used     0h (     0) of     4h bytes   (  0.0%)

Anbei das ganze Projekt. Ich habe auch den CC5X Compiler nicht, das ist 
mit dem Hi-Tech Compiler erstellt, der in der Lite-Version (keine 
Code-Optimierung) ebenfalls frei ist. Hoffe es hilft dir weiter, kannst 
du wahrscheinlich leicht für den CC5X Compiler anpassen, falls du den 
verwenden willst. Das HEX-File, mit Configuration-Bits, ist aber auch im 
ZIP-Archiv. Das kannst du importieren und brennen, sollte dann 
eigentlich direkt laufen.

Geld möchte ich keins, aber wenn du noch einen PIC12F683 zum Spielen für 
mich übrig hättest, würde ich mich freuen :-)

von Niko (Gast)


Lesenswert?

Hi Frank,

super vielen Dank für deine spitzen Hilfe. Hab's natürlich schon 
ausprobiert und es funktioniert! Allerdings in das Fading nicht wirklich 
so schöne wie gedacht. Wirkt immer noch ein wenig holprig. Aber auf 
jeden Fall kann man damit arbeiten (und lernen).

Eine Frage hab ich aber trotzdem noch: Was sind das denn für 
Headerdateien? "HTC.h, stdio.h, limits.h"

Werde mich gleich noch per PM bei dir melden.

von Lehrmann M. (ubimbo)


Lesenswert?

Niko schrieb:
> Eine Frage hab ich aber trotzdem noch: Was sind das denn für
> Headerdateien? "HTC.h, stdio.h, limits.h"

HTC.h hat was mit dem untergeordneten pic.h und anderen 
prozessor-spezifischen Einbindungen zu tun. Manche Makros funktionieren 
nicht, etc...
Daher weiß der Comiler was/wo z.B. sämtliche Register zu finden sind 
(LATA, ...)

stdio.h ist allgemein aus ANSI C bekannt und regelt 
Standart-Ein-und-Ausgabe-bezogene Dinge

limits.h hat was mit Datentypen (int, double, etc...) zu schaffen. Es 
definiert spez. Charakteristika der entsprechenden Datentypen, etc.

Genaueres kann man ergooogln ...

von Frank B. (foobar)


Lesenswert?

limits.h braucht man für den Sourcecode aktuell nicht. Hatte ich aus 
einem anderen Projekt kopiert und dort dann noch dieses Makro vor den 
typedefs geschrieben:
1
#if LONG_MAX < 0x7fffffff
2
#error "this program needs long with 4 bytes"
3
#endif

Dadurch konnte ich dann sicherstellen, daß "typedef signed   long 
int32_t;" tatsächlich einen 32-Bit typen definiert, was man ja manchmal 
in den Compiler-Settings umstellen kann und was dann zu Überaschungen 
führen kann. Wenn das falsch eingestellt ist, dann gibt das durch dieses 
Makro zur Compilierzeit einen Compilerfehler. Aber für den Code könnte 
man einige der Typedefs sowieso löschen und stdio.h ist auch vom 
copy-and-paste des größeren Projekts übriggeblieben.

von Frank B. (foobar)


Lesenswert?

Danke für den PIC, ist heute angekommen. Habe ihn eben programmiert und 
sieht so aus:

http://www.youtube.com/watch?v=ii2mPdSiErs

Das Fading ist perfekt, zumindest vom Scope her ist es genauso, wie 
gedacht, aber du hast schon recht, sieht dennoch nicht allzu sanft aus. 
Ich denke das liegt daran, wenn es für das Auge linear bis zur maximalen 
Helligkeit einblendet und dann sofort wieder linear ausblendet usw., es 
quasi ein Dreieck ist.

Eine Idee wäre, die Tabellengenerierung so zu ändern, daß statt des 
linearen Zählers erst ein Sinus generiert wird, der dann nochmals 
logarithmisch umgesetzt wird, sodaß daß Auge also den Sinus wahrnimmt. 
Dabei könnte man sich noch überlegen, ob man einen "springenden" Effekt 
haben will, also nur eine Halbwelle nimmt (bzw. eine viertel Welle, da 
man ja nur die Einblendung speichern braucht), sodaß es also relativ 
schnell hell wird, dann sanft bis zum Maximum einblendet, dort etwas 
bleibt und schnell wieder dunkel wird. Danach vielleicht noch etwas 
Auszeit und dann wieder von Anfang los. Oder auch sanft beim 
Dunkelwerden abbremsen.

von Ralf (Gast)


Lesenswert?

Hallo,

hast die den PWM Source Code für den PIC 12f683 für den CC5X Compiler ?

Im internet findet mall allerlei C-Beispiele an PWM aber sogur wie 
nichts für den PIC und den CC5X ..

Grüße Ralf

von Ralf (Gast)


Lesenswert?

Hallo Niko,

hast du den PWM Code vom Frank auf den CC5X für den PIC12f683 umgestellt 
? Ich hätte gerne den C Code um einen eine LED-Beleuchtung mit einer 
digitalen Poti-Lösung auf PWM mit dem 12f683 umzustellen ...

Grüße Ralf

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.