Pfad:AVR-DE => Anwendungen => Filmleuchte mit ATtiny13 => Software
Filmleuchte klein AVR-Anwendungen

Helligkeitssteuerung und Akku-Überwachung mit ATtiny13
Assembler-Software für die lineare Filmleuchte
Logo

Assembler-Software für die lineare Filmleuchte ATtiny13


;
; *********************************
; * Filmleuchte mit ATtiny13      *
; * Linear-Variante, Nov. 2018    *
; * (C)2018 avr-asm-tutorial.net  *
; *********************************
;
.nolist
.include "tn13adef.inc" ; Define device ATtiny13A
.list
;
; **********************************
;  D E B U G G I N G   S W I T C H
; **********************************
;
; This debugs the intensity control calculation
.equ debug_pwm = 0 ; 1=Debugging PWM calculation on
  .if debug_pwm == 1 ; Setting debugging parameters
    .equ cPot = 135 ; Degrees of the potentiometer
    .endif
;
; This debugs the voltage LED control
.equ debug_vtg = 0 ; 1=Debugging voltage on
  .if debug_vtg == 1 ; Setting debugging parameters
    .equ debug_voltage = 27000 ; Voltage in mV
    .endif
;
; This sets 15 Volt operating voltage
.equ debug_15V = 0 ; 1=Debugging 15 V operating voltage
  .if debug_15V == 1 ; Setting debugging parameteres
    .equ cVtgGnHigh =18000 ; Highest voltage in mV, LED is green
    .equ cVtgNom = 15000 ; Normal voltage in mV, LED is green
    .equ cVtgGnMin = 13000 ; Minimum voltage in mV, LED is green
    .equ cVtgRdMin = 11000 ; Voltage in mV where LEDs is fully red
    .endif
;
; **********************************
;        H A R D W A R E
; **********************************
;
; Device: ATtiny13A, Package: 8-pin-PDIP_SOIC
;            ___________
;         1 /           |8
; RESET o--|RES      VCC|--o +5V
;         2|            |7
;  Poti o--|PB3      PB2|--o LED rd anode
;         3|            |6
; Voltg o--|PB4      PB1|--o LED gn anode & PWM
;         4|            |5
;   0 V o--|GND      PB0|--o PWM constant-current-driver
;          |____________|
;

; **********************************
;  P O R T S   A N D   P I N S
; **********************************
;
.equ pOutO = PORTB ; Define the output port
.equ pDirD = DDRB ; Define the direction port
.equ bPwmO = PORTB0 ; Define the PWM output pin
.equ bGnAO = PORTB1 ; Define the green LED anode output pin
.equ bRdAO = PORTB2 ; Define the red LED anode output pin
.equ bAnyD = (1<<DDB0)|(1<<DDB1)|(1<<DDB2) ; Direct pins output
;
; **********************************
;   A D J U S T A B L E   C O N S T
; **********************************
;
.equ clock=1200000 ; Define clock frequency
;
; PWM constants for intensity control
;  Pwm value where the RC voltage is below 0.65 Volts
.equ cPwmMin = 22 ; Adjust this if your LEDs are not off when
;    the potentiometer is on the extreme left position
;
; Voltage measurement constants
.equ cR1 = 10 ; Lower resistor in kOhm
.equ cR2 = 82 ; Upper resistor in kOhm
.equ cVtgMax=(5000*(cR1+cR2)+cR1/2)/cR1 ; Maximum measurable voltage in mV
.if debug_15V == 0 ; Not debugging, normal operation
  .equ cVtgGnHigh =37000 ; Highest voltage in mV, LED is green
  .equ cVtgNom = 35000 ; Normal voltage in mV, LED is green
  .equ cVtgGnMin = 29600 ; Minimum voltage in mV, LED is green
  .equ cVtgRdMin = 26000 ; Voltage in mV where all the LEDs turn off
  .endif
; Set minimum voltage LED cycles
;   Led is green: at cVtgGnMin 25 out of 256 PWM cycles on
;   Led is red: at cVtgRdMax 25 out of 256 PWM cycles on
.equ cLedMin = 25 ; Minimum brightness of LED
;
; Multiplicator setting for green and red LED PWM
.equ cFactorGn = 256 ; Try with a multiplicator of 256 on green
.equ cFactorRd = 256 ; Try with a multiplicator of 256 on red
;
; Check multiplication factors
.if (cFactorGn!=256) && (cFactorGn!=512)
  .error "cFactorGn can only be 256 or 512!"
  .endif
.if (cFactorRd!=256) && (cFactorRd!=512)
  .error "cFactorRd can only be 256 or 512!"
  .endif
