嵌入式系统原理与应用 第3版 课件 第9、10章 微处理器S3C2410A定时计数器;Bootloader 设计基础、A-D转换、触摸屏与LCD程序设计_第1页
嵌入式系统原理与应用 第3版 课件 第9、10章 微处理器S3C2410A定时计数器;Bootloader 设计基础、A-D转换、触摸屏与LCD程序设计_第2页
嵌入式系统原理与应用 第3版 课件 第9、10章 微处理器S3C2410A定时计数器;Bootloader 设计基础、A-D转换、触摸屏与LCD程序设计_第3页
嵌入式系统原理与应用 第3版 课件 第9、10章 微处理器S3C2410A定时计数器;Bootloader 设计基础、A-D转换、触摸屏与LCD程序设计_第4页
嵌入式系统原理与应用 第3版 课件 第9、10章 微处理器S3C2410A定时计数器;Bootloader 设计基础、A-D转换、触摸屏与LCD程序设计_第5页
已阅读5页,还剩156页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1第9章微处理器S3C2410A的定时/计数器定时器部件在实时控制系统中起着举足轻重的作用,它可以实现对设备的周期性控制,同时使用定时器的PWM输出功能可以实现设备功率的控制,用于恒温控制系统等。S3C2410A芯片中的定时部件有多个,不同的定时部件有不同的用途。看门狗定时器(WATCHDOG)主要用来防止处理器的死机,需要在看门狗定时器规定的时间内喂狗,就是重新给看门狗定时器赋初值,否则时间到产生溢出复位信号,使ARM系统复位而重新启动;定时器(TIMER)主要用于定时或计数,还可用于脉宽调制PWM(PulseWidthModulation)的控制;实时时钟RTC(RealTimeClock)主要用于为系统提供日历与实时钟信号。定时部件虽然种类较多,但它们的工作原理基本相同。本章主要介绍各自的原理与应用。29.1S3C2410A定时/计数器原理定时器或计数器的逻辑电路是相同的,它们的主要区别在用途上。在应用时,定时器的输入信号来自于内部,是周期信号,从而通过计数实现了定时的功能;而计数器的输入信号一般来自于外部,是非周期信号,因而只能实现计数的功能。因此这样的逻辑电路被称为定时/计数器。图9-1是一般定时/计数器内部工作原理框图,它是以一个N位计数器(加1或减1)为核心,计数器的初值在编程时设置。计数器的输入脉冲分为2类:系统时钟和外部事件脉冲。微处理器S3C2410A使用的是具有减法功能的定时/计数器。39.2看门狗定时器(WATCHDOG)

S3C2410A中看门狗定时器的作用是,当系统程序出现功能错乱,引起系统程序出现死循环时,是系统重新启动开始工作。嵌入式系统由于使用环境的复杂,即使用环境中有较强的干扰信号,或者系统程序本身的不完善,因而不能排除系统程序不会出现死循环现象。当系统使用看门狗部件时,如果系统出现了死循环,看门狗定时器将产生一个具有一定宽度的复位信号,强迫系统复位,恢复系统的正常运行。看门狗定时器必须在小于定时的时间周期内,对其重新赋初值(俗称“喂狗”),使看门狗定时器不会产生复位信号,系统正常运行。当系统程序出现死循环时,无法给看门狗定时器喂狗或者说不能执行喂狗函数,将会产生复位信号。49.2.1看门狗定时器的工作原理

S3C2410A看门狗定时器有2种工作模式:

①带中断请求信号的常规时隙定时器。

②产生内部复位信号的定时器,即当定时器的值为0时,产生一个宽度为128PCLK(系统时钟周期)的复位脉冲信号。图9-2是看门狗定时器的逻辑功能图。看门狗定时器一旦启动工作,看门狗定时器的计数常数寄存器(WTDAT)就无法自动地装载到计数寄存器(WTCNT)中。因此应该在看门狗定时器工作之前,通过初始化编程将计数常数寄存器(WTDAT)的值写入到计数寄存器(WTCNT)中。59.2.2看门狗特殊功能控制寄存器

S3C2410A芯片的看门狗定时器逻辑中有3个控制其操作的特殊功能寄存器:看门狗控制寄存器(WTCON);计数常数寄存器(WTDAT)和看门狗计数寄存器(WTCNT)。它们的属性如表9-1。寄存器名占用地址读写属性描述初值WTCON0x53000000读/写看门狗控制寄存器0x8021WTDAT0x53000004读/写看门狗常数寄存器0x8000WTCNT0x53000008读/写看门狗计数寄存器0x800061.看门狗控制寄存器(WTCON)比特位描述初值[15:8]预分频值(PrescalerValue):范围0~2550x80[7:6]保留,但取值必须为0000[5]看门狗定时器使能位:1=使能;0=不使能1[4:3]分割因子(Clockselect):00=16;01=32;10=64;11=12800[2]中断请求使能位:1=允许中断(看门狗作为一般定时器使用时);0=不允许中断0[1]保留位,取值为00[0]看门狗定时器复位信号输出使能(ResetEnable/Disable):0=禁止看门狗定时器的复位功能;1=在看门狗定时器回0时复位信号有效。172.看门狗常数寄存器(WTDAT)看门狗常数寄存器WTDAT(WatchdogTimerDataRegister)用来存储看门狗定时器的溢出时间间隔常数值。看门狗计数寄存器从此值开始做减法计数,直到变为0为时间间隔。计数公式如下:

计数常数=所需时间间隔/计数时钟周期T=所需时间间隔*(PCLK/(预分频值+1)/分割因子)WTDAT是可读写的,地址为0x53000004,复位初值为0x8000。其位功能如下表所示。比特位描述初值[15:0]看门狗计数常数寄存器值(CountReloadValue)0x800083.看门狗计数寄存器(WTCNT)

看门狗计数寄存器WTCNT(WatchdogTimerCounterRegister)是一个实时动态变化的减法计数器,WTCNT工作时存储当前计数值。WTCNT是可读写的,地址为0x53000008,复位后初值为0x8000。看门狗计数寄存器的位功能描述如下表所示。比特位描述初值[15:0]看门狗计数器的当前值(CountValue)0x800099.2.3看门狗定时器应用示例

1.Bootloader中的看门狗定时器编程

在系统启动引导的Bootloader程序中,由于这时ARM系统的部件初始化需要进行大量的工作,需要关闭看门狗定时器,就是设置看门狗控制寄存器WTCON的b5=0(看门狗定时器使能位无效),b0=0(禁止看门狗定时器的复位功能),与其它位无关,因此控制字可为0x00,而且必须使用汇编语言编写程序。程序代码如下:WTDOGEQU0x53000000;定义WTCON的地址 LDRR0,=WTCON;WTCON地址送R0 LDRR1,=0x00;控制字0x00送R1

STRR1,[R0]

;控制字写入R02.程序正常运行时的看门狗定时器编程

看门狗可以实现ARM系统的复位,不需要外围的控制电路。要实现看门狗的功能,需要对看门狗的特殊功能寄存器进行配置操作。编程流程如下:①看门狗定时器作为一般定时器使用时,需要设置看门狗的中断操作,因为这是看门狗作为一般定时器使用时的唯一用法。除包括ARM系统的各个中断寄存器的设置外,还要看门狗自身中断使能有效。如果作为ARM系统的看门狗使用,这一步不用设置。②设置看门狗控制寄存器WTCON,主要包括预分频值、分割因子,看门狗定时器复位信号输出使能b0=1(在看门狗定时器回0时复位信号有效)。③在预估的预分频值、分割因子的情况下,计算看门狗的定时常数。只要计算的结果不大于WTDAT的数值范围即216-1均为有效数据。将定时常数赋给WTDAT寄存器和WTCNT寄存器。④启动看门狗定时器。使看门狗定时器使能位b5=1(使能有效电平信号)。1011应用实例使用看门狗功能时,必须事先进行初始化。初始化的主要工作就是设置WTCON寄存器和WTDAT寄存器。例如,实现S3C2410A芯片的看门狗功能,监测系统的周期不大于40us,PCKL=50Mhz。首先计算赋给WTDAT寄存器的初值。初值=40us*(PCKL/(预分频值+1)/分割系数)注意:这里PCKL的单位是赫兹,预分频值和分割系数必须事先有一个固定的值。本例中预分频值=0,分割系数=16,即设置WTCON的值为0x0021,允许看门狗定时器工作,允许看门狗复位信号有效。初值计算过程如下:初值=40*10-6*(50*106/(0+1)/16)=125=0x7d

程序代码如下:12汇编语言代码段WTCONEQU0x53000000WTDATEQU0x53000004 AREAWatchdog_Ini,CODE,READONLY ENTRY CODE32ldrr0,=WTDAT;将WTDAT寄存器地址值赋给r0ldrr1,=0x7d;将计数器初值0x7d赋给r1strr1,[r0];将r1的内容写到以r0内容为地址的单元中

ldrr0,=WTCON;将WTCON寄存器地址值赋给r0ldrr1,=0x0021/*设启动看门狗。看门狗复位使能、看门狗使能*/strr1,[r0]END C语言代码段#definerWTCON=(*(volatileunsignedchar*)0x53000000)#definerWTDAT=(*(volatileunsignedchar*)0x53000004)#definerWTCNT=(*(volatileunsignedchar*)0x53000008)voidwatchdog40(void){rWTCON=(rWTCON&0x0000)|(1<<8)|(1<<3);/*设置预分频值、分割因子*/rWTDAT=0x7d;rWTCNT=0x7d;rWTCON=rWTCON|(1<<5)|(1<<0);/*设启动看门狗。看门狗复位使能、看门狗使能*/}13149.3具有脉宽调制(PWM)的定时器(TIMER)Timer部件主要用于提供定时功能,脉宽调制(PWM)功能,它的应用比较灵活,对于需要一定频率的脉冲信号,一定时间间隔定时信号的应用场合,都能提供支持。9.3.1定时器Timer概述

S3C2410A芯片中有5个16位的Timer部件,其中Timer0~Timer3具有PWM功能,Timer4仅用于定时,不具有PWM功能,它没有输出引脚。Timer0是一个同时具有死区(dead-zone)发生器,通常用于控制大电流设备。15

9.3.2TIMER部件的操作每个定时/计数器都是16位的减法计数器,是通过定时器自己的时钟驱动的。当计数器减到0时,可产生定时器中断请求信号,通知CPU定时器的操作已经完成了。此时定时/计数缓冲寄存器TCNTBn(TimerCounterBufferRegistern)的值将自动装载到递减计数器,开始下一轮的操作。但是,若定时器停止工作,则TCNTBn的值将不会重新装载到计数器中。定时器比较缓冲寄存器TCMPBn(TimerCompareBufferRegistern)的值用于脉宽调制。当计数器的值与比较寄存器的值相同时,定时器的逻辑将改变输出电平。因此TCMPBn确定脉宽调制信号输出的上升时间(或下降时间)。每个定时器(TIMER4除外)均含有TCNTBn,TCNTn,TCMPBn和TCMPn四种计数缓冲寄存器,其中定时器计数寄存器TCNTn(TimerCounterRegistern)和定时器比较寄存器TCMPn(TimerCompareRegistern)是内部寄存器(编程不可见),内部寄存器TCNTn的值可以通过计数观察寄存器读取。16179.3.2TIMER部件操作(续)

每个定时器读时都是16位的减法计数器,是通过定时器自己的时钟驱动的。当计数器减到0时,可产生定时器中断请求信号,通知CPU定时器的操作已经完成了。此时TCNTBn的值将自动装载到递减计数器,开始下一轮的操作。但是,若定时器停止工作,则TCNTBn的值将不会重新装载到计数器中。

TCMPBn的值用于脉宽调制。当计数器的值与比较寄存器的值相同时,定时器的逻辑将改变输出电平。因此TCMPBn确定脉宽调制信号输出的上升时间(或下降时间)。每个定时器(TIMER4除外)均含有TCNTBn,TCNTn,TCMPBn和TCMPn四种计数缓冲寄存器,其中TCNTn和TCMPn是内部寄存器(编程不可见),内部寄存器TCNTn的值可以通过计数观察寄存器读取。181.自动重载和双缓冲器S3C2410A处理器的定时器具有双缓冲功能,即在不停止当前定时器运行的情况下,重载下次定时器运行周期(或频率)的参数、PWM波形的占空比。主要是指向TCNTBn,TCMPBn寄存器赋值。装载新值之后,在按原参数运行完前周期后,在下一个新的周期,按新的设置参数运行。当内部寄存器TCNTn的值减到0时将自动装载TCNTBn的值到TCNTn中,并可重新开始进行减法计数,前提条件是自动重载允许。如果TCNTn=0,但自动重载禁止,则定时器停止运行。19双缓冲功能编程图例当内部寄存器TCNTn的值减到0时将自动装载TCNTBn的值到TCNTn中,并可重新开始进行减法计数,前提条件是自动装载功能允许。如果TCNTn=0,但自动装载禁止,则定时器停止运行。2.复杂的定时器设置示例定时器初始化时,使用手动装载位和反转位。因为定时器的自动操作发生在减法计数器为0和TCNTBn没有预先赋值时。在这种情况下必须使用手动装载功能给TCNTBn赋初值。开启一个定时器的操作如下:①向TCNTBn和TCMPBn中写入初值;②定时器控制寄存器TCON(TimerControlRegister)相关的手动装载位置1,不管是否需要反转位功能,都将反转位的开关打开;③设置定时器控制寄存器TCON的相关启动位,同时清除其手动装载位;④如果定时器被强行关闭,TCNTn就保持原有的计数值,且不从TCNTBn重新自动装载计数值。如果必须重新设置新值,则必须使用手动装载。定时器的操作示例如下,以图9-5进行叙述。201)允许自动装载功能,给TCNTBn和TCMPBn赋值,这里控制TOUTn周期的TCNTBn=250,控制高电平持续时间的TCMPBn=150;使能手动装载功能,TCNTBn和TCMPBn的值将被复制到TCNTn和TCMPn寄存器中;最后设置在TCNTBn和TCMPBn的值分别为300和100,作为下一个周期定时器的工作参数。2)设置相应定时器的启动位为1,清除手动装载控制位为0,关闭反转开关,自动装载开始,定时器按照第一个设定的参数运行工作。3)当TCNTn的值等于TCMPBn的值时,TOUTn从低电平跳变到高电平。4)当TCNTn的值等于0时,定时器产生中断请求,同时TCNTBn=300和TCMPBn=100的值自动装载到TCNTn和TCMPn中,定时器使用这个参数将进行下一个周期的工作。5)在响应4)的中断服务程序中,对TCNTBn和TCMPBn重新赋值,这里分别是130和80,用于下一个周期的工作参数。6)当TCNTn的值等于TCMPBn的值时,TOUTn又从低电平跳变到高电平。7)重复4)的操作。8)在这个中断服务程序中,相应定时器的中断请求和自动装载功能被禁止,定时器将使用最后一个给定的参数工作完后,终止工作。9)同3)完成的操作相同。10)当TCNTn的值等于0时,由于自动装载被禁止,因此TCNTn将不再装载计数值,定时器停止工作。11)不再产生中断请求,工作过程彻底结束。21223.脉宽调制(PWM)

PWM的频率由TCNTBn的值来确定,PWM的每个周期中高电平(或低电平)的持续时间由TCMPBn的值来确定。如果TCON中某定时器的输出反转位置0(不反转),若要得到较高的PWM脉宽输出值(高电平持续时间),则需要增加TCMPBn的值;若要得到较低的PWM脉宽输出值,则需要减小TCMPBn的值。

如果TCON中某定时器的输出反转位置1(反转器被使能),若要得到较高的PWM脉宽输出值(高电平持续时间),则需要减小TCMPBn的值;若要得到较低的PWM脉宽输出值,则需要增加TCMPBn的值。基于双缓冲器的功能,下一周期TCMPBn的值,可以在中断服务程序中,并且在当前的PWM周期内的任何时刻写入。23脉宽调制(PWM)设置图例

图中上面的波形是减法计数器的计数过程示意图,为画图方便,使用(216-计数器值)。两条横线代表TCMPB的取值,取值为(TCNTBn-TCMPBn)。图例是在反转器关闭的情况下绘制的。244.输出电平控制输出电平控制是通过定时器TCON中的输出反转位控制的。包括定时器输出TOUTn的初值及工作过程的波形。在定时器的反转器开关关闭(即反转位置0),可以控制TOUTn电平的高或低,方法如下。①关闭TCON自动重载位之后,TOUTn变为高电平,并且定时器在TCNTn=0时停止;②通过对定时器的启动/停止位清0停止定时器工作。如果TCNTn不大于TCMPn,TOUTn输出高电平;如果TCNTn大于TCMPn,TOUTn输出低电平;③通过对TCON中的输出反转位置1控制TOUTn输出反相。开关。反转位开关控制TOUTn的波形如下。25定时器反转位控制TOUTn图例图例如下:265.死区(DZDeadZone)发生器死区DZ(DeadZone)是当定时器用于PWM,为大电流控制设备提供电能的时候,需要使用死区功能。这个功能允许在一个设备关闭和另一个设备开启之间插入一个时间间隔,可防止两个设备同时动作对电网及现场环境造成较大的危害。TOUT0是T0的PWM输出,nTOUT0是TOUT0的反相输出。如果允许死区功能,TOUT0和nTOUT0的输出波形就变为TOUT0_DZ和nTOUT0_DZ,nTOUT0_DZ在TOUT1引脚输出。定时器的死区功能使得TOUT0_DZ和nTOUT0_DZ不会同时发生变化。死区功能的波形图9-8所示。27死区功能允许波形图死区允许波形图即在原波形图上将上升沿延迟一个死区间隔时间,而其下降沿的时间与原波形图相同。6.DMA请求模式与中断

配置寄存器TCFG1中的DMA模式位可以用来控制定时器n产生DMA请求或中断使能,一个定时器只能在DMA方式或中断方式中选择其一,且最多只有一个定时器可以设置为DMA方式。现将TCFG1中的DMA方式位[23:20]设置如表9-5所示:28表9-5DMA模式字对应表29DMA模式字DMA请求T0中断T1中断T2中断T4中断T4中断0000未选择允许允许允许允许允许0001定时器T0关闭允许允许允许允许0010定时器T1允许关闭允许允许允许0011定时器T2允许允许关闭允许允许0100定时器T3允许允许允许关闭允许0101定时器T4允许允许允许允许关闭309.3.3TIMER部件内部功能寄存器控制TIMER控件的操作,需要编程设置TIMER内部的许多功能寄存器。主要有:

