2012年4月17日星期二

HTML生成PDF(c#)

HTML生成PDF(c#)

    最近因为工作需要,小小的研究了一下HTML生成PDF的方法,这方面的内容很多,但要么是不尽如人意的方法,要么就是那种收费的类库!为了广大.neter的福利,把自己的一点小小心得总结出来与大家分享!

    先说说我最后采用的方法吧!wkhtmltopdf,一个集成好了的exe文件(C++编写),基本的调用方法是,wkhtmltopdf www.jingzhengli.cn myhomepage.pdf,可以先在命令行测试一下,有其他的需要可以在命令行通过wkhtmltopdf --help查询,如果是超长页的花,可以用命令wkhtmltopdf www.jingzhengli.cn myhomepage.pdf -H --outline -H是添加默认标题,--outline是添加pdf的左侧概要哦!)而且可以批量生成哦,中间用空格隔开,用命令wkhtmltopdf www.jingzhengli.cn www.jingzhengli.com myhomepage.pdf   快去试试吧!提醒下:如果是转换GB2132编码的网页是会出现乱码的哦!  好了,其他的自己琢磨琢磨吧!上面都是在命令行下测试,下面给出在C#下的调用方法:

    using System.Diagnostics;
    /// <summary>
    /// HTML
生成PDF
    /// </summary>
    /// <param name="url">
地址</param>
    /// <param name="path">PDF
存放路径</param>
    public static bool HtmlToPdf(string url, string path)
    {
        try
        {
            if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(path))
                return false;
            Process p = new Process();
            string str = System.Web.HttpContext.Current.Server.MapPath("wkhtmltopdf.exe");
            if (!System.IO.File.Exists(str))
                return false;
            p.StartInfo.FileName = str;
            p.StartInfo.Arguments = " \"" + url + "\" " + path;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            System.Threading.Thread.Sleep(500);

            return true;
        }
        catch (Exception ex)
        {
            HttpContext.Current.Response.Write(ex);
        }
        return false;
    }

    调用方法:HtmlToPdf("网页URL", Server.MapPath("PDF存放路径"));

    下载地址:http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.8.3.exe
   
源码地址:http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.8.3.tar.bz2

    这里再给出个貌似是国人写的一个类似的,效果不佳,但值得鼓励:PageToPDF,调用方法类似,但这个的exe文件必须和itextsharp.dll放在同一目录下!且不支持长页面的生成PDF,转换新浪网就是一片白了!

    下面给出几个国外网站卖的C#编写的类库的试用版,功能强大,可惜需要License key,大家可以下载下来看看。我尝试用reflector反编译到一半就卡住不动,望有志达人为了广大.neter的福利,破解一下!
    1.ExpertPDF-HtmlToPdf-v5.4.0   $350(
真黑,知识就是money)
    2.WnvHtmlToPDF  (
这个一样的黑价,达人快来破解吧)
    3.PDFKit.NET 2.0   http://tallcomponents.com 这个网站的

    这收费的就太黑了,都开源时代了,还这样!下面呢,给出一些PDF生成相关的资料,有志之士可以自己研究下,说不定你也可以开发个类库,买¥350也好啊!

  1. iTextSharp,类库,创建PDFRTFXML等,并可解析PDF,功能最强;
  2. Report.NET,类库,创建PDF,不错;
  3. sharpPDF,类库,创建PDF,不错;
  4. iTextdotNET,类库,创建PDF,与Java原版最能保持更新同步;
  5. A pdf Forms Parser,类库,PDF解析器;
  6. pdf Library for creating pdf with tables and text, in C# ,类库,轻量级的创建,中文支持不好;
  7. pdfizer, a dumb HTML to pdf converter, in C#,转换HTMLPDF;
  8. TEXT to pdf Converter in .NET using Reporter.NET,利用Report.NET把纯文本转换成为PDF;
  9. pdf creation using C# (and Office) from RTF/DOC files,从RTF/Doc文件中生产PDF文件;
  10. Generate pdf docs from a HTML page using ASP.NET ,使用.NETHTML生成PDF.

    希望以上资料对大家有用!也希望达人破解后能留个言,或者发个邮件至我邮箱:calexj@163.com

 

2011年2月10日星期四

Facebook開發工具比較(for .Net)

 
Facebook開發工具比較(for .Net)
 
臉書整合服務寫於 2010年12月28日 6:53
 
Facebook官方提供的Api SDK,如果依程式語言來區分的話一共有以下幾種:
 
  • JavaScript SDK
  • PHP SDK
  • Python SDK
  • iOS SDK for iPhone, iPod touch, and iPad
  • Android SDK 
 
明 顯地,Facebook官方並沒有提供 for .Net的SDK,所以如果要使用.Net來開發Facebook的應用服務的話,就必須再借助第三方廠商所開發的SDK工具。我沒有實際去找出目前網路 上所有 for .Net的SDK,但就我爬文的結果,被使用最廣泛的主要有三套,如下:
 
 
 
(1) Facebook Developer Toolkit
 
(2) csharp-sdk
 
(3) Facebook C# SDK
 
 
 
來跟大家分享一下我比較的一些結果。
 
 
 
Facebook Developer Toolkit 
 
‧下載的網址:http://facebooktoolkit.codeplex.com/  (for .Net 2.0版本)
 
是 微軟官方所出版的Facebook for .Net SDK,沒錯!就是微軟官方所出的。一開始我看到好像找到寶一樣的開心,文件和範例都蠻齊全的。但是,我再詳細看這個SDK的支援還有最新更新的日期,才 發現它不支援Facebook新版的Graph API,也就是不支援OAuth 2.0 規格的登入授權方式。
 
舊版的 Facebook API登入是使用session_key以及動態的secret,新版的 Facebook API登入則是使用access_token(請參考:i am Jason: Facebook Open Graph的登入授權方式)。雖然現在Facebook API新舊並存,如果是用舊版的Api寫的程是目前都還可以跑,但不曉得哪Facebook要給它停掉,所以還是決定不採用。而且, 後來微軟官方自己也都沒有再更新這個套件了,我再去看這個工具的討論版,蠻多抱怨的文章 ,所以...
 
 
 
csharp-sdk
 
 
for .Net 4.0版本,而且要用Visual Studio 2010才能開啟專案檔,記得!還要自己將套件編譯過才能使用(給的很沒誠意!) 
 
本套件是Facebook官方開發人員所釋出的 for .Net SDK,但是從2010年7月17日公開到現在,一直都在Alpha版,沒錯!好像都沒再更新了。所以, Facebook也沒有將這個工具放在官方正式SDK清單裡面。
 
我看了[after dusk, before dawn]部落格針對該套件寫了幾篇文章,寫的很不錯,有興趣研究的可以連到[after dusk, before dawn: [Facebook] 臉書的C Sharp SDK]研究。
 
我 自己使用的感覺, csharp-sdk將比較繁瑣的Facebook訊息傳遞包裝成簡單的方法,並且提供便利的Jason物件解析方式(Facebook很多都是利用 Jason傳遞資料),基本上是一個麻雀雖小五臟俱全的工具。如果你要比較複雜的功能,或是後來Facebook又釋出的新功能,這個工具可能就達不到, 而要自己再開發。
 
Facebook使用者登入授權的方式主要有兩種,官方說明,一種是利用網頁傳地參數的方式,另一種是利用JS SDK取得Cookie來認證 ,csharp-sdk基本上是使用第一種方式,
 
利用網頁傳地參數的方式會有一些不便之處,後續再分享我的解決方式。
 
 
 
Facebook C# SDK
 
 ‧下載的網址:http://facebooksdk.codeplex.com/
 
for .Net 3.5 & 4.0版本,而且要用Visual Studio 2010才能開啟專案檔。一開始我以為是微軟官方的Facebook for .Net SDK,結果錯!不是微軟官方所出的,是另外的團隊所開發的,我看到的更新版本日期是
 
 
 
Current 4.1.0
 
Date    Fri Dec 17 2010 at 4:00 PM
 
 
 
真是好開心!有再更新耶~(標準越來越低了,有更新就好~),連微軟官方都公開直接支持這個 SDK(這是微軟的風格嗎?) ,範例也都有了,而且相當的齊全,連 Api文件都有了耶~佛心來著~
 
 
 
範例
 
 
 
馬上來測試看看,我是測試CSASPNETFacebookApp專案,但照上面的步驟來編譯,一直會出現Facebook授權失敗的錯誤訊息,我到專案的討論區上,也看到不少人有跟我同樣的問題,現在只能期待這個問題在下一個版本可以被修正。
 
 
 
【後續建議】
 
如果你的專案不大,我直接推薦csharp-sdk,快速上手又輕巧。
 
基本上我是蠻期待Facebook C# SDK這一套的工具的,但是Facebook常常在變動規則,要一直跟著 Facebook的隨興,又不會給搞死的第三方SDK套件,真的必須俱備有兩把刷子!
 
連微軟都索性不再更新官方的Facebook for .Net SDK了。Facebook C# SDK,加油! 
 
 
 
Best Regards
Miao
 
 

2011年1月24日星期一

USB设备描述符

 
USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,
配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。
USB报告描述符(Report Descriptor)HID设备中的一个描述符,它是比较
复杂的一个描述符。
USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。
输入报告是
USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等
信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送
USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是
一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点
输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出
端点
0发送,当有中断输出端点时,通过中断输出端点发出。
而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。
通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入
端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求
是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的
报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中
没有规定报告ID时,报告中就没有ID字段,开始就是数据。更详细的说明请参看
USB HID协议,该协议可从Http://www.usb.org下载。
 
一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。
USB主机在检测到USB设备插入后,就要对设备进行枚举了。为什么要枚举呢?枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,那么就已经成功大半了。
在说枚举之前,先大概说说
USB的一种传输模式――控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。
好了,下面我们来看看枚举的详细过程。
首先,
USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。
然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时
USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过它来进行访问该设备。
然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的
18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。
接下来,主机就会获取配置描述符。配置描述符总共为
9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。
如果有字符串描述符的话,还要获取字符串描述符。另外
HID设备还有HID描述符等。使用BUS HOUND以及通过串口返回信息,很容易看到具体的过程。总之是主机请求什么,你的程序就响应什么。
下面这些数据是使用BUS HOUND抓的,这个是在WIN2000下抓到的,如果在WINXP下,就看不到设置地址之前的数据。
写了注释下面的部分就是主机和设备之间的数据通信,而其它的则是主机跟根集线器之间的通信数据。
USB是个通用的总线,端口都是统一的。但是USB设备却各种各样,
例如
USB鼠标,USB键盘,U盘等等,那么USB主机是如何识别出不同的
设备的呢?这就要依赖于描述符了。
USB的描述符主要有设备描述符,配置描述符,接口描述符,
端点描述符,字符串描述符,
HID描述符,报告描述符等等。
关于报告描述符,请看我以前写的:《
USB HID报告及报告描述符简介
http://group.ednchina.com/93/198.aspx
一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,
USB
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。

每种描述符都有自己独立的编号,如下:
#define DEVICE_DESCRIPTOR 0x01 //设备描述符
#define CONFIGURATION_DESCRIPTOR 0x02 //配置描述符
#define STRING_DESCRIPTOR 0x03 //字符串描述符
#define INTERFACE_DESCRIPTOR 0x04 //接口描述符
#define ENDPOINT_DESCRIPTOR 0x05 //端点描述符

下面分别详细介绍一下各描述符。
1.设备描述符
//定义标准的设备描述符结构
typedef struct _DEVICE_DCESCRIPTOR_STRUCT
{
BYTE blength; //设备描述符的字节数大小
BYTE bDescriptorType; //设备描述符类型编号
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码
BYTE bDeviceSubClass; //USB分配的子类代码
BYTE bDeviceProtocol; //USB分配的设备协议代码
BYTE bMaxPacketSize0; //端点0的最大包大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //设备厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfigurations; //可能的配置数量
}
DEVICE_DESCRIPTOR_STRUCT, * pDEVICE_DESCRIPTOR_STRUCT;
//实际的设备描述符示例
code DEVICE_DESCRIPTOR_STRUCT device_descriptor= //设备描述符
{
sizeof(DEVICE_DESCRIPTOR_STRUCT), //设备描述符的字节数大小,这里是18字节
DEVICE_DESCRIPTOR, //设备描述符类型编号,设备描述符是01
0x1001, //USB版本号,这里是USB01.10,即USB1.1。由于51是大端模式,所以高低字节交换
0x00, //USB分配的设备类代码,0表示类型在接口描述符中定义
0x00, //USB分配的子类代码,上面一项为0时,本项也要设置为0
0x00, //USB分配的设备协议代码,上面一项为0时,本项也要设置为0
0x10, //端点0的最大包大小,这里为16字节
0x7104, //厂商编号,这个是需要跟USB组织申请的ID号,表示厂商代号。
0xf0ff, //该产品的编号,跟厂商编号一起配合使用,让主机注册该设备并加载相应的驱动程序
0x0100, //设备出厂编号
0x01, //设备厂商字符串的索引,在获取字符串描述符时,使用该索引号来识别不同的字符串
0x02, //描述产品字符串的索引,同上
0x03, //描述设备序列号字符串的索引,同上
0x01 //可能的配置数为1,即该设备只有一个配置
};
2.配置描述符
//定义标准的配置描述符结构
typedef struct _CONFIGURATION_DESCRIPTOR_STRUCT
{
BYTE bLength; //配置描述符的字节数大小
BYTE bDescriptorType; //配置描述符类型编号
WORD wTotalLength; //此配置返回的所有数据大小
BYTE bNumInterfaces; //此配置所支持的接口数量
BYTE bConfigurationValue; //Set_Configuration命令所需要的参数值
BYTE iConfiguration; //描述该配置的字符串的索引值
BYTE bmAttributes; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流
}
CONFIGURATION_DESCRIPTOR_STRUCT, * pCONFIGURATION_DESCRIPTOR_STRUCT;
2.接口描述符
//定义标准的接口描述符结构
typedef struct _INTERFACE_DESCRIPTOR_STRUCT
{
BYTE bLength; //接口描述符的字节数大小
BYTE bDescriptorType; //接口描述符的类型编号
BYTE bInterfaceNumber; //该接口的编号
BYTE bAlternateSetting; //备用的接口描述符编号
BYTE bNumEndpoints; //该接口使用的端点数,不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass; //接口子类型
BYTE bInterfaceProtocol; //接口遵循的协议
BYTE iInterface; //描述该接口的字符串索引值
}
INTERFACE_DESCRIPTOR_STRUCT, * pINTERFACE_DESCRIPTOR_STRUCT;
4.端点描述符
//定义标准的端点描述符结构
typedef struct _ENDPOINT_DESCRIPTOR_STRUCT
{
BYTE bLegth; //端点描述符字节数大小
BYTE bDescriptorType; //端点描述符类型编号
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttributes; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包大小
BYTE bInterval; //主机查询端点的时间间隔
}
ENDPOINT_DESCRIPTOR_STRUCT, * pENDPOINT_DESCRIPTOR_STRUCT;
下面是一个配置描述符集合的定义
typedef struct _CON_INT_ENDP_DESCRIPTOR_STRUCT
{
CONFIGURATION_DESCRIPTOR_STRUCT configuration_descriptor;
INTERFACE_DESCRIPTOR_STRUCT interface_descritor;
ENDPOINT_DESCRIPTOR_STRUCT endpoint_descriptor[ENDPOINT_NUMBER];
}CON_INT_ENDP_DESCRIPTOR_STRUCT;
配置描述符集合的示例

code CON_INT_ENDP_DESCRIPTOR_STRUCT con_int_endp_descriptor= //配置描述符集合
{
//configuration_descriptor //
配置描述符
{
sizeof(CONFIGURATION_DESCRIPTOR_STRUCT), //
配置描述符的字节数大小,这里为9
CONFIGURATION_DESCRIPTOR, //
配置描述符类型编号,配置描述符为2
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)*256+
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)/256, //
配置描述符集合的总大小
0x01, //只包含一个接口
0x01, //该配置的编号
0x00, //iConfiguration字段
0x80, //采用总线供电,不支持远程唤醒
0xC8 //从总线获取最大电流400mA
},
//interface_descritor //
接口描述符
{
sizeof(INTERFACE_DESCRIPTOR_STRUCT), //
接口描述符的字节数大小,这里为9
INTERFACE_DESCRIPTOR, //
接口描述符类型编号,接口描述符为3
0x00, //
接口编号为4
0x00, //
该接口描述符的编号为0
ENDPOINT_NUMBER, //
0端点数量为2,只使用端点主端点输入和输出
0x08, //定义为USB大容量存储设备
0x06, //使用的子类,为简化块命令
0x50, //使用的协议,这里使用单批量传输协议
0x00 //接口描述符字符串索引,为0,表示没有字符串
},
//endpoint_descriptor[]
{
{ //主端点输入描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数大小,这里为7
ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_IN, //端点号,主输入端点
ENDPOINT_TYPE_BULK, //使用的传输类型,批量传输
0x4000, //该端点支持的最大包尺寸,64字节
0x00 //中断扫描时间,对批量传输无效
},
{ //主端点输出描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数大小,这里为7
ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_OUT, //端点号,主输出端点
ENDPOINT_TYPE_BULK, //使用的传输类型,批量传输
0x4000, //该端点支持的最大包尺寸,64字节
0x00 //中断扫描时间,对批量传输无效
}
}
};
其中关于端点的类型定义如下
//定义的端点类型
#define ENDPOINT_TYPE_CONTROL 0x00 //控制传输
#define ENDPOINT_TYPE_ISOCHRONOUS 0x01 //同步传输
#define ENDPOINT_TYPE_BULK 0x02 //批量传输
#define ENDPOINT_TYPE_INTERRUPT 0x03 //中断传输
端点号的定义如下
#define MAIN_POINT_OUT 0x02 //2号输出端点
#define MAIN_POINT_IN 0x82 //2号输入端点
 
 
 
 

2011年1月21日星期五

FW: [嘻嘻哈哈] USB接口的红外电脑遥控

USB接口的红外电脑遥控

USB接口的红外电脑遥控

摘要:本设计采用2262,2272一对无线控制芯片来实现红外的发射和硬件解码。而在USB控制模块则采用51+PDIUSBD12来实现USB设备的枚举和数据传送。

本次设计的要点在于USB键盘的实现,因为本次设计最终与主机进行通信是将USB设备枚举成USB键盘,从而获得操作系统的支持,实现免驱动安装的目的。

(一)方案的选择

1:红外的软件解码

此方案是通过软件的复杂化来简化硬件结构,此方案不仅要求对红外协议的熟悉,而且软件解码耗时较大,不适合进行实时性数据的传送。

2:红外的硬件解码

此方案通过一对无线发射和接受芯片2262,2272来实现红外的解码。其特点是红外传送的实时性好,简化软件编写量,且外围硬件电路并不复杂,故在本次设计中采用此方案。

3:采用LPC2148来实现USB的控制

此方案中,LPC2148是一款内置USB模块的微控制器。用其来实现USB的控制和传送可以最大化的简化外围电路和程序的稳定性,但其缺点是芯片价格高,需要另外学习ARM7系列的编程特点。



4:采用51+PDIUSBD12来实现USB的控制

PDIUSBD12是一款性价比很高的USB 器件它通常用作微控制器系统中实现与微控制器进行通信的高速通用并行接口它还支持本地的DMA 传输,支持USB1.1协议。虽然采用51+PDIUSBD12形式使硬件复杂,但由此换来的软件编写环境的熟悉和价格上的优势,故采用此方案。

(二)USB协议和HID键盘的实现

本设计是通过将此USB设备枚举成USB键盘来实现电脑的控制,所以必定设计到USB设备的枚举,故在此先对USB的枚举进行简单的论述。

枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。 在说枚举之前,先大概说说USB的一种传输模式――控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。



1:枚举过程
首先,USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。
然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过它来进行访问该设备。
然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。
接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。

如果在设备描述符中定义了字符串描述符,而主机还需要获取字符串描述符。字符串描述符的长度不固定,可由程序员自行确定。
而在此设计中,由于键盘是一种HID设备,故主机还需要获取HID设备类描述符。HID设备类描述符包括HID描述符、报告描述符、物理描述符三种,其中报告描述符是必须的,而另外两种则为可选描述符。

主机得到各种正确的描述符,则为枚举成功,主机加载合适的驱动,即可进行通讯。

2:各种描述符

一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。


每种描述符都有自己独立的编号,如下:
DEVICE_DESCRIPTOR 0x01 //设备描述符
CONFIGURATION_DESCRIPTOR 0x02 //配置描述符
STRING_DESCRIPTOR 0x03 //字符串描述符
INTERFACE_DESCRIPTOR 0x04 //接口描述符
ENDPOINT_DESCRIPTOR 0x05 //端点描述符

设备描述符



BYTE blength; //设备描述符的字节数大小
BYTE bDescriptorType; //设备描述符类型编号
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码
BYTE bDeviceSubClass; //USB分配的子类代码
BYTE bDeviceProtocol; //USB分配的设备协议代码
BYTE bMaxPacketSize0; //端点0的最大包大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //设备厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfigurations; //可能的配置数量

配置描述符

BYTE bLength; //配置描述符的字节数大小
BYTE bDescriptorType; //配置描述符类型编号
WORD wTotalLength; //此配置返回的所有数据大小
BYTE bNumInterfaces; //此配置所支持的接口数量
BYTE bConfigurationValue; //配置值
BYTE iConfiguration; //描述该配置的字符串索引值
BYTE bmAttributes; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流



接口描述符
BYTE bLength; //接口描述符的字节数大小
BYTE bDescriptorType; //接口描述符的类型编号
BYTE bInterfaceNumber; //该接口的编号
BYTE bAlternateSetting; //备用的接口描述符编号
BYTE bNumEndpoints; //接口使用的端点数不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass; //接口子类型
BYTE bInterfaceProtocol; //接口遵循的协议
BYTE iInterface; //描述该接口的字符串索引值



端点描述符
BYTE bLegth; //端点描述符字节数大小
BYTE bDescriptorType; //端点描述符类型编号
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttributes; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包大小
BYTE bInterval; //主机查询端点的时间间隔



字符串描述符