;
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
;
;  Multiplicator for ADC value to convert to PWM value
.equ cPwmMult = 256-cPwmMin
;
; Timer TC0
.equ cTc0Presc = 1 ; Prescaler for TC0
.equ cPwmFrq = clock / cTc0Presc / 256 ; PWM frequency
;
; Voltage calculation
.equ cAdcCnt = 64 ; Number of measurement counts
.equ cAdcMult =(1023*cR1*cAdcCnt+(cR1+cR2)/2)/(cR1+cR2) ; Multiplicator mV to Adc
.equ cAdcGnHigh=(cVtgGnHigh*cAdcMult+2500)/5000 ; Maximum Green Adc sum
.equ cAdcGnMin=(cVtgGnMin*cAdcMult+2500)/5000 ; Minimum Green Adc sum
.equ cAdcRdHigh=cAdcGnMin-1 ; LED turns red equal or below this Adc sum
.equ cAdcRdMin=(cVtgRdMin*cAdcMult+2500)/5000 ; Adc sum when red LED is fully on
.equ cAdcMulGn=(cFactorGn*(255-cLedMin)+(cAdcGnHigh-cAdcGnMin)/2)/(cAdcGnHigh-cAdcGnMin) ; Multiplicator for green
.equ cAdcMulRd=(cFactorRd*(255-cLedMin)+(cAdcRdHigh-cAdcRdMin)/2)/(cAdcRdHigh-cAdcRdMin) ; Multiplicator red
;
; Check the range of the multiplication factors
.set MultiFactor = 0 ; No error
.if cAdcMulGn>=256 ; Green factor out of range
  .error "The green multiplication factor is out of range!"
  .set MultiFactor = 1 ; Set error condition
  .else
  .if cAdcMulGn>=256 ; Red factor out of range
    .error "The red multiplication factor is out of range!"
    .set MultiFactor = 2 ; Set error condition
    .endif
  .endif
.if MultiFactor == 0 ; No error
  ; Check the rounding effect of the multiplicators
  .if cFactorGn==256 ; Check if cFactorGn at 256
    .equ cAdcMulGnTst=(512*(255-cLedMin)+(cAdcGnHigh-cAdcGnMin)/2)/(cAdcGnHigh-cAdcGnMin) ; Multiplicator for green
    .if cAdcMulGnTst<256 ; Check range of factor 512
      .if (cAdcMulGnTst!=(2*cAdcMulGn)) ; Check if 512 is more accurat
        .message "Green LED: Using 512 for cFactorGn would be better!"
        .endif
      .endif
    .endif
  .if cFactorRd==256 ; Check if cFactorGn at 256
    .equ cAdcMulRdTst=(512*(255-cLedMin)+(cAdcRdHigh-cAdcRdMin)/2)/(cAdcRdHigh-cAdcRdMin) ; Multiplicator red
    .if cAdcMulRdTst<256
      .if cAdcMulRdTst!=(2*cAdcMulRd) ; Check if 512 more accurat
        .message "Red LED: Using 512 for cFactorRd would be better!"
        .endif
      .endif
    .endif
  .endif
;
; Simulate debugging the potentiometer calculation solely
  .if debug_pwm == 1
    .set cPwmValue = (cAdcCnt*1024*cPot+135)/270 ; Set ADC pot value
    .if cPwmValue > 65535
      .set cPwmValue = 65535 ; Avoid overflow by rounding
      .endif
    .endif
;
; Simulate debugging of voltage display solely
  .if debug_vtg == 1 ; Debugging parameters
    .equ debug_adcvtg=(debug_voltage*cR1+(cR1+cR2)/2)/(cR1+cR2) ; Voltage in mV
    .if debug_adcvtg>5000
      .error "Voltage on ADC input is too high! See smbol debug_adcvtg!"
      .endif
    .equ debug_adcsum=(debug_voltage*cAdcMult+2500)/5000 ; Convert to ADC sum
    .endif