●定时器配置寄存器0(TCFG0);

●定时器配置寄存器1(TCFG1);

●定时器控制寄存器(TCON);

●TIMER0计数缓冲寄存器和比较缓冲寄存器(TCNTB0/TCMPB0);

●TIMER0计数观察寄存器(TCNTO0)。以下分别予以介绍。表9-6定时器主要功能寄存器属性表31寄存器名占用地址读写属性描述初值TCFG00x51000000读/写配置预分频值0、预分频值1和死区长度0x00TCFG10x51000004读/写配置Timer0~Timer4的分割系数0x00TCON0x51000008读/写设置各定时器的自动装载、手动装载,启动/停止操作,反转输出等0x00TCNTBn0x510000××读/写设置各定时器的输出周期0x00TCMPBn0x510000××读/写正常输出,控制PWM输出高电平持续时间0x00TCNTOn0x510000××只读当需要观察当前的定时器数值时使用0x00注意:表中的××,对于不同的定时器取不同的数值,排列从定时器0开始到定时器3结束,按TCNTBn、TCMPBn、TCNTOn次序取值是0x0C、0x10、0x14、0x18…0x30、0x34、0x38。说明数值序列是等差数列,等差为4。由于定时器4没有PWM功能输出,所以没有TCMPB4,它的TCNTB4、TCNTO4最后2位取值是0x3C和0x40。321)

定时器配置寄存器0(TCFG0)TCFG0是可读写的,主要用来设置预分频系数的。其地址为0x51000000,复位初值是0x0。具体位定义如下:位描述初值[31:24]保留0x00[23:16]死区长度控制。死区长度的1个单位等于Timer0的定时间隔(dead-zonelength)0x00[15:8]Timer2-Timer4预分频值设置(Prescaler1)0x00[7:0]Timer0、Timer1预分频值设置(Prescaler0)0x00332)

定时器配置寄存器1(TCFG1)TCFG1是可读写的,主要用来设置分割器值。其地址为0x51000004,复位初值是0x0。具体位定义如下:位描述初值[31:24]保留0x00[23:20]选择DMA请求的定时器:0=不选择;1=选择Timer0;2=选择Timer1;3=选择Timer2;4=选择Timer3;5=选择Timer4;其它保留0x0[19:16]MUX4.Timer4分割器值:0=2;1=4;2=8;3=16;01xx=外部TCLK10x0[15:12]MUX3.Timer3分割器值:0=2;1=4;2=8;3=16;01xx=外部TCLK10x0342)TCFG1(Continue)位描述初值[11:8]MUX2.Timer2分割器值:0=2;1=4;2=8;

3=16;01xx=外部TCLK10x0[7:4]MUX1.Timer1分割器值:0=2;1=4;2=8;

3=16;01xx=外部TCLK00x0[3:0]MUX0.Timer0分割器值:0=2;1=4;2=8;3=16;01xx=外部TCLK00x035TCFG0和TCFG1的联合作用

通过TCFG0和TCFG1的设置,可以确定各定时器预分频系数和分割器的值,最后通过以下公式计算定时器的输入时钟频率。

定时器输入时钟频率=PCLK/(预分频值+1)/分割器值预分频器系数范围=0~255

分割器取值域={2,4,8,16}363.定时器控制寄存器(TCON)

定时器控制寄存器是可读写的,地址是0x51000008,复位初值是0x0。具体位定义如下表。位功能初值[22]Timer4自动装载控制位:1=自动装载;0=否0[21]Timer4手动更新控制位:1=更新TCNTB4;0=否0[20]Timer4启动/停止控制位:1=启动;0=不操作0[19]Timer3自动装载控制位:1=自动装载;0=否0[18]Timer3输出反转位:1=TOUT3反转;0=不反转0[17]Timer3手动更新控制位:1=更新TCNTB3和TCMPB3;0=不操作0[16]Timer3启动/停止控制位:1=启动;0=不操作037定时器控制寄存器(TCON)位定义(续)位功能初值[15:8]Timer2与Timer1定时器控制位,各使用4bit。Timer2使用b15-b12,Timer1使用b11-b8。控制位的次序和功能与Timer3控制位的b19-b16相同。0[7:5]保留000[4]死区使能操作控制位:1=使能;0=否0[3]Timer0自动装载控制位:1=自动装载;0=否0[2]Timer0输出反转位:1=TOUT3反转;0=不反转0[1]Timer0手动更新控制位:1=更新TCNTB0和TCMPB0;0=不操作0[0]Timer0启动/停止控制位:1=启动;0=不操作0384.TIMERn的三个计数寄存器TIMERn定时器的三个计数寄存器:有缓冲寄存器(TCNTBn)是可读写的;比较缓冲寄存器(TCMPBn)也是可读写的;和计数观察寄存器(TCNTOn),它是只读的。这里n=0~4,即指TIMER0~TIMER4。具体定义格式如下表。位描述初值TCNTBn[15:0]存放TIMERn计数寄存器初值0x0TCMPBn[15:0]存放TIMERn比较寄存器初值0x0TCNTOn[15:0]存放TIMERn的当前计数值0x0394.TIMERn三个计数寄存器(续)从TIMER0-TIMER4它们的三个计数寄存器有相同的格式位定义,但是TIMER4没有比较计数寄存器。它们分别占用不同的物理地址,具体如下表。地址为。地址为。Timer0的它们的复位初值均为0x0。TCNTBTCMPTCNTOTIMER00x5100000c0x510000100x51000014TIMER10x510000180x5100001c0x51000020TIMER20x510000240x510000280x5100002cTIMER30x510000300x510000340x51000038TIMER40x5100003c-0x510000409.3.4定时器Timer应用示例

定时器的应用非常广泛,也很灵活,不同的应用需求,将决定定时器使用不同的编程方式。可归结为以下几种:

●一种是作为定时器使用,需要根据定时时间和ARM系统提供的PCLK时钟,配置预分频值,分割器值计算数据缓冲寄存器的值等;

●二种是作为计数器使用,分割器的值选TCLK0或TCLK1,将计数的初值赋给数据缓冲寄存器等,启动定时/计数器即可;

