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

📄 usb90s23x3.asm

📁 单片机AT90S系列 制作简易USB接口(软件模拟,无usb硬件)。asm源代码
💻 ASM
📖 第 1 页 / 共 5 页
字号:
		out		UDR,temp0		;a vysli ukoncovaci znak na UART
		out		SREG,backupSREGTimer	;obnova SREG (a sucasne povolenie interruptu)
		rcall	InitCounter		;restartni citac na TSOP zmenu a zakaz interrupt
		pop		temp0
		reti
;********************************************************************
;* Init program
;********************************************************************
;------------------------------------------------------------------------------------------
reset:			;inicializacia procesora a premennych na spravne hodnoty
		ldi		temp0,StackBegin	;inicializacia stacku
		out		SPL,temp0

		clr		XH			;Infra pointer
		clr		YH			;USB pointer
		clr		ZH			;ROM pointer
		sts		InfraBufferBegin,YH	;znuluj dlzky Infra kodu v bufferi
		sts		InfraBufferBegin+1,YH	;znuluj pocitadlo infra kodov v bufferi

		clr		MyUpdatedAddress	;nova adresa USB -  nedekodovana
		rcall	InitACKBufffer		;inicializacia ACK buffera
		rcall	InitNAKBufffer		;inicializacia NAK buffera

		rcall	USBReset		;inicializacia USB adresy
		
		sbi		TSOPpullupPort,TSOPpin	;nahodit pull-up na TSOP vstupe

		ldi		temp0,(1<<LEDlsb0)+(1<<LEDlsb1)+(1<<LEDlsb2)
		out		LEDPortLSB,temp0	;nahodit pull-up na vsetkych LED vstupoch LSB
		ldi		temp0,(1<<LEDmsb3)+(1<<LEDmsb4)+(1<<LEDmsb5)+(1<<LEDmsb6)+(1<<LEDmsb7)
		out		LEDPortMSB,temp0	;nahodit pull-up na vsetkych LED vstupoch MSB

		sbi		PORTD,0			;nahodit pull-up na RxD vstupe
		ldi		temp0,BaudRate		;nastavitvysielaciu rychlost UART-u
		out		UBRR,temp0
		sbi		UCR,TXEN		;povolit vysielanie UART-u
		sbi		UCR,RXEN		;povolit prijimanie UART-u

		ldi		temp0,0x0F		;INT0 - reagovanie na nabeznu hranu
		out		MCUCR,temp0		;
		ldi		temp0,1<<INT0		;povolit externy interrupt INT0
		out		GIMSK,temp0
		rcall	InitCounter		;inicializacia citaca na TSOP zmenu
;------------------------------------------------------------------------------------------
;********************************************************************
;* Main program
;********************************************************************
		sei					;povolit interrupty globalne
Main:
		sbis	inputport,DATAminus	;cakanie az sa zmeni D- na 0
		rjmp	CheckUSBReset		;a skontroluj, ci to nie je USB reset

		cpi		ActionFlag,DoReceiveSetupData
		breq	ProcReceiveSetupData
		cpi		ActionFlag,DoPrepareOutContinuousBuffer
		breq	ProcPrepareOutContinuousBuffer
		rjmp	Main

CheckUSBReset:
		ldi		temp0,255		;pocitadlo trvania reset-u (podla normy je to cca 10ms - tu je to cca 100us)
WaitForUSBReset:
		sbic	inputport,DATAminus	;cakanie az sa zmeni D+ na 0
		rjmp	Main
		dec		temp0
		brne	WaitForUSBReset
		rcall	USBReset
		rjmp	Main

ProcPrepareOutContinuousBuffer:
		rcall	PrepareOutContinuousBuffer	;priprav pokracovanie odpovede do buffera
		ldi		ActionFlag,DoReadySendAnswer
		rjmp	Main
ProcReceiveSetupData:
		ldi		USBBufptrY,InputBufferBegin	;pointer na zaciatok prijimacieho buffera
		mov		ByteCount,InputBufferLength	;dlzka vstupneho buffera
		rcall	DecodeNRZI		;prevod kodovania NRZI na bity
		rcall	MirrorInBufferBytes	;prehodit poradie bitov v bajtoch
		rcall	BitStuff		;odstranenie bit stuffing
		rcall	CheckCRCIn		;kontrola CRC
		rcall	PrepareUSBOutAnswer	;pripravenie odpovede do vysielacieho buffera
		ldi		ActionFlag,DoReadySendAnswer
		rjmp	Main
;********************************************************************
;* Main program END
;********************************************************************
;------------------------------------------------------------------------------------------
;********************************************************************
;* Interrupt0 interrupt handler
;********************************************************************
INT0Handler:					;prerusenie INT0
		in		backupSREG,SREG
		push	temp0
		push	temp1

		ldi		temp0,3			;pocitadlo trvania log0
		ldi		temp1,2			;pocitadlo trvania log1
		;cakanie na zaciatok paketu
CheckchangeMinus:
		sbis	inputport,DATAminus	;cakanie az sa zmeni D- na 1
		rjmp	CheckchangeMinus
CheckchangePlus:
		sbis	inputport,DATAplus	;cakanie az sa zmeni D+ na 1
		rjmp	CheckchangePlus
DetectSOPEnd:
		sbis	inputport,DATAplus
		rjmp	Increment0		;D+ =0
Increment1:
		ldi		temp0,3			;pocitadlo trvania log0
		dec		temp1			;kolko cyklov trvala log1
		nop
		breq	USBBeginPacket		;ak je to koniec SOP - prijimaj paket
		rjmp	DetectSOPEnd
Increment0:
		ldi		temp1,2			;pocitadlo trvania log1
		dec		temp0			;kolko cyklov trvala log0
		nop
		brne	DetectSOPEnd		;ak nenastal SOF - pokracuj
		rjmp	EndInt0HandlerPOP2
EndInt0Handler:
		pop		ACC
		pop		InfraBufptrX
		pop		temp3
		pop		temp2
EndInt0HandlerPOP:
		pop		USBBufptrY
		pop		ByteCount
		mov		bitcount,backupbitcount	;obnova bitcount registra
EndInt0HandlerPOP2:
		pop		temp1
		pop		temp0
		out		SREG,backupSREG
		ldi		shiftbuf,1<<INTF0	;znulovat flag interruptu INTF0
		out		GIFR,shiftbuf
		reti				;inak skonci (bol iba SOF - kazdu milisekundu)

USBBeginPacket:
		mov		backupbitcount,bitcount	;zaloha bitcount registra
		in		shiftbuf,inputport	;ak ano nacitaj ho ako nulty bit priamo do shift registra
USBloopBegin:
		push	ByteCount		;dalsia zaloha registrov (setrenie casu)
		push	USBBufptrY
		ldi		bitcount,6		;inicializacia pocitadla bitov v bajte
		ldi		ByteCount,MAXUSBBYTES	;inicializacia max poctu prijatych bajtov v pakete
		ldi		USBBufptrY,InputShiftBufferBegin	;nastav vstupny buffer
USBloop1_6:
		in		inputbuf,inputport
		cbr		inputbuf,USBpinmask	;odmaskovat spodne 2 bity
		breq	USBloopEnd		;ak su nulove - koniec USB packetu
		ror		inputbuf		;presun Data+ do shift registra
		rol		shiftbuf
		dec		bitcount		;zmensi pocitadlo bitov
		brne	USBloop1_6		;ak nie je nulove - opakuj naplnanie shift registra
		nop				;inak bude nutne skopirovat shift register bo buffera
USBloop7:
		in		inputbuf,inputport
		cbr		inputbuf,USBpinmask	;odmaskovat spodne 2 bity
		breq	USBloopEnd		;ak su nulove - koniec USB packetu
		ror		inputbuf		;presun Data+ do shift registra
		rol		shiftbuf
		ldi		bitcount,7		;inicializacia pocitadla bitov v bajte
		st		Y+,shiftbuf		;skopiruj shift register bo buffera a zvys pointer do buffera
USBloop0:					;a zacni prijimat dalsi bajt
		in		shiftbuf,inputport	;nulty bit priamo do shift registra
		cbr		shiftbuf,USBpinmask	;odmaskovat spodne 2 bity
		breq	USBloopEnd		;ak su nulove - koniec USB packetu
		dec		bitcount		;zmensi pocitadlo bitov
		nop				;
		dec		ByteCount		;ak sa nedosiahol maximum buffera
		brne	USBloop1_6		;tak prijimaj dalej

		rjmp	EndInt0HandlerPOP	;inak opakuj od zaciatku

USBloopEnd:
		cpi		USBBufptrY,InputShiftBufferBegin+3	;ak sa neprijali aspon 3 byte
		brcs	EndInt0HandlerPOP	;tak skonci
		lds		temp0,InputShiftBufferBegin+0	;identifikator paketu do temp0
		lds		temp1,InputShiftBufferBegin+1	;adresa do temp1
		brne	TestDataPacket		;ak je dlzka ina ako 3 - tak to moze byt iba DataPaket
TestIOPacket:
		cp		temp1,MyAddress		;ak to nie je urcene (adresa) pre mna
		brne	TestDataPacket		;tak to moze byt este Data Packet
TestSetupPacket:;test na SETUP paket
		cpi		temp0,nNRZISETUPPID
		brne	TestOutPacket		;ak nie je Setup PID - dekoduj iny paket
		ldi		State,SetupState
		rjmp	EndInt0HandlerPOP	;ak je Setup PID - prijimaj nasledny Data paket
TestOutPacket:	;test na OUT paket
		cpi		temp0,nNRZIOUTPID
		brne	TestInPacket		;ak nie je Out PID - dekoduj iny paket
		ldi		State,OutState
		rjmp	EndInt0HandlerPOP	;ak je Out PID - prijimaj nasledny Data paket
TestInPacket:	;test na IN paket
		cpi		temp0,nNRZIINPID
		brne	TestDataPacket		;ak nie je In PID - dekoduj iny paket
		rjmp	AnswerToInRequest
TestDataPacket:	;test na DATA0 a DATA1 paket
		cpi		temp0,nNRZIDATA0PID
		breq	Data0Packet		;ak nie je Data0 PID - dekoduj iny paket
		cpi		temp0,nNRZIDATA1PID
		brne	NoMyPacked		;ak nie je Data1 PID - dekoduj iny paket
Data0Packet:
		cpi		State,SetupState	;ak bol stav Setup
		breq	ReceiveSetupData	;prijmi ho
		cpi		State,OutState		;ak bol stav Out
		breq	ReceiveOutData		;prijmi ho
NoMyPacked:
		ldi		State,BaseState		;znuluj stav
		rjmp	EndInt0HandlerPOP	;a prijimaj nasledny Data paket

AnswerToInRequest:
		push	temp2			;zazalohuj dalsie registre a pokracuj
		push	temp3
		push	InfraBufptrX
		push	ACC
		cpi		ActionFlag,DoReadySendAnswer	;ak nie je pripravena odpoved
		brne	NoReadySend		;tak posli NAK
		rcall	SendPreparedUSBAnswer	;poslanie odpovede naspat
		and		MyUpdatedAddress,MyUpdatedAddress	;ak je MyUpdatedAddress nenulova
		brne	SetMyNewUSBAddress	;tak treba zmenit USB adresu
		ldi		State,InState
		ldi		ActionFlag,DoPrepareOutContinuousBuffer
		rjmp	EndInt0Handler		;a opakuj - cakaj na dalsiu odozvu z USB
ReceiveSetupData:
		push	temp2			;zazalohuj dalsie registre a pokracuj
		push	temp3
		push	InfraBufptrX
		push	ACC
		rcall	SendACK			;akceptovanie Setup Data paketu
		rcall	FinishReceiving		;ukonci prijem
		ldi		ActionFlag,DoReceiveSetupData
		rjmp	EndInt0Handler
ReceiveOutData:
		push	temp2			;zazalohuj dalsie registre a pokracuj
		push	temp3
		push	InfraBufptrX
		push	ACC
		cpi		ActionFlag,DoReceiveSetupData	;ak sa prave spracovava prikaz Setup
		breq	NoReadySend		;tak posli NAK
		rcall	SendACK			;akceptovanie Out paketu
		clr		ActionFlag
		rjmp	EndInt0Handler
NoReadySend:
		rcall	SendNAK			;este nie som pripraveny s odpovedou
		rjmp	EndInt0Handler		;a opakuj - cakaj na dalsiu odozvu z USB
;------------------------------------------------------------------------------------------
SetMyNewUSBAddress:		;nastavi novu USB adresu v NRZI kodovani
		clr		MyAddress		;vychodzi stav odpovede - mojej nNRZI USB adresy
		ldi		temp2,0b00000001	;maska na xorovanie
		ldi		temp3,8			;pocitadlo bitov
SetMyNewUSBAddressLoop:
		mov		temp0,MyAddress		;zapamatat si koncovu odpoved
		ror		MyUpdatedAddress	;do carry vysielany bit LSB (v smere naskor LSB a potom MSB)
		brcs	NoXORBit		;ak je jedna - nemen stav
		eor		temp0,temp2		;inak sa bude stav menit podla posledneho bitu odpovede
NoXORBit:
		ror		temp0			;posledny bit zmenenej odpovede do carry
		rol		MyAddress		;a z carry do koncovej odpovede na miesto LSB (a sucasne prehodenie LSB a MSB poradia)
		dec		temp3			;zmensi pocitadlo bitov
		brne	SetMyNewUSBAddressLoop	;ak pocitadlo bitov nie je nulove opakuj vysielanie s dalsim bitom
		clr		MyUpdatedAddress	;znulovanie adresy ako priznak jej buduceho nemenenia
		rjmp	EndInt0Handler
;------------------------------------------------------------------------------------------
FinishReceiving:		;korekcne akcie na ukoncenie prijmu
		cpi		bitcount,7		;prenes do buffera aj posledny necely byte
		breq	NoRemainingBits		;ak boli vsetky byty prenesene, tak neprenasaj nic
		inc		bitcount
ShiftRemainingBits:
		rol		shiftbuf		;posun ostavajuce necele bity na spravnu poziciu
		dec		bitcount
		brne	ShiftRemainingBits
		st		Y+,shiftbuf		;a skopiruj shift register bo buffera - necely byte
NoRemainingBits:
		mov		ByteCount,USBBufptrY
		subi	ByteCount,InputShiftBufferBegin-1	;v ByteCount je pocet prijatych byte (vratane necelych byte)

		mov		InputBufferLength,ByteCount		;a uchovat pre pouzitie v hlavnom programe
		ldi		USBBufptrY,InputShiftBufferBegin	;pointer na zaciatok prijimacieho shift buffera
		ldi		InfraBufptrX,InputBufferBegin+1		;data buffer (vynechat SOP)
MoveDataBuffer:
		ld		temp0,Y+
		st		X+,temp0
		dec		ByteCount
		brne	MoveDataBuffer

		ldi		ByteCount,nNRZISOPbyte
		sts		InputBufferBegin,ByteCount		;ako keby sa prijal SOP - nekopiruje sa zo shift buffera
		ret
;------------------------------------------------------------------------------------------
;********************************************************************
;* Other procedures
;********************************************************************
;------------------------------------------------------------------------------------------
USBReset:		;inicializacia USB stavoveho stroja
		ldi		temp0,nNRZIADDR0	;inicializacia USB adresy
		mov		MyAddress,temp0
		clr		State			;inicializacia stavoveho stroja
		clr		BitStuffInOut
		clr		OutBitStuffNumber
		clr		ActionFlag
		clr		RAMread			;bude sa vycitavat z ROM-ky
		clr		ConfigByte		;nenakonfiguravany stav

⌨️ 快捷键说明

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