📄 avr309-usb 到 uart 协议转换程序.txt
字号:
ld temp0,Y ;从缓冲区取出数据
mov temp2,temp0 ;保存到temp2
ror temp2 ;将 C 移入
eor temp2,temp0 ;解码 NRZI
com temp2 ;取反
st Y+,temp2 ;将完成解码的数据存入
cp USBBufptrY,ByteCount ;所有数据解码完成吗?
brne NRZIloop ;没有完成,继续解码
pop ByteCount
pop USBBufptrY
ret
;------------------------------------------------------------------------------------------
BitStuff: ;位填充处理 (NRZI 编码 6个逻辑1之后插入一位0)
;在接收USB数据中删除/添加位填充。位填充是主机硬件依照USB规范为了数据采样同步而添加的。
;这个例程去除接收数据中的位填充,发送数据时添加位填充。
clr temp3 ;pocitadlo vynechanych bitov
clr lastBitstufNumber ;0xFF --> lastBitstufNumber
dec lastBitstufNumber
BitStuffRepeat:
push USBBufptrY ;临时保存
push ByteCount ;临时保存
mov temp1,temp3 ;pocitadlo vsetkych bitov
ldi temp0,8 ;每字节8位
SumAllBits: ;计算所有数据的总位数
add temp1,temp0
dec ByteCount
brne SumAllBits
ldi temp2,6 ;6个逻辑1之后插入一位0
pop ByteCount ;恢复数据,不改变堆栈内容
push ByteCount
add ByteCount,USBBufptrY ;指向缓冲区结尾
inc ByteCount ;+ 2 (kvoli posuvaniu)
inc ByteCount
BitStuffLoop:
ld temp0,Y ;从缓冲区取出数据
ldi bitcount,8
BitStuffByteLoop:
ror temp0 ;移位 LSB 到 C
brcs IncrementBitstuff ;判断最低位 LSB=0 ?
ldi temp2,7 ;为0,重新计数"6个逻辑1之后插入一位0"
IncrementBitstuff:
dec temp2 ;连续6个逻辑1吗?
brne DontShiftBuffer ;不是连续6个逻辑1,缓冲区的数据不操作
cp temp1,lastBitstufNumber ;是连续6个逻辑1
ldi temp2,6 ;初始化判断计数 (ak by sa nerobil bitstuffing tak sa musi zacat odznova)
brcc DontShiftBuffer ;ak sa tu uz robil bitstuffing - neposun buffer
dec temp1 ;
mov lastBitstufNumber,temp1 ;zapamataj si poslednu poziciu bitstuffingu
cpi bitcount,1 ;aby sa ukazovalo na 7 bit (ktory sa ma vymazat alebo kde sa ma vlozit nula)
brne NoBitcountCorrect
ldi bitcount,9
inc USBBufptrY ;zvys 指针 do 缓冲区
NoBitcountCorrect:
dec bitcount
bst BitStuffInOut,0
brts CorrectOutBuffer ;是增加位填充还是滤除位填充? 增加=1 滤除=0
rcall ShiftDeleteBuffer ;滤除填充位
dec temp3 ;zniz pocitadlo vynechani
rjmp CorrectBufferEnd
CorrectOutBuffer:
rcall ShiftInsertBuffer ;插入填充位
inc temp3 ;zvys pocitadlo vynechani
CorrectBufferEnd:
pop ByteCount ;obnov dlzku 缓冲区
pop USBBufptrY ;obnov 指针 do 缓冲区
rjmp BitStuffRepeat ;a restartni od zaciatku
DontShiftBuffer:
dec temp1 ;所有位都判断完成吗?
breq EndBitStuff ;ukonci cyklus
dec bitcount ;当前字节判断完成吗?
brne BitStuffByteLoop ;继续判断填充
;inak nahraj dalsi byte
inc USBBufptrY ;zvys 指针 do 缓冲区
rjmp BitStuffLoop ;a opakuj
EndBitStuff:
pop ByteCount ;obnov dlzku 缓冲区
pop USBBufptrY ;obnov 指针 do 缓冲区
bst BitStuffInOut,0
brts IncrementLength ;是增加位填充还是滤除位填充? 增加=1 滤除=0
DecrementLength: ;ak je In buffer - zniz dlzku In 缓冲区
cpi temp3,0 ;bolo aspon jedno znizenie
breq NoChangeByteCount ;ak nie - nemen dlzku 缓冲区
dec ByteCount ;ak je In buffer - zniz dlzku 缓冲区
subi temp3,256-8 ;ak nebolo viac ako 8 bitov naviac
brcc NoChangeByteCount ;tak skonci
dec ByteCount ;inak este zniz dlzku 缓冲区
ret ;a skonci
IncrementLength:
mov OutBitStuffNumber,temp3 ;zapamataj si pocet bitov naviac
subi temp3,8 ;ak nebolo viac ako 8 bitov naviac
brcs NoChangeByteCount ;tak skonci
inc ByteCount ;inak zvys dlzku 缓冲区
mov OutBitStuffNumber,temp3 ;a zapamataj si pocet bitov naviac (znizene o 8)
NoChangeByteCount:
ret ;skonci
;------------------------------------------------------------------------------------------
ShiftInsertBuffer: ;posuv 缓冲区 o jeden bit vpravo od konca az po poziciu: byte-USBBufptrY a bit-bitcount
;执行位填充增加时的辅助例程。添加一位到输出数据缓冲区会增加缓冲区的长度。缓冲区的剩余部
;分移出。
mov temp0,bitcount ;vypocet: bitcount= 9-bitcount
ldi bitcount,9
sub bitcount,temp0 ;do bitcount poloha bitu, ktory treba nulovat
ld temp1,Y ;nahraj byte ktory este treba posunut od pozicie bitcount
rol temp1 ;a posun vlavo cez Carry (prenos z vyssieho byte a LSB do Carry)
ser temp2 ;FF do masky - temp2
HalfInsertPosuvMask:
lsl temp2 ;nula do dalsieho spodneho bitu masky
dec bitcount ;az pokial sa nedosiahne hranica posuvania v byte
brne HalfInsertPosuvMask
and temp1,temp2 ;odmaskuj aby zostali iba vrchne posunute bity v temp1
com temp2 ;invertuj masku
lsr temp2 ;posun masku vpravo - na vlozenie nuloveho bitu
ld temp0,Y ;nahraj byte ktory este treba posunut od pozicie bitcount do temp0
and temp0,temp2 ;odmaskuj aby zostali iba spodne neposunute bity v temp0
or temp1,temp0 ;a zluc posunutu a neposunutu cast
ld temp0,Y ;nahraj byte ktory este treba posunut od pozicie bitcount
rol temp0 ;a posun ho vlavo cez Carry (aby sa nastavilo spravne Carry pre dalsie prenosy)
st Y+,temp1 ;a nahraj spat upraveny byte
ShiftInsertBufferLoop:
cpse USBBufptrY,ByteCount ;ak nie su vsetky cele byty
rjmp NoEndShiftInsertBuffer ;tak pokracuj
ret ;inak skonci
NoEndShiftInsertBuffer:
ld temp1,Y ;nahraj byte
rol temp1 ;a posun vlavo cez Carry (prenos z nizsieho byte a LSB do Carry)
st Y+,temp1 ;a nahraj spat
rjmp ShiftInsertBufferLoop ;a pokracuj
;------------------------------------------------------------------------------------------
ShiftDeleteBuffer: ;posuv 缓冲区 o jeden bit vlavo od konca az po poziciu: byte-USBBufptrY a bit-bitcount
;执行位填充删除时的辅助例程。从输出缓冲删除一位时会减少缓冲区长度。缓冲区的剩余部分移入。
mov temp0,bitcount ;vypocet: bitcount= 9-bitcount
ldi bitcount,9
sub bitcount,temp0 ;do bitcount poloha bitu, ktory este treba posunut
mov temp0,USBBufptrY ;uschovanie 指针a do 缓冲区
inc temp0 ;pozicia celych bytov do temp0
mov USBBufptrY,ByteCount ;maximalna pozicia do pointra
ShiftDeleteBufferLoop:
ld temp1,-Y ;zniz buffer a nahraj byte
ror temp1 ;a posun vpravo cez Carry (prenos z vyssieho byte a LSB do Carry)
st Y,temp1 ;a nahraj spat
cpse USBBufptrY,temp0 ;ak nie su vsetky cele byty
rjmp ShiftDeleteBufferLoop ;tak pokracuj
ld temp1,-Y ;zniz buffer a nahraj byte ktory este treba posunut od pozicie bitcount
ror temp1 ;a posun vpravo cez Carry (prenos z vyssieho byte a LSB do Carry)
ser temp2 ;FF do masky - temp2
HalfDeletePosuvMask:
dec bitcount ;az pokial sa nedosiahne hranica posuvania v byte
breq DoneMask
lsl temp2 ;nula do dalsieho spodneho bitu masky
rjmp HalfDeletePosuvMask
DoneMask:
and temp1,temp2 ;odmaskuj aby zostali iba vrchne posunute bity v temp1
com temp2 ;invertuj masku
ld temp0,Y ;nahraj byte ktory este treba posunut od pozicie bitcount do temp0
and temp0,temp2 ;odmaskuj aby zostali iba spodne neposunute bity v temp0
or temp1,temp0 ;a zluc posunutu a neposunutu cast
st Y,temp1 ;a nahraj spat
ret ;a skonci
;------------------------------------------------------------------------------------------
MirrorInBufferBytes: ;镜像输入缓冲区
;以字节为单位交换顺序,因为从USB 线接收到缓冲区的数据是反序的(LSB/MSB)
push USBBufptrY
push ByteCount
ldi USBBufptrY,InputBufferBegin
rcall MirrorBufferBytes
pop ByteCount
pop USBBufptrY
ret
;------------------------------------------------------------------------------------------
MirrorBufferBytes: ;镜像Y指针指定的缓冲区(Bit7←→BiT0、Bit4←→BiT3)
add ByteCount,USBBufptrY ;取得缓冲区有效数据的结束地址
MirrorBufferloop:
ld temp0,Y ;从缓冲区中取出数据
ldi temp1,8 ;每字节8位,为了移位计数
MirrorBufferByteLoop:
ror temp0 ;右移到C
rol temp2 ;将C中的数据左移到TEMP2,一个右移一个左移就完成了高低位交换
dec temp1 ;当前字节完成吗?
brne MirrorBufferByteLoop ;没有完成,接着移吧
st Y+,temp2 ;将镜像后的数据保存
cp USBBufptrY,ByteCount ;是否完成所有的数据
brne MirrorBufferloop ;没有完成,接着移吧
ret ;返回
;------------------------------------------------------------------------------------------
;CheckCRCIn:
;对接收的数据包进行CRC 校验。USB 包添加CRC 来检测数据的损坏。
; push USBBufptrY
; push ByteCount
; ldi USBBufptrY,InputBufferBegin
; rcall CheckCRC
; pop ByteCount
; pop USBBufptrY
; ret
;------------------------------------------------------------------------------------------
AddCRCOut:
;给输出数据包添加CRC 域。依照USB 规范提供的USB 域计算CRC。
push USBBufptrY
push ByteCount
ldi USBBufptrY,OutputBufferBegin
rcall CheckCRC
com temp0 ;取反 CRC
com temp1
st Y+,temp1 ;将CRC结果存入缓冲区 (MSB)
st Y,temp0 ;将CRC结果存入缓冲区 (LSB)
dec USBBufptrY ;指针指向 CRC 开始位置
ldi ByteCount,2 ;2字节 CRC 长度
rcall MirrorBufferBytes ;镜像Y指针指定的缓冲区 (CRC)
pop ByteCount
pop USBBufptrY
ret
;------------------------------------------------------------------------------------------
CheckCRC: ;提示: USBBufptrY = zaciatok spravy ,ByteCount = dlzka spravy
;检查和添加CRC 的辅助例程。
add ByteCount,USBBufptrY ;取得缓冲区有效数据的结束地址
inc USBBufptrY ;CRC 要包括 SOP
ld temp0,Y+ ;取得 PID
;a nastav 指针 na zaciatok spravy - vynechat aj PID
cpi temp0,DATA0PID ;判断是不是循环位 DATA0
breq ComputeDATACRC ;
cpi temp0,DATA1PID ;判断是不是循环位 DATA1
brne CRC16End ;不是循环位 DATA1/DATA0,不进行CRC处理
ComputeDATACRC:
ser temp0 ;初始化 LSB 到 0xff
ser temp1 ;初始化 MSB 到 0xff
CRC16Loop:
ld temp2,Y+ ;根据指针取出数据到缓冲区
ldi temp3,8 ;每字节8位
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -