⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 videodvm.asm

📁 Video-DVM is a very cheap DVM that shows how an output as complex as a videocomposite signal can be
💻 ASM
📖 第 1 页 / 共 2 页
字号:

;***************************************************************************
;* VIDEODVM.ASM
;*
;* a digital volt meter that displays data directly on your TV!
;* ---> composite video output showing giant digits
;* ---> comprehensive data display with current reading, max and min
;* ---> analog type bar-display, graduated from 0 to 100%, for quick checks
;* ---> selectable decimal point position
;* ---> 1200 baud, ASCII serial output is also provided
;*
;* Copyright (c) 1997 by Alberto Ricci Bitti
;* e-mail: a.riccibitti@ra.nettuno.it
;***************************************************************************

.DEVICE AT90S1200

;***************************************************************************
;* a few, very useful macros
;***************************************************************************

.LISTMAC

.MACRO  ADDI    
	subi @0, -@1
.ENDMACRO

;skip next instruction if not equal to zero
.MACRO skipne                   
.SET    _skipne = PC+2
	brne    _skipne
.ENDMACRO

;skip next instruction if carry set
.MACRO skipcs                   
.SET    _skipcs = PC+2
	brcs    _skipcs
.ENDMACRO

;skip next instruction if carry clear
.MACRO skipcc
.SET    _skipcc = PC+2
	brcc    _skipcc
.ENDMACRO

;skip next instruction if equal to zero
.MACRO  skipeq
.SET    _skipeq = PC+2
	breq    _skipeq
.ENDMACRO

;skip next instruction if lower
.MACRO skiplo                   
.SET    _skiplo = PC+2
	brlo    _skiplo
.ENDMACRO

;wait two cycles but waste only one instruction
.MACRO  doublenop
.SET    _doublenop = PC+1
	rjmp    _doublenop
.ENDMACRO

;***************************************************************************

;include AT90S1200 registers definitions
.include "1200def.inc"
;include font definitions
;fonts are stored in a EEPROM table, edit fonts.inc to modify it as you wish
.include "fonts.inc"

;***************************************************************************
;* VARIABLE ASSIGNEMENTS
;***************************************************************************
.CSEG

	.def    SaveStatus =    r0      ;status buffer during interrupts
	.def    CharHeight =    r1      ;character height (reload value)
	.def    CurrHeight =    r2      ;character height (running counter)
	.def    PrintAB =       r3      ;print buffer for BCD charachters,
	.def    PrintCD =       r4      ;the sequence is A B C D + measurement unit
	.def    PointPosition = r5      ;decimal point position
	.def    BarLenghtHigh = r6      ;lenght of analog bar, high byte
	.def    BarLenght =     r7	;lenght of analog bar, low byte
	.def    AdcLow =        r8      ;ADC result, low byte
	.def    AdcHigh =       r9      ;ADC result, high byte
	.def    AdcLowMax =     r10     ;max value memory
	.def    AdcHighMax =    r11
	.def    AdcLowMin =     r12     ;min value memory
	.def    AdcHighMin =    r13
	.def    TimeLow =       r14     ;time counter
	.def    TimeHigh =      r15
	
	
	.def    Position =      r16     ;identifies wich of the four line position
					;we are on (3=end of line, 0=sync pulse) when
					;an interrupt occurs
					;used by timer interrupt routine

	.def    Delay =         r17     ;used for delays - decremented each field
	.def    RowsModFour =   r18	;raster rows counter, split in two for
	.def    RowsDivFour =   r19     ;convenience of use. Counts up to 312

	;common data space used under interrupt
	.def    Arg1 =          r20     ;Temp variable used by interrupt
	.def    Arg2 =          r21     ; "      "      "          "
	.def    Arg3 =          r22     ; "      "      "          "
	.def    Arg4 =          r23     ; "      "      "          "

	;common data space used by main program
	.def    Main1 =         r24     ;Temp variable used by main program
	.def    Main2 =         r25     ; "      "      "       "      "
	.def    Main3 =         r26     ; "      "      "       "      "
	.def    Main4 =         r27     ; "      "      "       "      "

	.def    MiscFlags =     r28     ;Assorted flags

	;flags bit definition
	.equ    SerialReqBit =  1       ;

;***************************************************************************
;* Constants
;***************************************************************************

	.equ    DisplayRow =    150/4   ;counter value for display start 
	.equ    StartRetrace = (312/4)-1;counter value at wich retrace starts
	.equ    StopRetrace = (312/4)   ;maximum counter value
	.equ    BAUDRATE =      13      ;lines between bits: 15625/13=1200 baud


	;useful global constants
	.equ    ASCII_ZERO =    48      ;ascii value for '0'
	.equ    ASCII_RETURN =  13      ;ascii value for carriage return

;***************************************************************************
;* Port Pin Assignements
;***************************************************************************

	;port D bit definitions (OUTPUTS)
	.equ    CSyncBit =      0       ;set video output to composite sync level when low
	.equ    VideoBit =      1       ;set video level to white when high, black when low
	.equ    SCLKBit =       2       ;ADC serial clock output
	.equ    CSBit =         3       ;ADC chip select (active low)
	.equ    DINBit =        4       ;ADC serial data
	.equ    LedBit =        5       ;board led, 0 = ON
	.equ    RS232Bit =      6       ;1200 baud TTL level serial data

	;port B bit definitions (INPUTS)
	.equ    DOUTBit =       0       ;ADC serial data
	.equ    DPSel1Bit =     1       ;board jumpers: 1, 2 & 3, select
	.equ    DPSel2Bit =     2       ;decimal point position
	.equ    DPSel3Bit =     3       ;	
	.equ	ClearButton =   4	;Max Min Clear pushbutton



;***************************************************************************
;* VECTORS
;***************************************************************************

	rjmp    RESET           ;Reset Handle
	rjmp    RESET           ;Ext. interrupt request 0
	rjmp    TIMER           ;Timer




;***************************************************************************
;*
;* MAIN PROGRAM
;*
;***************************************************************************
;* INITAILIZATION
;***************************************************************************


RESET:  
		clt     ;clear T bit flag       ;VERY important: 
						;clear T flag, here used to 
						;verify if we were sleeping
		ldi     Arg1, 0b01111111        ;set port D bits to outputs
		out     DDRD, Arg1
		ldi     Arg1, 0b00000001        ;preset  output state
		out     PortD, Arg1
		ldi     Arg1, 0b00000000        ;set port B to inputs
		out     DDRB, Arg1
		ldi     Arg1,  0b11111111       ;turn on pullups on inputs
		out     PortB, Arg1
		ldi     Arg1, 1
		out     TCCR0, Arg1             ;dont'use timer prescaler             
		ldi     Arg1, 32
		out     MCUCR, Arg1             ;enable sleep idle mode
		ldi     Arg1, 2
		out     TIMSK, Arg1             ;enable timer interrupt 

		ldi     Arg1, 10		;preset display variables
		mov     CharHeight, Arg1
		mov     CurrHeight, CharHeight
		ldi     Delay, 5
		ldi	Arg1, 0x99		;preset minimum to "9999"
		mov	ADCLowMin,  Arg1
		mov	ADCHighMin, Arg1
		clr	ADCLowMax		;preset maximum to "0000"
		clr	ADCHighMax
		clr     Arg1			;and clear interrupt variables
		clr     Arg2
		clr     Arg3
		clr     Arg4
		clr     MiscFlags
		
		sei                     	;at last, allow interrupts
		

;***************************************************************************
;* MAIN LOOP
;***************************************************************************

FOREVER:                
		
j2:             cpi     Delay, 1
		brne    j1
		cbi     PortD, LedBit
