Code:
	/* 
  File:   main.c
  Date:   06.02.2021  
  Author: Siro
  Projekt: 10F322  RGB-Ansteuerung 
  18 LEDs für den K110 Hubschrauber
  Einige Assembler Optimierungen vorgenommen
  !!! PMDATH und PMDATL sind nicht initialisiert nach einem Reset
  250ns Instruction Cycle, 4 MHz
  Der Stripe mit 18 LEDs zieht knapp 100mA bei voller Helligkeit "einer" von 3 LEDs ROT oder GRÜN oder BLAU
  Bei halber Helligkeit 0x7F nur ca. 50mA
  RA3 low  LED heller  0xFF 
  RA3 high LED dunkler 0x7F
  Stripe mit 18 LEDs wiegt knapp 0,6 Gramm
  Auch bei 1,65 Volt lief die Schaltung noch mit LEDs !!!!!
  die blauen LEDs brauchen aber mindestens 2,5 Volt und sind dann noch recht dunkel
*/
 
// PIC10F322 Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = INTOSC    // Oscillator Selection bits (INTOSC oscillator: CLKIN function disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
#pragma config LPBOR = OFF      // Brown-out Reset Selection bits (BOR disabled)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#include <xc.h>   // die einzige Headerdatei die benötigt wird.
// benötigen wir nicht, das Delay erzeugen wir selbst mittel Timer 0
// #define _XTAL_FREQ 16000000  // für 4 MHz instrction cylce time wegen der 4 stage pipeline 
/*----------------------------------------------------------------------*/
/* hier habe ich meine eigenen Datentypen definiert:  */
typedef unsigned char BOOL;   /*  0=FALSE,  all others are TRUE */    
typedef unsigned char   U8;   /*  8 Bit ohne Vorzeichen */
typedef signed   char   S8;
typedef unsigned short U16;   /* 16 Bit ohne Vorzeichen */
typedef unsigned long  U32;   /* 32 Bit ohne Vorzeichen */
/* dem Datentyp BOOL sollten nur diese Konstanten zugeordnet werden:    */
#define FALSE (0)            /* Eine 0  bedeutet FALSE (falsch)         */
#define TRUE  (!FALSE)       /* alle anderen Werte bedeuten TRUE (wahr) */
// Die HARDWARE : 2 LEDs, 1 RGB Stripe WS2812 / SK68 kompatibel mit 18 LEDs
// LED 1 connected to pin RA0
#define LED1_ON  LATA0=1 
#define LED1_OFF LATA0=0
// LED 2 connected to pin RA1
#define LED2_ON  LATA1=1 
#define LED2_OFF LATA1=0
// 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 18         // Anzahl der anzusteuernden RGB Leds max 18 ???
TLed LedArray[LED_COUNT];   // gesamtes Datenarray der Ledkette 
// dieses Array wird dann per Assmblercode ausgeschoben
// U8 ArraySize = sizeof(LedArray);  // die Groesse des Arrays in Bytes
// hier liegt eine Tabelle mit den ADU Werten für die entsprechende Spannung
// ADU ==> Voltage.
const U8 ADU_Table[] = 
{
  161,  // 3,25
  160,  // 3,28
  158,  // 3,31
  157,  // 3,34
  156,  // 3.37
  154,  // 3,40
  153,  // 3,43
  152,  // 3,46
  150,  // 3,39
  149,  // 3,52
  148,  // 3,55
  146,  // 3,58
  145,  // 3,61
  144,  // 3,64
  143,  // 3,67
  142,  // 3,70
  141,  // 3,73
  128   // 4,10 
};
//------------------------------------------------------------------------------
// 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
// !!! PMDATH ist nach reset nicht initialisiert, aber selbst mit dem Wert FF
// habe ich das optisch nicht wahrnehmen können.
void asm_LedShiftOut(void)
{
//  asm ("clrf  PMDATH");    // wegen  optimierten bsf PMDATH,3  in der NextByte Loop 
//  asm ("incf  PMDATH,F");  // testweise mal gucken
  
  GIE=0;                       // global interrupt disable
  
  asm("movlw LOW _LedArray");  // address of LedArray
  asm("movwf FSR");            // to FSR index register
  asm("movlw 18*3");
  asm("movwf PMADRL");         // use PMADRL as byteCount
  
asm("Label_NextByte:");        // !! WICHTIG, der Doppelpunkt ab XC8 V2.20
  asm("bsf   PMDATH,3");       // PMDATH = 8
  asm("movf  INDF,W");         // load byte from LedArray
  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,2");           // set WS2812 DataLine to High 250ns
  asm("bcf LATA,2");           // set WS2812 DataLine to Low
  asm("goto Label_nextBit");
 
asm("Label_High:");            // High Databit
  asm("bsf LATA,2");           // set WS2812 DataLine to High
  asm("goto $+1");
  asm("bcf LATA,2");           // set Line to Low
asm("Label_nextBit:");
  asm("rlf PMDATL,F");          // databyte left
  asm("decfsz PMDATH,F");       // bitCount-1, scip if all bits done, bit count -1
  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
  GIE=1;                        // global interrupt enable
  //   __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 die Zeit ???
//   asm("movlw 0x85");           // das sind 100us 
//   asm("movwf PMDATL");
//   asm("Label_delay100:");
//   asm("decfsz PMDATL,F");
//   asm("goto Label_delay100");
// asm("NOP");   // nur um Breakpoint zu setzen, Zeit messen
}
//------------------------------------------------------------------------------
// global interrupt function
// PWM1DCH wird runtergezählt wenn noch nicht 0
// PWM1DCH dient also als globale Zählvariable
void __interrupt() isr(void)    // ORG 0x0004
{
  TMR0   = 100;  // restart timer 0 value for 10ms
  TMR0IF = 0;    // clear the timer 0 interrupt flag
  if (PWM1DCH)   // wenn die Zählvariable noch nicht 0 ist,
    PWM1DCH--;   // dann ziehen wir eins ab.
}
//------------------------------------------------------------------------------
// PWM1DCH wird im Timer 0 Interrupt alle 10ms um eins runtergezählt
// solange der Wert noch nicht 0 ist. 
// !! RAM ist knapp:
// PWM1DCH wird als Zählvariable benutzt, ein 8 Bit Register welches wir nicht 
// benötigen. 
void Delay_10ms(U8 cnt)
{
  PWM1DCH = cnt;      // setzte Wert für 10ms * cnt
  while (PWM1DCH) ;   // warte bis count 0 wird.
}
//------------------------------------------------------------------------------
void FillGreen(void)   // wird nicht benutzt
{ U8 i;
  for (i=0; i<LED_COUNT; i++)
  {
    LedArray[i].red   = 0x00;
    LedArray[i].green = 0x7F;
    LedArray[i].blue  = 0x00;      
  }  
}
void asm_FillGreen(void)   // wird nicht benutzt
{ 
  asm("movlw LOW _LedArray");  // address of LedArray
  asm("movwf FSR");            // to FSR index register
  asm("movlw 18");           // LED_COUNT  Led Counter
  asm("movwf PMADRL");       // use PMADRL as counter
asm("FillGreenLoop:");  
  asm("movlw 0x7F");
  asm("movwf INDF");         // save byte to Array .green
  asm("incf FSR,F");
  
  asm("clrw");
  asm("movwf INDF");         // save byte to Array .red
  asm("incf FSR,F");  
  
  asm("movwf INDF");         // save byte to Array .blue 
  asm("incf FSR,F");  
 
  asm("decfsz PMADRL,F");
  asm("goto FillGreenLoop");  
}
void asm_FillRed(void)
{ 
  asm("movlw LOW _LedArray");  // address of LedArray
  asm("movwf FSR");            // to FSR index register
  asm("movlw 18");           // LED_COUNT  Led Counter
  asm("movwf PMADRL");       // use PMADRL as counter
asm("FillRedLoop:");
  asm("clrw");
  asm("movwf INDF");         // save byte to Array .green
  asm("incf FSR,F");
  
  asm("movlw 0x7F");
  asm("movwf INDF");         // save byte to Array .red
  asm("incf FSR,F");  
  
  asm("clrw");
  asm("movwf INDF");         // save byte to Array .blue 
  asm("incf FSR,F");  
 
  asm("decfsz PMADRL,F");
  asm("goto FillRedLoop");  
}
void asm_FillBlue(void)
{ 
  asm("movlw LOW _LedArray");  // address of LedArray
  asm("movwf FSR");            // to FSR index register
  asm("movlw 18");           // LED_COUNT  Led Counter
  asm("movwf PMADRL");       // use PMADRL as counter
asm("FillBlueLoop:");
  asm("clrw");
  asm("movwf INDF");         // save byte to Array .green
  asm("incf FSR,F");
  
  asm("movwf INDF");         // save byte to Array .red
  asm("incf FSR,F");  
  
  asm("movlw 0x7F");
  asm("movwf INDF");         // save byte to Array .blue 
  asm("incf FSR,F");  
 
  asm("decfsz PMADRL,F");
  asm("goto FillBlueLoop");  
}
//------------------------------------------------------------------------------
void Calculate(void)
{ U8* p = (U8*)LedArray;
  U8 i;
  
  for (i=0; i < sizeof(ADU_Table); i++)
  {  
    if (ADRES < ADU_Table[i])    // kleiner weil ADU Werte invertiert laufen
    { 
      if (RA3) *p++=0x7F;   // green
          else *p++=0xFF;   // more light if jumper RA3 is set
      *p++=0x00;            // red 
      *p++=0x00;            // blue
    } else
    {  
      *p++=0x00;            // green
      if (RA3) *p++=0x7F;   // red
          else *p++=0xFF;   // more light if jumper RA3 is set
      *p++=0x00;            // blue
    } 
  }  
}
//------------------------------------------------------------------------------
// internal FRC Conversion time measured 26,50µs for one conversion
// we calculate the average value over 128 measurements
// RAM ist knapp: 
// Schleifenvariable i wird direkt im Register PMDATL ausgeführt
// Laufzeit ca. 3,8ms
void ReadAdu(void)
{ U16 value;
//  LATA1 = 1;  // testweise fuer die Zeitmessung
   
  value = 0;
  for (PMDATL=0; PMDATL<128; PMDATL++)
  { 
    GO_nDONE = 1;       // start ADU conversion 
    while (GO_nDONE) ;  // wait until adu ready
    value+=ADRES;       // add the result
  } 
  value >>=7;           // divide by 128
  ADRES=(U8)value;      // write back the filtered ADU result
  
//  LATA1 = 0;    // testweise fuer die Zeitmessung
  
}  
//------------------------------------------------------------------------------    
void main(void) 
{
  PMDATH = 0;         // ! register not initialized on reset
                      // used only in asm_LedShiftOut as bitcounter
  
  OPTION_REG = 0x07;  // prescale to timer 0, 1:256, enable pullups
                      // !!!! Pullps enabled with LOW on Bit 7
//  WPUA   = 0x08;      // Pullup only on RA3, all pullups enable at power on
  OSCCON = 0x70;      // 16 MHz clock
  INTCON = 0xF0;      // enable global, peripheral, timer 0 interrupts
  TRISA  = 0x08;      // all pins to output, RA3 is input only  
  
  // internal fixed voltage reference
  // set first the FREN Bit before changing the gain bits
  // see errata sheet
  FVREN  = 1;        // Fixed Voltage Reference is enabled
  ADFVR1 = 1;        // select the 2,048 Volt Reference
  
  // init the ADC
  // ANSELA=1;   AN0 as analog input, all others as digital output
  // we dont need an ADU input, always convert the fixed voltage reference 
  ADCON = (0x07 << 5)    // conversion clock internal FRC
       // + (0x00 << 2)  // select channel AN0, we dont need a channel
        + (0x07 << 2)    // select Fixed Voltage Reference  
        + (0x01 << 0);   // ADC enable
  
  while (1)   // the main loop
  { 
    ReadAdu();         // with average filter
    if (ADRES > 161)   // !! Abfrage invers < 3,25 Volt Unterspannung
    {
      asm_FillRed();
      asm_LedShiftOut();  // RGB LEDs ausschieben
      Delay_10ms(25);
      LATA0 = 1;          // erste  LED Wechselblinker am Heck
      LATA1 = 0;          // zweite LED Wechselblinker am Heck
     
      asm_FillBlue();
      asm_LedShiftOut();  // RGB LEDs ausschieben
      Delay_10ms(25); 
      LATA0 = 0;          // erste  LED Wechselblinker am Heck
      LATA1 = 1;          // zweite LED Wechselblinker am Heck 
    } else 
    { 
       Calculate();       // calculate the RGB Bargraph
       asm_LedShiftOut();    
       Delay_10ms(2);     // 20ms  Anzeige 
      LATA0 = 1;          // erste  LED Wechselblinker am Heck
      LATA1 = 1;          // zweite LED Wechselblinker am Heck 
    } // else
  } // while 
} // main
 
						
Lesezeichen