Siro
17.09.2020, 20:07
Hallo zusammen,
ich steuere grad mit dem PIC10F332 einen RGB-Stripe an.
Das fuktioniert auch schon ganz hervorragend, bin ganz begeistert.
Sein maximales Timing bekommt das grade so auf die Reihe.
Die Ausschiebefunktion musste ich jedoch in Assembler implementieren wegen der Laufzeit
und da taucht nun ein "kleines" Problemchen auf:
In der Ausschiebefunktion benötige ich auch die Anzahl der LEDs die ich mit
#define LED_COUNT 4
in "C" declariert habe.
Wie komme ich da aber ran innerhalb meiner Assembler Ausschiebefunktion ?
Natürlich kann ich in Assembler hier den Wert multipliziert mit 3 direkt ins Register laden,
aber dann muss ich bei Änderungen von LED_COUNT auch jedesmal den Assemblercode ändern,
das halte ich für eine "schlechte/unschöne" Programmierung.
....vegesse ich auch garantiert irgendwann wenn ich später mal Änderungen vornehme...;)
// Declaration einer einzelnen RGB LED
// Jede LED hat 3 Bytes, insgesamt also 24 Bits
typedef struct // __pack ? bei 8 Bittern unnötig, ist immer packed
{
U8 green; /* 8 Bit fuer die Helligkeit gruen */
U8 red; /* 8 Bit fuer die Helligkeit rot */
U8 blue; /* 8 Bit fuer die Helligkeit blau */
} TLed; /* Type Bezeichner ist TLed */
#define LED_COUNT 4 // Anzahl der anzusteuernden RGB Leds
TLed LedArray[LED_COUNT]; // gesamtes Datenarray der Ledkette
// dieses Array wird dann per Assmblercode ausgeschoben
//------------------------------------------------------------------------------
// Der Assembler-Code zum Ausschieben von LedArray:
// für 250ns Instruction Cycle Time 4 MHz
// PMDATL enthält das auszuschiebene Datenbyte für die WS2812 RGB-Led Kette
// wird also als Zwischenspeicher benutzt. (8 Bit Register)
// PMADRL wird für den Bytezähler benutzt (8 Bit Register)
// PMDATH wird als Bitzähler benutzt !!! ist nur ein 6 Bit Register
// das reicht aber, wir zählen ja nur von 8 bis 0
void asm_LedShiftOut(void)
{
asm("movlw LOW _LedArray"); // address of LedArray
asm("movwf FSR"); // to FSR index register
asm("movlw 12"); // <==== eigentlich LED_COUNT * 3) das geht aber nicht <======
asm("movwf PMADRL"); // use PMADRL as byteCount
asm("Label_NextByte:"); // !! WICHTIG, der Doppelpunkt ab XC8 V2.20 !!
asm("movlw 8"); // set bit count to 8
asm("movwf PMDATH"); // use PMDATH as Bitcounter
asm("movf INDF,W"); // load byte from LedArray to W register
asm("movwf PMDATL"); // save Databyte to PMDATL
asm("Label_ByteLoop:");
asm("btfsc PMDATL,7"); // scip if databit is clear (MSB)
asm("goto Label_High"); // else databit ist set
asm("bsf LATA,0"); // set WS2812 DataLine to High 250ns
asm("bcf LATA,0"); // set WS2812 DataLine to Low
asm("goto Label_nextBit");
asm("Label_High:"); // High Bit
asm("bsf LATA,0"); // set WS2812 DataLine to High
asm("NOP"); asm("NOP"); asm("NOP"); // hold Line High for 1000ns
asm("bcf LATA,0"); // set Line to Low
asm("Label_nextBit:");
asm("rlf PMDATL,F"); // databyte left
asm("decfsz PMDATH,F"); // bitCount-1, scip if all bits done
asm("goto Label_ByteLoop"); // next bit
asm("incf FSR,F"); // address pointer to next Led Byte
asm("decfsz PMADRL,F"); // byteCount-1 scip if all bytes done
asm("goto Label_NextByte"); // else send next byte
// __delay_us(100); // Das Ende der Datenübertragung erreicht wenn die Leitung länger als 50us Low bleibt.
// !!! mindestens 80us bei SK68 Leds
// hier brauche ich eigentlich nicht warten, weil der restliche Programmcode benötigt ja schon Zeit ???
asm("movlw 0x85"); // das sind 100us
asm("movwf PMDATL");
asm("Label_delay100:");
asm("decfsz PMDATL,F");
asm("goto Label_delay100");
}
Vielleicht habt Ihr eine Idee wie man das evtl. auch anders lösen kann.
Siro
ich steuere grad mit dem PIC10F332 einen RGB-Stripe an.
Das fuktioniert auch schon ganz hervorragend, bin ganz begeistert.
Sein maximales Timing bekommt das grade so auf die Reihe.
Die Ausschiebefunktion musste ich jedoch in Assembler implementieren wegen der Laufzeit
und da taucht nun ein "kleines" Problemchen auf:
In der Ausschiebefunktion benötige ich auch die Anzahl der LEDs die ich mit
#define LED_COUNT 4
in "C" declariert habe.
Wie komme ich da aber ran innerhalb meiner Assembler Ausschiebefunktion ?
Natürlich kann ich in Assembler hier den Wert multipliziert mit 3 direkt ins Register laden,
aber dann muss ich bei Änderungen von LED_COUNT auch jedesmal den Assemblercode ändern,
das halte ich für eine "schlechte/unschöne" Programmierung.
....vegesse ich auch garantiert irgendwann wenn ich später mal Änderungen vornehme...;)
// Declaration einer einzelnen RGB LED
// Jede LED hat 3 Bytes, insgesamt also 24 Bits
typedef struct // __pack ? bei 8 Bittern unnötig, ist immer packed
{
U8 green; /* 8 Bit fuer die Helligkeit gruen */
U8 red; /* 8 Bit fuer die Helligkeit rot */
U8 blue; /* 8 Bit fuer die Helligkeit blau */
} TLed; /* Type Bezeichner ist TLed */
#define LED_COUNT 4 // Anzahl der anzusteuernden RGB Leds
TLed LedArray[LED_COUNT]; // gesamtes Datenarray der Ledkette
// dieses Array wird dann per Assmblercode ausgeschoben
//------------------------------------------------------------------------------
// Der Assembler-Code zum Ausschieben von LedArray:
// für 250ns Instruction Cycle Time 4 MHz
// PMDATL enthält das auszuschiebene Datenbyte für die WS2812 RGB-Led Kette
// wird also als Zwischenspeicher benutzt. (8 Bit Register)
// PMADRL wird für den Bytezähler benutzt (8 Bit Register)
// PMDATH wird als Bitzähler benutzt !!! ist nur ein 6 Bit Register
// das reicht aber, wir zählen ja nur von 8 bis 0
void asm_LedShiftOut(void)
{
asm("movlw LOW _LedArray"); // address of LedArray
asm("movwf FSR"); // to FSR index register
asm("movlw 12"); // <==== eigentlich LED_COUNT * 3) das geht aber nicht <======
asm("movwf PMADRL"); // use PMADRL as byteCount
asm("Label_NextByte:"); // !! WICHTIG, der Doppelpunkt ab XC8 V2.20 !!
asm("movlw 8"); // set bit count to 8
asm("movwf PMDATH"); // use PMDATH as Bitcounter
asm("movf INDF,W"); // load byte from LedArray to W register
asm("movwf PMDATL"); // save Databyte to PMDATL
asm("Label_ByteLoop:");
asm("btfsc PMDATL,7"); // scip if databit is clear (MSB)
asm("goto Label_High"); // else databit ist set
asm("bsf LATA,0"); // set WS2812 DataLine to High 250ns
asm("bcf LATA,0"); // set WS2812 DataLine to Low
asm("goto Label_nextBit");
asm("Label_High:"); // High Bit
asm("bsf LATA,0"); // set WS2812 DataLine to High
asm("NOP"); asm("NOP"); asm("NOP"); // hold Line High for 1000ns
asm("bcf LATA,0"); // set Line to Low
asm("Label_nextBit:");
asm("rlf PMDATL,F"); // databyte left
asm("decfsz PMDATH,F"); // bitCount-1, scip if all bits done
asm("goto Label_ByteLoop"); // next bit
asm("incf FSR,F"); // address pointer to next Led Byte
asm("decfsz PMADRL,F"); // byteCount-1 scip if all bytes done
asm("goto Label_NextByte"); // else send next byte
// __delay_us(100); // Das Ende der Datenübertragung erreicht wenn die Leitung länger als 50us Low bleibt.
// !!! mindestens 80us bei SK68 Leds
// hier brauche ich eigentlich nicht warten, weil der restliche Programmcode benötigt ja schon Zeit ???
asm("movlw 0x85"); // das sind 100us
asm("movwf PMDATL");
asm("Label_delay100:");
asm("decfsz PMDATL,F");
asm("goto Label_delay100");
}
Vielleicht habt Ihr eine Idee wie man das evtl. auch anders lösen kann.
Siro