j1:                cpi     Delay, 0
		brne    FOREVER
		ldi     Delay, 10
		sbi     PortD, LedBit
		inc     TimeLow
		skipne
		inc     TimeHigh

		;*******************************
		;* ADC CONVERSION
		;*******************************
		ldi     Main1, 0                ;select ADC channel 0
		rcall   READADC			;ADC conversion, return result in Main3-4
		;*******************************
		;* BAR DISPLAY
		;*******************************
		mov     BarLenght, Main3       ;get binary data into 
		mov     BarLenghtHigh, Main4   ;BarLenght storage area
		lsr     BarLenghtHigh          ;and divide by 32 (shift 5
		ror     BarLenght              ;times) to adapt to our
		lsr     BarLenghtHigh          ;routine range (0-127)
		ror     BarLenght
		lsr     BarLenghtHigh
		ror     BarLenght
		lsr     BarLenghtHigh
		ror     BarLenght
		lsr     BarLenghtHigh
		ror     BarLenght
		;*******************************
		;* CONVERSION TO BCD
		;*******************************
		mov     Main1, Main3            ;set up parameters
		mov     Main2, Main4
		rcall   BIN_BCD                 ;and go convert
		mov     ADCLow, Main3           ;store result
		mov     ADCHigh, Main4
		;*******************************
		;* PEAK RECORDER
		;*******************************
		cp	ADCLowMax, ADCLow	;if current ADC value
		cpc	ADCHighMax, ADCHigh
		brsh	CHECK_MIN		;is greater than Max value
		mov 	ADCLowMax,  ADCLow	;then Max = Current value
		mov 	ADCHighMax, ADCHigh	;
CHECK_MIN:
		cp	ADCLowMin, ADCLow	;if current ADC value
		cpc	ADCHighMin, ADCHigh
		brlo	CHECK_CLEAR		;is less than Max value
		mov 	ADCLowMin,  ADCLow	;then Min = Current value
		mov 	ADCHighMin, ADCHigh	;
CHECK_CLEAR:
		sbic    PinB, ClearButton	;if Max-Min clear button pressed
		rjmp 	DONTCLEAR		;
		mov 	ADCLowMax,  ADCLow	;then reset Max value
		mov 	ADCHighMax, ADCHigh	;
		mov 	ADCLowMin,  ADCLow	;and Min value
		mov 	ADCHighMin, ADCHigh	;
DONTCLEAR:
		;*******************************
		;* SERIAL COMMUNICATIONS
		;*******************************
		mov     Main1, ADCHigh          ;send data to serial interface
		swap    Main1                   ;select first BCD digit
		andi    Main1, 0b00001111       ;cut out unwanted bits
		ADDI    Main1, ASCII_ZERO       ;convert to ASCII
		rcall   SENDSERIAL              ;and send to serial
		mov     Main1, ADCHigh          ;do the same for the following 3 digits
		andi    Main1, 0b00001111       ;hundreds...
		ADDI    Main1, ASCII_ZERO
		rcall   SENDSERIAL
		mov     Main1, ADCLow           ;tens...
		swap    Main1
		andi    Main1, 0b00001111
		ADDI    Main1, ASCII_ZERO
		rcall   SENDSERIAL
		mov     Main1, ADCLow           ;and units
		andi    Main1, 0b00001111
		ADDI    Main1, ASCII_ZERO
		rcall   SENDSERIAL
		ldi     Main1, ASCII_RETURN     ;add a carriage return (perfect
		rcall   SENDSERIAL              ;for QBasic programs...)

		rjmp    FOREVER                 ;loop forever





;****************************************************************************
;*
;* Timer Interrupt: occurs four times in each video line.
;*      The Position records which of four interrupt stages we are on.
;*      At the third stage, we go in sleep mode, in order to have constant
;*      servicing time for the fourth, crucial interrupt were we will output
;*      the sync waveform.
;*      This is the very heart of sync generation.
;*
;****************************************************************************


TIMER:
	;if we were sleeping, then this is a synchronizing cycle: just return
	brtc    TIMER_NOSLEEP   ;if T cleared, do timer routine
	reti                    ;otherwise return (sync sleep)