字符串描述符包括设备厂家描述符、产品描述符、设备序列号描述符。其作用主要是打上自己的商标,防止与其它厂家或其它产品一样,或者被其它厂家倒版,这一块有自己定义,长度也是由自己设定。

基本格式为:

BYTE bLegth; //字符串描述符字节数大小(N+2)
BYTE USB_STRING_DESCRIPTOR_TYPE //字符串类型编码

下面的数据有自己定义 //自己定义,长度为N


HID设备类描述符



通过上面的描述,主机可得到USB设备的大概信息,但如果仅只有以上那些的话,USB设备是不能和主机进行通信的。因为在上面的描述符中根本就没有定义USB设备的具体功能和传递信息的数据格式,而这就需要类描述符。

而因为本设计中的USB键盘所属的为人机接口类(HID),所以我们主要就叙述HID设备类描述符。



HID设备类描述符中自行定义了3种类描述符,分别为HID描述符、报告描述符和物理描述符,其中HID描述符和物理描述符不是必须的。

而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。
通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据。

以下为普通USB键盘的报告描述符(不支持多媒体功能)
0x05, 0x01, //USAGE_PAGE (Generic Desktop)用途页为通用桌面设备 0x09, 0x06, //USAGE (Keyboard) 用途为键盘
0xa1, 0x01, //COLLECTION (Application)集合开始 0x05, 0x07, //USAGE_PAGE (Keyboard) 用途页为按键
0x19, 0xe0, //USAGE_MINIMUM (Keyboard LeftControl)用途最小值
0x29, 0xe7, //USAGE_MAXIMUM (Keyboard Right GUI)用途最大值
0x15, 0x00, //LOGICAL_MINIMUM (0) 逻辑最小值为0
0x25, 0x01, //LOGICAL_MAXIMUM (1) 逻辑最大值为1
0x75, 0x01, //REPORT_SIZE (1) 报告大小(即这个字段的宽度)为1bit
0x95, 0x08, //REPORT_COUNT (8) 报告的个数为8,即总共有8个bits
//输入用,变量,值,绝对值。像键盘这类一般报告绝对值
0x81, 0x02, // INPUT (Data,Var,Abs)
/*上面这这几项描述了一个输入用的字段,总共为8个bits,每个bit表示一个按键,分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下,否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位,需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示特殊键,例如ctrl,shift,del键等 */
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)

0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs) 控制键盘上的LED用的
0x19, 0x01, // USAGE_MINIMUM (Num Lock) 数字键锁定灯
0x29, 0x05, // USAGE_MAXIMUM (Kana)
//输出,用来控制LED。变量,值,绝对值。1表示灯亮,0表示灯灭
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
//由于要按字节对齐,而前面控制LED的只用了5个bit,
//所以后面需要附加3个不用bit,设置为常量
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
/*以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个 按键,所以可以同时有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一个字节为相应的键值(具体的值参看HID Usage Tables),如果两个键按下,则第1、2两个字节分别为相应的键值,以次类推。*/

USB HID设备传送数据有两种方式:

一是通过报告来给传送数据,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出端点0发送,当有中断输出端点时,通过中断输出端点发出。在USB2.0协议中提出不提倡通过这种方式来进行传送数据。

二是通过端点的中断传送进行传递数据,在本设计中就是通过端点2的中断来进行与主机的数据交换。

(三)无线电脑遥控实现

本设计是通过2262配合红外发射头来进行发送数据,用与之相匹配的2267(地址,频率匹配)和红外接收头来接收数据。在单片机每次的定时器0中断的时候进行读取数据,通过每次的端点2的中断将数据传递至主机,从而实现对主机的相应控制。

具体实现为:在每一次2262的有按键按下的同时使2262工作,将数据传送至2272,而2272将从2262解码出数据,等待单片机的读取。若2262没有按键按下,则2272的数据为0。在定时器0中断的中断服务程序中,读出2272解码出来的其中的按键信息,将其变换成控制相应按键的USB键盘数据流,通过PDIUSBD12的端点2将数据传递至主机,从而实现一次相应的控制。因为端点2的中断和定时器0的中断是循环不断的进行,所以也就能实时地读取到键盘的信息,完成无线电脑遥控的目的。



05 01 // USAGE_PAGE (Generic Desktop)
09 03 //USAGE
a1 01 //collection

09 01 //USAGE
15 00 //最小值
26 ff 00

75 08 ,//REPORT_SIZE (8)
95 08 //报告的个数为8
81 00 //输入
15 00 //最小值
25 01 //最大值


95 40 //报告长度64
75 01 ,//每个段大小为3bits
05 08 //USAGE_PAGE (Generic Desktop)
19 01 //用途最小值
29 40 //用途最大值
91 02 //报告相对值
c0

HID报告描述符_百度文库
http://blog.sina.com.cn/s/blog_4cd5d2bb0100f72p.html

--
Best Regards



--
Kimi 于 1/21/2011 05:01:00 上午 发布在 嘻嘻哈哈 <http://joke-xixihaha.blogspot.com/2011/01/usb.html> 上

2010年6月3日星期四

什么是KDJ指标

http://www.shenmeshi.com/Business/Business_20070211204322.html


什么是KDJ指标

作者:未知 来源:网 络 点击数:1355904 日期:2007-2-11
文章导读
什么是KDJ指标?KDJ指标是什么意思?KDJ指标又叫随机指标,是由乔治-蓝恩博士(George Lane)最早提出的,是一种相当新 颖、实用的技术分析指标,它起先用于期货市场的分析,后被广泛用于股市的中短期趋势分析,是期货和股票市场上最常用的技术分析工具。…

KDJ指标又叫随机指标,是由乔治-蓝恩博士(George Lane)最早提出的,是一种相当新颖、实用的技术分 析指标,它起先用于期货市场的分析,后被广泛用于股市的中短期趋势分析,是期货和股票市场上最常用的技术分析工具。

KDJ指标的原理和计算方法

一、KDJ指标的原理

随机指标KDJ一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。

随机指标KDJ是以最高价、最低价及收盘价为基本数据进行计算,得出的K值、D值和J值分别在指标的坐标上形成的一个点,连接无数个这样的点位,就形成一个完整的、能反映价格波动趋势的KDJ指标。它主要是利用 价格波动的真实波幅来反映价格走势的强弱和超买超卖现象,在价格尚未上升或下降之前发出买卖信号的一种技术工具。它在设计过程中主要是研究最高价、最低价 和收盘价之间的关系,同时也融合了动量观念、强弱指标和移动平均线的一些优点,因此,能够比较迅速、快捷、直观地研判行情。

随机指标KDJ最早是以KD指标的形式出现,而KD指标是在威廉指标的基础上发展起来的。不过威廉指标只判断股票的超买超卖的现象,在 KDJ指标中则融合了移动平均线速度上的观念,形成比较准确的买卖信号依据。在实践中,K线与D线配合J线组成KDJ指标来使用。由于KDJ线本质上是一 个随机波动的观念,故其对于掌握中短期行情走势比较准确。

二、KDJ指标的计算方法

指标KDJ的计算比较复杂,首先要计算周期(n日、n周等)的RSV值,即未成熟随机指标值,然后再计算K值、D值、J值等。以日KDJ数值的计算 为例,其计算公式为

n日RSV=(Cn-Ln)÷(Hn-Ln)×100

公式中,Cn为第n日收盘价;Ln为n日内的最低价;Hn为n日内的最高价。RSV值始终在1—100间波动。

其次,计算K值与D值:

当日K值=2/3×前一日K值+1/3×当日RSV

当日D值=2/3×前一日D值+1/3×当日K值

若无前一日K 值与D值,则可分别用50来代替。

以9日为周期的KD线为例。首先须计算出最近9日的RSV值,即未成熟随机值,计算公式为

9日RSV=(C-L9)÷(H9-L9)×100

式中,C为第9日的收盘价;L9为9日内的最低价;H9为9日内的最高价。

K值=2/3×前一日 K值+1/3×当日RSV

D值=2/3×前一日K值+1/3×当日RSV

若无前一日K值与D值,则可以分别用50代替。

需要说明的是,式中的平滑因子1/3和2/3是可以人为选定的,不过目前已经约定俗成,固定为1/3和2/3。在大多数股市分析软件中,平滑因子已 经被设定为1/3和2/3,不需要作改动。另外,一般在介绍KD时,往往还附带一个J指标。

J指标的计算公式为:

J=3D—2K

实际上,J的实质是反映K值和D值的乖离程度,从而领先KD值找出头部或底部。J值范围可超过100。

J指标是个辅助指标,最早的KDJ指标只有两条线,即K线和D线,指标也被称为KD指标,随着股市分析技术的发展,KD指标逐渐演变成KDJ指标, 从而提高了KDJ指标分析行情的能力。另外,在一些股市重要的分析软件上,KDJ指标的K、D、J参数已经被简化成仅仅一个,即周期数(如日、周、月 等),而且,随着股市软件分析技术的发展,投资者只需掌握KDJ形成的基本原理和计算方法,无须去计算K、D、J的值,更为重要的是利用KDJ指标去分 析、研判股票行情。

和其他指标的计算一样,由于选用的计算周期的不同,KDJ指标也包括日KDJ指标、周KDJ指标、月KDJ指标年KDJ指标以及分钟KDJ指标等各 种类型。经常被用于股市研判的是日KDJ指标和周KDJ指标。虽然它们的计算时的取值有所不同,但基本的计算方法一样。

KDJ指标的一般研判标准

随机指标KDJ主要是通过K、D和J这三条曲线的所构成的图形关系来分析股市上的超买超卖,走势背离及K线、D线和J线相互交叉突破等现象,从而预测股价中、短期及长期趋势。KDJ是市场上绝大多数投资者熟知的分析工具,但具体运用时,投资者可能会发现 KDJ的分析结果和实际走势存在着特别大的差别,有时还会得出相反的结论,这其中原因主要是绝大多数投资者只知道KDJ的一般分析原理和方法,而对KDJ 分析指标的一些内涵和特定的分析技巧知之甚少。本节在介绍股市分析中市场上流行的KDJ的一般研判技巧和分析方法上,重点挖掘 KDJ指标的内在规律,详细分析KDJ的一些特殊研判功能。

KDJ指标是三条曲线,在应用时KDJ指标的一般研判标准主要是从KDJ三个参数的取值、KDJ曲线的形态、KDJ曲线的交叉、KDJ曲线的背离和 K线、D线、J线的运行状态以及KDJ曲线同股价曲线的配合等六个方面来考虑。

一、KDJ的取值

1、取值范围

KDJ指标中,K值和D值的取值范围都是0—100,而J值的取值范围可以超过100和低于0,但在分析软件上KDJ的研判范围都是0—100。通 常就敏感性而言,J值最强,K值次之,D值最慢,而就安全性而言,J值最差,K值次之,D值最稳。

2、超买超卖信号

根据KDJ的取值,可将其划分为几个区域,即超买区、超卖区和徘徊区。按一般划分标准,K、D、J这三值在20以下为超卖区,是买入信号;K、D、 J这三值在80以上为超买区,是卖出信号;K、D、J这三值在20—80之间为徘徊区,宜观望。

3、 多空力量对比

一般而言,当K、D、J三值在50附近时,表示多空双方力量均衡;当K、D、J三值都大于50时,表示多方力量占优;当K、D、J三值都小于50 时,表示空方力量占优。

二、KDJ曲线的形态

KDJ指标的研判还可以从KDJ曲线的形态来分析。当KDJ指标曲线图形形成头肩顶底形态、双重顶底形态(即M头W底)及三重顶底等形态时,也可以按照形态理论的研判方法加以分析。KDJ曲线出现的各种形态是判断行情走势、决定买卖 时机的一种分析方法。另外,KDJ指标曲线还可以划趋势线、压力线和支撑线等。

1、当KDJ曲线在50上方的高位时,如果KDJ曲线的走势形成M头或三重顶等顶部反转形态,可能预示着股价由强势转为弱势,股价即将大跌,应及时 卖出股票。如果股价的曲线也出现同样形态则更可确认,其跌幅可以用M头或三重顶等形态理论来研判。

2、当KDJ曲线在50下方的低位时,如果KDJ曲线的走势出现W底或三重底等底部反转形态,可能预示着股价由弱势转为强势,股价即将反弹向上,可以逢低少量吸纳股票。如果股价曲线 也出现同样形态更可确认,其涨幅可以用W底或三重底形态理论来研判。

3、KDJ曲线的形态中M头和三重顶形态的准确性要大于W底和三重底。

三、KDJ曲线的交叉

KDJ曲线的交叉分为黄金交叉和死亡交叉两种形式

一般而言,在一个股票的完整的升势和跌势过程中,KDJ指标中的K、D、J线会出现两次或以上的“黄金交叉”和“死亡交叉”情况。

1、当股价经过一段很长时间的低位盘整行情,并且K、D、J三线都处于50线以下时,一旦J线和K线几乎同时向上突破D线时,表明股市即将转强, 股价跌势已经结束,将止跌朝上,可以开始买进股票,进行中长线建仓。这是KDJ指标“黄金交叉”的一种形式。

2、当股价经过一段时间的上升过程中的盘整行情,并且K、D、J线都处于50线附近徘徊时,一旦J线和K线几乎同时再次向上突破D线,成交量再度放出时,表明股市处于一种强势之中,股价将再次上涨,可以加码买进股票或持股待涨,这就是KDJ指标 “黄金交叉”的一种形式。

3、当股价经过前期一段很长时间的上升行情后,股价涨幅已经很大的情况下,一旦J线和K线在高位(80以上)几乎同时向下突破D线时,表明股市即将 由强势转为弱势,股价将大跌,这时应卖出大部分股票而不能买股票,这就是KDJ指标的“死亡交叉”的一种形式。

4、当股价经过一段时间的下跌后,而股价向上反弹的动力缺乏,各种均线对股价形成较强的压力时,KDJ曲线在经过短暂的反弹到80线附近,但未能重 返80线以上时,一旦J线和K线再次向下突破D线时,表明股市将再次进入极度弱市中,股价还将下跌,可以再 卖出股票或观望,这是KDJ指标“死亡交叉”的另一种形式。

四、KDJ曲线的背离

KDJ曲线的背离就是指当KDJ指标的曲线图的走势方向正好和K线图的走势方向正好相反。KDJ指标的背离有顶背离和底背离两种。

当股价K线图上的股票走势一峰比一峰高,股价在一直向上涨,而KDJ曲线图上的KDJ指标的走势是在高位一峰比一峰低,这叫顶背离现象。顶背离现象 一般是股价将高位反转的信号,表明股价中短期内即将下跌,是卖出的信号。

当股价K线图上的股票走势一峰比一峰低,股价在向下跌,而KDJ曲线图上的KDJ指标的走势是在低位一底比一底高,这叫低背离现象。底背离现象一般 是股价将低位反转的信号,表明股价中短期内即将上涨,是买入的信号。

与其他技术指标的背离现象研判一样,KDJ的背离中,顶背离的研判准确性要高于底背离。当股价在高位,KDJ在80以上出现顶背离时,可以认为股价 即将反转向下,投资者可以及时卖出股票;而股价在低位,KDJ也在低位(50以下)出现底背离时,一般要反复出现几次底背离才能确认,并且投资者只能做战 略建仓或做短期投资

五、K、D、J曲线运行的状态

1、当J曲线开始在底部(50以下)向上突破K曲线时,说明股价的弱势整理格局可能被打破,股价短期将向上运动,投资者可以考虑少量长线建仓。

2、当J曲线向上突破K曲线并迅速向上运动,同时曲线也向上突破D曲线,说明股价的中长期上涨行情已经开始,投资者可以加大买入股票的力度。

3、当K、D、J曲线开始摆脱前期窄幅盘整的区间并同时向上快速运动时,说明股价已经进入短线强势拉升行情,投资者应坚决持股待涨。

4、当J曲线经过一段快速向上运动的过程后开始在高位(80以上)向下掉头时,说明股价短期上涨过快,将开始短线调整,投资者可以短线卖出股票。

5、当D曲线也开始在高位向下掉头时,说明股价的短期上涨行情可能结束,投资者应中线卖出股票。

6、当K曲线也开始在高位向下掉头时,说明股价的中短期上涨行情已经结束,投资者应全部清仓离场。

7、当K、D、J曲线从高位同时向下运动时,说明股价的下跌趋势已经形成,投资者应坚决持币观望。

六、KDJ曲线与股价曲线的配合使用

1、当KDJ曲线与股价曲线从低位(KDJ值均在50以下)同步上升,表明股价中长期趋势向好、短期内股价有望继续上涨趋势,投资者应继续持股或逢低买入。

2、当KDJ曲线与股价曲线从高位(KDJ值均在50以上)同步下降,表明短期内股价将继续下跌趋势,投资者应继续持币观望或逢高卖出。

3、当KDJ曲线从高位回落,经过一段时间强势盘整后再度向上并创出新高,而股价曲线也在高位强势盘整后再度上升创出新高,表明股价的上涨动力依然较强,投资者可继续持股待涨。

4、当KDJ曲线从高位回落,经过一段时间盘整后再度向上,但到了前期高点附近时却掉头向下、未能创出新高时,而股价曲线还在缓慢上升并创出新 高,KDJ曲线和股价曲线在高位形成了相反的走势,这可能就意味着股价上涨的动力开始减弱,KDJ指标出现了顶背离现象。此时投资者应千万小心,一旦股价 从下,应果断及时地离场。

5、当KDJ曲线在长期弱势下跌过程中,经过一段时间弱势反弹后再度向下并创出新低,而股价曲线也在弱势盘整后再度向下创出新低,表明股价的下跌动 能依然较强,投资者可继续持币观望。

6、当KDJ曲线从低位向上反弹到一定高位、再度向下回落,但回调到前期低点附近时止跌企稳、未能创出新低时,而股价曲线还在缓慢下降并创出新低,KDJ曲线和股价曲线在低位形成相反的走势,这 可能就意味着股价下跌的动能开始衰弱,KDJ指标出现了底背离现象。此时投资者也应密切关注股价动向,一旦股价向上就可以短线买入,等待反弹的出现。

KDJ的特殊分析方法

一、KDJ的分析周期

日、周、月、分钟(主要是60分钟)

10日以下为分析参数的KDJ的研判适用周期为3天左右(从金叉到死叉为3天时间)

50日以下为分析参数的KDJ的研判使用周期为10天左右

50日以上为分析参数的KDJ的研判适用周期为20天左右

二、 均线先行原则

股价一旦被长期均线压制,KDJ再怎么样金叉一般也只能做短线操作,切莫做中长线投资。这是KDJ使用的前提。在长期均线下,且远离均线,KDJ金 叉时,股价有超跌反弹的可能可做短线操作

三、 涨势的大体周期

日KDJ是短中期 最多维持15天——1个月

周KDJ是中期,维持时间为1个月——3个月(一旦金叉,一个月内基本会涨,但涨幅不能确定)

月KDJ是长期,维持时间一般为3个月——5个月

四、除权后,KDJ指标没有研判意义,起码要三个月以后才能重新研判

五、KDJ的参数的修改

随着技术分析的广泛应用,技术指标的重要性已是不言而喻。 但由于目前技术指标的运算已大为简化,这就造成技术指标大面积的雷同,并失去其指导作用。因此为尽量保持精确性、敏感性和时效性的和谐与统一,有必要对某 些指标重置参数,并注意以下通则:

第一、根据时间循环周期设定参数。无论大盘还是个股,时间周期对其运行都会产生较大的影响,而周期本身往往就是一个非常重要的参数,这一点在均线、 强弱指标等方面表现得尤为突出。至于周期的测量, 通常可由两个重要低点的时间跨度 来确定。同时,由于存在长、中、短线的区别,投资者必须根据具体情况设定个性化 且自己熟知的参数,而5(日)或其倍数、以及费波南兹数列在这方面都是不错的选择。

第二、保持不同时间标准的一致性。如果将适用于日线的参数放到分时里, 特别是震荡类指标就会过于敏感,用于周线或月线则会明显滞后,因此,在应用过程中, 这一原则必须适当变通后方可使用,这绝不是一个简单的计算问题,而是换算之后需要进行微调,尽管个别指标绝对保持一致仍能取得较好的效果。

第三、注意大盘与个股间的异同点。由于大盘与个股是一般与特殊的关系, 适合于大盘的同一指标参数,通常可直接或略作调整后用于大多数个股,但两者之间的差异毕竟存在,大盘的平均结果往往也会掩盖许多真相或忽略了个性化,即处 于超强或超弱状态的个股不同于大盘,其参数的设定理应另开小灶。

第四、随市场变化不断调整并优化。强势股和弱势股与大盘情形迥然不同, 平衡市与趋势运行也有所不同。面对不断变化的市场, 一旦发现原参数不太适合当时的市势,大家就需要对该参数进行修正以便优化指标,这应是一项长期的工作, 中短期参数更是如此。

六、不同周期参数的KDJ指标的研判

(一)34日KDJ(注:这是钱龙软件上的KDJ参数)的使用方法

对于大部分股市分析软件,投资者都可以根据不同的股票、股票不同时期的走势以及投资者的兴趣偏好来修改指标,从而得出不同的分析结论。把日KDJ的数值修改为34,下面在这里简单介绍34日KDJ使 用方法。

1、首先,把KDJ运行的区间分为20以下极弱势区,20——50之间为弱势区,50——80之间强势区和80以上极强势区,数值50是强弱的分界 线。

34日KDJ指标中的50线对于从弱势区起来的股价来说是一个强大的短线阻力位,只要KDJ中的D值没有有效冲上50位值,就不能说股价已经走出弱 势区,KD两值在此点位无功而返是非常正常的事,所以必须十分重视此阻力位的作用,很多股票的反弹都在此点位就结束。

34日KDJ指标中的50线对于从强势区跌下来的股价而言,虽有些支撑,却较为轻易击破,显得并没有重要参考意义。这与股价上涨要成交量配合,而下 跌没有量也能做到是同样的道理。

2、KDJ三值在极弱势区20以下运行时,一般不作买入计划,持币观望为主,特别是股价刚刚经历过一轮较长时间的下跌。除非是股价经过大跌并在低位 盘整了很长时间后,如果有反转意义的低位放量大阳线出现,或有反转意义K线组合形态明确告诉投资者进场。

