mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LED Fading mir PIC


Autor: Niko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lehrmann Michael (ubimbo)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: Stephan S. (uxdx)
Datum:

Bewertung
0 lesenswert
nicht 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
; Timer 2 für PWM einstellen

  bank0
  clrf   T2CON
; bsf    T2CON, T2CKPS1    ; Vorteiler 16:1
; bsf    T2CON, T2CKPS0
  bsf    T2CON, TMR2ON     ; Timer2 ein

; Frequenz + duty cycle

  bank1
  movlw  d'128'            ; xxx kHz
  movwf  PR2

  bank0
  movlw  d'64'             ; duty cycle: 50% von xxx sind yyy
  movwf  CCPR1L

  movlw  b'00001100'       ; Start, PWM active high
  movwf  CCP1CON

  bank0

bank0 und bank1 sind Makros, welche die Speicherbank einstellen.

Autor: Claus P. (claus_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Niko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stephan S. (uxdx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Niko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael, bist du heute da?

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Niko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Frank Buss (foobar)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
public class Log
{
  public static void main(String args[])
  {
    double steps = 122;
    double max = 1023;
    double start = 20;
    double base = Math.pow(max / start, 1.0 / (steps - 1));
    System.out.println("steps: " + steps);
    System.out.println("max: " + max);
    System.out.println("start: " + start);
    System.out.println("base: " + base);
    for (int i = 0; i < steps; i++) {
      System.out.print(Math.round(start * Math.pow(base, (double)i)));
      System.out.print(", ");
      if ((i % 8) == 7) System.out.println("");
    }
  }
}

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:
steps: 122.0
max: 1023.0
start: 20.0
base: 1.0330532092859641
20, 21, 21, 22, 23, 24, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 40, 41, 42,
44, 45, 47, 48, 50, 51, 53, 55,
57, 58, 60, 62, 64, 67, 69, 71,
73, 76, 78, 81, 84, 86, 89, 92,
95, 98, 102, 105, 108, 112, 116, 120,
124, 128, 132, 136, 141, 145, 150, 155,
160, 166, 171, 177, 183, 189, 195, 201,
208, 215, 222, 229, 237, 245, 253, 261,
270, 279, 288, 297, 307, 317, 328, 339,
350, 361, 373, 386, 398, 412, 425, 439,
454, 469, 484, 500, 517, 534, 551, 570,
589, 608, 628, 649, 670, 692, 715, 739,
763, 789, 815, 842, 869, 898, 928, 959,
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:
#include <htc.h>
#include <stdio.h>
#include "limits.h"

// Chip Konfiguration
__CONFIG(
  FCMDIS &  // Fail Clock Monitor Enable 
  IESODIS &  // Internal External Switch Over 
  BORDIS &  // Brown-out detect modes 
  UNPROTECT &  // Protection of data block 
  UNPROTECT &  // Protection of program code 
  MCLRDIS &  // Master clear reset
  PWRTEN &  // Power up timer enable 
  WDTDIS &  // Watchdog timer enable 
  INTIO  // Oscillator configurations: internal, IO-Funktion statt Clkin/Clkout
);

// ist normalerweise in stdint.h enthalten, was der Hi-Tech Compiler aber nicht kennt
typedef signed   char         int8_t;
typedef unsigned char        uint8_t;
typedef signed   int         int16_t;
typedef unsigned int        uint16_t;
typedef signed   short long  int24_t;  // Microchip specific
typedef unsigned short long uint24_t;  // Microchip specific
typedef signed   long        int32_t;
typedef unsigned long       uint32_t;

// PWM-Werte
static const uint16_t g_pwm[] =
{
  20, 21, 21, 22, 23, 24, 24, 25,
  26, 27, 28, 29, 30, 31, 32, 33,
  34, 35, 36, 37, 38, 40, 41, 42,
  44, 45, 47, 48, 50, 51, 53, 55,
  57, 58, 60, 62, 64, 67, 69, 71,
  73, 76, 78, 81, 84, 86, 89, 92,
  95, 98, 102, 105, 108, 112, 116, 120,
  124, 128, 132, 136, 141, 145, 150, 155,
  160, 166, 171, 177, 183, 189, 195, 201,
  208, 215, 222, 229, 237, 245, 253, 261,
  270, 279, 288, 297, 307, 317, 328, 339,
  350, 361, 373, 386, 398, 412, 425, 439,
  454, 469, 484, 500, 517, 534, 551, 570,
  589, 608, 628, 649, 670, 692, 715, 739,
  763, 789, 815, 842, 869, 898, 928, 959,
  990, 1023
};

// main Funktion
void main(void)
{
  // Ports initialisieren: alles auf Ausgang
  GPIO = 0;
  TRISIO = 0;

  // Oszillator auf 8 MHz einstellen
  OSCCON = (1 << 6) | (1 << 5) | (1 << 4) | 1;

  // Timer0 Counter zurücksetzen
  TMR0 = 0;

  // keine Pullups, Fosc/4 als Taktquelle für Timer0, 1:32 Prescaler:
  // ergibt bei 8 MHz also Fosc/4/32/256 = 244 Hz
  OPTION = (1 << 7) | (1 << 2);

  // Period Register von Timer2 auf Maximum
  PR2 = 255;

  // Timer2 on, Prescaler 1
  // zusammen mit PR2 ergibt das eine Frequenz von 8 MHz/4/(PR2+1)=4 MHz / 256 = 7812.5 Hz
  T2CON = 1 << 2;

  // keine Interrupts für Timer2
  PIE1 = 0;

  // PWM-Mode für das CCP-Modul aktivieren
  CCP1CON = 15;

  // global interrupt enable, Timer0 overflow enable und Interrupt Flag löschen
  INTCON = (1 << 7) | (1 << 5);

  // der Rest läuft im Interrupt ab
  while (1) {
  }
}

// Interruptroutine
void interrupt timerInterrupt(void)
{
  // LED mit ca. 1 Hz blinken lassen
  static uint8_t counter = 0;
  static uint8_t value = 0;
  if (counter++ == 122) {
    GPIO = value;
    value = 255 - value;
    counter = 0;
  }

  // Tastverhältnis vom PWM-Ausgang aktualisieren
  static uint8_t pwmIndex = 0;
  static uint8_t direction = 0;
  uint16_t pwm = g_pwm[pwmIndex];
  CCPR1L = (pwm >> 2) & 0xff;
  CCP1CON = 15 | ((pwm & 3) << 4);

  // PWM-Index aktualisieren: zählt einmal rauf und dann wieder runter
  if (direction) {
    if (pwmIndex == sizeof(g_pwm) / sizeof(uint16_t) - 1) {
      direction = 0;
    } else {
      pwmIndex++;
    }
  } else {
    if (pwmIndex == 0) {
      direction = 1;
    } else {
      pwmIndex--;
    }
  }

  // Interruptflag zurücksetzen
  T0IF = 0;
}

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:
Memory Summary:
    Program space        used   1B9h (   441) of   800h words   ( 21.5%)
    Data space           used    11h (    17) of    80h bytes   ( 13.3%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    Configuration bits   used     1h (     1) of     1h word    (100.0%)
    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 :-)

Autor: Niko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lehrmann Michael (ubimbo)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht 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:
#if LONG_MAX < 0x7fffffff
#error "this program needs long with 4 bytes"
#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.

Autor: Frank Buss (foobar)
Datum:

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

Youtube-Video "LED Fading with PIC12F683"

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.

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.