TIMER_NOSLEEP:        
	in      SaveStatus, SREG
	;if not at line start,simply decrement position counter and return
	;otherwise do the real thing...
	dec     Position                ;Position range from 2 down to -1
	breq    WAITNEWLINE             ;if Position = 0 then wait (sleeping) for new line
TIMER_EXIT:        
	out     SREG, SaveStatus        ;otherwise do nothing
	reti
WAITNEWLINE:
	
	set                             ;set T flag to tell we are sleeping
	sei                             ;re-enable interrupts, otherwise we sleep forever!
	sleep                           ;wait sleeping the next timer interrupt
	nop                             ;(during sleep we have constant interrupt recovery time)
	cli                             ;disable further interrupts
	clt                             ;clear T, used for sleep flag
NEWLINE:                                ;when awaken, we will restart here
	ldi     Position, 3             ;reset position index
	in      Arg1, PortD             ;read previous CSync level
	ldi     Arg2, 0b00000001        ;load mask for toggle csync bit

TOGGLESYNC:
	eor     Arg1, Arg2              ;toggle CSync output
	out     PortD, Arg1             ;now we are in the horizontal sync pulse
HOUSEKEEPING:        
	;once in horizontal sync pulse space, we have 
	;enough time to do some housekeepying routines...
	inc     RowsModFour             ;increment row counters
	cpi     RowsModFour, 4          ;if RowsModFour == 4
	brne    _1           
	inc     RowsDivFour             ;then increment RowsDivFour
_1:     andi    RowsModFour, 0b00000011 ;clear anyway bit 2

CHECKLASTLINE:        
	;when at last line, the sync pulse is stretched to half line
       cpi     RowsDivFour, StopRetrace        ;if at last line 
       brsh    LASTLINE            ;the sync pulse stops at half line

WAITSYNCEND:                            ;else wait sync pulse end
	in      Arg1, TCNT0             ;note that now we are perfectly in
	cpi     Arg1, 64                ;sync with timer.        64 = 4 uS
	brlo    WAITSYNCEND

	ldi     Arg2, 0b00000001         ;prepare mask for csync toggle

VERTICALRETRACE:        
	ldi     Arg1, StartRetrace
	cpi     RowsModFour, 0          ;if at start of vertical retrace pulse
	cpc     RowsDivFour, Arg1                   
	brne    HSYNCEND                ;then leave CSync low
	ldi     Arg2, 0

HSYNCEND:        
	in      Arg1, PortD             ;
	eor     Arg1, Arg2              ;toggle CSync output
	out     PortD, Arg1             ;now we are in the color burst space

	rcall   SERIALDRIVER
WAITVISIBLEPORTION:        
	in      Arg1, TCNT0             ;wait for start of visible area
	cpi     Arg1, 220               ;decreasing this moves display left
	brlo    WAITVISIBLEPORTION
	rjmp	BUILDSCREEN		;go to display building table

LASTLINE:
	;this is a good time to make slow (1/50 sec.) housekeepings,
	;or to do things that are made once every screen picture
	clr     RowsDivFour             ;reset row counters
	clr     RowsModFour             
	tst     Delay                   ;if Delay <> 0
	breq    WAITHALFLINE
	dec     Delay                   ;then decrement it

WAITHALFLINE:
	in      Arg1, TIFR              ;wait for two timer overflows
	sbrs    Arg1, TOV0              ;(each overflow is a quarter line)
	rjmp    WAITHALFLINE
	ldi     Arg1, EXP2(TOV0)        ;reset timer overflow bit
	out     TIFR, Arg1
SECONDQUARTER:
	in      Arg1, TIFR              ;wait second overflow
	sbrs    Arg1, TOV0              ;
	rjmp    SECONDQUARTER
	ldi     Arg1, EXP2(TOV0)        ;reset timer overflow bit
	out     TIFR, Arg1
	ldi     Position, 1             ;and align position counter
	sbi     PortD, CSyncBit         ;and end composite sync
	rjmp    TIMER_EXIT

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -