📄 ——基于8位微控制器控制硬盘进行hdtv码流读写.htm
字号:
<TR class=main>
<TD align=middle width="16%">CS1FX</TD>
<TD align=middle width="16%">CS3FX</TD>
<TD align=middle width="17%">DA2</TD>
<TD align=middle width="17%">DA1</TD>
<TD align=middle width="17%">DA0</TD>
<TD align=middle width="17%">Address</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">170</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">171</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">172</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">173</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">174</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">175</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">176</TD></TR>
<TR class=main>
<TD align=middle width="16%">1</TD>
<TD align=middle width="16%">0</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">177</TD></TR>
<TR class=main>
<TD align=middle width="16%">0</TD>
<TD align=middle width="16%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">0</TD>
<TD align=middle width="17%">376</TD></TR>
<TR class=main>
<TD align=middle width="16%">0</TD>
<TD align=middle width="16%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">1</TD>
<TD align=middle width="17%">377</TD></TR>
<TR class=main>
<TD align=middle width="16%">0</TD>
<TD align=middle width="16%">1</TD>
<TD align=middle width="17%">*</TD>
<TD align=middle width="17%">*</TD>
<TD align=middle width="17%">*</TD>
<TD align=middle width="17%">未用</TD></TR></TBODY></TABLE>
<P
style="TEXT-INDENT: 30px">·数据寄存器(170R/W):这是一个16位PIO数据寄存器,用于对扇区的读、写和格式化操作。MCU通过该寄存器向硬盘控制寄存器写入或从硬盘控制器读出扇区缓冲区的数据。</P>
<P
style="TEXT-INDENT: 30px">·错误寄存器(171R):该寄存器是一个8位的寄存器,它反映控制寄存器在诊断方式或操作方式下的错误原因。</P>
<P
style="TEXT-INDENT: 30px">·扇区数寄存器(172R/W):它记录读、写命令的扇区数。当多扇区传输时,每完成一个扇区操作,该寄存器自动减1,直至为0。如果初值为0,则表示256;如果有错误生,该寄存器包含已经操作成功的扇区数。</P>
<P
style="TEXT-INDENT: 30px">·扇区号寄存器(173R/W):它记录读、写和校验命令指令起始扇区号。本文用LBA模式。该寄存器记录逻辑扇区的0字节。</P>
<P style="TEXT-INDENT: 30px">·柱面号寄存器(174 175
R/W):它记录读、写、校验、寻址和格式化命令指定的柱面号,在LBA寻址方式下,这2个寄存器包含起始扇区的1和2字节。</P>
<P
style="TEXT-INDENT: 30px">·驱动器/磁头寄存器(176R/W):它记录读、写、校验、寻道和格式化命令指定的驱动器号、磁头号和寻址方式。在ATA/ATAPI-4中其定义如表2所示。<BR><BR><B>表2
驱动器/磁头寄存器在ATA/ATAPI-4中的定义</B></P>
<TABLE border=1 borderColorDark=#ffffff borderColorLight=#000000
width="100%">
<TBODY>
<TR class=main>
<TD align=middle width="12%">D7</TD>
<TD align=middle width="12%">D6</TD>
<TD align=middle width="12%">D5</TD>
<TD align=middle width="12%">D4</TD>
<TD align=middle width="13%">D3</TD>
<TD align=middle width="13%">D2</TD>
<TD align=middle width="13%">D1</TD>
<TD align=middle width="13%">D0</TD></TR>
<TR class=main>
<TD align=middle width="12%">1</TD>
<TD align=middle width="12%">L</TD>
<TD align=middle width="12%">1</TD>
<TD align=middle width="12%">DEV</TD>
<TD align=middle width="13%">HS3</TD>
<TD align=middle width="13%">HS2</TD>
<TD align=middle width="13%">HS1</TD>
<TD align=middle width="13%">HS0</TD></TR></TBODY></TABLE>
<P style="TEXT-INDENT: 30px">HS0~HS3(磁头选择):在LBA方式中,是逻辑扇区的高4位。</P>
<P style="TEXT-INDENT: 30px">DEV驱动器选择:0选择主驱动器,1选择从驱动器。</P>
<P
style="TEXT-INDENT: 30px">L(LBA方式):L=1,置驱动器为LBA模式;L=0,置驱动器为CHS模式。</P>
<P style="TEXT-INDENT: 30px">·状态寄存器(177
R);反映了硬盘执行命令后的状态。读该寄存器清除中断请求信号,为避免清除中断,可以读辅助状态寄存器376h。这两个寄存器的内容完全一样。在ATA/ATAPI-4中其定义如表3所示。</P>
<P style="TEXT-INDENT: 30px">BSY:驱动器忙。</P>
<P style="TEXT-INDENT: 30px">DRDY:驱动器准备好。</P>
<P style="TEXT-INDENT: 30px">DRQ:请求服务,驱动器请求通过寄存器与处理器交换一个字节数据。</P>
<P style="TEXT-INDENT: 30px">ERR:命令执行错误。</P>
<P style="TEXT-INDENT: 30px">3.2 硬盘PIO方式下特定区域多扇区读的操作</P>
<P
style="TEXT-INDENT: 30px">如果想从硬盘的特定扇区读出码流信息,首先主机(C8051F015)要对驱动器/磁头寄存器、柱面号寄存器、扇区号寄存器、扇区数寄存器设置参数。完毕后要等待至少400ns才能去读状态寄存器的参数判断以上设置是否有效。硬盘接收命令后置BSY=1,并开始执行命令。硬盘如果准备好传送数据包,就置DRQ=1,同时清零BSY。当机循环读状态寄存器或辅助状态寄存器判断BSY=0&DRQ=1,一旦硬盘状态符合要求,主机写参数0x80(128扇区)到数据寄存器(0x170),并写0x20(PIO读)到命令寄存器(0x177),表示要求读出硬盘相应地址里的数据块。硬盘判断数据寄存器被置数后立即置BSY=1&DRQ=0。主机读到置位信息后给硬盘读时钟,硬盘输出数据直到数据包传完为止。<BR><BR><B>表3
状态寄存器在ATA/ATAPI-4中的定义</B></P>
<TABLE border=1 borderColorDark=#ffffff borderColorLight=#000000
width="100%">
<TBODY>
<TR class=main>
<TD align=middle width="12%">D7</TD>
<TD align=middle width="12%">D6</TD>
<TD align=middle width="12%">D5</TD>
<TD align=middle width="12%">D4</TD>
<TD align=middle width="13%">D3</TD>
<TD align=middle width="13%">D2</TD>
<TD align=middle width="13%">D1</TD>
<TD align=middle width="13%">D0</TD></TR>
<TR class=main>
<TD align=middle width="12%">BSY</TD>
<TD align=middle width="12%">DRDY</TD>
<TD align=middle width="12%">#</TD>
<TD align=middle width="12%">#</TD>
<TD align=middle width="13%">DRQ</TD>
<TD align=middle width="13%">obsolete</TD>
<TD align=middle width="13%">obsolete</TD>
<TD align=middle width="13%">ERR</TD></TR></TBODY></TABLE>
<P style="TEXT-INDENT: 0px"><B>4 系统设计方案</B></P>
<P style="TEXT-INDENT: 30px">4.1 系统硬件构成</P>
<P
style="TEXT-INDENT: 30px">基于8位微控制器的系统设计方案如图2所示。主系统中以C8051F015为控制核心,C8051F015产生硬盘和FIFO的读写时序(为了避免硬盘寄存器参数也被写入FIFO,在硬件上要把二者的读写时钟分开。);硬盘输出的16位数据分离低8位分别送入两片64KB的FIFO缓存。数据经缓存后持续地输出到CPLD,CPLD对16位数据流进行拆分,同时识别包同步和字节同步。这样,原始的一路HDTV码流就被分成3路输送给解码器解码。主系统通过串行总线与前面板相连,采用通用单片机AT89C51为前面板的控制核心。AT89C51接收来自键盘的命令并在LCD上以文字和图形的方式展现在用户面前,同时通过串口通信,启动主控制器执行命令。</P>
<P style="TEXT-INDENT: 30px">4.2 系统软件设计</P>
<P style="TEXT-INDENT: 30px">4.2.1 存码流部分</P>
<P
style="TEXT-INDENT: 30px">本系统没有引入操作系统和文件格式,所以码流文件存入硬盘时就不能按文件格式,而只能按二进制流的方式从PC机的码流文件中读出数据,再按同样的方式写入裸盘。为了解决码流的总是,试图调用BIOS中断,让BIOS的硬盘服务流程负责把INT13的读写请求转化为ATA界面对硬盘的请求,并执行数据I/O传输的物理动作。但由于BIOS本身寄存器的限制,用它去访问硬盘有8.4G容限的问题。如果想突破这个限制而用扩展的INT13,将是一个比较复杂的过程。可以利用PC机上的Secondary
IDE
Channel(0x170~0x177)作为硬盘寄存器的端口地址。在这个硬件平台下,可以直接将fread()函数读出的码流按块写入目标硬盘,甚至不要求大多地考虑时序问题。</P>
<P style="TEXT-INDENT: 30px">4.2.2 读码流部分</P>
<P
style="TEXT-INDENT: 30px">这部分软件是在上述硬件系统平台上直接编程。系统在启动硬盘前要等待串行中断,接收由前面板发出的命令,再根据接收的数据信息具体决定应该播放哪几个节目;随后对硬盘、FIFO进行初始化,启动CPLD,FIFO输出数据时钟信号,并让硬盘按命令输出数据流。数据在总线稳定的时间内给FIFO写时钟,以采集正确的码流信息(这里强调时序)。FIFO有“半满”(HF)标志,用HF去触发中断,有中断请求,就让硬盘输出64KB的数据。如此循环,保证FIFO不空。当FIFO输出第一个数据时,CPLD开始对数据流进行拆分,并按照HDTV码流的格式标准对数据流进行判别(HDTV码流188字节为一个包,每个包头是0x47),即每计数1次,就输出一个比特同步,每计数188次并识别下一个数为0x47,就输出一个包同步。这部分程序流程如图3。<BR>IP<IMG
border=0 height=311 hspace=45
src="——基于8位微控制器控制硬盘进行HDTV码流读写.files/3c.gif" vspace=10
width=444><BR><FONT size=3> </FONT><SPAN
class=main1>4.2.3 应用程序</P>
<P
style="TEXT-INDENT: 30px">系统设置硬盘寄存器参数时,首先调用SetMode()函数设定硬盘的IDLE状态和自掉电功能,可以保证硬盘在不工作的情况下,磁头会复位到“登陆区”;然后调用SetAdress()函数选择对应的寄存器;接下来可以调用ReadSector()函数进行多扇区读操作。以下是寄存器选择子函数和多扇区读子函数。</P>
<P style="TEXT-INDENT: 30px">//寄存器选择子函数;</P>
<P style="TEXT-INDENT: 30px">void SetAddress(unsigned char
cs,unsigned char adr){</P>
<P style="TEXT-INDENT: 30px">DA0=((adr & 0x01)= =0x01;</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -