📄 新建 文本文档.txt
字号:
;***************************************************************************
;* U S B S T A C K F O R T H E A V R F A M I L Y
;*
;* 文件名 :"USB90S2313.asm"
;* 标题 :AVR309:USB 到 UART 协议转换程序 (简易的 - 少量的FIFO)
;* 日期 :24.11.2004
;* 版本 :2.2
;* 目标 MCU :AT90S2313-10
;* 创造者 :Ing. Igor Cesko
;* Slovakia
;* cesko@internet.sk
;* http://www.cesko.host.sk
;* 翻译 :吴险峰
;* 描述:
;* 通过 MCU 执行 USB 协议,完成软 USB 接口:
;* 设备:
;* 通用的 USB 接口 (8-bit I/O口 + RS232 串行通讯 + EEPROM)
;* + 附加的 RS232 FIFO 缓冲器
;*
;* 使用 12 MHz 振荡器 ( MCU 超频 !!!)
;*
;*
;* 添加自己的功能 - 请看: TEMPLATE OF YOUR FUNCTION
;*
;* 做成自己公司的产品必须更改 VendorUSB ID (VID)
;* 获得分配到自己公司的 VID (更多的信息请查看 www.usb.org)
;*
;***************************************************************************
.include "2313def.inc"
.equ inputport =PINB
.equ outputport =PORTB
.equ USBdirection =DDRB
.equ DATAplus =1 ;PB1模拟 D+ 信号
.equ DATAminus =0 ;PB0模拟 D- 信号 - 接1.5K上拉电阻,低速模式
.equ USBpinmask =0b11111100 ;屏蔽 PB 低2位 (D+,D-)
.equ USBpinmaskDplus =~(1<<DATAplus) ;屏蔽 PB D+ 位
.equ USBpinmaskDminus =~(1<<DATAminus);屏蔽 PB D- 位
.equ TSOPPort =PINB
.equ TSOPpullupPort =PORTB
.equ TSOPPin =2 ;红外遥控接收头 TSOP1738 输出到 PB2
.equ LEDPortLSB =PORTD ;用户自定义 PD 输出口
.equ LEDPinLSB =PIND ;用户自定义 PD 输入口
.equ LEDdirectionLSB =DDRD ;用户自定义 PD 口方向
.equ LEDPortMSB =PORTB ;用户自定义 PB 输出口
.equ LEDPinMSB =PINB ;用户自定义 PB 输入口
.equ LEDdirectionMSB =DDRB ;用户自定义 PB 口方向
.equ LEDlsb0 =3 ;用户自定义口 PD3
.equ LEDlsb1 =5 ;用户自定义口 PD5
.equ LEDlsb2 =6 ;用户自定义口 PD6
.equ LEDmsb3 =3 ;用户自定义口 PB3
.equ LEDmsb4 =4 ;用户自定义口 PB4
.equ LEDmsb5 =5 ;用户自定义口 PB5
.equ LEDmsb6 =6 ;用户自定义口 PB6
.equ LEDmsb7 =7 ;用户自定义口 PB7
.equ SOPbyte =0b10000000 ;Start of Packet byte
.equ DATA0PID =0b11000011 ;PID pre DATA0 pole
.equ DATA1PID =0b01001011 ;PID pre DATA1 pole
.equ OUTPID =0b11100001 ;PID pre OUT pole
.equ INPID =0b01101001 ;PID pre IN pole
.equ SOFPID =0b10100101 ;PID pre SOF pole
.equ SETUPPID =0b00101101 ;PID pre SETUP pole
.equ ACKPID =0b11010010 ;PID pre ACK pole
.equ NAKPID =0b01011010 ;PID pre NAK pole
.equ STALLPID =0b00011110 ;PID pre STALL pole
.equ PREPID =0b00111100 ;PID pre PRE pole
.equ nSOPbyte =0b00000001 ;Start of Packet byte - opacne poradie
.equ nDATA0PID =0b11000011 ;PID pre DATA0 pole - opacne poradie
.equ nDATA1PID =0b11010010 ;PID pre DATA1 pole - opacne poradie
.equ nOUTPID =0b10000111 ;PID pre OUT pole - opacne poradie
.equ nINPID =0b10010110 ;PID pre IN pole - opacne poradie
.equ nSOFPID =0b10100101 ;PID pre SOF pole - opacne poradie
.equ nSETUPPID =0b10110100 ;PID pre SETUP pole - opacne poradie
.equ nACKPID =0b01001011 ;PID pre ACK pole - opacne poradie
.equ nNAKPID =0b01011010 ;PID pre NAK pole - opacne poradie
.equ nSTALLPID =0b01111000 ;PID pre STALL pole - opacne poradie
.equ nPREPID =0b00111100 ;PID pre PRE pole - opacne poradie
.equ nNRZITokenPID =~0b10000000 ;PID maska pre Token paket (IN,OUT,SOF,SETUP) - opacne poradie NRZI
.equ nNRZISOPbyte =~0b10101011 ;Start of Packet byte - opacne poradie NRZI
.equ nNRZIDATA0PID =~0b11010111 ;PID pre DATA0 pole - opacne poradie NRZI
.equ nNRZIDATA1PID =~0b11001001 ;PID pre DATA1 pole - opacne poradie NRZI
.equ nNRZIOUTPID =~0b10101111 ;PID pre OUT pole - opacne poradie NRZI
.equ nNRZIINPID =~0b10110001 ;PID pre IN pole - opacne poradie NRZI
.equ nNRZISOFPID =~0b10010011 ;PID pre SOF pole - opacne poradie NRZI
.equ nNRZISETUPPID =~0b10001101 ;PID pre SETUP pole - opacne poradie NRZI
.equ nNRZIACKPID =~0b00100111 ;PID pre ACK pole - opacne poradie NRZI
.equ nNRZINAKPID =~0b00111001 ;PID pre NAK pole - opacne poradie NRZI
.equ nNRZISTALLPID =~0b00000111 ;PID pre STALL pole - opacne poradie NRZI
.equ nNRZIPREPID =~0b01111101 ;PID pre PRE pole - opacne poradie NRZI
.equ nNRZIADDR0 =~0b01010101 ;Adresa = 0 - opacne poradie NRZI
;stavove byty - State
.equ BaseState =0 ;
.equ SetupState =1 ;
.equ InState =2 ;
.equ OutState =3 ;
.equ SOFState =4 ;
.equ DataState =5 ;
.equ AddressChangeState =6 ;
;Flagy pozadovanej akcie
.equ DoNone =0
.equ DoReceiveOutData =1
.equ DoReceiveSetupData =2
.equ DoPrepareOutContinuousBuffer =3
.equ DoReadySendAnswer =4
.equ CRC5poly =0b00101 ;CRC5 polynom
.equ CRC5zvysok =0b01100 ;CRC5 zvysok po uspesnpm CRC5
.equ CRC16poly =0b1000000000000101 ;CRC16 polynom
.equ CRC16zvysok =0b1000000000001101 ;CRC16 zvysok po uspesnom CRC16
.equ MAXUSBBYTES =14 ;USB 输入最大的字节数
.equ MAXRS232LENGTH =36 ;maximalna dlzka RS232 kodu (pocet jednotiek a nul spolu) (pozor: MAXRS232LENGTH musi byt parne cislo !!!)
.equ NumberOfFirstBits =10 ;kolko prvych bitov moze byt dlhsich
.equ NoFirstBitsTimerOffset =256-12800*12/1024 ;Timeout 12.8ms (12800us) na ukoncenie prijmu po uvodnych bitoch (12Mhz:clock, 1024:timer predivider, 256:timer overflow value)
.equ InitBaudRate =12000000/16/57600-1 ;nastavit vysielaciu rychlost UART-u na 57600 (pre 12MHz=12000000Hz)
.equ InputBufferBegin =RAMEND-127 ;zaciatok prijimacieho shift 缓冲区
.equ InputShiftBufferBegin =InputBufferBegin+MAXUSBBYTES ;zaciatok prijimacieho 缓冲区
.equ RS232BufferBegin =InputShiftBufferBegin+MAXUSBBYTES ;zaciatok 缓冲区 pre RS232 prijem
.equ MyInAddressSRAM =RS232BufferBegin+MAXRS232LENGTH+1
.equ MyOutAddressSRAM =MyInAddressSRAM+1
.equ OutputBufferBegin =RAMEND-MAXUSBBYTES-2 ;zaciatok vysielacieho 缓冲区
.equ AckBufferBegin =OutputBufferBegin-3 ;zaciatok vysielacieho 缓冲区 Ack
.equ NakBufferBegin =AckBufferBegin-3 ;zaciatok vysielacieho 缓冲区 Nak
.equ StackBegin =NakBufferBegin-1 ;堆栈开始位置
.def ConfigByte =R1 ;0=unconfigured state
.def backupbitcount =R2 ;INT0 中保存 bitcount
.def RAMread =R3 ;ci sa ma citat zo SRAM-ky
.def backupSREGTimer =R4 ;定时器中断中的SREG备份
.def backupSREG =R5 ;INT0 中断中的SREG备份
.def ACC =R6 ;accumulator
.def lastBitstufNumber =R7 ;pozicia bitstuffingu
.def OutBitStuffNumber =R8 ;kolko bitov sa ma este odvysielat z posledneho bytu - bitstuffing
.def BitStuffInOut =R9 ;ci sa ma vkladat alebo mazat bitstuffing
.def TotalBytesToSend =R10 ;发送的总字节
.def TransmitPart =R11 ;传送的次数
.def InputBufferLength =R12 ;dlzka pripravena vo vstupnom USB bufferi
.def OutputBufferLength =R13 ;dlzka odpovede pripravena v USB bufferi
.def MyOutAddress =R14 ;moja USB adresa na update
.def MyInAddress =R15 ;moja USB adresa
.def ActionFlag =R16 ;工作标志
.def temp3 =R17 ;临时寄存器
.def temp2 =R18 ;临时寄存器
.def temp1 =R19 ;临时寄存器
.def temp0 =R20 ;临时寄存器
.def bitcount =R21 ;counter of bits in byte
.def ByteCount =R22 ;pocitadlo maximalneho poctu prijatych bajtov
.def inputbuf =R23 ;prijimaci 寄存器
.def shiftbuf =R24 ;posuvny prijimaci 寄存器
.def State =R25 ;byte stavu stavoveho stroja
.def RS232BufptrX =R26 ;XL 寄存器 - 用作 prijatych IR kodov 缓冲区指针
.def RS232BufferFull =R27 ;XH 寄存器 - priznak plneho RS232 缓冲区
.def USBBufptrY =R28 ;YL 寄存器 - 用作 USB 输入/输出缓冲区指针
.def ROMBufptrZ =R30 ;ZL 寄存器 - 用作 ROM 缓冲区 dat 指针
;poziadavky na deskriptory
.equ GET_STATUS =0
.equ CLEAR_FEATURE =1
.equ SET_FEATURE =3
.equ SET_ADDRESS =5
.equ GET_DESCRIPTOR =6
.equ SET_DESCRIPTOR =7
.equ GET_CONFIGURATION =8
.equ SET_CONFIGURATION =9
.equ GET_INTERFACE =10
.equ SET_INTERFACE =11
.equ SYNCH_FRAME =12
;typy deskriptorov
.equ DEVICE =1
.equ CONFIGURATION =2
.equ STRING =3
.equ INTERFACE =4
.equ ENDPOINT =5
.equ USER_FNC_NUMBER =100
;------------------------------------------------------------------------------------------
;********************************************************************
;* Interrupt table
;********************************************************************
.cseg
;------------------------------------------------------------------------------------------
.org 0 ;po resete
rjmp reset
;------------------------------------------------------------------------------------------
.org INT0addr ;externe prerusenie INT0
rjmp INT0handler
;------------------------------------------------------------------------------------------
.org URXCaddr ;prijem zo seriovej linky
push temp0
in temp0,UDR ;读入异步串行数据到 temp0
sei ;打开中断,为了模拟 USB
in backupSREGTimer,SREG ;保存 SREG
cbi UCR,RXCIE ;清除 UART 接收完成标志
cpi RS232BufferFull,MAXRS232LENGTH-4
brcc NoIncRS232BufferFull
push RS232BufptrX
lds RS232BufptrX,RS232BufferBegin+2 ;nastavenie sa na zaciatok 缓冲区 zapisu RS232 kodu : 3.byte hlavicky (dlzka kodu + citanie + zapis + rezerva)
st X+,temp0 ;a uloz ho do 缓冲区
cpi RS232BufptrX,RS232BufferBegin+MAXRS232LENGTH+1 ;ak sa nedosiahol maximum RS232 缓冲区
brne NoUARTBufferOverflow ;tak pokracuj
ldi RS232BufptrX,RS232BufferBegin+4 ;inak sa nastav na zaciatok 缓冲区
NoUARTBufferOverflow:
sts RS232BufferBegin+2,RS232BufptrX ;ulozenie noveho offsetu 缓冲区 zapisu RS232 kodu : 3.byte hlavicky (dlzka kodu + citanie + zapis + rezerva)
inc RS232BufferFull ;zvys dlzku RS232 缓冲区
pop RS232BufptrX
NoIncRS232BufferFull:
pop temp0
out SREG,backupSREGTimer ;恢复 SREG
cli ;zakazat interrupt kvoli zacykleniu
sbi UCR,RXCIE ;允许 interrupt od prijimania UART
reti
;------------------------------------------------------------------------------------------
;********************************************************************
;* 初始化程序
;********************************************************************
;------------------------------------------------------------------------------------------
reset: ;初始化AVR资源:堆栈、串行口、USB缓冲区、中断
ldi temp0,StackBegin ;初始化堆栈
out SPL,temp0
clr XH ;RS232 指针
clr YH ;USB 指针
clr ZH ;ROM 指针
sts RS232BufferBegin+0,YH ;znuluj dlzky RS232 kodu v bufferi
ldi temp0,RS232BufferBegin+4
sts RS232BufferBegin+1,temp0;znuluj ukazovatel citania
sts RS232BufferBegin+2,temp0;znuluj ukazovatel zapisu
clr RS232BufferFull
rcall InitACKBufffer ;初始化 ACK 缓冲区
rcall InitNAKBufffer ;初始化 NAK 缓冲区
rcall USBReset ;初始化 USB 接口到默认值
sbi TSOPpullupPort,TSOPpin ;上拉红外接收口
ldi temp0,(1<<LEDlsb0)+(1<<LEDlsb1)+(1<<LEDlsb2)
out LEDPortLSB,temp0 ;用户自定义 PD 输出高
ldi temp0,(1<<LEDmsb3)+(1<<LEDmsb4)+(1<<LEDmsb5)+(1<<LEDmsb6)+(1<<LEDmsb7)
out LEDPortMSB,temp0 ;用户自定义 PB 输出高
sbi PORTD,0 ;上拉串行接收口 RxD
ldi temp0,InitBaudRate ;串行通讯波特率
out UBRR,temp0
sbi UCR,TXEN ;允许串行发送
sbi UCR,RXEN ;允许串行接收
sbi UCR,RXCIE ;允许 interrupt od prijimania UART
ldi temp0,0x0F ;设置 INT0、INT1 上升沿中断
out MCUCR,temp0 ;
ldi temp0,1<<INT0 ;允许外部中断 INT0
out GIMSK,temp0
;------------------------------------------------------------------------------------------
;********************************************************************
;* Main program
;********************************************************************
sei ;允许全局中断
Main:
sbis inputport,DATAminus ;测试 D- 是否为0
rjmp CheckUSBReset ;如果为0检查 USB 复位
cpi ActionFlag,DoReceiveSetupData ;是否接收到配置数据
breq ProcReceiveSetupData
cpi ActionFlag,DoPrepareOutContinuousBuffer ;是否准备从缓冲区输出连续数据
breq ProcPrepareOutContinuousBuffer
rjmp Main
CheckUSBReset:
ldi temp0,255 ;进入 USB 复位时间 (10ms - 100us),集线器发出至少10mS
WaitForUSBReset:
sbic inputport,DATAminus ;测试 D+ 是否为0
rjmp Main
dec temp0 ;等待复位
brne WaitForUSBReset ;集线器开始重新设置本设备前,会复位本设备
rcall USBReset ;USB 复位
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -