Forum: Mikrocontroller und Digitale Elektronik PIC12F675 brauche Hilfe


von Stefan H. (stefan_haussmann)


Lesenswert?

Hallo,

Für meine Abschlussarbeit ist es erforderlich einen PIC12F675 in C zu 
Programmieren. MPLAB und der Hitech C Compiler arbeiten einwandfrei.
Als Board habe ich das Vellemann V111 K8048 (oder so ähnlich geholt)...

Nun habe ich folgende Situation:

Zum testen habe ich einen PIC16F84A Programmiert. Das Programm und das 
Brennen, sowie die Abarbeitung des Programms haben einwandfrei 
funktioniert. (Dieser PIC wird über einen externen Quarz getaktet).

Nun wollte ich ein kleines Testprogramm in C für den PIC12F675 
schreiben.
Das Problem ist dass ich keine Erfahrungen mit PIC Mikrokontrollern habe 
und nicht weiß wie ich bei diesem PIC die Register setzen muss um die 
Pins als Ein-Oder ausgänge zu verwenden.
Außerdem wird dieser PIC nicht über einen externen Quarz getaktet, 
sondern muss den internen verwenden (das sollte ja möglich sein).

Ich hoffe dass es in diesem Forum einige Experten gibt, die mir einen 
kleinen C-Code zukommen lassen könnten. ich benötige lediglich einen 
eingang und einen Ausgang (Erstmal egal welche Pins, das zu ändern krieg 
ich auch noch hin).

Wäre toll wenn mir jemand helfen könnte, vielleicht auch über MSN oder 
ICQ oder sonnstwas.


Stefan

von Peter D. (peda)


Lesenswert?

Stefan Haussmann schrieb:
> Das Problem ist dass ich keine Erfahrungen mit PIC Mikrokontrollern habe
> und nicht weiß wie ich bei diesem PIC die Register setzen muss um die
> Pins als Ein-Oder ausgänge zu verwenden.

Es reicht völlig die "Erfahrung", daß man sich das Datenblatt vom 
Hersteller runter laden kann.
Und dann einfach anschauen, wo die IO-Pins beschrieben sind und deren 
Konfigurationsregister.


Peter

von Wolfgang M. (womai)


Lesenswert?

Kleiner Stolperstein, während bei den größeren PICs wie 16F84 die Ports 
als PORTA, PORTB usw. bezeichnet ist, lautet die Bezeichnung beim 12F675 
"GPIO" (general purpose I/O). Also statt

PORTA fuer den Port
TRISA fuer die Datenrichtung (Eingang/Ausgang)

verwendet man GPIO und TRISIO. Ansonsten hilft wie von Peter gesagt ein 
Blick ins Datenblatt - Ansprechen der Ports ist bei beiden PICs 
ansonsten identisch, bloss die RAM-Adressen sind anders. Die 
Oszillatorauswahl ist auch ausführlich beschrieben, das wichtig Register 
ist hier OSCCON.

Wolfgang

von Stefan Haussmann (Gast)


Lesenswert?

Kann ich einzelne ports so ansprechen?:

GPIO3=1;

oder muss ich das hier anders machen (beim 16F84 sind die Bezeichnungan 
ja RA, beziehungsweise RB...)

von usuru (Gast)


Lesenswert?

MPLAB versteht beim 12F675 sowohl GP4 als auch GPIO4 für das Bit4 des 
Ports (wobei der 12F675 natürlich nur die Bits 0 bis 5 hat). Für das 
Datenrichtungsregister gibt es TRISIO4 für das Bit4 (auch nur 0 bis 5).

von Stefan Haussmann (Gast)


Lesenswert?

Hat von euch jemand das Velleman PIC Board?

von Anja (Gast)


Lesenswert?

Stefan Haussmann schrieb:
> und nicht weiß wie ich bei diesem PIC die Register setzen muss um die
> Pins als Ein-Oder ausgänge zu verwenden.

Tipp: vergiß nicht die Pins von Analog-Eingang auf Digital 
umzukonfigurieren.
Ansonsten: Die Initialisierung steht prinzipiell im Datenblatt.

Gruß Anja

von Stefan Haussmann (Gast)


Lesenswert?

Hey Anja...


hast du vielleicht ein kleines Programm für diesen PIC?

Ich glaub dieser Tip war bisher der wichtigste :-)

von Stefan (Gast)


Lesenswert?

Ja habe ich.

von Stefan Haussmann (Gast)


Lesenswert?

Cool...mcht es dir was aus den Code hier zu veröffentlichen?

von Stefan (Gast)


Lesenswert?

ANSEL = 0
 CMCON = 7
 GPIO = 0
 TRISIO.0 = 0  Ausgang 0
 TRISIO.1 = 0  Ausgang 1
 TRISIO.2 = 1  Eingang 2

GP0_bit = 0 Ausgang 0 auf 0
GP1_bit = 0 Ausgang 1 auf 0

Wenn dein Compiler das versteht.

von Stefan Haussmann (Gast)


Lesenswert?

Dein Programm ist ein sehr guter Anhaltspunkt...
Ich versuch morgen mal den Code in meinen Compiler zu 
übertragen...welchen Compiler verwendest du?

von Stefan (Gast)


Lesenswert?

Von Mikroelektronika

von Michael L. (michaelx)


Lesenswert?


von Jens B. (nixiefreak)


Lesenswert?

Wenn du den HI-Tech verwendest, kannst du mal in den "include"-Ordner im 
Compilerverzeichnis schauen und nach der Datei "pic16f675.h" oder 
ähnlich suchen; dort stehen alle definierten Symbole drin, die der 
Compiler kennt.

Jetzt musst du das nur noch mit dem Datenblatt abgleichen, ist nicht so 
wild. Für eine Abschlussarbeit sollte das drin sein ;-)

Wenn du dann detailliertere Fragen hast, kannst du dich hier ja noch 
einmal melden.

Gruß
Jens

von Stefan H. (stefan_haussmann)


Lesenswert?

Vielen Dank...werde ich auf jeden fall tun...

von Stefan H. (stefan_haussmann)


Lesenswert?

Also...

Vorweg erstmal besten Dank an euch...

Ich bin jetzt auf den micro C PRO Compiler vom Mikroelectronica 
umgestiegen bei welchem die Konfiguration sofort Funktioniert hat.
Ein/Ausgänge ansprechen war überhaupt kein Problem mehr.


Jetzt kommt allerdings der Hauptteil.
Ich möchte (muss!!!) eine Pulsweitenmodulation Programmieren (für einen 
Modellbauservo) Das heißt, dass alle 20ms ein Signal zwischen 900us und 
2ms an einem Ausgang (Welcher ist egal) anliegen sollte.

Gibt es irgendwelche Ideen oder Tips, wie man das mit dem oben genannten 
PIC (12F675) oder einem anderen PIC der 12F Reihe diese Aufgabe Lösen 
kann.
Hier dachte ich an den PIC12F683, welcher laut Datenblatt einen 
integrierten PWM Generator hat.

Das Programm sollte also so sein, dass über eine Variable alle 20ms eine 
neue Pulslänge eingestellt werden kann (zum Beispiel soll nach 5 Minuten 
das Signal die Pulsweite von 900us bis 1,5ms durchlaufen)

Der PIC ist in meiner Abschlussarbeit leider nur eine Nebensache mit der 
ich fast schon auf Kriegsfuß stehe, aber man beißt sich irgendwie durch.

Wär cool, wenn wieder mal ein paar Experten ihr Know How zur verfügung 
stellen würden...

von Wolfgang M. (womai)


Lesenswert?

Ja, MikroC gefaellt mir auch, weil da aben vieles gleich mal 
funktioniert.

Das PWM-Modul kann leider so lange Perioden nicht erzeugen, ausser du 
laesst den PIC auf einer sehr geringen Taktfrequenz laufen (dann wird 
aber die Abarbeitungsgeschwindigkeit fuer alles andere sehr langsam).

Eine Periode von 20ms ist aber fuer den PIC ohnehin sehr lange, da kann 
man das - wenn sonst nichts zu tun ist - einfach als Schleife 
implementieren. Die Funktionen Delay_ms und Delay_us in MikroC (oder 
Mikrobasic) kommen da gerade recht. Achtung, diese Funktionen akzepieren 
nur Konstanten, und du musst built_in.h einbinden.

Also in etwa so

while (1)
{
  hier Variable   hochzaehlen, Zeit in 100usEinheiten
  for (high_time = 90; high_time <= 150; high_time++)
  {
     low_time = period - high_time;

     N-mal wiederholen (N so waehlen, dass die Aenderung
     der Pulsbreite mir der gewuenschten Geschwindigkeit verlaeuft,
     z.B. N=50 umd die Breite alles 1sec um 100us zu erhoehen):
     for (j = N; j; j--)
     {
        pin auf low setzen
        for (i=low_time; i; i--) { Delay_us(100); }
        pin auf high setzen
        for (i=high_time; i; i--) { Delay_us(100); }
     }
  }
} // Pulsbreite wieder auf Minimum und wieder vom Anfang an

Wenn mann es genauer machen will, muss man noch die Ausfuehrungszeit der 
Befehle abziehen, das ist aber eine eher kleine Korrektur hier (deshalb 
habe ich auch 100us als Basiseinheit gewaehlt - mit 1us waere das nicht 
der Fall!).

Wolfgang

von Stefan H. (stefan_haussmann)


Lesenswert?

Klasse Sache... Ich werde morgen das mal ausprobieren...mal schauen ob 
ich das hinbekomme.


Danke Wolfgang dass du deine Zeit für mich aufbringst...

von Stefan H. (stefan_haussmann)


Angehängte Dateien:

Lesenswert?

Ich habe das im Anhang hinterlegte Programm ja schon durch eure Hilfe 
hinbekommen.
Allerdings scheitere ich bei der Implementierung folgender 
Zusatzfunktionen:

-Wenn an GP0 kein Signal mehr anliegt, soll sich die Pulsweite nichtmehr 
verändern.


-Wenn der obere Block (PWM UP) einmal durchlaufen ist, soll die 
Pulsweite gehalten werden (Servo bewegt sich nicht)und es soll ein 
Signal an GP4 ausgegeben werden. Mit einem Signal an GP5 soll dann der 
untere Block (PWM DOWN) gestartet werden, welcher den Servo auf die 
ursprüngliche Position zurücksetzt und das Signal an GP5 soll auf 0 
gehen.

Ich hoffe ihr versteht was ich meine :-)




Danke im voraus

Stefan

von Michael S. (rbs_phoenix)


Lesenswert?

Wolfgang M. schrieb:
> Das PWM-Modul kann leider so lange Perioden nicht erzeugen, ausser du
> laesst den PIC auf einer sehr geringen Taktfrequenz laufen (dann wird
> aber die Abarbeitungsgeschwindigkeit fuer alles andere sehr langsam).

Bei dem PIC12F1822 oder 12F1840 kann man einen Prescaler von 64 
einstellen, bei dem 683 nur von 16. D.h. bei internen 2Mhz sind das Als 
Periodendauer: (PR2 + 1)  4  Tosc * TMR2Prescaler -> (155 + 1)  4  
1/2MHz * 64 = 19,968ms. Bei dem 10bit PWMModul ist das eine Auflösung 
von 19,5µs, was ja ausreichen sollte. Damit wäre 46 (0x00 0010 1110) 
0,897ms und 77 (0x00 0100 1101) 1,5015ms.

Nur musst du entscheiden, ob eine Frequenz von 2Mhz (also intern 500kHz) 
ausreichend ist und ob du den PIC nehmen kannst/willst. Was sind denn 
deine Vorgaben bzw was musst du benutzen und was darfst du nicht 
benutzen? Im ersten Beitrag meintest du ja, dass "es erforderlich einen 
PIC12F675 in C zu Programmieren". Später bist du zum 683 gewechselt, 
also warum nicht auch zum 1822 oder 1840 (oder was ganz anderes?)

von frankman (Gast)


Lesenswert?

1
#include <pic.h>
2
#include <htc.h>
3
__CONFIG(MCLREN & INTCLK &  INTIO);
4
5
main()
6
{
7
    int iTest;
8
    
9
    TRIS0 = 1; // Input
10
    TRIS5 = 0; // Output
11
    TRIS4 = 0; // Output
12
    WPU5  = 1; //Pullup 
13
    WPU4  = 1; //Pullup
14
15
    iTest = 1000;
16
    while(iTest--)
17
        {
18
        GPIO5 = 0;
19
        GPIO4 =1;
20
        }// endwhile
21
    iTest = 1000;
22
    while(iTest--)
23
        {
24
        GPIO5 = 1;
25
        GPIO4 = 0;
26
        }//endwhile
27
}// endfuction

von Michael S. (rbs_phoenix)


Lesenswert?

Michael Skropski schrieb:
> Bei dem PIC12F1822 oder 12F1840 kann man einen Prescaler von 64
> einstellen, bei dem 683 nur von 16. D.h. bei internen 2Mhz sind das Als
> Periodendauer: (PR2 + 1)  4  Tosc * TMR2Prescaler -> (155 + 1)  4
> 1/2MHz * 64 = 19,968ms. Bei dem 10bit PWMModul ist das eine Auflösung
> von 19,5µs, was ja ausreichen sollte. Damit wäre 46 (0x00 0010 1110)
> 0,897ms und 77 (0x00 0100 1101) 1,5015ms.

Ich hab nochmal nachgeguckt. Die Maximale Frequenz, die du nehmen 
kannst, gibt es sogar als Quarz bei Reichelt -> 3,2768 MHz (819,2kHz 
intern). Dann hast du (255 + 1) mal 4 mal 1/3,2768MHz mal 64 = 20ms.
Auflösung bleibt so ziemlich gleich, da die Zeit ja kaum unterschiedlich 
ist.

Aber wie gesagt, schreib mal deinen Auftrag bzw was musst du benutzen 
und was darfst du nicht und was muss es am Ende können.

von Stefan H. (stefan_haussmann)


Lesenswert?

Tut mir leid für meinen Ausdruck...ich werde heute Mittag eine 
Datailierte Beschriebung liefern....danke für eure Hilfe

von Stefan H. (stefan_haussmann)


Angehängte Dateien:

Lesenswert?

Also...hier die vollständige Eklärung:

Das Aktuelle Programm lässt einen servo im Prinzip hin und her fahren.
Der Obere Teil des Programms (PWM UP) lässt den servo ansteigen, der 
untere Teil (PWM DOWN) lässt diesen kontrolliert zurückfahren.
Das Signal des Servos wird an GP4 Ausgegeben.

Nun sollen folgende Verbesserungen Stattfinden.

1. Die Pulsweite soll sich nur verändern wenn an GP5 ein High Signal 
anliegt (Der Servo soll seine Position halten).

2. Das zurückfahren des Servos (PWM DOWN) soll erst erfolgen, sobald an 
dem Eingang GP0 ein High Signal anliegt (Taster).

3.Sobald der Servo seinen Zielwert erreicht hat (im angefügten Programm 
120 -->im PWM UP Teil) solll GP4 auf High schalten (LED Signalisiert, 
dass der Servo seinen Zielwert erreicht hat).
Diese LED Soll nach dem Zurückstellen des Servos wieder Erlischen.

Ich hoffe diese Beschreibung ist etwas besser...

von Michael S. (rbs_phoenix)


Lesenswert?

Also hattest du das Programm schon gegeben und sollst es nur erweitern? 
Dann bringt dir auch kein PIC mit PWM-Modul was, auch wenn der Timer 
einen großen Vorteiler hat.

Wenn du dein Programm, was du angehängt hast, benutzen bzw erweitern 
musst, ist das ja nicht weiter tragisch, ein paar ifs an der richtigen 
stelle. Z.b. Wenn GP5==1, high_time++, ansonsten das weglassen.

Ich glaube aber nicht, dass das Programm gegeben ist (es sei denn der 
Aufgabensteller will nicht nur eine Erweiterung sondern auch eine 
Fehlersuche), denn die Deklaration von Variablen kommen ganz am Anfang 
der Funktionen. Also haben die in der while nichts zusuchen, sondern 
gehören direkt unter das "void main(){".

Wenn du es denn so willst, was eine neue programmierung bedeutet, kannst 
du (wenn du in der PIC12F Familie bleiben sollst) den von mir erwähnten 
PIC12F1822 mit dem 3,2768MHz Quarz nehmen und kannst das PWM-Modul 
benutzen. Es ist nicht nur angenehmer zu programmieren, sondern auch 
übersichtlicher, eleganter und vorallem läuft das PWM-Modul automatisch 
im Hintergrund. Das heißt, er gibt die PWM aus und du kannst im Programm 
machen, was du willst. Wenn du eine Schleife mit wartefunktionen im 
Programm stehen hast, verfälscht du die Zeit mit jedem Befehl (sogar 
schon mit dem Setzen/Löschen des Ausgangs und der Schleife). Das ist bei 
hoher Taktfrequenz und kleiner PWM-Frequenz natürlich weniger schlimm, 
aber solche Module gibts ja nicht umsonst. Und ~800kHz reicht aus, um ne 
LED zu setzen oder nen Eingang abzufragen. Die Konfiguration vom 
PWM-Modul steht ja quasi schon oben, also wird es außer der einmaligen 
Initialisierung am Anfang vom Programm nen 10-20 Zeiler.

von Stefan H. (stefan_haussmann)


Lesenswert?

OK, ich bin jetzt am Rande des Wahnsinns...

Ich habe hier nochmal die Aufgabe hineinkopiert:

Das Programm PWM.c findet ihr weiter oben.
Das Programm lässt einen servo im Prinzip hin und her fahren.
Der Obere Teil des Programms (PWM UP) lässt den servo ansteigen, der
untere Teil (PWM DOWN) lässt diesen kontrolliert zurückfahren.
Das Signal des Servos wird an GP4 Ausgegeben.

Nun sollen folgende Verbesserungen Stattfinden.

1. Die Pulsweite soll sich nur verändern wenn an GP5 ein High Signal
anliegt (Der Servo soll seine Position halten).

2. Das zurückfahren des Servos (PWM DOWN) soll erst erfolgen, sobald an
dem Eingang GP0 ein High Signal anliegt (Taster).

3.Sobald der Servo seinen Zielwert erreicht hat (im angefügten Programm
120 -->im PWM UP Teil) solll GP4 auf High schalten (LED Signalisiert,
dass der Servo seinen Zielwert erreicht hat).
Diese LED Soll nach dem Zurückstellen des Servos wieder Erlischen.



Ich bin absolut kein Programmiergenie so wie manch andere hier...ich 
benötige deswegen einen Leitfaden oder persönlichen Kontakt.

Ich Programmier das Ding neu, anhand dem was ihr mir hier sagen 
werdet...es reicht auch eine Strategie z.B.
Bit....Setzen
TCON....Setzen
...
...
...

Gibt es eine Möglichkeit die PWM Ohne den externen Oszillator zu machen? 
Zum beispiel mit einem Timer oder sowas??? Das zurückfahren des Servos 
könnte man ja Mithilfe eines Interrupts an GP2 machen. Also sobald an 
GP2 eine High Flanke kommt kann ja das "Rückfahr Programm" Ausgeführt 
werden und die Pulsweite im normalen Programm wieder zurückgesetzt 
werden.

Danke an alle die mich so geduldig ertragen!!!

von Wolfgang M. (womai)


Lesenswert?

Viel Zeit habe ich gerade nicht, deshalb keine vollstaendige Loesung.

Aber ich hab mal einen Blick auf Dein urspruengliches Programm geworfen. 
Da ist TRISIO=0 gesetzt. Das heisst aber, alle Pins sind als Ausgaenge 
geschaltet - klar, dass Du da kein Eingangssignal lesen kannst. 
Stattessen

//  GP-->  76543210
TRISIO = 0b00100001; // binaer ist es leichter lesbar - ein bit pro Pin

macht GP0 und GP5 zu Eingaengen. JETZT kannst Du da Signale anlegen und 
einlesen. Wenn das ueber Taster geschehen soll, brauchst Du noch 
Pull-Down-Widerstaende. Also Taster zwischen VCC und Eingang, einen 1 
kOhm-Widerstand zwischen Eingang und GND. Damit ist der Eingang solide 
auf GND, wenn der Taster nicht betaetigt ist.

LED Einschalten: gp4_bit = 1;
LED Ausschalten: gp4_bit = 0;

GP5 high? abfragen:
if (gp5_bit) { .... }
oder
if (gp5_bit > 0) { .... }

warten solange GP0 noch low ist:
while (!gp0_bit) {}
oder
while (gp0_bit == 0) {}

PWM und externer Oszillator haben miteinander nichts zu tun. Du kannst 
genauso den internen Oszillator verwenden, und den kann man auch 
verschnieden schnell einstellen (oder genauer gesagt, den Takt 
verschieden herunterteilen).

Wenn Du MikroC verwendest, gibt es vorgefertigte Funktionen in der 
Library zum Einschalten der PWM sowie zum Veraendern des 
Tastverhaeltnisses (= Pulsbreite, Duty Cycle).

Wolfgang

von Stefan H. (stefan_haussmann)


Lesenswert?

Das mit den Eingängen ist korrekt...die waren in dem ersten Programm 
noch nicht mit drin...

Ich hoffe, dass die Aufgabe jetzt etwas klarer beschrieben ist.
Ich benutze MicroC...Wie komme ich auf die vorgefertigten Funktionen?
Das PWM Zeugs kenne ich bisher nur aus dem Datenblatt.

Theoretisch kann ich die Pausenzeit ja Fix auf 15ms lassen und mit dem 
PWM Modul einen High Puls erzeugen der von ca. 500us bis 1500us 
ansteigt, oder?

von Michael S. (rbs_phoenix)


Lesenswert?

Ich weiß nicht ob mikroC eine Software PWM Library hat. Das normale 
PWM1_Init ist jedenfalls für das interne PWM Modul. Das nützt dir nur 
nichts, wenn du die Frequenz nicht weit genug teilen kannst.

Du kannst auch eine Fix-Pause von 18ms nehmen und die differenz von der 
Highzeit zu 2ms zusätzlich auch Low schalten und warten. Nur bringt es 
nicht unbedingt Vorteile. Du hast eine Variable die du hochzählst, wenn 
GP5 und GP0 auf high ist und zusätzlich, wenn die Variable kleiner als 
die maximale Highzeit ist. Beim runterzählen entsprechend. Und wenn der 
maximalwert erreicht ist, soll gp4 gesetzt werden.
1
if(GP5) // musst gucken, wie die gp5 variable heißt
2
  if(!GP0 && variable_warten < maximalzeit) variable_warten++; //oder variable_warten += zeit_zum_addieren;
3
  if(GP0 && variable_warten > minimalzeit) variable_warten--;
4
}
5
if(variable_warten >= maximalzeit) GP4 = 1;
6
else GP4 = 0;
7
8
GP2 =1;
9
us_vdelay(variable_warten);
10
GP2 = 0;
11
us_vdelay(20000 - variable_warten);

Ich bin am Handy also kann ich nichts nachgucken. Du musst gucken, ob 
das Programm das so macht wie es soll. Ich weiß auch nicht die 
konstanten für die Bits (GP5 z.b. glaube es is eher GPIO.GP5_bit oder 
so) oder wie genau die funktion heißt, die eine variable zeit wartet 
aber das kannst du ja nachgucken.

Vielleicht hilft das ja.

von Stefan H. (stefan_haussmann)


Lesenswert?

Einige schreiben, dass das mit dem internen PWM Modul nicht 
funktioniert...ist das so oder nicht. Ich habe auch eine Lösung gesehen, 
in der mit 2 Timern gearbeitet wird...allerdings wäre mir das PWM Modul 
lieber...

von Wolfgang M. (womai)


Lesenswert?

Wie schon früher erwähnt: Das PWM-Modul hat Grenzen in der Frequenz nach 
unten. PWM benutzt einen Hardware-Timer (Zähler), dessen Eingangstakt 
kommt vom Oszillatortakt, u.U. heruntergeteilt (typischerweise in 
Zweierpotenzen bis 2^8=256 möglich). Für eine bestimmte 
Oszillatorfrequenz kann man also das PWM nicht beliebig langsam laufen 
lassen.