●三种是作为周期脉冲信号的输出,即PWM输出,这时除需要一种的工作外,还要设置比较缓冲寄存器的数值,以决定在反转位=0时高电平的持续时间或反转位=1时低电平的持续时间。这一功能也可以用于恒温控制系统的功率调节(在一个周期内高电平的持续时间越长,直流分量越大,对应的平均功率越大),必要时可以使用死区这一功能。401.定时器的程序设计流程

1)设置配置寄存器0。内容是设置预分频器0或预分频器1的值,以及Timer0的死区宽度。2)设置配置寄存器1。内容是各个定时器的分割器值,DMA方式或中断方式。3)根据前2项的设置、PCLK的时钟,以及实际需要,计算计数缓冲寄存器TCNTBn和TCMPBn的初值并赋之。

4)设置定时器控制寄存器TCON。计数初值自动装载、手动装载位=1、设置反转位=1等。

5)重新设置定时器控制寄存器TCON。清除手动装载位、设置反转位=0,启动定时器。41422.应用实例实例需要产生一个500ms的PWM脉冲周期信号,高电平的持续时间占40%,系统的PCLK为66MHz。选用定时器TIMER0,要求从ARM的引脚TOUT0输出。编程叙述如下。1)根据需要的脉冲信号周期500ms及系统PCLK=66MHz,确定预分频系数和分割器值,并计算计数缓冲寄存器初值。本例预分频值取31,分割器值取16,则计数缓冲寄存器的初值计算如下:

初值=定时间隔/(1/(PCLK/(预分频系数+1)/分割器值))=500ms*(66MHz/32/16)=500*10-3*(66*106/32/16)=64453=0xfbc5

比较缓冲寄存器的初值=64453×40%=0x64b5432)编写定时器程序:先设置TCFG0、TCFG1寄存器,再设置TCNTB0寄存器,最后设置TCON寄存器启动定时器工作。3)编写程序#definerTCFG0(*(volitaleunsigned*)0x51000000/*定义定时器配置寄存器0地址*/#definerTCFG1(*(volitaleunsigned*)0x51000004/*定义定时器配置寄存器1地址*/#definerTCON(*(volitaleunsigned*)0x51000008

/*定义定时器控制寄存器地址*/#definerTCNTB0(*(volitaleunsigned*)0x5100000C#definerTCOMB0(*(volitaleunsigned*)0x51000010#definerGPBCON(*(volitaleunsigned*)0x56000010

/*定义B端口控制寄存器地址*/#definerGPBDAT(*(volitaleunsigned*)0x56000014

/*定义B端口数据寄存器地址*/#definerGPBUP(*(volitaleunsigned*)0x56000018/*定义B端口上拉电阻寄存器地址*/voidtimer0(void){GPBCON=rGPBCON|(2<0);/*设置GPB0为第2功能TOUT0*/rGPBUP=rGPBUP&(~(1<0));/*使能GPB0上拉电阻*/rTCFG0=(rTCFG0&0x00)|(31<<0);

/*deadzone=0,Timer0预分频系数31*/rTCFG1=(rTCFG1&0x00)|(3<<0);/*均工作在中断方式,分割系数16*/rTCNTB0=0xfbc5;rTCMPB0=0x64b5;rTCON=rTCON|(1<<2)|(1<<1);

/*反转位置1,手动装载TCNTB0和TCMPB0*/rTCON=rTCON&(~(1<<2))&(~(1<<1))|(1<<3)|(1<0);/*手动装载清0,自动装载置1,并启动*/}44459.4实时时钟(RTC)S3C2410A提供RTC(RealTimeClock)实时时钟单元,在系统掉电后由后备电池供电继续工作。RTC是用于提供年、月、日、时、分、秒、星期等实时时间信息的定时部件。它由外部时钟驱动工作,时钟频率为32.768khz。

以下主要介绍它的工作原理、功能控制寄存器和编程方法。46479.4.1RTC概述

RTC部件可以将提供实时信息的8位数据以BCD码的格式输出,同时还具有各种报警功能。其主要特点有:

1.年、月、日、时、分、秒、星期等实时时间信息采用BCD码表示;

2.闰年发生器;

3.具有报警功能,提供报警中断或者系统在节电模式下的唤醒;

4.拥有独立的电源引脚(RTCVDD);

5.支持RTOS内核时间片所需的毫秒计时中断;

6.进位复位功能。489.4.1RTC概述(续1)RTC部件提供专门的电源引脚可以由备用电源供电。当系统电源关闭时,微处理器接口和RTC逻辑电路均是断开的,后备电池仅驱动RTC部件的振荡器和BCD码计数器,以使功耗降到最低。在节电模式或正常运行模式下,RTC可以在特定的时候触发蜂鸣器。在正常运行模式下,激活的是报警中断信号(ARMINT)。在节电模式下,激活的是电源管理器部件的唤醒信号(PMWKUP)并同时激活报警中断信号(ARMINT)。RTC内部的报警寄存器(RTCALM)可以设置报警工作状态的使能/不使能以及报警时间的条件。499.4.1RTC概述(续2)RTC的时间片计时器用于产生一个中断请求,TICNT寄存器有一个中断使能位,和计数器中的值一起用来控制中断。当计数器的值变为0时,引起时间片计时中断。中断信号的周期计算如下:

周期s=(n+1)/128