3、KDJ三值在极强势区80以上运行时,一般不作卖出计划,以持股待涨为主。除非有反转意义的高位放量大阴线乌云盖顶,穿头破脚)出现,或有反转意义的K线组合形态明确告诉投资者离场。

4、KDJ在20以下极弱势区运行的时间越长,在极弱势区内发出的金叉信号越应该重视,特别是那些向上角度较大、能迅速脱离20线的金叉,K线组合 形态也在明确告诉我们有反转的可能,更应该重视此金叉的意义,这很有可能是中短期底部形成的第一个信号。

5、KDJ在80以上极强势区运行的时间越长,在极强势区内发出的死叉信号越应该重视,特别是那些向下的角度较大能迅速跌破80线的死叉,K线形态 组合也在明确告诉我们有反转的可能,更应该重视此死叉的意义,这很有可能是顶部形成的第一个信号。

6、KDJ在20以上(弱势区)和50以上(强势区)的每次KDJ金叉都是介入机会,金叉的位置越高市场意义越大,同时还必须关注KDJ金叉角度大 小,角度越大越好。另外,还要注意K线形态组合和成交量配合情况。如我们在高位KDJ金叉(80线以上)介入之后不久却又看见KDJ死叉,投资者要立即止损离场,防止扩大损失。但20以下的金叉如无KD两值迅速脱离20极弱势区或K线组合形态确认反转,无多大市 场意义。

7、KDJ在80以下(强势区)和50以下(弱势区)的每次KDJ死叉都是必须离场的信号,死叉的位值越高下跌的风险也越大。但KDJ在20以下的极弱势区内的死叉,如果KD两值没有继续走低则无多大参考意义。

8、股价短期暴涨,会引起KDJ滞后的连续上升,这时我们要保持冷静,切忌盲目追涨,此时股价走势可能正与KDJ的走势相反,耐心等待KDJ走势与 股价走势的同步运行。然后再寻找介入机会,同样股价的短期暴跌,也会引起KDJ的滞后下降,股价也会出现暴跌后的反弹走势是与KDJ走势相反的情况。当 KDJ走势与股价走势同步时,正是我们反弹离场之时。

9、在下跌的市道中,反弹时产生的KDJ金叉位置也会越来越低,从而引起KDJ的死叉位置也会越来越低,在上涨的市道中,回调时产生的KDJ死叉位 置越来越高,从而引起KDJ的金叉位置也会越来越高。

10、KDJ在冲出极弱势区20以后,KDJ会出现报复性的上窜,即股价并没有上涨很多,KDJ就很快进入强势区,这时我们要注意KDJ的回调整 理,要注意KDJ在强势区的第二次金叉,因为第二次金叉的介入意义会比每一次更大。更有上涨空间。

11、KDJ的使用只是作为一种辅助手段而存在,投资者应参考股价的K线组合,量价关系,趋势形态与KDJ指标一起研判,当它们发出的买卖信号趋于 一致之时,这样的买卖信号比较可靠。

(二)89日KDJ(注:这是钱龙软件上的KDJ参数)参数的使用方法

如果把34日KDJ指标作为一个比较有实际研判意义的KDJ短线指标,那么89日KDJ指标就是一个比较重要的KDJ中线研判指标,它和34日 KDJ指标在研判上虽有很多相似的地方,但也有不少不同步骤,具体研判如下:

1、和34日KDJ指标的研判相同的是,89日KDJ运行区间也分为20以下极弱势区,20——50之间为弱势区,50——80之间强势区和80以 上极强势区,数值50是强弱的分界线。

89日KDJ指标中的50线对于从弱势区起来的股价来说是一个强大的短线阻力位,只要KDJ中的D值没有有效冲上50位值,就不能说股价已经走出弱 势区,KD两值在此点位无功而返是非常正常的事,所以必须十分重视此阻力位的作用,很多股票的反弹都在此点位就结束。

89日KDJ指标中的50线对于从强势区跌下来的股价而言,虽有些支撑,却较为轻易击破,显得并没有重要参考意义。这与股价上涨要成交量配合,而下 跌没有量也能做到是同样的道理。

2、要关注0—20区间的KDJ,越靠近底部股价越有上升力度。和34日KDJ指标一样, 89日KDJ在20以下极弱势区运行的时间越长,在极弱势区内发出的金义越应该重视,特别是那些向上角度较大、能迅速脱离20线的金叉,K线组合形态也在 明确告诉我们有反转的可能,更应该重视此金叉的意义,这很有可能是中长期底部形成的第一个信号。

3、89日KDJ指标中的80这条强弱分界线对于中线卖出股票有着重要的指导意义。只要89KDJ曲线没有向下突破80区间,就可以一路持股,直到 该指标中的J线、K线、D线都向下跌破80这条多方防线以后,就可以中线卖出全部或大部分股票。

4、89日KDJ中的K、D、J这三条曲线在80以上极强势区运行的时间越长,那么它们在极强势区内发出的死叉越应该重视,特别是那些向下的角度较 大能迅速跌破80线的死叉,K线形态组合也在明确告诉我们有反转的可能,更应该重视此死叉的意义,这很有可能是中长期顶部形成的第一个信号。

5、当89日KDJ指标在80以上的高位死叉、并开始朝下发散时,应立刻卖出余下的股票更不要轻易买进股票(死叉向下发散应观望)

6、一旦89日KDJ指标在20以下金叉并开始向上发散,不要轻易卖出股票,直到确定它高位死叉。

(三)55周KDJ(注:这是钱龙软件上的KDJ参数)使用方法

相比较34日和89日KDJ指标,55周KDJ指标就是KDJ指标研判中的一种长期指标,它对于研判一个股票未来半年以上的走势具有很强的参考意 义。

1、周K线(55周)KDJ的使用方法与日K线(34天)KDJ的使用方法大同小异。

首先,和日KDJ指标研判一样,把周KDJ运行的区间分为20以下极弱势区,20——50之间的为弱势区,50——80之间的为强势区和80以上极 强势区,50线是强弱的分界线。

周KDJ指标中的50线对于从弱势区涨起来的股价来说是一个强大的阻力位,只要KDJ中的D值没有有效冲上50数值,就不能说股价已经走出弱势 区,KD两值在此点位无功而返是非常正常的事,很多股票的反弹都在此点位就结束。

周KDJ指标中的50线对于从强势区跌下来的股价而言,是一个较强的支撑位。如果周KDJ指标在50线附近获得支撑,股价的中长线还是看好,而一旦 KDJ曲线再次跌破50线,则表明股价的中长线依然看坏。

2、周(55周)KDJ在80以下任何区域的金叉和在K线形态量价支持下的J值强力拐头都是介入持仓信号。

金叉的数值越低市场意义越大,同时还必须关注KDJ金叉角度大小,角度越大越好,另外还要注意K线形态组合和成交量配合情况。如我们在KDJ金叉介 入之后KDJ又出现死叉的,要立即止损离场。

3、周K线(55周)KDJ在50以上区域的死叉和在K线形态破位时的J值强力拐头都是离场止损信号。死叉的位值越高下跌的风险也越大。

4、周K线(55周)KDJ三值在极弱势区20以下运行时,一般不作买入计划,持币观望是上上策。除非有反转意义的低位放量大阳线(一阳指)出现, 或有反转意义K线组合形态明确告诉我们进场。