Natürlich kann man sich selber ein Timer-PWM basteln. Du verwendest 
MikroC, da schau mal in den mitgelieferten Beispielen unter Timer nach. 
Da hast Du ein vollständiges, lauffähiges Programm dazu. Musst nur noch 
Prescaler und Preload-Werte verändern, damit Du statt 1 Hz eben z.B. 20 
Hz bekommst. (schau auch das "alte" MikroC an, also nicht MikroC Pro, da 
gibt es sogar ein Besipiel genau für the 12F673).

von Stefan H. (stefan_haussmann)


Lesenswert?

Ich probier die Strategie mit den Timern, das klingt am 
vielversprechensten.
Da kann man relativ leicht sachen hinzuprogrammieren.

Die werte ausrechnen ist kein problem..das hat nichts mit Syntax oder 
erfahrung zu tun :-)

Tausend Dank

von Michael S. (rbs_phoenix)


Lesenswert?

Wie ich weiter oben schon geschrieben hatte hat der 683 nur einen 
prescaler von 16. Bei 20ms PWM Periodendauer, also 50Hz kannst du den 
PIC nur bis zu einer bestimmten Frequenz takten. Da der PIC12F1822/1840 
einen 64 Teiler haben, kannst du ihn also 4 mal schneller takten, da du 
ihn halt mehr teilen kannst.
Deswegen frag ich ja auch was deine Aufgabe ist. Wenn du dieses von dir 
gepostete Programm erweitern sollst, bringt dir ein PWM-Modul rein 
garnichts, weil das im Programm ja garnicht vorkommst. Und wenn du die 
Freiheit hast, das ganze Programm neu zu schreiben, nämlich mit einem 
PWM-Modul, dann hast du ja evtl auch die Freiheit einen anderen PIC zu 
wählen, eben den 12F1822. Das Beispiel dazu hab ich ja weiter oben schon 
geschrieben. Wenn der PIC aber nichts anderes machen soll ist es egal ob 
delay (aus dem letzten Post von mir), timer mit interrupt oder pwm modul 
in Verbindung mit einem sehr langsamen Takt.

von Stefan H. (stefan_haussmann)


Angehängte Dateien:

Lesenswert?

Das hier ist der Versuch das genze mit einem interrupt zu gestalten.

Das Programm (welches natürnich NICHT funktioniert) hat folgenden 
Ablauf:

Timer0 löst alle 20ms einen interrupt aus
GP2 Ausgang geht auf 1
Timer1 Bestimmt die Pulslänge
Wenn Timer1 überlauf bekommt geht der GP2 Ausgang wieder auf 0.

Allerdings funktioniert da was nicht. Bitte mal durchschauen.
Das Programm ist ohne Extras, soll also nur mal eine feste Pulslänge 
erzeugen (Länge ziemlich egal).

MfG
Stefan

von Stefan (Gast)


Lesenswert?

Wenn ich mich nicht verrechnet habe,
komme ich auf ca. 65 ms für Timer 0.
Hier muß ein H hin:
TMR1H=253; //High Byte berechnen
TMR1L=232; //Low Byte berechnen

von Peter D. (peda)


Lesenswert?

Stefan Haussmann schrieb:
> Timer0 löst alle 20ms einen interrupt aus
> GP2 Ausgang geht auf 1
> Timer1 Bestimmt die Pulslänge
> Wenn Timer1 überlauf bekommt geht der GP2 Ausgang wieder auf 0.

Welchen Grund gibt es, dafür verschiedene Timer zu nehmen?

Wenn Timings aufeinander folgen, nehme ich dazu auch den gleichen Timer, 
das ist einfacher.
Ideal ist dazu ein Compareinterrupt. Dann kann der Timer durchlaufen und 
man setzt einfach nur den nächsten Comparewert.


Peter

von Stefan H. (stefan_haussmann)


Lesenswert?

Das Programm soll später die Pulsweiten verändern. Außerdem hab ich 
nicht wirklich ahnung was du meinst.

von Peter D. (peda)


Lesenswert?

Stefan Haussmann schrieb:
> Außerdem hab ich
> nicht wirklich ahnung was du meinst.

Sorry, hab grad ins Datenblatt geschaut. Die Timer sind ja wirklich nur 
sehr rudimentär ausgestattet. Comparemode gibt es keinen.

Ich bin das vom AVR so gewöhnt, daß selbst die kleinen 8-Pinner sehr 
flexible Timerfunktionen haben.
Da gibt es mindestens 2 Compareregister, die auch einen Pin direkt 
umschalten können. D.h. es entsteht kein Jitter durch die 
Interruptlatenz.
Das Schalten erfolgt auf den CPU-Zyklus genau.


Gibt es irgendeinen Grund, warum Du gerade diesen PIC nimmst?
Ich würde einen mit leistungsfähigerem Timer nehmen.


Peter

von Stefan H. (stefan_haussmann)


Lesenswert?

Ich möchte keinen anderen Mikrocontroller verwenden...hab den 10 mal 
hier rumliegen. Ich habe das Programm übertragen und es funktioniert 
irgendwie nicht und ich weiß nicht warum. Ich bin im Programmieren nicht 
unbedingt ein Experte. Falls du da ahnung hast kannst du dir mal die 
Aufgabe durchlesen und schauen warum das nicht geht...bin schon am 
verzweifeln.

von Peter D. (peda)


Lesenswert?

Das hier sieht schonmal komisch aus.
1
        TMR1L=253; //High Byte berechnen
2
        TMR1L=232; //Low Byte berechnen
Zweimal TMR1L?


Vielleicht kann Dein Compiler den Timer als 16Bit zugreifen, dann muß 
man low und high-Byte nicht selber auseinanderfriemeln.
Auch kann C Konstanten selber ausrechnen. Man schreibt daher besser die 
Formel hin und keine magischen Zahlenwerte.

Hier mal ein Beispiel für den AVR-GCC:
1
#define F_CPU 16e6                           // 16MHz
2
#define T1_PRESCALER 8                       // F_CPU / 8
3
4
  OCR1A = F_CPU / T1_PRESCALER * 20e-3 - 1;  // 20e-3 = 20ms


Peter

von Stefan (Gast)


Lesenswert?

PIE1 muß gesetzt werden und das INTCON Register auch.
Aber nicht in der Interrupt Routine.
Was sonst noch falsch war hab ich ja schon geschrieben.

von Stefan H. (stefan_haussmann)


Angehängte Dateien:

Lesenswert?

Ich muss doch nur GIE setzen, das tu ich in "void timer0()"...das ist ja 
nicht die interrupt routine...Der schreibfehler (H und L) ist behoben.
Funktioniert aber nicht.

Ich möchte erstmal überhaupt einen Puls haben bevor ich die genauen 
werte berechne.

von Stefan (Gast)


Lesenswert?

Ich rede von Timer 1 und nicht von Timer 0.

von Stefan H. (stefan_haussmann)


Lesenswert?

was genau muss ich denn da setzen oder nicht setzen...kannst du mir die 
zeilen gschwind schiecken?

von Stefan H. (stefan_haussmann)


Lesenswert?

Ich versteh nicht was du genau meinst mit dem INTCON Register und 
Timer1.
Bitte erklär mir das mal oder sag wo ich was reinschreiben muss.

von PICfan (Gast)


Lesenswert?

3 dinge die mir aufgefallen sind:

1- Du startest Timer0 nicht (daher keinen interrupts)

2- Du sollst den Timer0 Int Flag am ende des ISR wieder löschen.

3- Wenn Timer1 geschrieben wird ist es empfohlen den Timer vorher 
anzuhalten.

von Stefan H. (stefan_haussmann)


Lesenswert?

Wie Starte ich Timer0?? ich hab da so nichts gefunden

von PICfan (Gast)


Lesenswert?

Stefan Haussmann schrieb:
> Wie Starte ich Timer0?? ich hab da so nichts gefunden

Sorry hast recht, dachte an einen anderen PIC gerade.

Ich hab dein SW ein wenig angepasst. Es ist noch ungetestet da ich 
keinen 12F675 da habe, aber vom Prinzip soll es gehen.
Ich glaub dein problem lag an den "TMR1IF".  Anderseits sagts du 
"T0IF_bit".  Ich benutze den HiTech compiler zu wenig um das richtige zu 
erkennen, also bitte nachschlagen.

------------------------------------------------------------------------ 
--
int Count;     //Zähler für durchläufe

void Init()
 {
  ANSEL=0;
  CMCON=7;
  TRISIO=0;

  OPTION_Reg=0b11000111;
         /*    1-------;  Betrifft nicht Timer0
               -1------;  Betrifft nicht Timer0
               --0-----;  Intern Takt für Timer0 verwenden
               ---0----;  Bei ext. Takt b. stg Flanke inkr. (nicht 
relevant)
               ----0---;  Prescaler für Timer 0 verwenden
               -----111;  Prescaler   (1:256)
         */

  T0IF_bit=0; //Timer0 Interrupt Flag löschen
  T1IF_bit=0; //Timer1 Interrupt Flag löschen
  T0IE_bit=1; //Timer0 Interrupt erlauben
  T1IE_bit=1; //Timer1 Interrupt erlauben
  TMR0=180;   // Timer0 Value


 }

 static void interrupt (void)  //ISR
 {
    if (T0IF_bit)   // Timer0 überlauf
    {
      GP2_bit=1; //Ausgang auf 1
      TMR1H=253; //High Byte berechnen
      TMR1L=232; //Low Byte berechnen
      //Timer1 Starten
      T1CON=0b00000001;
        /*    0-------; Nicht relevant
              -0------; Nicht relevant
              --00----; Precsaler (1:1)
              ----0---; Sync. m. ext. Takt (Hier nicht relevant)
              -----0--; Internet Tackt verwenden
              -------1; Timer starten
        */
      T0IF_bit=0; //Timer0 Interrupt Flag löschen
    }

    if (T1IF_bit)     // Timer1 überlauf
    {
       GP2_bit=0;             //Ausgang auf 0
       Count++;               //Zähler um 1 erhöhen
      //Timer1 Stoppen
      T1CON=0b00000000;
      T1IF_bit=0; //Timer1 Interrupt Flag löschen
    }
 }



void main()
{
 Init();

 GIE_bit=1;  //Alle unmaskierten interrupts erlauben

 while(1) {}

 }

----------------------------------------------------------------------

von Der Rächer der Transisitormorde (Gast)


Lesenswert?

Stefan Haussmann schrieb:
> Wie Starte ich Timer0?? ich hab da so nichts gefunden

RTFM Seite 29

> Timer mode is selected by clearing the T0CS bit
> (OPTION_REG<5>).

Das ist dein erstes Kommando

> In Timer mode, the Timer0
> module will increment every instruction cycle (without
> prescaler).

Das macht er dann

> Counter mode is selected by setting the T0CS bit
> (OPTION_REG<5>). In this mode, the Timer0 module
> will increment either on every rising or falling edge of
> pin GP2/T0CKI.

Das willst du nicht


> 4.2 Timer0 Interrupt
> A Timer0 interrupt is generated when the TMR0
> register timer/counter overflows from FFh to 00h. This
> overflow sets the T0IF bit

Das Flag kannst du ohne Interrupt Abfragen.



Stefan Haussmann schrieb:
> Ich hoffe dass es in diesem Forum einige Experten gibt, die mir einen
> kleinen C-Code zukommen lassen könnten.

> http://forum.htsoft.com/all/showflat.php? 
Cat=0&Board=pic&Number=193402&Searchpage=1&Main=193122&Words=+NexxuSix&t 
opic=&Search=true


Google: code example 12F675 hightech c (1 Eintrag)

von Stefan H. (stefan_haussmann)


Lesenswert?

Hey PICfan,
du bist klasse...das ding funktioniert...du bist einer der ersten die 
mal konkret gesagt haben wo das Problem liegt und was zu tun ist. Dass 
du das Pgogramm selber geändert hast finde ich riesig. Danke

von PICfan (Gast)


Lesenswert?

Bitte sehr.  Es freut mich das ich helfen könnte (und vor allem das es 
funktioniert hat :-))

von EGS_TI (Gast)


Lesenswert?

Hi, um niedrigere Frequenzen zu

Stefan Haussmann schrieb:
> Kann ich einzelne ports so ansprechen?:
>
> GPIO3=1;
>
> oder muss ich das hier anders machen (beim 16F84 sind die Bezeichnungan
> ja RA, beziehungsweise RB...)

