Hallo! Ich bin neu hier und brauche dringend Hilfe. Ich muss für mein Studium ziemlich bald ein Projekt abgeben, habe jedoch keine Ahnung, wie ich überhaupt beginne. Es wird mit MPLAB-IDE im Assembler programmiert, Demoboard mit PICKit3 und Prozessor 16F886. Unser Professor hat uns ein Grundgerüst zur Verfügung gestellt und folgende Aufgabe muss ich jetzt selbst programmieren: ## Projekt µController: Schreiben sie ein Programm, welches die Helligkeit der roten Led mittels Poti einstellen kann. Der AD-Wert des Poti wird ausgelesen und modifiziert am Display ausgegeben. z.B AD=0 --> Anzeige „-00-„ AD=255 --> Anzeige „-99-„ (Anzeige der Helligkeit in Prozent) Der AD-Wert des Poti wird auch zur Ansteuerung der roten Led verwendet, die Helligkeit lässt sich am besten mit einer einfachen PWM (Pulsweitenmodulation) realisieren. Hinweis: Da die rote Led nicht am PWM-Pin des PICs angeschlossen ist, kann nicht die Standard PWM des Controllers genommen werden. Die PWM Realisierung muss daher mittels Software (richtiges ein/ausschalten) realisiert werden. Es wäre wirklich toll, wenn mir jemand helfen könnte. Nicht falsch verstehen, ich brauch niemanden, der mir das Programm schreibt, sondern einfach nur Hilfe. Liebe Grüße Lisa
Lisa Zwiletitsch schrieb: > Es wird mit MPLAB-IDE im Assembler programmiert Muß in deinem Prjekt in Assembler programmiert werden?
Peter Xuang schrieb: > Lisa Zwiletitsch schrieb: >> Es wird mit MPLAB-IDE im Assembler programmiert > > Muß in deinem Prjekt in Assembler programmiert werden? Ja, es muss in Assembler programmiert werden.
hallo, natürlich wird dir hier geholfen. Was konkret ist denn dein Problem?
Hallo Lisa, Wie ist dein aktueller Stand? Benötigst du Unterstützung beim Schreiben des Programms, oder hängts bereits bei der Inbetriebnahme der Toolchain?
Hallo Lisa, Indem Euer Prof die Nutzung des CCP/PWM-Moduls nicht zulaesst, bleibt Dir nur uebrig PWM per Software zu verwirklichen. Eine gute Einfuehrung hierfuer ist die microchip Druckschrift AN654 "PWM, a Software Solution for the PIC16CXXX" Darin sind diverse Codebeispiele sowie auch einige Flussdiagramme enthalten. Allerdings ist das Ganze in englischer Sprache. Google einfach nach "AN654" oder besorge Dir das PDF-File direkt bei [http://www.microchip.com]. Gruss Ottmar
Manuel W. schrieb: > Hallo Lisa, > > Wie ist dein aktueller Stand? > Benötigst du Unterstützung beim Schreiben des Programms, oder hängts > bereits bei der Inbetriebnahme der Toolchain? Ich benötige nur unterstützung beim schreiben.
Lisa Zwiletitsch schrieb: > Manuel W. schrieb: >> Hallo Lisa, >> >> Wie ist dein aktueller Stand? >> Benötigst du Unterstützung beim Schreiben des Programms, oder hängts >> bereits bei der Inbetriebnahme der Toolchain? > > Ich benötige nur Unterstützung beim schreiben. Okay. Und was genau ist das Problem an dem du hängst? Ich denke es fehlen noch einige Infos um dir helfen zu können.
Man könnte das Programm in 4 Bestandteile zerlegen. 1. AD Wandlung 2. Soft-PWM 3. Von 8bit in Prozent (in C eine Zeile, in ASM schon umständlicher) 4. Display ansteuern Die Frage ist: Wo brauchst du Hilfe? Und ist das Problem bei der Software - Realisierung oder beim Verständnis.
Manuel W. schrieb: > Lisa Zwiletitsch schrieb: >> Manuel W. schrieb: >>> Hallo Lisa, >>> >>> Wie ist dein aktueller Stand? >>> Benötigst du Unterstützung beim Schreiben des Programms, oder hängts >>> bereits bei der Inbetriebnahme der Toolchain? >> >> Ich benötige nur Unterstützung beim schreiben. > > Okay. Und was genau ist das Problem an dem du hängst? Ich denke es > fehlen noch einige Infos um dir helfen zu können. Ich habe schon mal ein Programm mit AD-Wandlung geschrieben, jedoch kann man mittels Poti nur die Frequenz verstellen, mit der die rote und die grüne LED abwechselnd blinken sollen. Wie kann ich das auf die Helligkeit umschreiben und dann habe ich noch keine Idee, wie das mit der Ausgabe der Prozentzahlen funktionieren könnte.
Michael Skropski schrieb: > Man könnte das Programm in 4 Bestandteile zerlegen. > 1. AD Wandlung > 2. Soft-PWM > 3. Von 8bit in Prozent (in C eine Zeile, in ASM schon umständlicher) > 4. Display ansteuern > > Die Frage ist: Wo brauchst du Hilfe? Und ist das Problem bei der > Software - Realisierung oder beim Verständnis. Das Problem liegt schon beim Verständnis, da ich nicht weiß, wie ich diese Punkte im Programm realisieren kann. Ich habe jedoch schon mal ein Programm geschrieben, bei dem mittels AD-Wandlung die abwechselnde Blinkfrequenz von roter und grüner LED eingestellt werden kann. Wie kann ich das auf die Helligkeit umlegen? Bei der PWM und der Prozentausgabe habe ich keine Idee, wie ich das realisieren könnte.
nicht"Gast" schrieb: > hallo, > > natürlich wird dir hier geholfen. Was konkret ist denn dein Problem? Ich weiß nicht, wie ich die PWM und die Ausgabe realisieren könnte.
also wenn du per poti die frequenz der led´s ändern kannst, heißt das eigentlich duty cycle. bei pwm ist normalerweise die frequenz fest und du änderst nur den duty cycle. um dir jetzt allerdings helligkeitswerte in form einer gedimmten led auszugeben versuchst, musst du tatsächlich die frequenz der pwm erhöhen. irgendwo in den khz bereich... wenn du dann mit dem duty cycle rumspielst, wirst du sehen wie sich die helligkeit der led verändert.
Lisa Zwiletitsch schrieb: > Ich weiß nicht, wie ich die PWM und die Ausgabe realisieren könnte. Die PWM sollte einfach zu realisieren sein. Einfach mit einem Timer einen IR auslösen, darin zählen auf den Periodenendwert (z.B. 255) Bei Null LED einschalten Den Wert vom AD Wandler als Duty Cycle verwenden. (Mit Zähler vergleichen und gegebenenfalls die LED ausschalten) Gibt es für die Displayausgabe eine Bibliothek ?
:
Bearbeitet durch User
Den PWM macht man mit einem timer, den man jeweils anders laedt. T1 + T2 ergeben die Repetitionsfrequenz, waehrend T1, die Einschaltzeit ist. Also definieren der timer frequenz auf zB 1ms. Ergibt N counts. Nun ist dann T1_counts : = T1 * N /(T1+T2) und T2_counts := N - T1_counts. Im Timer interrupt bewegt man dann den Port-Pin, und laedt den timer neu.
:
Bearbeitet durch User
Michael Skropski schrieb: > 3. Von 8bit in Prozent (in C eine Zeile, in ASM schon umständlicher) Umständlicher als in C auf jeden Fall aber nicht unbedingt schwierig - das MSB entspricht der Hälfte von 100% - das jeweils nächste der Hälfte des vorherigen ... Es gibt vielleicht weniger langweilige Lösungen, aber Umsetzten in Assembler Code sollte so absolut kein Problem darstellen.
Volker SchK schrieb: > Michael Skropski schrieb: >> 3. Von 8bit in Prozent (in C eine Zeile, in ASM schon umständlicher) > > Umständlicher als in C auf jeden Fall aber nicht unbedingt schwierig > - das MSB entspricht der Hälfte von 100% > - das jeweils nächste der Hälfte des vorherigen ... Ja, aber ohne weiteres addieren, je nach dem ob ein bit gesetzt ist, ist auch umständlich. Bei 50% und 25% macht es ja noch nichts, aber bei 12,5% muss man schon "Komma"Zahlen nehmen, was in ASM nicht direkt machbar ist (LSB wäre 0.390625%). Zumindest nicht, dass ichs wüsste. Und dann kommt noch ein Runden der Zahl und Trennung der einzelnen Ziffern für die Anzeige. Da lobe ich mir einen * und / Operator und ein printf(). Das ganze gerechne und Datentypen ist für mich ein großer Vorteil einer Hochsprache. Pinwackeln, Register beschreiben, das ist in ASM ja auch kein Ding. Aber manches.. Ich weiß noch, einmal sollte ich in der Ausbildung was in ASM realisieren, u.a. eine Berechnung. Da habe ich einen C Compiler genommen, die Berechnung da realisiert und hab mir neben der Hex noch die ASM ausgeben lassen. Ich konnte es dann auch nachvollziehen, aber wenn ich es von vornherein selbst hätte lösen sollen, hätte es deutlich länger gedauert. Dafür ist eine Hochsprache ja da, also nehme ich sie dafür auch.
Michael Skropski schrieb: > Volker SchK schrieb: >> Michael Skropski schrieb: >>> 3. Von 8bit in Prozent (in C eine Zeile, in ASM schon umständlicher) >> >> Umständlicher als in C auf jeden Fall aber nicht unbedingt schwierig >> - das MSB entspricht der Hälfte von 100% >> - das jeweils nächste der Hälfte des vorherigen ... > > Ja, aber ohne weiteres addieren, je nach dem ob ein bit gesetzt ist, ist > auch umständlich. Bei 50% und 25% macht es ja noch nichts, aber bei > 12,5% muss man schon "Komma"Zahlen nehmen, was in ASM nicht direkt > machbar ist (LSB wäre 0.390625%). Zumindest nicht, dass ichs wüsste. Das ist doch theoretischer Unfug 50,25,12,6,3,2,1,0 und fertig (gibt genau 99 ;-) Das Ganze ist eh ein bisschen fragwürdig, da das Auge keine lineare Wahrnehmung der Helligkeitsänderungen hat. Bei den kleinen Prozentzahlen wird man das viel stärker empfinden. Wenn man die % Anzeige an das Auge "anpassen" wollte, dann könnte man sich so einfach seine Wertigkeiten anpassen.
:
Bearbeitet durch User
Michael Skropski schrieb: > Ich weiß noch, einmal sollte ich in der Ausbildung was in ASM > realisieren, u.a. eine Berechnung. Da habe ich einen C Compiler > genommen, die Berechnung da realisiert und hab mir neben der Hex noch > die ASM ausgeben lassen. Ich konnte es dann auch nachvollziehen, aber > wenn ich es von vornherein selbst hätte lösen sollen, hätte es deutlich > länger gedauert. Dafür ist eine Hochsprache ja da, also nehme ich sie > dafür auch. Manchmal hab ich das Gefühl, Gleitkommazahlen werden nur benutzt weil eine Hochsprache das so einfach erscheinen lässt. Wirklich notwendig ist es doch in einer 8bit Umgebung eher selten.
:
Bearbeitet durch User
Volker SchK schrieb: > Das ist doch theoretischer Unfug > 50,25,12,6,3,2,1,0 und fertig (gibt genau 99 ;-) Naja. Wenn man 12 und 6 addiert, kommt 18 raus, wenn man 12,5 und 6,25 addiert, kommt 18.75, also gerundet 19 raus. Volker SchK schrieb: > Das Ganze ist eh ein bisschen fragwürdig, da das Auge keine lineare > Wahrnehmung der Helligkeitsänderungen hat. Bei den kleinen Prozentzahlen > wird man das viel stärker empfinden. Das ist richtig, vielleicht will der Lehrer darauf hinaus. Wer weiß. Volker SchK schrieb: > Manchmal hab ich das Gefühl, Gleitkommazahlen werden nur benutzt weil > eine Hochsprache das so einfach erscheinen lässt. > Wirklich notwendig ist es doch in einer 8bit Umgebung eher selten. Würde ich nicht sagen. 8bitter werden ja da genutzt, wo es nicht auf Rechenleistung ankommt. Also Labornetzteile, Waagen, Messschieber, Abstandsmesser... Alles da, wo genau gemessen wird (z.B. externer ADC) und intern dann mit einer (Gleit) kommazahl gearbeitet und ggf auch angezeigt wird. Ich arbeite fast ausschließlich mit PIC18, also 8bitter und habe schon oft float/double genutzt. Wäre manchmal vielleicht auch ohne gegangen, aber das würde dann das Programm umständlicher machen. Und nur, damit man sagen kann: "ich habs ohne hinbekommen" ? Vorausgesetzt, man ist nicht am Leistungslimit und muss Ressourcen sparen, wo es nur geht.
Michael Skropski schrieb: > Naja. Wenn man 12 und 6 addiert, kommt 18 raus, wenn man 12,5 und 6,25 > addiert, kommt 18.75, also gerundet 19 raus. Klar ist das nicht so genau wie eine Gleitkomma Berechnung (13,6,3,1,1,0 wäre vielleicht auch besser) aber brauch ich das wirklich ? Michael Skropski schrieb: > Würde ich nicht sagen. 8bitter werden ja da genutzt, wo es nicht auf > Rechenleistung ankommt. Also Labornetzteile, Waagen, Messschieber, > Abstandsmesser... Alles da, wo genau gemessen wird (z.B. externer ADC) > und intern dann mit einer (Gleit) kommazahl gearbeitet und ggf auch > angezeigt wird. Da wo es notwendig ist, sollte man es natürlich machen, aber dann vielleicht nicht unbedingt in ASM. Oft hilft es ja auch schon viel, wenn man bei der Maßeinheit in der gerechnet werden soll eine Stufe runter geht (z.B von Gramm auf 1/10, 1/100, Milligramm ... ) Den Dezimalpunkt in der Anzeige wird man dann schon noch hinkriegen.
Hallo Lisa, ich versuche mal Dir nachfolgend konkret Hilfestellung zu geben. Mit den nachstehenden Lösungsansätzen müsstes Du eigentlich zurecht kommen. Wenn nicht - frage bitte konkret nach. mfG Ottmar Zunächst das PWM-Prinzip mittels Interrupt-Service-Routine (ISR):
1 | ORG 0x004 ;Interrupt-Vector |
2 | TMR0-Overflow-Interrupt |
3 | z.B. Zyklus 100µs, wird erreicht mit fosc=8MHz, Prescaler TMR0 1:2 |
4 | ergibt mit korrektem TMR0-Preset einen overflow nach 100cyclen |
5 | (2.000.000Hz / 2 / 100 = 10.000 entspricht 0,0001s = 100µs |
6 | verwendete Register: OPTION_REG (clock source, Prescaler) |
7 | INTCON (GIE, T0IE, T0IF) |
8 | WREG + STATUS Register retten |
9 | ISR: |
10 | clrf INTCON,T0IF ;Interruptflag zurücksetzen |
11 | Preset TMR0 für overflow nach 100 TMR0-counts |
12 | ; |
13 | incf cntCycle,f ;bei jedem Interrpt +1 |
14 | ; |
15 | movlw .100 ;Reset des Zykluszählers beim wert=100 |
16 | xorwf cntCycle,w |
17 | btfsc STATUS,Z |
18 | clrf cntCycle |
19 | ; |
20 | ;PWM-Pin auf H setzen wenn cntPulsewidth >= cntCycle |
21 | ;PWM-Pin auf L setzen wenn cntPulsewidth < cntCycle |
22 | ; | PulseWidth | |
23 | ; |-ADC-Ergebnis/41-| |
24 | ; | z.b.50 | |
25 | ; |_________________| |
26 | ; | |____________| |
27 | ; 0 50 100 cntCycle |
28 | ; |
29 | ;PWM-OUTPUT |
30 | ;PWM-Pin = H wenn PulseWidth >= cntCycle |
31 | ; = L " " < cntCycle |
32 | movf cntCycle,w ;Zyklus innerhalb der Pulsbreite? |
33 | bcf STATUS,C ; (wird durch Subtraktion ermittelt) |
34 | subwf PulseWidth,w |
35 | btfsc STATUS,C ;C=1 Set PWM-Pin = H wenn C=1 |
36 | bsf PWM_OUT ; cntPulseWidth > cntCycle |
37 | btfss STATUS,C ;C=0 Set PWM-Pin = L Wenn C=0 |
38 | bcf PWM_OUT |
39 | ; |
40 | WREG + STATUS wieder herstellen |
41 | RETFIE |
42 | ;--------------------------------------------------------- |
43 | ; |
44 | -INIT |
45 | ADC-PORT initialsieren, analog-Input und PWM-Output-Pin festlegen |
46 | Register: PORTA, ANSEL, TRISA |
47 | Interner Oscillator max. 8MHz (entfällt bei Quarzoszillator) |
48 | PIC-CONFIG _INTRC_OSC_NOCLKOUT |
49 | Register: OSCCON |
50 | ADC-Modul |
51 | Register: ADCON0, ADCON1 |
52 | TMR0-Overflow-Interrupt |
53 | Register: INTCON,GIE, -,T0IE, -,T0IF |
54 | ;---------------------------------------------------------- |
55 | |
56 | -MAIN |
57 | CALL ADC ;Schleiferspannung des Poti in Binaerwert |
58 | CALL DIV16_8 ;(16Bit : 8Bit Ergebnis 8Bit) |
59 | movf f_divlo,w ;nomierten ADC-Wert kopieren |
60 | movf PulseWidth ;ISR-Vergleichsvariable fuer Pulsbreite |
61 | CALL Out_7Segment ;Duty Cycle 0-99 in LED-Anzeige ausgeben |
62 | GOTO MAIN |
63 | ;---------------------------------------------------------- |
64 | |
65 | ADC - siehe Datenblatt des 16F886 S. 101 und Codebeispiel S. 106 |
66 | movf ADRESH,w ;ADC-Ergebnis in Übergabevariable für |
67 | movwf f_divHi |
68 | movf ADRESL,w |
69 | movwf f_divlo |
70 | RETURN |
71 | ;---------------------------------------------------------- |
72 | ADC-Ergebnis = 0 - 4095 normiert auf 0 - 100 durch Division des ADC- |
73 | Ergebnisses durch 41 (4095/100 = 41 aufgerundet). |
74 | ; |
75 | DIV16_8 - siehe www.piclist.com/techref/microchip/math/div/16by8lz.htm |
76 | ;Divident: f_divhi:f_divlo, Ergebnis in f_divlo |
77 | movlw .41 ;Divident im WREG übergeben |
78 | CALL DIV16_8 |
79 | ; |
80 | movf f_divlo,w ;Quotient in Pulsbreitenzähler kopieren |
81 | movwf PulseWidth |
82 | RETURN |
83 | |
84 | Out_7Segment |
85 | vgl.: www.sprut.de/electronic/pic/programm/led.htm |
86 | RETURN |
87 | ; 7-Segment-Tabelle |
88 | Segmente |
89 | addwf PCL, f |
90 | retlw B'00011000' ; 0 |
91 | retlw B'11011110' ; 1 |
92 | retlw B'00110010' ; 2 |
93 | retlw B'01010010' ; 3 |
94 | retlw B'11010100' ; 4 |
95 | retlw B'01010001' ; 5 |
96 | retlw B'00010001' ; 6 |
97 | retlw B'11011010' ; 7 |
98 | retlw B'00010000' ; 8 |
99 | retlw B'01010000' ; 9 |
100 | -END |
:
Bearbeitet durch User
Ottmar K. schrieb: > Hallo Lisa, > > ich versuche mal Dir nachfolgend konkret Hilfestellung zu geben ... Und ich hab gedacht wir hätten schon viel zu viel geholfen und sollten abwarten ob konkrete Fragen von Lisa kommen, die ja auch selber was tun wollte ;-) Wirklich "ORG" ? Hoffentlich benutzt der Prof. in seinem "Grundgerüst" schon "CODE" (so wie die "relocatable" templates welche mit MPASM kommen)
1 | RESET_VECTOR CODE 0x0000 ; processor reset vector |
2 | pagesel start |
3 | goto start ; go to beginning of program |
4 | |
5 | |
6 | INT_VECTOR CODE 0x0004 ; interrupt vector location |
Volker SchK schrieb: > Wirklich "ORG" ? > Hoffentlich benutzt der Prof. in seinem "Grundgerüst" schon "CODE" Na ja, wenn es da nicht mehr zu kritisieren gibt... Es duerfte ja jemanden mit ein bisschen Ahnung von MPASM-Assembler ueberhaupt nicht schwerfallen, absoluten code in relocatable umzusetzen! Von relocatable code war ja bisher nicht die Rede... mfG Ottmar
Ok sorry. (das mit dem "ORG" und am besten noch Variablen über EQU scheint so einen Reflex bei mir auszulösen ;-) Ich habe die Auffassung, absoluten Code sollte man einem Anfänger gar nicht mehr zeigen. Zugegeben an meiner Hochschule gibt es sowas auch noch. "Aus didaktischen Gründen" :-(
Absoluten Code hat gewisse Vorteile, aber es stimmt, wenn man sowieso nur ARDUINO MEGA und STM32 verwenden wird, bzw gleich RPI weil man mit kleineren nicht zurechtkommt, wie es heute ist, dann stimmt der Gedankengang. Speziell bei Pic ist relativer code problematisch, da man lcall verwenden muss, aber bei Lcall sind skipc, usw praktisch nicht verwendbar, da lcall ein macro aus 2-3 Befehlen ist.
chris schrieb: > Absoluten Code hat gewisse Vorteile... Echt, welche ? Mir fällt jetzt spontan nichts ein, was ich relocatable nicht auch machen könnte. ABER, ich verwende nur noch sehr selten Assembler, also bin ich da vielleicht nicht so sensibel ...
Ottmar K. schrieb: > Hallo Lisa, > > ich versuche mal Dir nachfolgend konkret Hilfestellung zu geben. > Mit den nachstehenden Lösungsansätzen müsstes Du eigentlich zurecht > kommen. Wenn nicht - frage bitte konkret nach. > > mfG Ottmar > > Zunächst das PWM-Prinzip mittels Interrupt-Service-Routine (ISR): > ORG 0x004 ;Interrupt-Vector > TMR0-Overflow-Interrupt > z.B. Zyklus 100µs, wird erreicht mit fosc=8MHz, Prescaler TMR0 1:2 > ergibt mit korrektem TMR0-Preset einen overflow nach 100cyclen > (2.000.000Hz 2 100 = 10.000 entspricht 0,0001s = 100µs > verwendete Register: OPTION_REG (clock source, Prescaler) > INTCON (GIE, T0IE, T0IF) > WREG + STATUS Register retten > ISR: > clrf INTCON,T0IF ;Interruptflag zurücksetzen > Preset TMR0 für overflow nach 100 TMR0-counts > ; > incf cntCycle,f ;bei jedem Interrpt +1 > ; > movlw .100 ;Reset des Zykluszählers beim wert=100 > xorwf cntCycle,w > btfsc STATUS,Z > clrf cntCycle > ; > ;PWM-Pin auf H setzen wenn cntPulsewidth >= cntCycle > ;PWM-Pin auf L setzen wenn cntPulsewidth < cntCycle > ; | PulseWidth | > ; |-ADC-Ergebnis/41-| > ; | z.b.50 | > ; |_________________| > ; | |____________| > ; 0 50 100 cntCycle > ; > ;PWM-OUTPUT > ;PWM-Pin = H wenn PulseWidth >= cntCycle > ; = L " " < cntCycle > movf cntCycle,w ;Zyklus innerhalb der Pulsbreite? > bcf STATUS,C ; (wird durch Subtraktion ermittelt) > subwf PulseWidth,w > btfsc STATUS,C ;C=1 Set PWM-Pin = H wenn C=1 > bsf PWM_OUT ; cntPulseWidth > cntCycle > btfss STATUS,C ;C=0 Set PWM-Pin = L Wenn C=0 > bcf PWM_OUT > ; > WREG + STATUS wieder herstellen > RETFIE > ;--------------------------------------------------------- > ; > -INIT > ADC-PORT initialsieren, analog-Input und PWM-Output-Pin festlegen > Register: PORTA, ANSEL, TRISA > Interner Oscillator max. 8MHz (entfällt bei Quarzoszillator) > PIC-CONFIG _INTRC_OSC_NOCLKOUT > Register: OSCCON > ADC-Modul > Register: ADCON0, ADCON1 > TMR0-Overflow-Interrupt > Register: INTCON,GIE, -,T0IE, -,T0IF > ;---------------------------------------------------------- > > -MAIN > CALL ADC ;Schleiferspannung des Poti in Binaerwert > CALL DIV16_8 ;(16Bit : 8Bit Ergebnis 8Bit) > movf f_divlo,w ;nomierten ADC-Wert kopieren > movf PulseWidth ;ISR-Vergleichsvariable fuer Pulsbreite > CALL Out_7Segment ;Duty Cycle 0-99 in LED-Anzeige ausgeben > GOTO MAIN > ;---------------------------------------------------------- > > ADC - siehe Datenblatt des 16F886 S. 101 und Codebeispiel S. 106 > movf ADRESH,w ;ADC-Ergebnis in Übergabevariable für > movwf f_divHi > movf ADRESL,w > movwf f_divlo > RETURN > ;---------------------------------------------------------- > ADC-Ergebnis = 0 - 4095 normiert auf 0 - 100 durch Division des ADC- > Ergebnisses durch 41 (4095/100 = 41 aufgerundet). > ; > DIV16_8 - siehe www.piclist.com/techref/microchip/math/div/16by8lz.htm > ;Divident: f_divhi:f_divlo, Ergebnis in f_divlo > movlw .41 ;Divident im WREG übergeben > CALL DIV16_8 > ; > movf f_divlo,w ;Quotient in Pulsbreitenzähler kopieren > movwf PulseWidth > RETURN > > Out_7Segment > vgl.: www.sprut.de/electronic/pic/programm/led.htm > RETURN > ; 7-Segment-Tabelle > Segmente > addwf PCL, f > retlw B'00011000' ; 0 > retlw B'11011110' ; 1 > retlw B'00110010' ; 2 > retlw B'01010010' ; 3 > retlw B'11010100' ; 4 > retlw B'01010001' ; 5 > retlw B'00010001' ; 6 > retlw B'11011010' ; 7 > retlw B'00010000' ; 8 > retlw B'01010000' ; 9 > -END Zuerst mal danke für die Hilfe!! Theoretisch habe ich die Vorgehensweise verstanden, aber nachfolgend noch ein paar Fragen: 1. Wo realisiere ich die PWM im Programm? Vor der Mainroutine oder danach? 2. Das Programm, das ich als "Vorlage" verwende, sieht derzeit folgendermaßen aus:
1 | TITLE "UE1.asm" ; |
2 | LIST C=135 ;number of columns |
3 | LIST N=65 ;number of lines |
4 | #include <p16f886.inc> |
5 | LIST p=16F886 |
6 | |
7 | |
8 | ;################# Configurationsbits Einstellung |
9 | __config _CONFIG1,0x23E4 |
10 | __config _CONFIG2,0x3EFF |
11 | ;############ |
12 | |
13 | ;************************************************************************************** |
14 | ; HW Konfiguration declaration |
15 | ;************************************************************************************** |
16 | ;## 7 Segmentanzeige |
17 | #define A_SEG PORTC,0 |
18 | #define B_SEG PORTC,1 |
19 | #define C_SEG PORTC,2 |
20 | #define D_SEG PORTC,3 |
21 | #define E_SEG PORTC,4 |
22 | #define F_SEG PORTC,5 |
23 | #define G_SEG PORTA,4 |
24 | #define DP_SEG PORTB,4 |
25 | |
26 | #define SEG0 PORTB,0 |
27 | #define SEG1 PORTB,1 |
28 | #define SEG2 PORTB,2 |
29 | #define SEG3 PORTB,3 |
30 | |
31 | ;## Leds |
32 | #define LED_GRUEN PORTA,5 |
33 | #define LED_ROT PORTA,6 |
34 | #define LED_GELB PORTA,7 |
35 | |
36 | ;## Analogpins |
37 | #define POTI PORTA,0 |
38 | #define TEMP PORTA,1 |
39 | #define LDR PORTA,2 |
40 | |
41 | ;## Taster |
42 | #define S1 PORTB,5 |
43 | #define S2 PORTA,3 |
44 | |
45 | ;## RS232 |
46 | #define TX PORTC,6 |
47 | #define RX PORTC,7 |
48 | ;************************************************************************************** |
49 | |
50 | ;Makros |
51 | Bank0 MACRO ;macro to select data RAM bank 0 |
52 | bcf STATUS,RP0 |
53 | bcf STATUS,RP1 |
54 | ENDM |
55 | |
56 | Bank1 MACRO ;macro to select data RAM bank 1 |
57 | bsf STATUS,RP0 |
58 | bcf STATUS,RP1 |
59 | ENDM |
60 | Bank2 MACRO ;macro to select data RAM bank 2 |
61 | bcf STATUS,RP0 |
62 | bsf STATUS,RP1 |
63 | ENDM |
64 | |
65 | Bank3 MACRO ;macro to select data RAM bank 3 |
66 | bsf STATUS,RP0 |
67 | bsf STATUS,RP1 |
68 | ENDM |
69 | |
70 | |
71 | ;************************************************************************************** |
72 | ; declaration of used variables (register) |
73 | ;************************************************************************************** |
74 | CBLOCK 20h ;starting adress of variables |
75 | zahl |
76 | temp |
77 | wait_tmp1 |
78 | wait_tmp2 |
79 | ad_low |
80 | ad_high |
81 | ENDC ;end of byte variables |
82 | |
83 | |
84 | ;************************************************************************************** |
85 | ; Program: |
86 | ; ******************************************************************************* |
87 | ; written by ZWILETITSCH |
88 | ; |
89 | ; Date: 05.10.2012 Version: 1.0 |
90 | ; Last modify: |
91 | ; ******************************************************************************* |
92 | ; CPU running with 4 MHz oscillator |
93 | ;************************************************************************************** |
94 | ORG 0000 |
95 | goto main |
96 | ORG 0004 |
97 | ;goto int_sub ;falls benutzt einblenden |
98 | ORG 0008 |
99 | |
100 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
101 | ;Lookup Tabelle -a- |
102 | ; Segmentaufteilung -gfedcba f b |
103 | ; -g- |
104 | ; e c |
105 | ; -d- |
106 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
107 | get_value addwf PCL,f |
108 | retlw b'00111111' ;Zahl 0 |
109 | retlw b'00000110' ;Zahl 1 |
110 | retlw b'01011011' ;Zahl 2 |
111 | retlw b'01001111' ;Zahl 3 |
112 | retlw b'01100110' ;Zahl 4 |
113 | retlw b'01101101' ;Zahl 5 |
114 | retlw b'01111101' ;Zahl 6 |
115 | retlw b'00000111' ;Zahl 7 |
116 | retlw b'01111111' ;Zahl 8 |
117 | retlw b'01101111' ;Zahl 9 |
118 | retlw b'01110111' ;Zahl 10=A |
119 | retlw b'01111100' ;Zahl 11=b |
120 | retlw b'01011000' ;Zahl 12=c |
121 | retlw b'01011110' ;Zahl 13=d |
122 | retlw b'01111001' ;Zahl 14=E |
123 | retlw b'01110001' ;Zahl 15=F |
124 | |
125 | |
126 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
127 | ;Beginn des Mainprogrammes |
128 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
129 | |
130 | ;************************************************************************************** |
131 | ; MAINROUTINE: main |
132 | ;************************************************************************************** |
133 | main call init_pic ;Aufruf Subroutinen |
134 | call wait_1ms |
135 | |
136 | ;Aktivierung rote LED |
137 | set_0 bsf LED_ROT ;Rote LED einschalten |
138 | |
139 | ;Tastenabfrage |
140 | frage btfss S1 ;Taste 1 gedrückt? |
141 | goto $-1 ; goto previous instruction |
142 | |
143 | ;Aktivierung LEDs blinken |
144 | set_wechsel call init_adc |
145 | call adc_8bit |
146 | |
147 | |
148 | bsf LED_ROT |
149 | |
150 | |
151 | movwf ad_low |
152 | call wait_xms |
153 | |
154 | bcf LED_ROT |
155 | |
156 | ; bsf LED_GRUEN |
157 | ; |
158 | ; |
159 | ; movwf ad_low |
160 | ; call wait_xms |
161 | ; |
162 | ; bcf LED_GRUEN |
163 | ; |
164 | ; |
165 | ; btfss S2 ;wenn S2 gedrückt, nächste Zeile überspringen |
166 | ; goto set_wechsel |
167 | ; goto set_0 ;wenn S2 gedrückt, zurück zu nur roter LED |
168 | ; |
169 | |
170 | |
171 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
172 | ;Beginn der Subroutines |
173 | ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
174 | |
175 | ;************************************************************************************** |
176 | ; SUBROUTINE: Wartezeiten |
177 | ; @ 4MHz |
178 | ; 1Takt=1usec exakte wartezeit=1028us |
179 | ;************************************************************************************** |
180 | wait_1ms clrf wait_tmp1 |
181 | nop |
182 | decfsz wait_tmp1,f |
183 | goto $-2 |
184 | return |
185 | |
186 | wait_xms movwf wait_tmp2 |
187 | call wait_1ms |
188 | decfsz wait_tmp2,f |
189 | goto $-2 |
190 | return |
191 | |
192 | ;************************************************************************************** |
193 | ; SUBROUTINE: initial PIC |
194 | ;************************************************************************************** |
195 | init_pic Bank0 ;select Bank 0 |
196 | clrf PORTA ;initialice porta, portb and portc |
197 | clrf PORTB |
198 | clrf PORTC |
199 | |
200 | ;register configure BANK 1 |
201 | Bank1 ;select Bank 1 |
202 | |
203 | ;Internen Oszilator einstellen 4MHz |
204 | movlw b'01100001' |
205 | movwf OSCCON |
206 | |
207 | ;option_reg Control-Register??? |
208 | movlw b'10000111' ;pullup disable, |
209 | movwf OPTION_REG ;option_reg register (tm0 1:256 etc.) |
210 | |
211 | ;Port Control-Register??? |
212 | movlw b'00001111' ;OUT/IN definieren |
213 | movwf TRISA |
214 | movlw b'11100000' ;OUT/IN definieren |
215 | movwf TRISB |
216 | movlw b'10000000' ;OUT/IN definieren |
217 | movwf TRISC |
218 | |
219 | ;Interrupt Control-Register??? |
220 | movlw b'00000000' ;all Interrupts disable |
221 | movwf INTCON |
222 | |
223 | ;register configure BANK 3 |
224 | Bank3 ;select Bank 3 |
225 | movlw b'00000111' |
226 | movwf ANSEL ;AN0,1,2 = Analog |
227 | clrf ANSELH ;Rest digital |
228 | |
229 | ;register configure BANK 0 |
230 | Bank0 ;select Bank 0 |
231 | clrf ADCON0 ;AD Converter = off |
232 | |
233 | retlw 00h |
234 | ;************************************************************************************** |
235 | |
236 | ;************************************************************************************** |
237 | ; SUBROUTINE: Zahl ausgeben |
238 | ;************************************************************************************** |
239 | set_zahl andlw b'00001111' ;auf 0-15 limitieren |
240 | call get_value ;Wert aus Lookup holen |
241 | movwf temp ;Zwischenspeichern |
242 | movwf PORTC ;Segmente setzen |
243 | btfss temp,6 ;Segment g extra setzen |
244 | bcf G_SEG |
245 | btfsc temp,6 |
246 | bsf G_SEG |
247 | return |
248 | ;************************************************************************************** |
249 | |
250 | ;************************************************************************************** |
251 | ; SUBROUTINE: ADC - Messung |
252 | ;************************************************************************************** |
253 | |
254 | init_adc ;AD0,1,2 als Input und Analog (bereits in Init_pic passiert) |
255 | |
256 | ;ADCON Register konfigurieren |
257 | |
258 | Bank1 |
259 | movlw b'10000000' ;Right justified, Vss,Vdd=Referenz |
260 | movwf ADCON1 |
261 | Bank0 |
262 | movlw b'01000001' ;FOSC/8, AN0(poti) default, AD=on |
263 | movwf ADCON0 |
264 | return |
265 | |
266 | ;----------------- |
267 | |
268 | adc_8bit Bank1 |
269 | bcf ADCON1,ADFM ;left justified |
270 | Bank0 |
271 | bsf ADCON0,GO_DONE ;Messung starten |
272 | btfsc ADCON0,GO_DONE ;Messung fertig? |
273 | goto $-1 |
274 | movf ADRESH,w |
275 | movwf ad_low ;Wert ins Low eintragen |
276 | clrf ad_high ;High loeschen |
277 | return |
278 | |
279 | |
280 | end |
Kann ich diesen grundsätzlich so weiterverwenden? LG Lisa
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.