;
; **********************************
;          T I M I N G
; **********************************
;
; TC0 is the 8-bit PWM
;   clock               = 2,400,000 Hz
;   TC0 prescaler       =         8
;   TC0 clock frequency =   300,000 Hz
;   PWM clock cycles    =       256
;   PWM cycle frequency =     1,171.9 Hz
;   PWM pulse duration  =       853.3 us
;
; ADC measurements of the voltages on
;   a) the potentiometer voltage (intensity)
;   b) the voltage input pin
;   are initiated by the TC0 compare match,
;   at the end of the on period of the LEDs.
;   On each channel a) and b) eight measurements
;   are summed up and the Compare A and B values
;   are calculated and set.
;   OCR0A matches          = 1,171.9 Hz
;   Number of channels     =     2
;   Measurements summed up =    64
;   Update frequency       =     9.155 Hz
;   Update cycle           =   109.2 ms
;
; Duration of ADC measurements
;   TC0 compare matches trigger AD conversion
;     therefore conversion time has to be
;     shorter than trigger duration
;   clock                     = 2,400,000 Hz
;   ADC clock prescaler       =       128
;   ADC clocks per conversion =        13
;   Conversion duration       =       693.3 us
;   % of PWM cycle time       =        81.3%
;
; **********************************
;       R E G I S T E R S
; **********************************
;
; free: R0 to R5
.def rMul0  = R6 ; Multiplication result, Byte 0
.def rMul1  = R7 ; dto., Byte 1
.def rMul2  = R8 ; dto., Byte 2
.def rAdc0  = R9 ; Multiplicator, Byte 0
.def rAdc1  = R10 ; dto., Byte 1
.def rAdc2  = R11 ; dto., Byte 2
.def rAdcRL = R12 ; Last ADC result, LSB
.def rAdcRH = R13 ; dto., MSB
.def rAdcL  = R14 ; ADC result sum, LSB
.def rAdcH  = R15 ; dto., MSB
.def rmp    = R16 ; Multipurpose register
.def rAdc   = R17 ; ADC counter
; free: R18 to R29
; used: R31:R30 = Z for diverse purposes
;
; **********************************
;           S R A M
; **********************************
;
; ( No SRAM used)
;
; **********************************
;         C O D E
; **********************************
;
.cseg
.org 000000
;
; **********************************
; R E S E T  &  I N T - V E C T O R S
; **********************************
  rjmp Main ; Reset vector
  reti ; INT0, not used
  reti ; PCI0, not used
  reti ; OVF0, not used
  reti ; ERDY, not used
  reti ; ACI, not used
  reti ; OC0A, not used
  reti ; OC0B, not used
  reti ; WDT, not used
  rjmp AdcIsr ; ADCC
;
; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
;
; ADC conversion complete interrupt service routine
AdcIsr:
  set ; Set T flag
  reti
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
  ldi rmp,Low(RAMEND)
  out SPL,rmp ; Init LSB stack pointer
  ; Init ports
  ldi rmp,bAnyD ; Direction output for digital pins
  out pDirD,rmp ; to direction port
  ldi rmp,0 ; All outputs low
  out pOutO,rmp ; in port register
  ; Init ADC
  ldi rmp,(1<<ADC0D)|(1<<ADC2D)|(1<<ADC3D) ; Disable digital input pins
  out DIDR0,rmp ; in disable port
  ldi rmp,(1<<MUX1) ; Start with potentiometer channel
  out ADMUX,rmp ; to ADC multiplexer
  clr rAdcL ; Clear sum, LSB
  clr rAdcH ; dto., MSB
  ldi rAdc,cAdcCnt ; Start 8 measurements
  ldi rmp,(1<<ADTS1)|(1<<ADTS0) ; Start ADC on TC0 Compare Match A
  out ADCSRB,rmp ; in ADC control port B
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) ; Presc=128, ADATE, Int
  out ADCSRA,rmp ; in ADC control port
  ; Init TC0 as PWM and ADC starter
  ldi rmp,0 ; Set PWM outputs off
  out OCR0A,rmp ; in compare A, light array
  out OCR0B,rmp ; and in compare B, voltage control LED
  ldi rmp,(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00) ; Fast PWM, clear on match
  out TCCR0A,rmp ; to TC0 control port A
  ldi rmp,1<<CS00 ; Prescaler = 1
  out TCCR0B,rmp ; to TC0 control port B
  ; Debug voltage
  .if debug_vtg == 1 ; Debugging parameters
    ldi rmp,Low(debug_adcsum) ; Set ADC sum, LSB
    mov rAdcRL,rmp
    ldi rmp,High(debug_adcsum) ; dto., MSB
    mov rAdcRH,rmp
    rjmp AdcDbg
    .endif
  ; Debug PWM value conversion
  .if debug_pwm == 1 ; Debug the pot-PWM conversion
    ldi rmp,High(cPwmValue) ; Set the ADC value, MSB
    mov rAdcRH,rmp
    ldi rmp,Low(cPwmValue) ; dto., LSB
    mov rAdcRL,rmp
    rcall Debug_PwmEntry ; Call the conversion routine
    .endif
  ; Sleep mode enable
  ldi rmp,1<<SE ; Sleep enable, sleep mode idle
  out MCUCR,rmp
  sei ; Enable interrupts for ADC
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
  sleep ; Go to sleep
  nop ; Dummy for wake-up
  brtc Loop ; If T flag not set
  clt ; Clear flag
  ; Read the ADC result
  in rmp,ADCL ; Read result, LSB
  add rAdcL,rmp ; Add LSB
  in rmp,ADCH ; dto., MSB
  adc rAdcH,rmp ; dto., MSB
  dec rAdc ; Count measurements
  brne Loop ; Back to loop
  ldi rAdc,cAdcCnt ; Restart 64 measurements
  mov rAdcRL,rAdcL ; Copy LSB result
  mov rAdcRH,rAdcH ; Copy MSB result
  clr rAdcL ; Restart sum, LSB
  clr rAdcH ; dto., MSB
  sbic ADMUX,MUX0 ; Read current channel
  rjmp AdcVtg ; Voltage has been measured
  ; Potentiometer has been measured 64 times
  ldi rmp,(1<<MUX1)|(1<<MUX0) ; Channel ADC3
  out ADMUX,rmp ; to ADMUX
Debug_PwmEntry:
  mov rAdc0,rAdcRL ; Copy measuring result, LSB
  mov rAdc1,rAdcRH ; dto., MSB
  ldi rmp,cPwmMult ; Load multiplication factor
  rcall Multiply
  ldi rmp,cPwmMin ; Load minimum
  add rmp,rMul2 ; Add minimum to MSB result
  out OCR0A,rmp ; Write result to compare A
  rjmp Loop ; Back to loop
AdcVtg:
  ; Voltage has been measured
  ; Set channel MUX to ADC2
  ldi rmp,(1<<MUX1) ; Channel ADC2
  out ADMUX,rmp ; to ADMUX
AdcDbg:
  mov rAdc0,rAdcRL ; Copy measuring result, LSB
  mov rAdc1,rAdcRH ; dto., MSB
  ldi rmp,Low(cAdcGnHigh) ; Load max. ADC sum
  cp rAdc0,rmp ; Compare with maximum green, LSB
  ldi rmp,High(cAdcGnHigh)
  cpc rAdc1,rmp ; dto., MSB
  ldi rmp,255 ; Fully green
  brcc AdcSetPwmGn ; Set PWM green
  ldi rmp,Low(cAdcGnMin) ; Subtract green minimum, LSB
  sub rAdc0,rmp
  ldi rmp,High(cAdcGnMin) ; dto., MSB
  sbc rAdc1,rmp
  brcs AdcLow ; Voltage smaller than min.
  ldi rmp,cAdcMulGn ; Load multiplicator
  rcall Multiply ; Multiply the difference
  .if cFactorGn == 512
    lsr rMul2 ; Divide by 2
    ror rMul1
    ror rMul0
    .endif
  rcall AddLedMin ; Add the minimum LED
AdcSetPwmGn:
  out OCR0B,rMul1 ; Write result to OCR-B
  cbi pOutO,bRdAO ; Clear red anode
  rjmp Loop
AdcLow:
  mov rAdc0,rAdcRL ; Copy measuring result, LSB
  mov rAdc1,rAdcRH ; dto., MSB
  ldi rmp,Low(cAdcRdMin) ; Subtract red minimum, LSB
  sub rAdc0,rmp
  ldi rmp,High(cAdcRdMin) ; dto., MSB
  sbc rAdc1,rmp
  ldi rmp,0x00
  brcs AdcSet ; Voltage smaller than min, set fully red
  ldi rmp,cAdcMulRd ; Set red multiplicator
  rcall Multiply
  .if cFactorRd == 512
    lsr rMul2 ; Divide by 2
    ror rMul1
    ror rMul0
    .endif
  mov rmp,rMul1
AdcSet:
  out OCR0B,rmp ; Write rmp to compare B
  sbi pOutO,bRdAO ; Set red anode
  rjmp loop
;
; Multiply rAdc1:rAdc0 by rmp
;   Result is in rMul2:rMul1:rMul0
Multiply:
  clr rAdc2 ; Clear upper byte
  clr rMul0 ; Clear result, byte 0
  clr rMul1 ; dto., byte 1
  clr rMul2 ; dto., byte 2
Multiply1:
  lsr rmp ; Shift multiplicator right
  brcc Multiply2 ; Not one, skip adding
  add rMul0,rAdc0 ; Add multiplicator, byte 0
  adc rMul1,rAdc1 ; dto., byte 1
  adc rMul2,rAdc2 ; dto., byte 2
Multiply2:
  lsl rAdc0 ; Shift multiplicator left
  rol rAdc1 ; dto., byte 1
  rol rAdc2 ; dto., byte 2
  tst rmp ; Multiplicator = 0?
  brne Multiply1
  ret
;
; Add Led min to result
AddLedMin:
  ldi rmp,0x80 ; Round LSB
  add rMul0,rmp
  ldi rmp,cLedMin ; Add minimum
  adc rMul1,rmp
  ldi rmp,0
  adc rMul2,rmp
  tst rMul2
  breq Multiply3
  ldi rmp,0xFF
  mov rMul1,rmp
Multiply3:
  ret
;
; End of source code



Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über das Kommentarformular an mich.

©2018 by http://www.avr-asm-tutorial.net