Also wenn du schon für die einfachsten Fragestellungen die Hilfe vom 
Forum benötigst, dann wirst du es nicht weit bringen.
Willst du denn dann dein gesamtes Projekt durch Foren zusammenpicken?

von Stefan H. (stefan_haussmann)


Lesenswert?

Es gibt doch noch ein kleines Problem...ich erhalte mit dem Programm 
eine gleichmäßige Pulsfolge, kann aber die Hochzeit nicht einstellen. 
Irgend was ist da noch faul. Ich habe den Timer0 jetzt auf etwa 15ms 
eingestellt.
Nun erhalte ich 15ms low und 15ms high...

von Der Rächer der Transisitormorde (Gast)


Lesenswert?

Stefan Haussmann schrieb:
> Nun erhalte ich 15ms low und 15ms high

Wenn du z.B den Pin nur toggelst

GPIOx != GPIOx


kann nur ein symmetrisches Puls/Pausenverhältnis rauskomnmen.

von EGS_TI (Gast)


Lesenswert?

Stefan Haussmann schrieb:
> Wie Starte ich Timer0?? ich hab da so nichts gefunden

Krass

von Stefan H. (stefan_haussmann)


Lesenswert?

Der Rächer der Transisitormorde schrieb:
> Stefan Haussmann schrieb:
>> Nun erhalte ich 15ms low und 15ms high
>
> Wenn du z.B den Pin nur toggelst
>
> GPIOx != GPIOx
>
>
> kann nur ein symmetrisches Puls/Pausenverhältnis rauskomnmen.


Also das klingt zwar gut aber ich weiß nicht was du meinst...

von Stefan H. (stefan_haussmann)


Angehängte Dateien:

Lesenswert?

Hallo...

Also jetzt tick ich demnächst aus.
Ich hab eine Schaltung aufgebaut, so wie im Anhang.
Allerdings habe ich das Problem, dass ich aus irgend einem Grund die 
Eingangssignale nicht lesen. Ich verwende folgende Konfiguration:
1
//##############VARIABLENDEFINITION#############################
2
3
//##############HARDWAREKONFIGURATION###########################
4
//Diese Variablen sind vom Anwender selbst einzutragen.
5
6
int LowTime=19000;         //Eingestellte Pausenzeit (18,5ms)
7
int HighTime=800;          //Eingestellte Pulslänge (STARTWERT)
8
int HighTimeMax=2000;      //Maximale Pulslänge (ENDWERT)
9
int RateOfChange=1000;     //Änderungsgeschwindigkeit
10
11
//##############SYSTEMVARIABLEN#################################
12
int Time;                  //Variable für Timerwert
13
char Ausgang=0;            //Status des Ausgangsports
14
int counter=0;             //Zähler für Änderungsgeschwindigkeit
15
//##############################################################
16
17
18
  void Init()             //Initialisierungsroutine für Timer
19
 {
20
21
      ANSEL=0;            //Alle Ausgänge Digital
22
      CMCON=7;            //Kein Komperator
23
      TRISIO=0b00110000;  //GP4,GP5 als Eingang
24
      T1CON=0b00000001;   //Timer 1 Konfigurieren und starten
25
       /*     0-------;    Nicht relevant
26
              -0------;    Nicht relevant
27
              --00----;    Precsaler (1:1)
28
              ----0---;    LP Oszilator aus (nicht relevant)
29
              -----0--;    Sync. ext. Takt (Hier nicht relevant)
30
              ------0-;    Internet Takt verwenden
31
              -------1;    Timer starten
32
       */
33
      GIE_bit=1;  //Alle unmaskierten interrupts erlauben
34
      PEIE_bit=1; //PERIPHERAL INTERRUPTS ENABLE
35
      T1IE_bit=1; //Timer1 Interrupt erlauben

von Martin S. (drunkenmunky)


Lesenswert?

was ist des eigentlich für eine Abschlussarbeit?
Tüftelst du da jetzt schon 3 Monate an dem Problem?

Zeig halt mal dein ganzes Programm. Vielleicht ist ja auch die Abfrage 
falsch...

von Stefan H. (stefan_haussmann)


Lesenswert?

Das mit dem Servo ist nur Bonus...also das sahnehäubchen...das wollt ich 
nebenher machen...jetzt bin ich mit dem andern zeug fertig, doku ist 
auch fast fertig und jetzt will ich das auch noch auf die reihe kriegen.

Also das Programm funktioniert auf der Vellemann-Entwicklungsplatine, 
aber bei meiner selbst gelöteten schaltung ist das net so :-)


Das hier ist das Vollständige Programm:
1
//##############VARIABLENDEFINITION#############################
2
3
//##############HARDWAREKONFIGURATION###########################
4
//Diese Variablen sind vom Anwender selbst einzutragen.
5
6
int LowTime=19000;         //Eingestellte Pausenzeit (18,5ms)
7
int HighTime=800;          //Eingestellte Pulslänge (STARTWERT)
8
int HighTimeMax=2000;      //Maximale Pulslänge (ENDWERT)
9
int RateOfChange=1000;     //Änderungsgeschwindigkeit
10
11
//##############SYSTEMVARIABLEN#################################
12
int Time;                  //Variable für Timerwert
13
char Ausgang=0;            //Status des Ausgangsports
14
int counter=0;             //Zähler für Änderungsgeschwindigkeit
15
16
//##############################################################
17
18
19
  void Init()             //Initialisierungsroutine für Timer
20
 {
21
22
      ANSEL=0;            //Alle Ausgänge Digital
23
      CMCON=7;            //Kein Komperator
24
      TRISIO=0b00110000;  //GP4 und GP5 als Eingang
25
      T1CON=0b00000001;   //Timer 1 Konfigurieren und starten
26
       /*     0-------;    Nicht relevant
27
              -0------;    Nicht relevant
28
              --00----;    Precsaler (1:1)
29
              ----0---;    LP Oszilator aus (nicht relevant)
30
              -----0--;    Sync. ext. Takt (Hier nicht relevant)
31
              ------0-;    Internet Takt verwenden
32
              -------1;    Timer starten
33
       */
34
      GIE_bit=1;  //Alle unmaskierten interrupts erlauben
35
      PEIE_bit=1; //PERIPHERAL INTERRUPTS ENABLE
36
      T1IE_bit=1; //Timer1 Interrupt erlauben
37
38
 }