5、周K线(55周)KDJ三值在极强势区80以上运行时,一般不作卖出计划,持股待涨是上上策。除非有反转意义的高位放量大阴线(乌云盖顶,穿头 破脚)出现,或有反转意义的K线组合形态明确告诉我们退场。

6、股价短期暴涨,会引起KDJ滞后的连续上升,这一点比日(34)KDJ更明显,这时我们要保持冷静,切忌盲目追涨,此时股价走势可能正与KDJ 的走势相反,耐心等待KDJ走势与股价走势的同步运行。然后再寻找介入机会,同样股价的短期暴跌,也会引起KDJ的滞后下降,股价也会出现暴跌后的反弹走 势是与KDJ走势相反的情况。当KDJ走势与股价走势同步时,正是我们反弹离场之时。

7、KDJ死叉的位值越高,对股价的风险就越大,同样KDJ金叉的位值越低,对股价的上涨就越有保障。在下跌的市道中,反弹时产生的KDJ金叉位值 也会越来越低,从而引起KDJ的死叉位值也会越来越低,在上涨的市道中,回调时产生的KDJ死叉位值越来越高,从而引起KDJ的金叉位值也会越来越高。

8、KDJ在冲出极弱势区20以后,KDJ会出现报复性的上窜,即股价并没有上涨很多,KDJ就很快进入强势区,这时我们要注意KDJ的回调整理, 要注意KDJ在强势区的第二次金叉,因为第二次金叉的介入意义会比每一次更大、更有上涨空间。

9、KDJ的使用只是作为一种辅助手段而存在,特别对于周K线KDJ来说,滞后效应更明显,决不能盲目根据周K线KDJ来选择进出点,但周K线 KDJ也有它的优点,那就是它的稳定性,中长期趋势的指向性比较明确。

2009年12月8日星期二

C++模板使用介绍

1. 模板的概念。

我们已经学过重载(Overloading),对重载函数而言,C++的检查机制能通过函数参数的不同及所属类的不同。正确的调用重载函数。例如,为求两个数的最大值,我们定义MAX()函数需要对不同的数据类型分别定义不同重载(Overload)版本。

//函数1.

int max(int x,int y);
{return(x>y)?x:y ;}

//函数2.
float max( float x,float y){
return (x>y)? x:y ;}

//函数3.
double max(double x,double y)
{return (c>y)? x:y ;}

但如果在主函数中,我们分别定义了 char a,b; 那么在执行max(a,b);时 程序就会出错,因为我们没有定义char类型的重载版本。

现在,我们再重新审视上述的max()函数,它们都具有同样的功能,即求两个数的最大值,能否只写一套代码解决这个问题呢?这样就会避免因重载函数定义不 全面而带来的调用错误。为解决上述问题C++引入模板机制,模板定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。

2.   函数模板的写法

函数模板的一般形式如下:

Template <class或者也可以用typename T>

返回类型 函数名(形参表)
{//
函数定义体 }

说明: template是一个声明模板的关键字,表示声明一个模板关键字class不能省略,如果类型形参多余一个 ,每个形参前都要加class <类型 形参表>可以包含基本数据类型可以包含类类型.

请看以下程序:

//Test.cpp

#include <iostream>

using std::cout;

using std::endl;

//声明一个函数模版,用来比较输入的两个相同数据类型的参数的大小,class也可以被typename代替,

//T可以被任何字母或者数字代替。

template <class T>

T min(T x,T y)

{ return(x<y)?x:y;}

void main( )

{

     int n1=2,n2=10;

     double d1=1.5,d2=5.6;

     cout<< "较小整数:"<<min(n1,n2)<<endl;

     cout<< "较小实数:"<<min(d1,d2)<<endl;

     system("PAUSE");

}

程序运行结果: 

 

程序分析:main()函数中定义了两个整型变量n1 , n2 两个双精度类型变量d1 , d2然后调用min( n1, n2); 即实例化函数模板T min(T x, T y)其中T为int型,求出n1,n2中的最小值.同理调用min(d1,d2)时,求出d1,d2中的最小值.

3. 类模板的写法

定义一个类模板:

Template < class或者也可以用typename T >
class
类名{
//类定义......
};

说明:其中,template是声明各模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。

例如:定义一个类模板:

// ClassTemplate.h
#ifndef ClassTemplate_HH

#define ClassTemplate_HH

template<typename T1,typename T2>

class myClass{

private:

     T1 I;

     T2 J;

public:

     myClass(T1 a, T2 b);//Constructor

     void show();

};

//这是构造函数

//注意这些格式

template <typename T1,typename T2>

myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}

//这是void show();

template <typename T1,typename T2>

void myClass<T1,T2>::show()

{

     cout<<"I="<<I<<", J="<<J<<endl;

}

类模板与模板类

原创  类模板与模板类

1.类模板与模板类的概念

什么是类模板 一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

  如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表着一类类。

类模板定义 定义一个类模板,一般有两方面的内容:

A.       首先要定义类,其格式为:

template <class T>

class foo

{

……

}

foo 为类名,在类定义体中,如采用通用数据类型的成员,函数参数的前面需加上T,其中通用类型T可以作为普通成员变量的类型,还可以作为conststatic成员变量以及成员函数的参数和返回类型之用。例如:

template<class T>

class Test{

private:

    T n;

    const T i;

    static T cnt;

public:

    Test():i(0){}

    Test(T k);

    ~Test(){}

    void print();

    T operator+(T x);

};

B.       在类定义体外定义成员函数时,若此成员函数中有模板参数存在,则除了需要和一般类的体外定义成员函数一样的定义外,还需在函数体外进行模板声明

例如

template<class T>

void Test<T>::print(){

    std::cout<<"n="<<n<<std::endl;

    std::cout<<"i="<<i<<std::endl;

    std::cout<<"cnt="<<cnt<<std::endl;

 

}

如果函数是以通用类型为返回类型,则要在函数名前的类名后缀上"<T>"。例如:

template<class T>

Test<T>::Test(T k):i(k){n=k;cnt++;}

template<class T>

T Test<T>::operator+(T x){

               return n + x;

               }

C.       在类定义体外初始化const成员和static成员变量的做法和普通类体外初始化const成员和static成员变量的做法基本上是一样的,唯一的区别是需在对模板进行声明,例如

template<class T>

int Test<T>::cnt=0;

template<class T>

Test<T>::Test(T k):i(k){n=k;cnt++;}

类模板的使用 类模板的使用实际上是将类模板实例化成一个具体的类,它的格式为:类名<实际的类型>

  模板类是类模板实例化后的一个产物。说个形象点的例子吧。我把类模板比作一个做饼干同的模子,而模板类就是用这个模子做出来的饼干,至于这个饼干是什么味道的就要看你自己在实例化时用的是什么材料了,你可以做巧克力饼干,也可以做豆沙饼干,这些饼干的除了材料不一样外,其他的东西都是一样的了。

2.类模板的派生

  可以从类模板派生出新的类,既可以派生类模板,也可以派生非模板类。派生方法:

⑴ 从类模板派生类模板可以从类模板派生出新的类模板,它的派生格式如下例所示:

template <class T>

class base

{

……

};

 

template <class T>

class derive:public base<T>

{

……

};

与一般的类派生定义相似,只是在指出它的基类时要缀上模板参数,即base<T>

⑵ 从类模板派生非模板类  可以从类模板派生出非模板类,在派生中,作为非模板类的基类,必须是类模板实例化后的模板类,并且在定义派生类前不需要模板声明语句:template<class>。例如:

template <class T>

class base

{

……

};

 

class derive:public base<int>

{

……

};

在定义derive类时,base已实例化成了int型的模板类。