51单片机的复位〈转〉

复位是单片机的初始化操作。单片机启运运行时,都需要先复位,其作用是使CPU和系统中其他部件处于一个确定的初始状态,并从这个状态开始工作。因而,复位是一个很重要的操作方式。但单片机本身是不能自动进行复位的,必须配合相应的外部电路才能实现。

复位电路:

当MCS-5l系列单片机的复位引脚RST(全称RESET)出现2个机器周期以上的高电平时,单片机就执行复位操作。如果RST持续为高电平,单片机就处于循环复位状态。
根据应用的要求,复位操作通常有两种基本形式:上电复位和上电或开关复位。
上电复位要求接通电源后,自动实现复位操作。常用的上电复位电路如下图A中左图所示。图中电容C1和电阻R1对电源十5V来说构成微分电路。上电后,保持RST一段高电平时间,由于单片机内的等效电阻的作用,不用图中电阻R1,也能达到上电复位的操作功能,如下图(A)中右图所示。
  

上电或开关复位要求电源接通后,单片机自动复位,并且在单片机运行期间,用开关操作也能使单片机复位。常用的上电或开关复位电路如上图(B)所示。上电后,由于电容C3的充电和反相门的作用,使RST持续一段时间的高电平。当单片机已在运行当中时,按下复位键K后松开,也能使RST为一段时间的高电平,从而实现上电或开关复位的操作。
根据实际操作的经验,下面给出这两种复位电路的电容、电阻参考值。
上图(A)中:Cl=10-30uF,R1=1kO
上图1.27(B)中:C:=1uF,Rl=lkO,R2=10kO

单片机复位后的状态:

单片机的复位操作使单片机进入初始化状态,其中包括使程序计数器PC=0000H,这表明程序从0000H地址单元开始执行。单片机冷启动后,片内RAM为随机值,运行中的复位操作不改变片内RAM区中的内容,21个特殊功能寄存器复位后的状态为确定值,见下表。
值得指出的是,记住一些特殊功能寄存器复位后的主要状态,对于了解单片机的初态,减少应用程序中的初始化部分是十分必要的。
说明:表中符号*为随机状态;
A=00H,表明累加器已被清零;

特殊功能寄存器
初始状态
特殊功能寄存器
初始状态
A
00H
TMOD
00H
B
00H
TCON
00H
PSW
00H
TH0
00H
SP
07H
TL0
00H
DPL
00H
TH1
00H
DPH
00H
TL1
00H
P0~P3
FFH
SBUF
不定
IP
***00000B
SCON
00H
IE
0**00000B
PCON
0*******B

PSW=00H,表明选寄存器0组为工作寄存器组;
SP=07H,表明堆栈指针指向片内RAM 07H字节单元,根据堆栈操作的先加后压法则,第一个被压入的内容写入到08H单元中;
Po-P3=FFH,表明已向各端口线写入1,此时,各端口既可用于输入又可用于输出;
IP=×××00000B,表明各个中断源处于低优先级;
IE=0××00000B,表明各个中断均被关断;

系统复位是任何微机系统执行的第一步,使整个控制芯片回到默认的硬件状态下。51单片机的复位是由RESET引脚来控制的,此引脚与高电平相接超过24个振荡周期后,51单片机即进入芯片内部复位状态,而且一直在此状态下等待,直到RESET引脚转为低电平后,才检查EA引脚是高电平或低电平,若为高电平则执行芯片内部的程序代码,若为低电平便会执行外部程序。

51单片机在系统复位时,将其内部的一些重要寄存器设置为特定的值,至于内部RAM内部的数据则不变。

转自:http://www.zxbc.cn/html/20070726/25303.html

USB的挂起和唤醒 (Suspend and Resume)〈转〉

  USB协议的第9章讲到USB可见设备状态[Universal Serial Bus Specification, Section 9.1.1, Pg 239],分为连接(Attached),上电(Powered),默认(Default),地址(Address),配置(Configured)和挂起(Suspended)6个状态。所谓可见,即USB系统和主机可见的状态,其他状态属于USB设备内部而不可见。其中有关电源的,大致可分下面三类:
1. 连接状态(Attached):设备连接,但未提供电源。
2. 上电状态(Powered):设备被复位(Reset),或者说处于地址、配置状态。(参见USB枚举过程,USB Specification, page 241)
3. 挂起状态(Suspended):3 ms未见总线活动而处于省电状态,设备不可用,但仍然保持原有的USB地址和配置。

设备的挂起
我们知道,在USB系统中,正常状态下hub或root hub会一直周期性地发送SOF包(Start Of Frame,全速USB每1ms发送一个,高速USB则是125µs发送一个)。根据USB协议,如果USB线上一直处于空闲(Idle)状态超过3ms,设备应该把它当作一个挂起(Suspended)信号,要求设备在10ms内进入挂起状态,并把设备所需的电流大小降到规定的值(对于low-power设备,要求是500
µA,而对于high-power或支持远程唤醒(remote wakeup)功能的设备是2.5mA【Section 7.2.3, Pg176】)。在挂起状态中,设备必须继续向数据项D+/D-的上拉电阻提供电压以维持Idle状态。而对于USB2.0高速设备,还有些额外的要求:
1. 高速设备在
收到挂起信号(3ms空闲)后,应在0.125ms内切换到全速状态,也就是说要把终端电阻移除,并在D+数据线上重新挂上1.5k上拉电阻。
2. 设备在随后的100-875µs内检测数据线上的状态。如果该状态是一个
Full speed J,那么说明host发下来的是一个挂起信号;如果此时该状态是SE0,说明是host drive数据线D+到0,这是一个复位信号(复位信号会持续至少10ms时间)。
  要注意的是高速设备在挂起状态时处于高速模式,只是所用的是全速信号。一旦从挂起状态恢复回来,会马上进入高速工作状态而无需进行复位操作。


USB High Speed Suspend Signal

  如上图所示,Host在a点停止发送SOF,系统处于SE0状态,b点是3ms时间点,之后的125µs内,设备移除终端电阻,并挂上1.5k上拉。此时如host发送的是suspend信号,那它就不会不drive
D+数据线,导致D+被设备拉高,形成一个Full Speed J状态。在c点之后
100-875µs内设备检测此时host行为,发现是suspend信号,设备内部进入低功耗的挂起(suspend)状态。(假如hsot发送的是复位信号,那么当设备在c点挂1.5k电阻之后,由于host对D+线的drive作用,D+线无法被拉高,仍然处于SE0状态,设备在c点之后的检测,发现的还是SE0状态,等到10ms后就可判断这是一个复位信号,进行设备复位操作。)


设备的唤醒
  设备处于挂起状态时,任何总线上的活动(非空闲信号)都可以把设备唤醒/恢复,从而退出低功耗模式。(同样,设备也可以换醒host,比如电脑待机时通过USB键盘来换醒主机,这种功能称之为“远程唤醒”(remote wakeup),不在本文的讨论范围内。)
  因为设备挂起时处于全速信号,在当host需要把将设备退出suspend状态时,需要先发送一个持续时间超过20ms的Fulll Speed K状态。设备看到K状态结束的1.3us内醒过来,而host需要在3ms内发送uSOF信号以维持正常的高速信号模式,否则设备又将进入suspend。如下图所示:

原文转自:http://apps.hi.baidu.com/share/detail/17542952

USB枚举过程〈转〉

                                USB架构中, hub负责检测设备的连接和断开,利用其中断IN端点(Interrupt IN Endpoint)来向主机(Host)报告。在系统启动时,主机轮询它的根hub(Root Hub)的状态看是否有设备(包括子hub和子hub上的设备)连接。USB总线拓扑结构见下图(最顶端为主机的Root Hub):

 

 

USB总线拓扑结构
(USB Bus Topology


一旦获悉有新设备连接上来,主发送一系列的请求(Resqusts)给设备所挂载的hub,再由hub建立起一条连接主机(Host)和设备(Device)之间的通信通道。然后主机以控制传输(Control
Transfer)的方式,通过端点0(Endpoint 0)对设备
发送各种请求,设备收到主机发来的请求后回复相应的信息,进行枚举(Enumerate操作所有的USB设备必须支持标准请求(S
tandard
Requests),控制传输方式(Control
Transfer和端点0Endpoint 0


从用户角度来看,枚举过程是自动完成并不可见的。但很多初次使用的设备连接时,系统会弹出说新硬件检测到,设备安装成功,可以使用之类的消息提示框,而且有时还需要用户配合选择安装相关的驱动。


当枚举完成后,这个新添加的设备可在Windows的设备管理器里面看到,当用户删除这个设备/硬件时,系统把这个设备从设备管理器里删除。

对于一般的设备,固件(Firmware)内包含主机所要请求的信息,而有些设备则是完全由硬件来负责响应主机的请求。在主机方面则是由操作系统而非应用程序负责处理相关枚举操作。


枚举步骤

USB协议定义了设备的6种状态,仅在枚举过程种,设备就经历了4个状态的迁移:上电状态(Powered),默认状态(Default),地址状态(Address)和配置状态(Configured)(其他两种是连接状态和挂起状态(Suspend))。


下面步骤是Windows系统下典型的枚举过程,但是固件不能依此就认为所有的枚举操作都是按照这样一个流程行进。设备必须在任何时候都能正确处理所有的主机请求。


1.用户把USB设备插入USB端口或给系统启动时设备上电

    这里指的USB端口指的是主机下的根hub或主机下行端口上的hub端口。Hub给端口供电,连接着的设备处于上电状态。

 


2.Hub监测它各个端口数据线上(D+/D-)的电压

    在hub端,数据线D+和D-都有一个阻值在14.25k到24.8k的下拉电阻Rpd,在设备端,D+(全速,高速)和D-(低速)上有一个1.5k的上拉电阻Rpu。当设备插入到hub端口时,有上拉电阻的一根数据线被拉高到幅值的90%的电压(大致是3V)。hub检测到它的一根数据线是高电平,就认为是有设备插入,并能根据D+还是D-被拉高来判断到底是什么设备全速/低插入端口(全速、高速设备的区分在我将来的文章中描述)。如下图。

USB全速/高速设备上电连接

(Full-speed Device Cable and Resistor Connections)


    检测到设备后,hub继续给设备供电,但并不急于与设备进行USB传输。

 


3. Host了解连接的设备

 

  
每个hub利用它自己的中断端点向主机报告它的各个端口的状态(对于这个过程,设备是看不到的,也不必关心),报告的内容只是hub端口的设备连接断开的事件。如果有连接断开事件发生,那么host会发送一个
Get_Port_Status请求(request)以了解更多hub上的信息。Get_Port_Status等请求属于所有hub都要求支持的hub类标准请求(standard hub-class requests)。

 


4.Hub检测所插入的设备是高速还是低速设备

    hub通过检测USB总线空闲(Idle)时差分线的高低电压来判断所连接设备的速度类型,当host发来Get_Port_Status请求时,hub就可以将此设备的速度类型信息回复给host。(USB
2.0规范要求速度检测要先于复位(Reset)操作)。

 


5.hub复位设备

   
当主机获悉一个新的设备后,主机控制器就向hub发出一个 Set_Port_Feature请求让hub复位其管理的端口。hub通过驱动数据线到复位状态(D+和D-全为低电平 ),并持续至少10ms。当然,hub不会把这样的复位信号发送给其他已有设备连接的端口,所以其他连在该hub上的设备自然看不到复位信号,不受影响。


6.Host检测所连接的全速设备是否是支持高速模式

 

 

   
因为根据USB 2.0协议,高速(High Speed)设备在初始时是默认全速(Full Speed )状态运行,所以对于一个支持USB 2.0的高速hub,当它发现它的端口连接的是一个全速设备时,会进行高速检测,看看目前这个设备是否还支持高速传输,如果是,那就切到高速信号模式,否则就一直在全速状态下工作。

   
同样的,从设备的角度来看,如果是一个高速设备,在刚连接bub或上电时只能用全速信号模式运行(根据USB 2.0协议,高速设备必须向下兼容USB 1.1的全速模式)。随后hub会进行高速检测,之后这个设备才会切换到告诉模式下工作。假如所连接的hub不支持USB
2.0,即不是高速hub,不能进行高速检测,设备将一直以全速工作。

   
高速设备检测的过程在我另外一篇文章
USB2.0速度识别中有详细描述,这里不具体深入。

 


7.
Hub建立设备和主机之间的信息通道

    主机不停得向hub发送 Get_Port_Status请求,以查询设备是否复位成功。Hub返回的报告信息中有专门的一位用来标志设备的复位状态。

    当hub撤销了复位信号,设备就处于默认/空闲状态(Default state),准备着主机发来的请求。设备和主机之间的通信通过控制传输,默认地址0,端点号0进行。在此时,设备能从总线上得到的最大电流是100mA。

 


8.主机发送Get_Descriptor请求获取默认管道的最大包长度

   
默认管道(Default Pipe)在设备一端来看就是端点0。主机此时发送的请求是默认地址0,端点0,虽然所有位分配地址的设备都是通过地址0来获取主机发来的信息,但由于枚举过程不是多个设备并行处理,而是一次枚举一个设备的方式进行,所以不会发生多个设备同时响应主机发来的请求。

    设备描述符的第8字节代表设备端点0的最大包大小。对于Windows系统来说,Get_Descriptor请求中的wLength一项都会设为64,虽然说设备所返回的设备描述符(Device Descriptor)长度只有18字节,但系统也不在乎,此时,描述符的长度信息对它来说是最重要的,其他的瞄一眼就过了。Windows系统还有个怪癖,当完成第一次的控制传输后,也就是完成控制传输的状态阶段,系统会要求hub对设备进行再一次的复位操作(USB规范里面可没这要求)。再次复位的目的是使设备进入一个确定的状态。

 


9.主机给设备分配一个地址

    主机控制器通过Set_Address请求向设备分配一个唯一的地址。在完成这次传输之后,设备进入地址状态(Address state),之后就启用新地址继续与主机通信。这个地址对于设备来说是终生制的,设备在,地址在;设备消失(被拔出,复位,系统重启),地址被收回。同一个设备当再次被枚举后得到的地址不一定是上次那个了。

 


10.主机获取设备的信息

   
主机发送 Get_Descriptor请求到新地址读取设备描述符,这次主机发送Get_Descriptor请求可算是诚心,它会认真解析设备描述符的内容。设备描述符内信息包括端点0的最大包长度,设备所支持的配置(Configuration)个数,设备类型,VID(Vendor ID,由USB-IF分配), PID(Product ID,由厂商自己定制)等信息。
Get_Descriptor请求(Device
type)和设备描述符(已抹去VID,PID等信息)见下图:


 

标准Get_Descriptor请求

Get_Descriptor Request


 

 

设备描述符(Device Descriptor)

 

    之后主机发送Get_Descriptor请求,读取配置描述符(Configuration Descriptor),字符串等,逐一了解设备更详细的信息。事实上,对于配置描述符的标准请求中,有时wLength一项大于实际配置描述符的长度(9字节),比如255。这样的效果便是:主机发送了一个Get_Descriptor_Configuration
请求,设备会把接口描述符,端点描述符等后续描述符一并回给主机,主机则根据描述符头部的标志判断送上来的具体是何种描述符。


11.主机给设备挂载驱动(复合设备除外)

主机通过解析描述符后对设备有了足够的了解,会选择一个最合适的驱动给设备。在驱动的选择过程中,Windows系统会和系统inf文件里的厂商ID,产品ID,有时甚至用到设备返回来的产品版本号进行匹配。如果没有匹配的选项,Windows会根据设备返回来的类,子类,协议值信息选择。如果该设备以前在系统上成功枚举过,操作系统会根据以前记录的登记信息而非inf文件挂载驱动。当操作系统给设备指定了驱动之后,就由驱动来负责对设备的访问。

    对于复合设备,通常应该是不同的接口(Interface)配置给不同的驱动,因此,需要等到当设备被配置并把接口使能后才可以把驱动挂载上去。

    设备-配置-接口-端点关系见下图:

 

 

USB 设备-配置-接口-端点关系
(Device Configuration)

  

    实际情况没有上述关系复杂。一般来说,一个设备就一个配置,一个接口,如果设备是多功能符合设备,则有多个接口。端点一般都有好几个,比如Mass Storage设备一般就有两个端点(控制端点0除外)。


12. 设备驱动选择一个配置

    驱动(注意,这里是驱动,之后的事情都是有驱动来接管负责与设备的通信)根据前面设备回复的信息,发送Set_Configuration请求来正式确定选择设备的哪个配置(Configuration)作为工作配置(对于大多数设备来说,一般只有一个配置被定义)。至此,设备处于配置状态,当然,设备也应该使能它的各个接口(Interface)。

   对于复合设备,主机会在这个时候根据设备接口信息,给它们挂载驱动。

 


13. 设备可使用


********************

写在最后

   
写此文是为了自己对最近一段时间学习USB有个总结,也希望能让其他USB初学者有点小小的收获。本文主要参考来源是Jan
Axelson的
Enumeration: How the Host Learns about Devices(http://www.lvr.com/usbcenum.htm)和Danny Simpson的An Overview of the Universal Serial Bus (USB) (http://www.sss-mag.com/usb.html),并结合些自己的一些体会和理解,辅以图片。由于我自己也是刚接触USB不久,文中必有一些瑕疵,还请各位高手多多指教了:)

原文来自:http://apps.hi.baidu.com/share/detail/44244162

USB2.0速度识别

  我们知道USB2.0向下兼容USB1.x,即高速2.0的hub能支持所有的速度类型的设备,而USB1.x的hub不能支持高速设备(High Speed Device)。因此,如果高速设备挂到USB1.x的hub上,那该设备只能工作在全速模式下。不管是hub还是设备(device),对于速度的区分是非常重要的,否则,后续的通信根本无法进行。

全速和低速识别
  
  根据规范,全速(Full Speed)和低速(Low Speed)很好区分,因为在设备端有一个1.5k的上拉电阻,当设备插入hub或上电(固定线缆的USB设备)时,有上拉电阻的那根数据线就会被拉高,hub根据D+/D-上的电平判断所挂载的是全速设备还是低速设备。如下两图:

USB全速设备上电连接

(Full-speed Device Cable and Resistor Connections)


USB低速设备上电连接

(Low-speed Device Cable and Resistor Connections)


高速识别

  
  USB全速/低速识别相当简单,但USB2.0,USB1.x就一对数据线,不能像全速/低速那样仅依靠数据线上拉电阻位置就能识别USB第三种速度:高速。因此对于高速设备的识别就显得稍微复杂些。

  高速设备初始是以一个全速设备的身份出现的,即和全速设备一样,D+线上有一个1.5k的上拉电阻。USB2.0的hub把它当作一个全速设备之后,hub和设备通过一系列握手信号确认双方的身份。在这里对速度的检测是双向的,比如高速的hub需要检测所挂上来的设备是高速、全速还是低速,高速的设备需要检测所连上的hub是USB2.0的还是1.x的,如果是前者,就进行一系列动作切到高速模式工作,如果是后者,就以全速模式工作。

  下图展示了一个高速设备连到USB2.0 hub上的情形:



  hub检测到有设备插入/上电时,向主机通报,主机发送Set_Port_Feature请求让hub复位新插入的设备。设备复位操作是hub通过驱动数据线到复位状态SE0(Single-ended 0,即D+和D-全为低电平),并持续至少10ms。

  高速设备看到复位信号后,通过内部的电流源向D-线持续灌大小为17.78mA电流。因为此时高速设备的1.5k上拉电阻还未撤销,在hub端,全速/低速驱动器形成一个阻抗为45欧姆(Ohm)的终端电阻,2电阻并联后仍是45欧姆左右的阻抗,所以在hub端看到一个约800mV的电压(45欧姆*17.78mA),这就是Chirp
K信号。
Chirp K信号的持续时间是1ms~7ms

  在hub端,虽然下达了复位信号,并一直驱动着SE0,但USB2.0的高速接收器一直在检测Chirp K信号,如果没有Chirp
K信号看到,就继续复位操作,直到复位结束,
之后就在全速模式下操作如果只是一个全速的hub,不支持高速操作,那么该hub不理会设备发送的Chirp K信号,之后设备也不会切换到高速模式。

  设备发送的Chirp K信号结束后100us内,hub必须开始回复一连串的KJKJKJ….序列,向设备表明这是一个USB2.0的hub。这里的KJ序列是连续的,中间不能间断,而且每个K或J的持续时间在40us~60us之间。KJ序列停止后的100~500us内结束复位操作。hub发送Chirp
KJ序列的方式和设备一样,通过电流源向差分数据线交替灌17.78mA的电流实现。


  再回到设备端来。设备检测到6个hub发出的Chirp信号后(3对KJ序列),它必须在500us内切换到高速模式。切换动作有:
1. 断开
1.5k的上拉电阻。
2. 连接D+/D-上的高速终端电阻(high-speed termination),实际上就是全速/低速差分驱动器。
3. 进入默认的高速状态。

  执行1,2两步后,USB信号线上看到的现象就发生变化了:hub发送出来的Chirp KJ序列幅值降到了原先的一半,400mV。这是因为设备端挂载新的终端电阻后,配上原先hub端的终端电阻,并联后的阻抗是22.5欧姆。400mV就是由17.78mA*22.5Ohm得来。以后高速操作的信号幅值就是400mV而不像全速/低速那样的3V。

  至此,高速设备与USB2.0 hub握手完毕,进行后续的480Mbps高速信号通信。

最后附上几幅实际USB高速识别的示波器抓图,图中蓝色信号是D+,黄色信号是D-。

1.数据线D+在T点之前挂上1.5K电阻,在T点被host拉成SE0状态。在近2ms后,设备发送第一个Chirp K,向host通知说:我是一个高速设备,如果可能,请用高速方式与我通信。其幅度是800mV(17.78mA * (45Ohm ||1.5kOhm)
= 800mV,见上文解释)。在这里,
Chirp K的持续时间是2.13ms(a,b两点之间)。


2.这幅图显示了host发出的chirp KJ信号的幅度,头几个KJ是800mv(a,b之间),随后的是400mV。图中可以看到设备在收到第三个chirp J(蓝色短条)后马上把1.5k电阻取消,导致chirp J的幅值下降到400mV。(17.78mA * (45Ohm ||45Ohm)
= 17.78mA * 22.5
Ohm = 400mV)


3.量测了一个chirp J的宽度:43.5us。

 

 

最后附上一张来自Don Anderson的USB System Architecture里的USB HS接口图:


原文来自 http://hi.baidu.com/doyanger/blog/item/af45d995dd64f419d31b704d.html

windbg与虚拟机双机联调笔记

折腾了好几天,终于把双机联调给弄成功了,把参数与步骤放在这里,希望对与我一样的人有点帮助!

1.首先,安装windbg,并把它的快捷方式发送到桌面上并把中的内容改为:

D:/WinDDK/7600.16385.1/Debuggers/windbg.exe -b -k com:pipe,port=//./pipe/com_1,resets=0

然后点file->symbols file path,打开如下对话框

在里面输入上“srv*c:/symbols*http://msdl.microsoft.com/download/symbols;自已的工程路径”(以分号隔开);

2.然后点file->source file path会出现如下对话框

3.在其中输入要调试的源码文件所在的路径

然后点file->image file path会出现如下对话框

4.输入驱动文件的生成路径!

最后设置windows环境变量(不设环境变量有时会出现错误,可能我的设置有些问题)

变量名如上,变量值与Windbg中的第一个值一样也是“ srv*c:/symbols*http://msdl.microsoft.com/download/symbols”

5.最后为虚拟机设置串口

虚拟串口如上。

6.进入虚拟机系统

右键我的电脑->属性

 

在如下位置单击设置

 

 

 

 

进入如下输入并单击编辑

 

会打开boot.ini文件,拷入以下代码:

 [boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)/WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)/WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect /noguiboot
multi(0)disk(0)rdisk(0)partition(1)/WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect /debug /debugport=com1 /baudrate=115200 /noguiboot

保存重启即可!

7.重启动在虚拟机中选择调试模式引导

然后打开windbg

在出现一如下界面

 

 

依次在”kd>”中输入.!smy noisy

.sympath+ srv*c:/symbols*http://msdl.microsoft.com/download/symbols

.reload /f

来更新符号包,这时windbg会从网上下载符号包,windbg会表现出死机一样的现象,但不能关闭!可能一次会更新不完,有可能需要多次更新!

8.在最后调试时

使用“SRVINSTW_内核驱动安装.EXE”工具或“driver studio”附带的工具”driver monitor”时一定要先把生成的驱动文件拷到C:/windows/system32/drivers后再使用

 

“SRVINSTW_内核驱动安装.EXE”工具安装服务(目标文件要选择拷到C:/windows/system32/drivers目录下的我们自己的驱动文件),才会成功安装!要不然使用“net start 服务名”时会出现找不到路径!

关于ld -Ttext中的大小与text段在elf文件中的偏移之间的关系的猜想

在操作系统加载elf文件时都是按页映射的,而IA32下一页一般为4k,如果ld-Ttext 0x80400那么在操作系统去映设分页时应该是映射到0x80000~0x81000这个页表上的,但因为我们的text段入口地址为0x80400为了让程序去正确找到入口点,可以在text段之前构造SHT_NULL类型的无效段以便使text在文件中的偏移为0x400,这样在映射到页后,在加载时,直接跳到0x80400程序就能正常运行!

真正认识 realloc 的工作方式〈转〉

转自http://hi.baidu.com/419836321/blog/item/6f158d22797008469258070b.html realloc 用过很多次了。无非就是将已经存在的一块内存扩大。 char* p = malloc(1024);char* q = realloc(p,2048); 现在的问题是我们应该如何处理指针 p。 刚开始按照我最直观的理解,如果就是直接将 p = NULL;。 到最后只需要释放 q的空间就可以了。 因为最近在做个封装。结果在做单元测试的时候发现。有时候我在 free(q); 的时候会出错。这样我就郁闷了。 后来仔细一跟踪,发现 realloc 完以后 q 和 p 的指针地址是一样。不过有时候又不一样。 仔细查了下资料。得到如下信息:        1.如果 当前连续内存块足够 realloc 的话,只是将p所指向的空间扩大,并返回p的指针地址。 这个时候 q 和 p 指向的地址是一样的。         2.如果 当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存,q,并将 p指向的内容 copy到 q,返回 q。并将p所指向的内存空间删除。 这样也就是说 realloc 有时候会产生一个新的内存地址 有的时候不会。所以在分配完成后。我们需要判断下 p 是否等于 q。并做相应的处理。 这里有点要注意的是要避免 p = realloc(p,2048); 这种写法。有可能会造成 realloc 分配失败后,p原先所指向的内存地址丢失。 ========================================= 关于realloc函数说明的补充:函数定义:void *realloc(void *ptr, size_t size);上面的分析基本没有问题,但有两点要注意:1.返回值可能与ptr的值不同,如果是不同的话,那么realloc函数完成后,ptr指向的旧内存已被free掉了。2。如果返回NULL值,则分配不成功,而原来的ptr指向的内存还没有被free掉,要求程序显式free.故p = (int *) realloc (p, sizeof(int) *15);语句有这么一个问题,调用前p指向一个已分配成功的内存,而调用realloc时却失败(即返回NULL),此时,p原来指向的内存还没有free掉,而现在又找不到地址,这样就出现memory leak了。关于这一点的确要注意,最好如下:int *qq = (int *) realloc (p, sizeof(int) *15);if(!q) p =q; ====================================================== 首先看一下下面的C程序片断: #include char *p; p = (char * ) malloc (10); p = (char * ) realloc (p,20); …………………………     这段程序的意思很简单,只有稍有点C基础的人都可以看懂。函数首先定义了一个字符型的指针p,然后为指针p分配了一个10个字节大小的内存空间,接着将这个内存块的大小增加到20个字节。     这里有什么问题吗?上机运行一下,好像没有问题!     是的,这样上机运行是没有问题的,但是这里存在着也许我们不太注意的隐患!隐患在那里?这就是我在本文中要详细说明的realloc()函数了。     再看一下下面一段来自MSDN的话: realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value. 这段E文还不算是晦涩难懂,所以我就不翻译了,大致的意思是说关于realloc返回值的。但是这里对他的返回值分了几种情况: 1、 返回void * 指针,调用成功。 2、 返回NULL,当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL,此时原内存变成了“freed(游离)”的了。 3、 返回NULL,当没有足够的空间可供扩展的时候,此时,原内存空间的大小维持不变。 第一种情况告诉了我们在得到需要的内存空间后需要做类型转换的工作; 第二种情况可能只有傻瓜才会去使用吧! 第三种情况,内存空间不够的时候就会维持未来的大小不变。         MSDN上面说内存空间不够的时候就不会扩展原来的内存空间的大小,这话固然没有错,但是有点含糊,似乎遗漏了一种情况!我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平;可如果数据后面的字节不够的话,问题就出来了,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上。这句话传递的一个重要的信息就是数据可能被移动!看到这里,也许我们已经发现一开始我给出的程序的问题了。为了更清楚地说明问题,可以将上面的程序改成下面的形式: #include char *p,*q; p = (char * ) malloc (10); q=p; p = (char * ) realloc (p,20); …………………………     这段程序也许在编译器中没有办法通过,因为编译器可能会为我们消除一些隐患!在这里我们只是增加了一个记录原来内存地址的指针q,然后记录了原来的内存地址p,如果不幸的话,数据发生了移动,那么所记录的原来的内存地址q所指向的内存空间实际上已经放回到堆上了!这样一来,我们应该终于意识到问题的所在和可怕了吧!     这个问题似乎有点牛角尖的味道,因为我们也许从来不曾遇上过,但是我们应该明白这样的事情的始终存在,只有这样,在万一我们碰上的时候才会去有意识的去避免这种隐患,否则,一旦这样的隐患一旦发作,程序崩溃不说,恐怕查错也不是一件容易的事!     候俊杰在《深入浅出MFC》中引用林语堂的《朱门》中的一句话,我很有感触,虽然不可能有他的感触深,但是抱着向前辈学习的心态,所以也拿来作为本为的结束: “只用一样东西,不明白他的道理,实在不高明”。

开发人员应该知道的一些东西〈转〉

 鉴于经常看到很多傻傻的问题,比如xx语言干什么用的,xxx语言是不是落伍了?(不过说实在的,这些问题初学者都会有.)
  我在这里说说开发人员应该知道的一些东西。但是这些只是我在平日里看到和想到的。难免有所偏差,请见谅.
 
软件开发,是一个综合性的活计。软件开发,并不仅仅是编写代码.学会了用c这些编程语言进行编程只是第一步,一个最最基本要求。其他要的东西还多着呢。在
我看来,程序员大致可以分为两类.当一个工作任务分配到程序员身上时,一种程序员知道为什么要这样去做.另外一种则知道怎么去做完这个工作.
  
而这个区别就大了.如果你知道为什么要这样去实现,这个至少说明你能把握住你的任务在软件工程里面的位置.如果你只是仅仅知道怎么去完成他.那只是说明你
能做完这个工作而已.想做好就不一定能行了.而第一种程序员一定能做好.做的最优.看看下面的条条,希望对大家都有所帮助.

  第一要说的,编程的关键是什么?
  编程不是实现了代码就可以了.引用我的友人的一句话,“编程讲究是一个整体的平衡性。”
 
 对于这个他是这样解释的。“平衡性,是软件的很重要的部分,从平衡性的角度去考虑编程,就会抑制你想要用最新技术,最新系统等等一些想法。因为从平衡性
的角度考虑,只要你的软件有一个瓶颈出现,你的程序就是失败。你首先要考虑的是怎么消除程序中可能存在的一些瓶颈。在这个基础上你才有权利去考虑提高你程
序的性能”.就算你拥有最新的技术,最好系统,如果你的代码不行。只要你的程序有性能瓶颈存在,等于什么都没有做。
   
  在这里我想说的就是程序是人写的。如果你的水平不行,再好的现成的技术也是用不起来的。就算用起来了,你可能没有办法说清楚,为什么这样用?

  第二要说的,怎么编程?
 
 我想很多人看到这个问题,一定会在心里把我骂的体无完肤的。心想这小子活腻了。骂也无妨。暂且听我说。我说的怎么编程不是要说怎么写详细的代码,而是你
的程序最终是怎么形成的。我想写到这里又有人把我给陵迟了一次了。但实际上编写代码是在软件的生产过程中占有时间比较少的一块。

  我个人觉得要包含以下的几个部分:
  1。市场潜力分析
  分析你要写的软件能不能卖出去,或者说我要编写什么样的软件?
  2。同类产品竞争分析
  看看你的同类产品的优缺点,设计你的软件的卖点.(如果没有卖点,就没有必要继续了)
  3。软件设计
  写出详细的软件流程,数据流程。主要算法。软件架构等
  4。编写代码
  不用说了吧
  5。bug测试和试运行
  6。卖

  这些事,有的是市场的事,有的是系统分析员的事,还有的是编程的事。但是在很多小公司,本着小公司事必亲恭的办事原则。大家多了解一点是不会有错的。
   
  举个具体的例子来说。假如我要编写一个共享软件。我要怎么做呢?
   
  1。要好好想想我要写的软件有没有“钱”途。时间在15天-30天左右。在这段时间里面一定要好好的做一下市场考察.这个可是最关键的一步.
  2。好,我已经决定要写xxx软件了。
  3。在网上找几个对xxx最有威胁的同类软件,分析它们优缺点。要它们的优点,不要他们的缺点。设计出自己软件的卖点.
  4。根据前面分析的结果,大概的列出xxx软件应该具有的功能表
  5。写出1.0版的基本功能表,写出1.x的功能表。不要一次就做完全部的功能,这样的话,你的软件永远都没有出世的机会  
  6。选择编程语言 (看看,编程语言到这里才出来)
  7。上网找类似的源代码,算法。RFC标准文档。吃透.软件代码和算法的良好重用,会让你事半功倍的.
  8。根据你选定语言,算法,标准文档,写出xxx的详细设计文档。文档一定要用,不然你的计划性就不强.计划性不强,随意性就大.随意性大了,软件很容易失败的.
  9。按照设计文档编写代码
  10。测试和卖

  第三,哪里有资料,标准文档
  
 
 代码的世界是千变万化的,
在开始一个新的项目之前,完全可以找一个类似功能的代码来看看。这样可以更好的改进你的程序。有时还可以加快进度。还有当新的技术出来时,你要看看相关的
文档。虽然不要完全了解它的功能,好处。但是你至少要知道新的技术能用在什么地方。怎么用。配合什么其他的技术用能更好的发挥它的作用。编写软件不是全部
的东西都是自己写的。有很多的功能是一种标准,也许是标准算法。像图形的,多媒体的,加密解密的算法。有的是一个标准的文件格式,像各种图像文件,多媒体
文件。还有的是一种标准的约定。像email,telnet等常见的网络工具。

  所以你要知道你可以从哪里找你要的资料。我把我知道的都写在这里

  源代码和技术资料站点
  www.vchelp.net gb
  www.csdn.net gb
  www.codeguru.com en
  www.codetools.com en
  www.dexv.com en
  msdn.microsoft.com en
  www.programmerheaven.com en
  www.freshmeat.net en
  www.sourceforge.net en
  www-900.ibm.com/developerWorks/ gb
  
  论坛和标准,组织
  www.linuxaid.com.cn gb
  www.linuxbyte.com gb
  www.aka.org.cn gb
  www.rfc.org en gb

  第四,要掌握的工具和知识
  工具,可以让你的工作更加的有效率和不易出错。
  
  下面的工具也许你用过,也许你没有用过。不过没有关系的。同行的老鸟会教我们怎么用的。(我想到哪个就写哪个。没有顺序问题)
  1。数据库工具
   建数据库工具,代表 powerdesigner
   数据库分析工具。很多大型的数据库都会带的。
  2。流程图设计 代表 visio 2000 , smartdraw
  3。case工具 代表 rose
  4。代码分析工具 
   代表 bounderchecker(for vc delphi),smartcheck(for vb) ….
  5。编辑器 
   代表 vi,vic,Ultra Edit
  6。源代码管理
   代表 vss ,cvs
  7。编程工具,不要我多说了吧
  8。其他的,我没有用过的,但是也许在某个行业用的很多的工具。(废话 :))  

  知识的话,因为每一个人的发展方向不一样,所以大部分人的知识结构都不一样。但是有几点应该是一样的。

  1。英语能力
 
  主要的新的技术,文档资料都是用英语来作为首发的。如果要学到更好更新的知识,技巧。不懂点英语也是不行的。也不要指望有人给你翻译出来。一般来说,
这些资料,看的懂的人不需要翻译,看不懂的人没有办法翻译。半懂不懂的人翻译出来的文章我想你也不敢看。所以大部分的资料还是英语原文的。当然也有很多的
人在翻译这些文章,但是对于这么多的资料来说,翻译过来的只是很小很小的一部分。求人不如求己。多学点英语没有错的。

  2。设计能力
 
 虽然一般来说,正规的公司有系统分析员做设计(我猜的)。但是70%-80%的小公司,可就不一定了。知道一点软件工程的知识,知道一些文档设计工具怎
么用。或者知道应该有哪些设计文档。也是很有好处的。比较这些东西如果你学到了,就是你自己的了。而且这些可是加工资的好东西。很有钱途的。:)

  3。语文写作能力
   作为一个程序员,大部分时间是都是在写代码。但是代码的注释,各种文档,测试报告,说明文档,使用手册编写,这些都需要文字功底的。 还有用email,bbs,qq这些工具与人交流的时候,如果话都说不清楚,那交流就更谈不上了。水平提高进步也就有点问题了。

  4。学习能力
 
  没有几个人是全部学会了再去工作的。这个不是很现实。目前社会也不太允许这样做。一边工作一边学习是很常见的。也许很多人是在工作之中才学会做某些事
情的。很多技能也是这样会的。此外,很多新的项目的到来。很新的技术的到来都要求我们能适应新的工作环境,新的工作要求。如果没有好好的学习是很容易被一
个项目踢掉的。呵呵。
另外有一点,当上司让你做你不会的东西时,你要告诉他,你不会,但是会在XX天内把他搞定。不会没有关系,会学习也是会上进的一种好表现。

  5。知道自己要做什么,要学什么,要发展什么。
   世界上软件技术是多的像9个牛上的毛一样多,也许还要多很多。如果我们什么都要知道。哦,天哪,我不想活了。
   作为一个软件人员也好,作为一个初学者也好。知道自己要往那个方向走是很重要的。不然很容易的就饿死在软件技术迷宫里的。最后只好不干这一行了。这个可不太好。

般来说,作为一个软件人员,掌握一到两个语言的开发能力就可以了。另外除非你是想做软件技术的研发(这些工作最有钱,在大型的公司是最受欢迎)。如果不是
做软件技术的研发,只是一般的应用程序编写的话,不用太关注今天出来什么新的技术,明天又出来什么新的技术。这些东西只要知道就行了。知道有这么回事就可
以了。以后有用的到的地方再去认真的关注也是不迟的。自己选择一个发展的方向,努力的向前走。不要被各种各样的新技术诱惑过去。说句实话,很多的所谓新技
术的怎么怎么好,怎么怎么优异,很多时候都是有商业行为在里面的。要自己会判断才行。如果不能判断怎么办,看下面的一条。

  第六:知道的更多
 
  很多初学者最麻烦的事是怎么在这么多的软件技术里面选择一种又好学,又有前途(钱途),又能做点什么伟大的事情的技术来开拓软件开发这个他们未知的领
域。对于这个麻烦的问题,很少有解。如果你能遇到一个很好的老师,那就是你的福气,千万要抓住这个机会。如果你不得不一人做出这个决定,那只能是小心翼翼
地来了。不过一般来说学c和c++都是一个不错的选择。
  初学者的另外一个麻烦的问题是,当我选择之后,在学习过程中出现的很多这个和那个的新
技术,新的变化。我该怎么办。这个也基本无解。只能是你自己慢慢慢慢积累。积累到你能理解这些新技术的出现是为了什么,这些新变化的发生是为知道的更
多……,这些新变化的发生是为了什么之后。你就会不怕这些的新的东西。
  我一向坚持,如果我知道的更多,我的力量就会更大。我就更不会怕出现变化。如果因为你的信息不足,而无法对某件事情进行判断时,千万不要强行进行判断。对你没有好处的。

转自http://topic.csdn.net/u/20110308/19/01ead01d-787f-44e5-bf30-b2795efc4c00.html

关于《orange‘s一个操作系统的实现》中调用门部分的补充和纠正

在《orange‘s一个操作系统的实现》中书对调用门中参数复制一点一略而过,并没有对参数大小等做出解释!上网找了很久发现并没有太多这方面的描述于是自已动手实验了一下并查了80386指令手册得出如下结论:

经过实验发现:如果调用门是向32位代码段跳转时,那么调用门在用param count复制时以一个参数为双字大小进得复制,也是就要复制的参数大小为(param count)*4字节,如果调用门是向16位代码段跳转时,那么调用门在用param count复制时以一个参数为单字大小进得复制,也是就要复制的参数大小为(param count)*2字节。那么什么时候向32位代码段中跳转,什么时候向16位代码段中跳呢?这关系到门描述符中TYPE字段中的内容,如果TYPE字段的值为4则为16位门描述符用来向16位代码跳转,如果TYPE字段的值为c时则为32位门描述符,用来向32位代码段跳转!

在指令返回时本书中那副堆栈示意图旁边那段代码疑似有错误,因为RET 中的参数应与调用门中的(param count)就该是对应关系,也就是说如果是16位调用门跳转时返回时应用retf/ret  (param count)*2来返回,如果是32位调用门跳转时返回时就用retf/ret  (param count)*4,这样堆栈才能平衡!但那一小段代码竟用ret 3!

以下为参考资料和实验代码:


Changing Size of Call
When adding 32-bit gates to 16-bit procedures, it is important to consider
the number of parameters. The count field of the gate descriptor specifies
the size of the parameter string to copy from the current stack to the stack
of the more privileged procedure. The count field of a 16-bit gate specifies
the number of words to be copied, whereas the count field of a 32-bit gate
specifies the number of doublewords to be copied; therefore, the 16-bit
procedure must use an even number of words as parameters.

There are three ways to cause a 16-bit procedure to execute a 32-bit call:
1. Use a 16-bit call to a 32-bit interface procedure that then uses a
  32-bit call to invoke the intended target.
2. Bind the 16-bit call to a 32-bit call gate.
3. Modify the 16-bit procedure, inserting an operand-size prefix before
  the call, thereby changing it to a 32-bit call.
Likewise, there are three ways to cause a 32-bit procedure to execute a
16-bit call:
1.
Use a 32-bit call to a 32-bit interface procedure that then uses a
16-bit call to invoke the intended target.

 

2. Bind the 32-bit call to a 16-bit call gate.
3. Modify the 32-bit procedure, inserting an operand-size prefix before
  the call, thereby changing it to a 16-bit call. (Be certain that the
 return offset does not exceed 64K.)
Programmers can utilize any of the preceding methods to make a CALL in a
USE16 segment match the corresponding RET in a USE32 segment, or to make a
CALL in a USE32 segment match the corresponding RET in a USE16 segment.


以下为代码:

代码: 


 

Win7中IE8中二级链接打不开

我朋友最近老是吵着IE坏了,今天抽空去看了一下,发现症状如下,打开IE后可以打开百度,但搜索后打不开二级链接,上网搜索发现网上有很多和这种情况一样的朋友,也有很多网友提供了很多方法,但大都不太管用!在这里贴出自己的经验,希望给有和我一样情况的朋友一点帮助!

 


思路是这样的,既然IE坏了,肯定是某个DLL文件失效或是某些文件损坏最省事的方法就是重装一下IE。能基本解决大部分IE问题。

 

1.打开控制面板 —> 程序

出现如下界面

然后单击“打开或关闭Windows功能

出现如下界面

2.将其中“Internet Explorer 8″勾选掉,然后单击确定。

然后根据提示重启电脑,在重启过程中会出现类似更新补丁的界面。

3.重启后再按前面步骤把



中的”Internet Explorer 8″勾中,然后再根据提示重启电脑,重启后发现IE的问题已经消失了。这种方法可以解决绝大部分IE问题,缺点是稍嫌麻烦!