Code:
; Program for CDD interface -> UART
; 5.2006
; Target : tiny26
;****************************************************************************
;Hardware: CCD Line sensor with inverters to port A
; UART at port B
.include "tn26def.inc"
;***** Pin definitions
.equ RxD =6 ; option schalter high res mode (slow)
.equ TxD =3 ; Transmit pin is PB3
.equ ccdport = PORTA
.equ ccdportdr = DDRA
.equ mux = 6 ; AD input = ADC6
; Bit numbers for output pins (geaetzte Platine)
.equ P1 = 1 ; Kabel 3
.equ P2 = 0 ; Kabel 1 (weiss)
.equ TG = 6 ; Kabel 8 Transfer gate
.equ rg = 5 ; Kabel 7 read Gate
.equ CL = 4 ; Kabel 5 Clamp
; Kabel 2,9,11 = GND, Kabel 4 = +5 V, Kabel 6=15V, Kabel 10 = Signal
; Polatities (0 = high puls or 1 = low puls)
.equ P1pol = 0
.equ P2pol = 0
.equ TGpol = 1 ; Transfer gate
.equ rgpol = 0 ; read Gate
.equ CLpol = 1 ; Clamp
; combine to one word - do xor (^ is bitwise xor) with this values befor writing to port
.equ allpol = P1pol * (1<<P1) + P2pol * (1<<P2) + Tgpol * (1<<Tg) + rgpol * (1<<rg) + CLpol * (1<<CL)
.equ ddrval = (1<<P1) + (1<<P2) + (1<<Tg) + (1<<rg) + (1<<Cl)
; ccd states:
.equ ccd_P1 = allpol ^ (1<<p1) ; first shift
.equ ccd_rg = allpol ^ ((1<<p1) + (1<<rg)) ; read pulse
.equ ccd_cl = allpol ^ ((1<<p1) + (1<<CL)) ; Clamp pulse (Bit Clamp mode)
.equ ccd_P2 = allpol ^ (1<<p2) ; second shift (read out phase)
.equ ccd_tg = allpol ^ ((1<<p1) + (1<<tg)) ; transfer gate aktive
.equ cellspg = 16 ; number of cells per group
; with 1 reading per Cell max 64 and min. 22
; with 2 readings max 32 min 11
.equ cellsg1 = 16 ; number of cells in first group (fine adjust position)
.equ groups = (1500/cellspg) + 1 ; groups * cellspg >= 1200 ! (number of ccd cells)
.equ cellspg_slow = 8 ; number of cells per group: min Value = 21 / AD readings
.equ groups_slow = (1500/cellspg_slow) + 1 ; groups * cellspg >= 1200 ! (number of ccd cells)
.equ Xtal = 16000 ; Clock in kHz
.equ badr = $80 ; UART out buffer in RAM: 32 Byte cyclic buffer
;***** Global register variables
.def stsave = R2 ; status save
.def bitcnt =R18 ; bit counter UART Send
.def TXbyte =R6 ; UART send data - aktive byte
.def Txinpos =R28 ; = YL next free place for data to be transmitted
.def Txoutpos =R26 ; = XL next data to be transmitted , no data if txinpos = txoutpos
.def it = r19 ; interrupt use tmp
.def tmp =R20 ;tmporary storage register
.def t2 = R21
.def t3 = r22
.def t4 = r23
.def sumL = r13
.def sumH = r14
.cseg
.org 0
rjmp reset
rjmp EXT_INT0 ; IRQ0 handler
rjmp PIN_CHANGE ; Pin change handler
rjmp TIM1_CMP1A ; Timer1 compare match 1A
rjmp TIM1_CMP1B ; Timer1 compare match 1B
rjmp TIM1_OVF ; Timer1 overflow handler
rjmp TIM0_OVF ; Timer0 overflow handler
rjmp USI_STRT ; USI Start handler
rjmp USI_OVF ; USI Overflow handler
rjmp EE_RDY ; EEPROM Ready handler
rjmp ANA_COMP ; Analog Comparator handler
rjmp ADC_con ; ADC Conversion Handler
;dummys:
EXT_INT0:
PIN_CHANGE:
TIM1_CMP1A:
TIM1_CMP1B:
TIM0_OVF:
TIM1_OVF:
USI_STRT: ; USI Start handler
USI_OVF: ; USI Overflow handler
EE_RDY: ; EEPROM Ready handler -> unused
ANA_COMP: ; Analog Comparator handler
RETI ; just in case an interrupt happens
;**************************************************************
;***** ADC ready
; does UART Send as well !, sendet jeweils 1 Bit
ADC_con:
in stsave,SREG
tst bitcnt ; do UART send first
brne U_send ; send rest of byte
cp Txinpos,Txoutpos ; test for new byte
breq uart_done ; no new data to send
ld txbyte,x+ ; get data and count on
andi XL,$9F ; cyclic buffer 32 bytes (A0 changes to 80)
ldi bitcnt,10 ; 8 data + 2 stop
sbi PORTB,TxD ; send a '1' = Start bit
rjmp uart_done
U_send: lsr TXbyte ; get new data to carry, stop bits at end
brcs putchar1 ;If carry set
cbi PORTB,TxD ; send a '0'
rjmp putchar2 ;else
putchar1: sbi PORTB,TxD ; send a '1'
putchar2:
dec bitcnt
uart_done:
; adc is read in main prog ! interupt is for UART only
intdone:
out SREG,stsave
set ; set t flag to signal AD done ! (do this after restoring SREG!)
reti
;***************************************************************************
;* "putchar"
; put one byte into output buffer
putchar: ; no test for buffer overflow yet !
com tmp ; data are inverted (better here than later)
cli
st y+,tmp
andi Txinpos,$9F ; cyclic buffer $80 to $9F
sei
ret ; return
;*************************
wait: dec tmp ; load waiting time to tmp delay. Delay is 3 * tmp + 4 Cycles , (including rcall and ret)
brne wait
ret
;*************************
; CCD Specific routines:
;***************************************************************************
; ccd shift ohne AD:
ccdshift: ; shift data out (with bitclamp)
ldi tmp,ccd_p1
ldi t2,ccd_rg
out ccdport,tmp ; P1 Signal
out ccdport,t2 ; output gate (soll 200ns?)
nop
nop
nop
ldi t2,ccd_CL
out ccdport,tmp ; P1 Signal ?? noeting ?
out ccdport,t2 ; Clamp signal: (soll ca. 200 ns ? nicht zu lang ?)
nop
nop
nop
nop
out ccdport,tmp ; P1 Signal
nop
ldi tmp,ccd_p2
out ccdport,tmp ; output data are now visible !
; delay in calling procedure !, needed only if data are needed
ret
;*******************
ccdshiftAD:
rcall ccdshift ; shift new data to output
ad_read:
clt ; clear t Flag to wait for next AD
done1: brtc done1 ; wait for AD ready
in tmp, adcl
add sumL,tmp
in tmp, adch
adc sumH,tmp
ldi tmp,30 ; wait ca 3 us (Sample and hold and highest bit to be done)
rcall wait
ret
; AD result is data from cell before this shift!
;*****************************
; READ CCD and send out data
;*****************************
ccd_loop:
ldi t3,groups ; number of groups of cells = number of data to send
ldi t4,cellsg1 ; number of cells for first group (initial zeros), no real min number because of buffer
rcall ccdshiftAD ; get first dataset; first A/D value is useless (old)
; use version with AD to get in Sync with AD timing
ccd_lp1:
clr sumL ; clear sum of AD values
clr sumH
ccd_lp2:
rcall ad_read ; get AD data (read every cell twice for longer integration)
rcall ccdshiftAD ; get AD data and shift to new cell for next AD val
dec t4
brne ccd_lp2
mov tmp,sumL
rcall putchar ; send low byte (buffered)
mov tmp,sumH
rcall putchar ; send high byte
ldi t4,cellspg ; number of cells per group, at least 20 or 21 AD Readings to get data out
dec t3
brne ccd_lp1
ret
;*****************************
; READ CCD and send out data, slow mode
;*****************************
ccds_loop:
ldi t3,groups_slow ; number of groups of cells = number of data to send
ldi t4,cellsg1 ; number of cells for first group (initial zeros), no real min number because of buffer
rcall ccdshiftAD ; get first dataset; first A/D value is useless (old)
; use version with AD to get in Sync with AD timing
ccds_lp1:
clr sumL ; clear sum of AD values
clr sumH
ccds_lp2:
rcall ad_read ; get AD data (read every cell twice for longer integration)
rcall ad_read ; get AD data (read every cell twice for longer integration)
rcall ccdshiftAD ; get AD data and shift to new cell for next AD val
dec t4
brne ccds_lp2
mov tmp,sumL
rcall putchar ; send low byte (buffered)
mov tmp,sumH
rcall putchar ; send high byte
ldi t4,cellspg_slow ; number of cells per group, at least 20 or 21 AD Readings to get data out
dec t3
brne ccds_lp1
ret
;********************************
shiftloop : ; shift out large number of bits (all cells ?)
ldi t4,groups ; low byte of number of shifts
ldi t3,6 ; high byte of number of shifts
sl_lp:
rcall ccdshift
ldi tmp,255 ; extra delay for slow readout, long exposure
rcall wait
ldi tmp,255 ; extra delay for slow readout, long exposure
rcall wait
dec t4
brne sl_lp
dec t3
brne sl_lp
ret
Tgate:
ldi tmp,ccd_p1 ; well defined start state
out ccdport,tmp
ldi tmp,6 ; wait for setteling (about 1 us)
rcall wait
ldi tmp,ccd_tg
out ccdport,tmp
ldi tmp,50 ; wait transfer time (about 10 us)
rcall wait
ldi tmp,ccd_p1
out ccdport,tmp
ldi tmp,8 ; wait for setteling after readout (about 1,5 us)
rcall wait
ret
;***** Program Execution Starts Here
reset: ldi tmp,ramend ; init stackpointer
out SP,tmp
; set data directions:
ldi tmp,0 ; initial value port A
out PORTA,tmp
ldi tmp,ddrval ; AD at PA7 (CCD) and PA2 (optionale Photodiode)
out DDRA,tmp
ldi tmp,255 ; TX passive , pullups aktivieren um floating inputs zu vermeiden
out PORTB,tmp
ldi tmp,8 ; PB3 as output, rest as inputs
out DDRB,tmp
;init AD
ldi tmp,mux ; A/D Wandler status setzen, Ref = VCC, 8 Bit Ergebnis
out ADMUX,tmp
ldi tmp, (1<<ADEN)+(1<<ADSC)+(1<<ADFR)+(1<<ADIE)+7 ; A/D einschalten , free running mode und Interupt aktivieren
; takt = 16 MHz / 2^7 = 125 kHz (-> 9600 Baud)
out ADCSRA, tmp
ldi YL,$80 ; UART out buffer start position in RAM
ldi XL,$80
meldung1: ldi R31,HIGH(2*welcome) ; setup Z pointer hi welcome is word address
ldi r30,LOW(2*welcome) ; setup Z pointer lo
meldung: LPM tmp,Z
inc ZL
brne izh1
inc ZH
izh1: cpi tmp,0
breq meldung_done
rcall putchar ; sei is done in putchar!: enable interrupts : ad,uart - send
rjmp meldung
meldung_done:
rcall wait_uart
; rjmp meldung1
;************* main loop starts here
lop:
; rcall getchar ; wait and get byte to tmp
; rcall putchar ; send;
; rjmp lop
rcall tgate ; transfer data to shift cells
ldi tmp, $FF
rcall putchar
ldi tmp, $FF ; start signal ! to allow sync on PC
rcall putchar
in tmp,pinb
andi tmp,1<<6
breq lop_slow
rcall ccd_loop ; read and send data out
rjmp lop
lop_slow:
rcall ccds_loop ; read and send data out, high resolution - slow
rjmp lop
;****** subroutines:
wait_uart:
cp Txinpos,Txoutpos
brne wait_uart ; wait for all data to be send
ret
.cseg
welcome: ; Text message to be send at beginning (good for debuging without actual signal)
; maximum = 31 bytes (geht erst in den Puffer)
.db "CCD Line Sensor Interface",0
.db "xxxxxxx "
Die Kommentare sind leider etwas Deutsch/Englisch gemischt, da zum Teil auf PC mit amerikanerscher Tastatur geschrieben. Durch die Software
Lesezeichen