39
40
 void interrupt ()
41
 {                             //BEGIN ISR
42
   if (Ausgang==0)             //Ausf. wenn Status=0
43
   {   GPIO.B2 = 1;            //Ausgang auf High
44
   Time=HighTime;              //Timer auf High Pulslänge setzen
45
   TMR1H=(65536-Time)/256;     //Highbyte setzen
46
   TMR1L=(65536-Time)%256;     //Lowbyte setzen
47
   T1IF_bit=0;                 //Timer1 Interrupt Flag löschen
48
   Ausgang=1;                  //Status auf 1
49
   
50
   if (GPIO.B4==1)            //Prüfen ob Freigabe=1
51
    {   
52
     counter++;                //Impulszähler um 1 erhöhen
53
    }
54
    
55
   if((HighTime<HighTimeMax)&&(counter=RateOfChange))
56
    {
57
    Hightime++;                //Impuls verlängern
58
    }
59
     
60
    if (Hightime==HighTimeMax) //Hochzeit erreicht?
61
     {
62
     GPIO.B1=1;                //Ausgang HALTESIGNAL setzen
63
     }
64
    else
65
     {
66
     GPIO.B1=0;                //Ausgang HALTESIGNAL löschen
67
     }
68
    
69
    if (GPIO.B5==1)            //Prüfen ob Reset Taster==1
70
    {
71
    Hightime=HighTime;         //HighTime auf Startwert setzen
72
    }
73
   }
74
75
   else                        //Ausf. wenn Status=1
76
   {
77
   GPIO.B2 = 0;                //Ausgang auf Low
78
   Time=LowTime;               //Timer auf Low Pulslänge setzen
79
   TMR1H=(65536-Time)/256;     //Highbyte setzen
80
   TMR1L=(65536-Time)%256;     //Lowbyte setzen
81
   T1IF_bit=0;                 //Timer1 interrupt Flag löschen
82
   Ausgang=0;                  //Status auf 0
83
   }
84
85
 }                             //END ISR
86
87
88
void main()         //MAIN LOOP
89
{
90
     Init();        //Konfiguration ausführen
91
}                   //END MAIN LOOP

von Michael S. (rbs_phoenix)


Lesenswert?

Stefan Haussmann schrieb:
> void main()         //MAIN LOOP
> {
>      Init();        //Konfiguration ausführen
> }                   //END MAIN LOOP

Das ist keine Main-Loop, sondern eine Main-Funktion, die einmal 
durchläuft. Da du kein "while(1);" drin hast, ist das Programm durch und 
ist entweder irgendwo im undefinierten Programmspeicher oder aber am 
Ende.


Stefan Haussmann schrieb:
> counter=RateOfChange

Dir ist bewusst, dass das eine Zuweisung ist und kein Vergleich auf 
Gleichheit? Meist wird in if-Bedingungen ja geprüft ob es gleich ist.


Stefan Haussmann schrieb:
> if((HighTime<HighTimeMax)&&(counter=RateOfChange))
>     {
>     Hightime++;                //Impuls verlängern
>     }
>
>     if (Hightime==HighTimeMax) //Hochzeit erreicht?
>      {
>      GPIO.B1=1;                //Ausgang HALTESIGNAL setzen
>      }
>     else
>      {
>      GPIO.B1=0;                //Ausgang HALTESIGNAL löschen
>      }
>
>     if (GPIO.B5==1)            //Prüfen ob Reset Taster==1
>     {
>     Hightime=HighTime;         //HighTime auf Startwert setzen
>     }

Also wenn ich das Programm richtig verstehe, dann müsste es hier überall 
statt HighTime nur Time heißen, außer ganz unten dann time = HighTime. 
Damit wäre Time die Variable, die hochgezählt wird und die immer größer 
werdende Zeit, wielange das signal auf high ist und HighTime wäre der 
Startwert (der demnach nicht hochgezählt werden soll). Doch dann muss 
das Time = Hightime ganz oben weg, denn dann überschreibst du das 
hochgezählte immer wieder mit dem Startwert. Dann müsste aber Time bei 
der Definition den Startwert bekommen.

Wenn du das so wie oben geschrieben behalten willst, brauchst du eine 
Variable mit dem Startwert der Hightime, den du nicht veränderst (so wie 
im moment mit "HighTime++;"). Dann wäre aber folgendes überflüssig:

Stefan Haussmann schrieb:
>    Time=HighTime;              //Timer auf High Pulslänge setzen
>    TMR1H=(65536-Time)/256;     //Highbyte setzen
>    TMR1L=(65536-Time)%256;     //Lowbyte setzen

Denn dann könntest du auch schreiben:

>    TMR1H=(65536-HighTime)/256;     //Highbyte setzen
>    TMR1L=(65536-HighTime)%256;     //Lowbyte setzen

Und wenn du das so änderst und die Variable für den Startwert 
hinzufügst, wirst du sehen, es ist genau das gleiche wie ich davor 
beschrieben hab, nur dass die Variablen-Namen anders sind;)

von Stefan H. (stefan_haussmann)


Lesenswert?

OK, was ist mit den Abfragen an den beiden Eingängen...passt das zum 
Schaltplan...(Verschaltung, TRISIO Register usw...)

von Michael S. (rbs_phoenix)


Lesenswert?

Ansich ja. Ist die Schaltung da mit Target gezeichnet? Wenn ja ist 
meines Wissens so ein Quadrat mit nem Kreuz drin ein Fehler, also keine 
Verbindung oder zu dicht etc.
Ist deine Platine geätzt oder gefräst oder so iwie mit Lochraster. Wenns 
bei einer Platine funktioniert und bei einer anderen nicht, liegt es 
meist bei der Platine. Wobei ich bezweifle, dass das Programm da oben so 
funktioniert, wie es soll.

von Stefan H. (stefan_haussmann)


Lesenswert?

Haha...ich hab das vorhin schnell abgezeichnet von meinem Blockblatt 
gg....hab das mit Silberdraht gelötet. Und ja.....es ist Target.

Das dauert noch bis die Platine Ätzfertig ist...

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.