其中n是时间片计数器中的值,范围在0-127之间。RTC的时间片计时器可以用来产生实时操作系统内核所需的时间片。进位复位功能可以由RTC的进位复位寄存器(RTCRST)来控制。秒的进位周期可以进行选择(30、40、50),在进位复位发生后,秒的数值又循回到0。例如当前时间是23:37:47,进位周期选为40秒,则当前时间将变为23:38:00。509.4.2实时时钟RTC控制寄存器RTC的内部有许多用于控制操作的寄存器。通过程序对这些寄存器进行设置,用户就可控制RTC部件的工作。以下介绍这些寄存器的功能及位定义。511.RTC控制寄存器(RTCCON)RTC控制寄存器(RTCCON)是可读/写的,地址为0x57000040,初值是0x0。该寄存器仅使用4位,RTCEN控制BCD码寄存器的读写使能,同时控制微处理器和RTC间的所有接口的使能。因此,在系统复位后需要对RTC进行操作时,RTCEN=1。而在其它时间,RTCEN应清0,以防数据无意地写入到RTC的寄存器中。52RTC控制寄存器RTCCON的位定义位描述初值[3]RTC时钟计数器复位使能(RTCRST):0=不复位;1=复位0[2]BCD码选择位(CNTSEL):0=合并BCD码;1=保留0[1]BCD码时钟选择位(CLKSEL):0=2-16XTAL;1=保留0[0]RTC使能位(RTCEN):0=不使能;1=使能0532.时间片计数器(TICNT)计数器TICNT是可/读写的,地址为0x57000044,初值为0x0。具体格式定义如下表。位描述初值[7]时间片计数器中断使能(TICNTINTENABLE):1=使能;0=不使能0[6:0]时间片计数器的值(TICKTIMECOUNT)0x0543.报警控制寄存器(RTCALM)报警控制寄存器(RTCALM)是可读/写的,地址为0x57000050,初值是0x0。RTCALM的组成格式如下所示。注意:在节电模式下,RTCALM寄存器通过ALMINT和PMWKUP来产生报警信号;而在正常操作模式下,只通过ALMINT产生报警信号。位描述初值[6]全局报警使能位ALMEN:1=使能;0=不使能0[5]年报警使能位YEAREN:1=使能;0=不使能0[4]月报警使能位ALMEN:1=使能;0=不使能0[3]日报警使能位ALMEN:1=使能;0=不使能0[2]时报警使能位ALMEN:1=使能;0=不使能0[1]分报警使能位ALMEN:1=使能;0=不使能0[0]秒报警使能位ALMEN:1=使能;0=不使能0554.报警秒数据寄存器(ALMSEC)寄存器ALMSEC是可/读写的,地址为0x57000054,初值为0x0。具体格式定义如下表。位描述初值[6:4]报警定时器秒数据十位BCD码值),范围0~5。0[3:0]报警定时器秒数据个位BCD码值,范围0~9。0565.报警分数据寄存器(ALMMIN)寄存器ALMMIN是可/读写的,地址为0x57000058,初值为0x0。具体格式定义如下表。位描述初值[6:4]报警定时器分数据十位BCD码值,范围0~5。0[3:0]报警定时器分数据个位BCD码值,范围0~9。0576.报警时数据寄存器(ALMHOUR)寄存器ALMHOUR是可/读写的,地址为0x5700005C,初值为0x0。具体格式定义如下表。位描述初值[5:4]报警定时器时数据十位BCD码值,范围0~2。0[3:0]报警定时器时数据个位BCD码值,范围0~9。0587.报警日数据寄存器(ALMDATE)寄存器ALMDATE是可/读写的,地址为0x57000060,初值为0x01。具体格式定义如下表。位描述初值[5:4]报警定时器日数据十位BCD码值,范围0~3。0[3:0]报警定时器日数据个位BCD码值,范围0~9。0598.报警月数据寄存器(ALMMON)寄存器ALMMON是可/读写的,地址为0x57000064,初值为0x01。具体格式定义如下表。位描述初值[4]报警定时器月数据十位BCD码值,范围0~1。0[3:0]报警定时器月数据个位BCD码值,范围0~9。0609.报警年数据寄存器(ALMYEAR)寄存器ALMYEAR是可/读写的,地址为0x57000068,初值为0x0。具体格式定义如下表。位描述初值[7:0]报警定时器年数据BCD码值,范围0~99。06110.循环复位寄存器(RTCRST)寄存器RTCRST是可/读写的,地址为0x5700006C,初值为0x0。具体格式定义如下表。位描述初值[3]循环复位使能位(SRSTEN):1=使能;0=不使能0[2:0]秒循环进位周期:010=超过30s;100=超过40s;101=超过50s;其它组合不会发生进位,但是秒值可以复位。06211.秒数据寄存器(BCDSEC)寄存器BCDSEC是可/读写的,用来存储当前时间的秒数据,即合并的BCD码格式。地址为0x57000070,初值不定。具体格式定义如下表。位描述初值[6:4]秒数据十位BCD码值,范围0~5。0[3:0]秒数据个位BCD码值,范围0~9。06312.分数据寄存器(BCDMIN)寄存器BCDMIN是可/读写的,用来存储当前时间的分数据,即合并的BCD码格式。地址为0x57000074,初值不定。具体格式定义如下表。位描述初值[6:4]分数据十位BCD码值,范围0~5。0[3:0]分数据个位BCD码值,范围0~9。06413.时数据寄存器(BCDHOUR)寄存器BCDHOUR是可/读写的,用来存储当前时间的时数据,即合并的BCD码格式。地址为0x57000078,初值不定。具体格式定义如下表。位描述初值[5:4]时数据十位BCD码值,范围0~2。0[3:0]时数据个位BCD码值,范围0~9。06514.日数据寄存器(BCDDATE)寄存器BCDDATE是可/读写的,用来存储当前日期的日数据,即合并的BCD码格式。地址为0x5700007C,初值不定。具体格式定义如下表。位描述初值[5:4]日数据十位BCD码值,范围0~3。0[3:0]日数据个位BCD码值,范围0~9。06615.星期数据寄存器(BCDDAY)寄存器BCDDAY是可/读写的,用来存储当前日期对应的星期数据,即合并的BCD码格式。地址为0x57000080,初值不定。具体格式定义如下表。位描述初值[2:0]星期数据BCD码值,范围1~7。06716.月数据寄存器(BCDMON)寄存器BCDMON是可/读写的,用来存储当前日期的月数据,即合并的BCD码格式。地址为0x57000084,初值不定。具体格式定义如下表。位描述初值[4]月数据十位BCD码值,范围0~1。0[3:0]月数据个位BCD码值,范围0~9。06817.年数据寄存器(BCDYEAR)寄存器BCDYEAR是可/读写的,用来存储当前日期对应的年数据,即合并的BCD码格式。地址为0x57000088,初值不定。具体格式定义如下表。位描述初值[7:0]年数据BCD码值,范围00~99。0699.4.3RTC编程举例(应用C语言编程)#definerRTCCON(*(volitaleunsigned*)0x57000040#definerTICNT(*(volitaleunsigned*)0x57000044#definerRTCALM(*(volitaleunsigned*)0x57000050#definerRTCRST(*(volitaleunsigned*)0x5700006C

………#defineuint8unsignedcharuint8year,month,day,wkday,hour,minute,second,flag;/*RTC初始化函数.函数名:RTC_Init(void);

功能:初始化RTC,同时设置RTC的当前日期和时间*/voidRTC_Init(void){year=14;//2014month=11;day=18;wkday=4;//Thursday709.4.3RTC编程举例(续1)hour=11,minute=18,second=00;rRTCCON=(uint8)(rRTCCON|0x01);//使能RTC读写操作

rRTCALM=(uint8)0x0;//关闭所有的报警

rRTCRST=(uint8)0x0;//关闭复位操作

rTICNT=(uint8)0x0;//关闭时间片中断

rRTCCON=(uint8)(rRTCCON&0xfe);//关闭RTC读写操作}/*RTC写函数。函数名RTC_Write(void);

功能:完成将初始化函数中设置的日期与时间参数写到RTC中*/voidRTC_Write(void){uint8Y,MO,D,W,H,MI,S;/*以下完成将数据转换为BCD码*/if(year>1999)year=year-2000;Y=uint8(year/10*16+year%10);

719.4.3RTC编程举例(续2)MO=uint8(month/10*16+month%10);D=uint8(day/10*16+day%10);W=uint8(wkday/10*16+wkday%10);H=uint8(hour/10*16+hour%10);MI=uint8(minute/10*16+minute%10);S=uint8(second/10*16+second%10);rRTCCON=(uint8)(rRTCCON|0x01);/*使能RTC读写操作*//*将当前日期与时间参数写入各自的数据寄存器中*/rBCDYEAR=Y,rBCDMON=MO,rBCDDATE=D,rBCDDAY=W;rBCDHOUR=H,rBCDMIN=MI,rBCDSEC=S;rRTCCON=(uint8)(rRTCCON&0xfe);//关闭RTC读写操作}729.4.3RTC编程举例(续3)

/*RTC读函数。函数名RTC_Read(void);

功能:完成将RTC日期与时间的BCD码参数值读出*/voidRTC_Read(void){uint8Y,MO,D,W,H,MI,S;/*以下完成读RTC各数据寄存器BCD码*/rRTCCON=(uint8)(rRTCCON|0x01);/*使能RTC读写操作*/Y=rBCDYEAR,MO=rBCDMON,D=rBCDDATE,W=rBCDDAY;H=rBCDHOUR,MI=rBCDMIN,S=rBCDSEC;rRTCCON=(uint8)(rRTCCON&0xfe);/*关闭RTC读写操作*/

/*以下是将合并的BCD码转换为十进制数,放入对应的变量中*/739.4.3RTC编程举例(续4)Year=Y&0x0f+Y&0xf0/16*10;month=MO&0x0f+MO&0xf0/16*10;day=D&0x0f+D&0xf0/16*10;wkday=W&0x0f+W&0xf0/16*10;hour=H&0x0f+H&0xf0/16*10;minute=MI&0x0f+MI&0xf0/16*10;second=S&0x0f+S&0xf0/16*10;}74第8章习题9-1何为定时/计数器?定时与计数有什么区别?9-2试述看门狗定时器的功能和主要控制寄存器的作用。9-3看门狗定时器的主要作用是什么?在程序的编写工作中需要做什么工作?9-4S3C2410A的看门狗有那些工作方式。设计一个监测系统程序周期不大于50us,在PCLK=100Mhz时的看门狗程序。9-5试述S3C2410A的TIMER部件组成及主要功能。9-6试述S3C2410A的TIMER部件的控制寄存器及主要功能。9-7使用TIMER部件的TIMER1定时/计数器,设计产生一个周期为1000ms,占空比为1/2的脉冲信号。已知系统的PCLK=66Mhz,编写初始化程序。9-8论述S3C2410A芯片中RTC部件的主要功能、主要控制寄存器的作用。9-9编写使用RTC部件的初始化程序、设置当前日期与时间程序和读取RTC的当前日期和时间数据。

第10章Bootloader

设计基础

7510.1Bootloader

概述

Bootloader,启动引导程序,又叫引导加载程序,功能强大的Bootloader也就直接叫做板级支持包(BSP,BoardSupportPacket)或者固件(Firmware)。近年来,为了方便嵌入式产品的推广,也有些直接将Bootloader叫做BIOS。BIOS是PC机的“基本输入输出系统”,烧录在电脑主板上一块专门的芯片中。一般BIOS由主板厂商或者专门的BIOS生产商提供,不是开源的,用户不能修改其中的代码进行定制。而嵌入式系统的开发则离不开Bootloader的开发,它也是整个系统开发中的难点之一。

7610.1.1Bootloader

的作用

Bootloader是在嵌入式操作系统内核运行之前运行的一段小程序,也是系统开机后执行的第一段程序。通过这段小程序,可以初始化硬件设备、建立内存空间,从而将系统的软硬件环境设置成一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。Bootloader是依赖于底层硬件而实现的,因此建立一个通用的嵌入式系统Bootloader几乎是不可能的。在PC机中,主板的BIOS和位于硬盘0磁道上的主引导记录(MasterBootRecord,MBR)中的引导程序(如LILO或GRUB等),两者一起的作用就相当于Bootloader在嵌入式系统中的作用,即实现整个系统的启动引导,并最终能引导操作系统的运行。7710.1.1Bootloader

的作用(续1)在嵌入式系统中,Bootloader对嵌入式设备中的主要部件如CPU、SDRAM、FLASH、串口等进行了初始化,这样可以使用Bootloader通过串口下载各种文件到设备的SDRAM中或者烧录Flash,然后将操作系统内核读入到内存中来或者直接跳转到内核的入口点,从而实现操作系统的引导。现在有些Bootloader也把对以太网的支持等功能也加进去了,这样一个功能比较强大的Bootloader实际上就已经相当于一个微型的操作系统了。7810.1.1Bootloader

的作用(续2)Bootloader从第一条指令跳转后,就开始初始化各种最重要的硬件,比如CPU的工作频率、定时器、中断、看门狗、检测RAM大小和Flash等。一般,硬件初始化的这段程序是用汇编语言编写的,其后就用C语言编写。总体上Bootloader主要完成以下工作:

初始化CPU速度;初始化内存,包括启用内存库,初始化内存配置寄存器等;初始化中断控制器,在系统启动时,关闭中断,关闭看门狗;初始化串行端口(如果在目标上有的话);启用指令/数据高速缓存;7910.1.1Bootloader

的作用(续3)

设置堆栈指针;设置参数区域并构造参数结构和标记,即引导参数;执行POST(上电自检)来标识存在的设备并报告有何问题;为电源管理提供挂起/恢复支持;传输操作系统内核镜像文件到目标机。也可以将操作系统内核镜像文件事先存放在Flash中,这样就不需要Bootloader和主机传输操作系统内核镜像文件,这通常是在做成产品的情况下使用。而一般在开发过程中,为了调试内核的方便,不将操作系统内核镜像文件固化在Flash中,这就需要主机和目标机进行文件传输;跳转到内核的开始,在此又分为ROM启动和RAM启动。所谓ROM启动就是用XIP技术直接在Flash中执行操作系统镜像文件;所谓RAM启动就是指把内核镜像从Flash复制到RAM中,然后再将PC指针跳转到RAM中的操作系统启动地址。8010.1.1Bootloader

的作用(续4)

在嵌入式Linux软件系统的开发中,一般将软件分为启动引导程序(Bootloader)、操作系统内核(OSKernel)、根文件系统(FileSystem)、图形窗口系统(GUI)和应用程序(AP)等几个部分,其中前三部分是一个可运行的嵌入式系统必不可少的,它们在开发的过程中,被分别独立地编译链接或打包为一个二进制目标文件,然后下载(烧录)到嵌入式系统的ROM(一般是Flash)中。后两部分如果有的话,通常也是和根文件系统一起打包后烧录到Flash中。因此在Bootloader阶段,也提供了对Flash设备的分区格式化的支持,其空间分配通常如图所示。8110.1.2Bootloader

的工作模式

对于嵌入式系统的开发人员而言,Bootloader通常包含“启动加载”和“下载”这两种不同的工作模式。当然,这两种工作模式的区别一般仅仅对于开发人员才有意义,而对最终用户来说,Bootloader

的作用就是用来加载操作系统,从而启动整个嵌入式系统。

8210.1.2Bootloader

的工作模式(续1)启动加载(Bootloading)模式--正常启动模式下载(Downloading)模式--提供给开发人员或者技术支持人员使用8310.1.3Bootloader

的启动流程

启动流程分为stage1和stage2两个阶段一般依赖于CPU体系结构的代码,比如设备初始化代码等,都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍且启动快的目的;而stage2则通常用C语言来实现,这样可以实现各种复杂的功能(比如串口、以太网接口的支持等)

841、Bootloader的第一阶段

①硬件设备初始化。包括屏蔽所有中断;关闭看门狗;设置CPU的速度与时钟;RAM初始化;关闭CPU内部指令/数据cache等。

②为加载Bootloader

的stage2准备RAM空间。

③拷贝

Bootloader的stage2到RAM空间中。

④设置好堆栈。

⑤跳转到stage2的C入口点main()函数处。852、Bootloader的第二阶段

①初始化本阶段要使用到的硬件设备。②检测系统内存映射(memorymap)。③将kernel映像和根文件系统映像从flash上读到RAM空间中。④为内核设置启动参数。⑤调用内核。8610.2S3C2410平台下Linux的BootloaderViviU-BOOT8710.2.1vivi1.vivi简介

vivi是由韩国mizi公司为ARM处理器系列设计的一个bootloader。它同样支持启动加载模式和下载工作模式。在下载模式下,vivi为用户提供一个命令行人机接口,通过这个人机接口可以使用vivi提供的一些命令。如果嵌入式系统没有键盘和显示,那么可以利用vivi中的串口,将其和宿主机连接起来,利用宿主机中的串口软件(如windows中的超级终端或者Linux中的minicom)来控制。8810.2.1vivi(续1)vivi常用的命令Load命令:将二进制文件写入Flash或RAM。例如:

Loadflashx表示向flash芯片中烧录内核映像zImage文件,与宿主机的通信采用xmodem协议。Part命令:操作MTD分区信息,比如显示、增加、删除、复位MTD分区等。例如partshowBon命令:用于NANDFlash的简单分区。Param命令:用于设置参数。Boot命令:启动系统。Flash命令:管理Flash.例如删除Flash的数据。892.vivi文件结构

Vivi的文件目录包括arch,init,lib,drivers和include等几个目录,共200多条文件。

arch:包括vivi支持的所有目标板(CPU的类型)。

init:只包含main.c和version.c两个文件,vivi将从main.c函数开始执行。

lib:一些公共平台接口代码。

drivers:设备驱动程序代码,其中包含引导内核需要的设备驱动程序(mtd和串口),mtd目录下又分为map,nand,nor这3个子目录。

include:头文件共用目录。其中s3c2410.h定义了s3c2410CPU的所用寄存器,而platform/smdk2410.h则定义了开发板相关的资源配置参数等。903.vivi的配置和编译vivi的配置和嵌入式Linux内核一样,可以采用菜单化的形式进行。其步骤主要如下:

①#makedistclean。清除一些早先生成的无用的目标文件。

②#makemenuconfig。然后可以根据菜单中的信息进行配置。

③编译。菜单配置完毕后,保存退出。然后执行“make”命令开始编译。914.Vivi的第一阶段分析

vivi的第一阶段主要完成了依赖于CPU的体系结构硬件初始化,包括禁止中断、初始化串口、复制第二阶段到RAM中等。由于这些代码是和硬件紧密相关的,因此要求读者在阅读时对照S3C2410处理器的数据手册,查阅相关的寄存器的描述,以便更好地理解。这些汇编代码全部就集中在vivi\arch\s3c2410目录下的head.S这一个汇编文件中,当然还有相关的头文件。

程序代码参见WORD文档925.vivi第二阶段的分析vivi的第二阶段的入口就是init/main.c,按照源代码的组织流程,根据模块化划分的原则,共分为8个功能模块即八个步骤,在源代码的注释中以step非常清晰的给出了区分。935.vivi第二阶段的分析(续1)第一步:vivi从main()函数开始执行,函数开始通过putstr(vivi_bannner)打印出vivi的版本。第二步:主要是初始化GPIO,本的思路和方法就是在把握好整个系统硬件资源的前提下,根据芯片的数据手册把所有的初始值设定,在这里利用set_gpios这个函数就可以完成初始化了。

第三步:进行内存映射初始化和内存管理单元(MM

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论