PID Anti-Windup method: Back-calculation

最近在编矢量控制的程序,其中电机的定子电流、转子速度要通过PID进行调节。在学习TI的ACI_Motor例程的时候,发现例程中的pid_reg3模块的框图和平时用到的PID的框图不同,增加了anti-windup环节。其在积分部分中又引入了反馈以抗积分饱和,这片笔记记录一下大致原理。

当误差的正负方向在比较长的一段时间内都处于一个方向时,积分环节的输出容易过大,导致整个PID的输出在这个方向上在较长的时间内维持一个比较大的值。

而后方的执行机构由于存在限制,即使执行机构接收到了PID的输出,也由于饱和无法进一步改变输出。从外部来看,执行机构的输出并不随着PID的输出而改变,即闭环结构在这种情况下变成了开环结构。

所以在设计PID的时候要考虑这种情况的出现,增加Anti-Windup环节。

Back-calculation PID的结构如图所示:

anti-windup pid

其中除去1/Tt这条路上的反馈之后其实就是个普通的PID。所做的改动只有加入了这条反馈。其控制顺序大致如下:

1.如果PID的积分部分过大,则PID的输出会很大。然而由于执行装置具有限值,执行装置的输出并不能随着PID的输出增大而增大。

2.所以输入1/Tt的信号会随着PID的输出增大而减小,输出一个幅度更大的负值。

3.该信号经过1/Tt的增益之后会叠加到积分之前的信号,经过积分就会减小PID中的积分部分。

可以推测,Tt变小,即1/Tt增大会使执行装置的输出更快的退出饱和状态,使系统更快的进入闭环工作状态,靠近参考值。接下来会证明一下Tt的值对于输出的影响。在simulink中搭好如下图所示的模型。其中step信号设定为初始值10,终值5,跳变时间100。传递函数延时2。

pid_systems

图中包含四个PID,左上角的没有back-calculation,无法抗饱和;其余的均有back-calculation,左下的Tt=10,右上的Tt=1e-1,右下的Tt=1e-3。下方分别使用三个scope观察系统的输出、PID中积分部分的大小、执行装置什么时候能退出饱和状态。

先对比一下使用和不使用抗积分饱和的输出结果。下图中黄色的信号为ref信号。蓝色为Tt=0.1的有back-calculation的抗饱和积分PID的输出结果,粉色为没有进行back-calculation的普通PID的输出结果。可以看出蓝色信号对于给定信号跟踪的更好,能够更快的进入±5%的范围内。

pid_output

而带有back-calculation的PID能使输出更快稳定的直接原因是其执行装置能更快的退出饱和状态,如下图所示。途中四条线均为执行机构的输出,黄色为普通PID,粉红色的为Tt=10的,蓝色为Tt=1e-1的,红色为Tt=1e-3的。可以看出红色的最先退出饱和状态,随着Tt的增大,退出饱和状态的速度越来越慢,普通PID的最慢。

actuator_output

之所以会产生如此差别其实根本原因是各个系统中对于积分部分的抑制能力不同。如下图所示,各个颜色对应的与上图相同。红色和蓝色的积分部分的抑制作用非常明显。

integrator_output

最后对比一下各个系统的输出,明显Tt值更小一些的能很快的进入稳定状态。图中颜色对应关系也与上文中的相同。

system_output

后记:

实际上,TI提供的ACI_Motor中的pid_reg3.pdf page5中的抗积分饱和模型是错误的。

esat经过Kc的增益之后输出到了积分部分中,并未输出到积分环节之前。使用matlab模拟之后的结果显示,这样的结构无论如何增大Kc的值,虽然能够使积分部分的大小被大大抑制,但是并不能使执行装置快速退出饱和状态。而是和普通PID一样,在同样的时间点退出饱和状态。所以对于快速进入闭环工作状态没有帮助,并不能起到预期的效果。

最终用C实现的代码见下,大致的参考了一下TI的例程,不过框图是按照正确的做的。

void PID_calc(PID_handler v)
{
	float error,up,ui,ud,out_presat;
	error = ref - fdb;
	up = error*v->kp;
	ui = (error*v->ki+v->kc*v->satErr)*v->T_sampling + v->ui;
	ud = v->kd*(error-v->err_old)/v->T_sampling;
	out_presat = up + ui + ud;
	if(out_preset>v->outMax)
	{
		v->out = outMax;
	}
	else if(out_preset<v->outMin)
	{
		v->out = outMin;
	}
	else
	{
		v->out = out_presat;
	}
	v->satErr = v->out - v->out_presat;
	v->err_old = err;
}

其实本文可以归结为一句话:

TI罪大恶极,搞得百姓怨声载道啊!

 

参考资料:

anti-windup-control-using-a-pid-controller

Visioli A. Practical PID control[M]. Springer, 2006.

Freescale Kinetis E系列设计SWD接口笔记

这几天在搞的控制液晶的板子上有个Freescale家的Kinetis E系列的KE02Z32,要往里面烧程序控制液晶,这片短文记录一下如何设计下载接口。

ARM一共规定了三种接口。下面两张图中黑色的为JTAG接口,橙色为SWD替代的接口。因为Kinetis E系列只支持SWD,所以需要按照橙色的接口接线。

而所使用的USB Multilink Universal, Rev. B支持Kinetis系列的只有“Port B:20-pin Standard ARM”和“Port G:10-pin MINI”两种,同时支持JTAG和SWD。所以三种接口中的“Cortex 20-pin JTAG/SWD/ETM Connector Pinout”就不能使用了。

其实绝大多数脚都是用不到的。必要的脚只有SWDIO、SWDCLK、VCC和GND四个脚(SWO并不是必要的),另外对于某些MCU,RESET也是必要的,所以要加上RST。一共VCC、GND、SWDIO、SWDCLK、RST五个脚。

其次SWDCLK要加10k—100k的下拉电阻,SWDIO要加10k—100k的上拉电阻,以防止信号漂移。

接下来说两种接口。

1.Traditional ARM JTAG/SWD Connector Pinout

20pinJTAG

2.Cortex 10-pin JTAG/SWD Connector Pinout

10pinJTAG

由于大多数脚都用不到,而UMultilink那面的脚数又是固定的,所以需要在中间进行转换。比较推荐用下面那个脚的个数比较少的,仔细看的话会发现它叫“Cortex Debug Connector”,实在上面那个之后推出的。

最后去看KE02的管脚如何与这五个SWD的脚对应。VCC和GND自不必说,SWDIO所对应的是PTA4(pin-32),SWDCLK对应的是PTC4(pin-30)。RST信号自行设置即可,可以用按键也可以不用。

最后将对应的脚连上就可以了。

参考资料:

Serial Wire Debug 串行线调试

Cortex-M Debug Connectors

J-Link Debug Probes Interface description

CoreSight™ Components Technical Reference Manual

SWD / JTAG Connectors and Pinout

Technical Summary for USB Multilink Universal

What Maisie Knew

whatmaisieknew

最近看了一部叫做《What Maisie Knew》的电影,电影的情节简单的令人发指。简单来说就是小女孩Maisie的亲爹娘离婚再婚后,Maisie的继父母成为超越亲父母的存在的故事。

整个影片几乎就是童话的现代版本,一个可爱的小女孩,有个有钱的爹,有个有才的娘。继母善良,继父温厚。小女孩的父母离婚之后,母亲在美帝巡演,父亲带着家大业大衣锦还乡,继父母勇担莫名其妙的责任和小女孩愉快的生活在了一起。

整个影片中除了Maisie被他妈抛弃之后寄住一晚的那个服务员家有些阴暗之外,Maisie妈的公寓,Maisie继母的公寓,Maisie妈乐队的房车,Maisie继父工作的酒吧,Maisie继母的海边小屋,就连Maisie的学校都是一股宜家范。人们都友好而亲切的对待着这个陌生的小女孩,世界上充满了真善美。

看完电影之后,即使是在喝了如此之大剂量的鸡汤的情况下,我依旧努力的保持清醒,尝试回忆起大二那年骑车回家路上碰见的那对焦急的父母。

他们拿着一张普通的照片,说着蹩脚的普通话,急切的问我在路上有没有见过这个小女孩。我可以看出来他们已经急疯了,甚至开始慌不择路的向我这个穿着骑行服的行踪可疑的人询问。我虽然能够看出来他们很着急,却也对这个大环境无能为力,只好告诉他们抓紧报警,然后再尝试沿着国道寻找。

之所以会提到这个故事,我是想说,这个世界也并不像这个电影中那么美好。非洲还有很多儿童生活在饥饿和战火之中;有的民工的子女还没办法解决上学问题;还有一些可怜的儿童在煤矿下面做苦力。童话之所以是童话,就在于它是给小孩子看的东西,它也只有小孩子才会相信,才会被治愈。

而其之所以只能治愈小孩儿而不能治愈一个心智成熟的大人,就是因为童话都只是生活中的特殊情况。灰姑娘穿上水晶鞋赢得了王子的芳心,可多数普通的姑娘们还是在后娘的压迫下苦不堪言,只有漂亮的姑娘才有青春;史瑞克从喷火龙的老巢中救来了公主,可是多数普通的骑士都被烹饪成了人肉罐头;あひろ君愉快的和其他鸟类共同生活,可是鸭子只是鸭子,战斗力不满1鹅早就被别的鸟吃了。

同样这个故事之所以显得美好、治愈,也是因为这个故事中的特殊情况太多。父母都很有钱,继父母是俊男美女,Maisie你真的不怕你的那个亚裔姑娘小伙伴嫉妒你么?Maisie更是在外面晃荡也从未遭遇任何不测,说好的小学生最高呢?

就像心灵鸡汤只是提供鸡汤而不提供鸡汤的烹制方法一样,本片也一上来就强制性的规定了故事的背景:Maisie是个幸福的人。这又和变相炫耀有什么不一样呢。

写文章讲究言之有物。相对于这样的电影,我更喜欢《上帝之城》这样的电影。说一些现实的事情,把自己的关注给予应当给予的人群,我觉得一个电影更应该做这样的有点现实意义的事情。而不是让我们像看《小时代》一样,除了赞叹“你说女主怎么就这么pp”“女主他爹好有钱诶”以外,在心里激不起一丝波纹。

逐帧提取《Bad Apple》至txt文件

最近实验室要搞一块液晶屏,决定也跳到俗坑里去,在液晶屏上跑一次《Bad Apple》。

不过鉴于液晶屏用哪家还没决定,所以先把前期的准备工作做好。这篇短文中将介绍下如何将《Bad Apple》中的每帧的像素点存到txt文件中。

继续按照着将大象塞到冰箱里需要三步的思路做这件事。将《Bad Apple》逐帧将像素点存入txt中也只需要三步。

1. 上网找到一个1440x1080的《Bad Apple》的视频。

当然分辨率低一些也无所谓啦,反正液晶屏那么渣。假设下载到的《Bad Apple》的视频文件名叫做“BA.mp4”。

2. 将该视频逐帧截图,并将截图按照顺序保存。

这一步可以通过两个方法实现。

2.1  第一个方法是简单的方法:用KMPlayer捕捉。

首先去下载软件。然后安装。

然后用KMPlayer打开“BA.mp4”,播放窗口右击会看到叫做“Capture”的菜单,选择"CaptureFrame Extract"(中文版本中为"捕捉画面:高级捕捉"),这个时候会打开一个窗口进行设置。

  • “Extract to”(捕获到)中设置图片输出的路径;
  • “Image format”(图像格式)中选择是输出bmp(位图)、jpeg还是png(我用的jpeg)
  • “Numbers to extract”(要捕获的数量)选择“continuously”(连续)
  • “Size to extract”(捕获尺寸)中选择“Original size”(原始尺寸)或是“Specified size”(自定义大小,注意长宽比和原视频一致。)
  • “Frames to extract”(要捕获的帧)中选择截取画面的方式,可以选择“Every frame”(所有帧),不过鉴于缩小图包体积的考虑,我选择了“In 1sec. 30 frame(s)”(在一秒内30帧)。

一切设置妥当之后一定要记得点击播放,否则是不会截图的!将视频从头到尾播放一遍,会自动的在指定的路径输出一堆图片。

比如在我的设置中就是在“E:BA”这个路径下输出了“BA.mp40000.jpg”——“BA.mp43570.jpg”,共3571张图。其中文件名中的“BA.mp4”为视频文件名,之后的“0000.jpg”——“3570.jpg”为图片的编号。

可以在cmd中用ren命令和通配符批量把文件名前缀“BA.mp4”修改掉,不过鉴于之后还要使用matlab进行下一步处理,我觉得就没有这个必要了。

2.2  接下来介绍第二步的第二种方法,这种方法比较麻烦:用opencv读取视频文件,然后逐帧输出。

鉴于opencv的开发环境配置比较繁琐,且本人在两年前使用了半年的opencv+VS2010之后就再也没有接触过这个东西,久远的记忆几乎没怎么剩下,只剩下了本人硬盘上的一堆代码。所以opencv的开发环境配置过程在此不表,出门google一下,具体过程叙述得很详细。

下面说一下opencv中截取帧的大概思路。

int pic_index = 0;  //图片编号
CvCapture* capture;
IplImage* frame;
char picname[] = "";
char filename[]="E:BA.avi";  //因为不知道mp4文件是不是能打开,记得avi是可以打开的
capture = cvCaptureFromFile(filename);
if(!capture)
	return 1;
while(1)
{
	frame = cvQueryFrame(capture);
	if(!frame)
		break;
        /*picname[] = ???; 这段懒得想了...一想类型转换就头大...*/
	cvSaveImage(picname,frame);
        pic_index++;
}
cvReleaseCapture(&capture);

最后应当也能在picname对应的路径下生成像对应的图片,不过鉴于这个方法本人并没有尝试,且opencv的开发环境配置起来实在麻烦,所以还是比较推荐用第一个比较傻瓜的方法。

3. 第三步就是将所得到的图片二值化,以在液晶中显示。

这一步按说也有两种方法,一种方法是用matlab;另一种方法还是用opencv。

3.1  先介绍用matlab的方法。

刚才提到输出了“BA.mp40000.jpg”——“BA.mp43570.jpg”多个文件。下面这段代码就是在matlab中处理这3000多张图,进行二值化的。

for i=0:3570  %图片编号
    str2 = num2str(i);  %将类型转化为str
    switch length(str2)  %判断图片编号的位数,然后再前面补0,以符合“BA.mp4xxxx.jpg”的命名规则
        case 1
            str2 = strcat('000',str2);  %一位数补仨0,以此类推
        case 2
            str2 = strcat('00',str2);
        case 3
            str2 = strcat('0',str2);
    end
I = imread(strcat('E:BABA.mp4',str2,'.jpg'));  %读取制定路径下的图片

t = graythresh(I);  %用Otsu's method(我也不知道这是啥)找到一个合适的阈值以进行二值化
I_2 = im2bw(I,t);  %进行二值化,这个时候I_2是一个存着像素点数据的矩阵,每个点0为黑,1为白。

fid = fopen(strcat('E:BA2txt',str2,'.txt'),'wt');  %将I_2的数据写到txt文件中,并且按照分辨率进行换行
for i=1:480  %此处是因为我按帧截图的分辨率是640*480,所以矩阵一共有480行
    fprintf(fid,'%d',I_2(i,:));
    if i~=480  %不加以末行判断的话最后会有一行空行
        fprintf(fid,'n');
    end
end
fclose(fid);

imwrite(I_2,strcat('E:BA2',str2,'.jpg'));  %将二值化之后的图像输出至对应路径
end

之后就会在对应路径下生成一系列记录着每个二值图片每个像素点的信息的txt文件,和一系列二值图片。

3.2  然后大概介绍下opencv中的方法。

如果第二步用了opencv,第三步还是可以继续用opencv的,这样不仅能够把开发环境配置的代价分摊到两步里,还可以使用opencv里的cvSmooth函数对图像进行平滑处理,能减少不少毛刺。不过鉴于cvSmooth函数并不属于本次的内容,所以也就在此一笔带过好了。

首先还是要读取原图片,然后大概的思路其实和matlab里的也差不多。

IplImage* blkWhtImage1;  //二值图
IplImage* grayImage = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);  //灰度图
cvCvtColor(srcImage,grayImage,CV_BGR2GRAY);
cvThreshold(grayImage,blkWhtImage1,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU);  //转换成二值图

具体也可以参照官网文档中的示例代码进行二值化。

接下来介绍读取像素点的过程。

int color;
for(int row=0; row!=480; row++)
{
	for(int col=0; i!=640; col++)
	{
		color = cvGet2D(blkWhtImage1,row,col).val[0];  //由于blkWhtImage是一个单通道图像,所以数据存在cvScalar.val[0]中
                /*对color进行处理,按照行数和列数存到文件中即可。fopen什么的文件操作很烦,懒得看了...*/
	}
}

到此图片的像素点的信息就存到txt中去了。

结尾:当然在液晶上跑坏苹果这只是其中很很简单的一步,具体的硬件的设计以及通讯如何进行则是更麻烦的事情。

如果显示的载体是示波器则更麻烦,需要进行边界识别。在matlab中需要调用bwperim函数,在opencv中则需要调用cvFindContours函数。不过鉴于本次是在液晶上跑,就不再赘述了。

Mary and Max

最近看了一部叫做《Mary and Max》的电影。

mary_and_max

影片大致介绍了生活在墨尔本的一个叫做Mary的小女孩,心血来潮和一个生活在纽约的独身大叔Max成为笔友的故事。

Mary出生在一个冰冷的家庭,Mary的妈妈是一个终日泡在雪莉酒中的酒鬼,只会带着Mary到处“借”东西;Mary的爸爸是一个制作茶包的工人,业余时间也只会在自己的房间里制作标本。孤独的Mary没有朋友,在学校里也被欺负,回到家里被父母敷衍。故事中的Max也一如Mary,儿时被欺负,长大没有一个朋友,他每周按时去参加嗜食者互戒会,患有严重的社交障碍、失眠和肥胖症,面对新鲜事物和压力会无所适从。

有一天Mary被妈妈带去邮局“借”信封的时候突发奇想,想出了解决自己关于小孩到底从哪来的疑惑的方法,便随机挑选了一个人名,给身处纽约的Max寄去了一封信询问美国的小孩子是如何诞生到这个世界上的。一来二去,两人便成为了笔友。Mary向Max询问如何面对生活中的问题比如校园欺凌,Max也从Mary那里得到了来自朋友的关怀。

逐渐的Mary长大,她的父母相继去世,她也在大学中使用Max作为标本研究如何治疗精神疾病并在大学毕业之后写了一本书讲述治疗亚斯伯格综合症。她将这本书寄给了Max,希望Max能为此而开心。但是Max因为Mary没有和他商量便利用了他而愤怒不已。愤怒之下的他拆毁了自己打字机的M键,决定再也不与Mary联系。Mary为此销毁了自己所有的书,并给Max寄去了道歉信;在丈夫离开她的打击下,Mary几欲自杀。

直到有一天,Max终于原谅了Mary,给Mary寄去了原谅的信件,拯救了寻死中的Mary。Mary也决定来纽约看望Max。

可在Mary到达Max的住所之后,才发现Max在写完这封原谅信不久就安详的在沙发上离开了人世。随着Max最后一封信中的最后一句“You are my best friend. You are my only friend”, 和西去的Max一同靠在沙发上的Mary在看到贴在天花板上被Max精心塑封的来往信件后,不禁流下了眼泪。

看完这部电影之后不禁感叹一句人类是怎么样纠结的一种动物。

就像虽然Mary和Max之间的信件来往在出书事件前风平浪静,Mary也终会有一天出那么一本书,在满足自己心理预期的同时无意间伤害到Max。人类也许就是这样一种动物,自己一个人的时候孤独寂寞,希望有人陪伴;可一旦出现了那么一个人,却又肆意妄为,在满足自己的私欲时伤害到别人。就像冬天的两只刺猬,离远了冷,离近了疼。

Max最后还是原谅了Mary,可那也许是Max只有Mary一个朋友,自然也是他最好的朋友。在水中即将溺亡的人又怎么会嫌弃一根浮木细小呢?想必是有的抓不会被淹死就不错了吧。

实际生活中又有谁只有那么一个朋友呢?如果Max是一个“现充”,周围有着许多的朋友,且不论Mary在伤害了Max之后Max是否会原谅他,Max在收到Mary的第一封信时会不会回信都未可知吧。

所以说Mary和Max之间的关系并不像理想中的友谊关系——单方面心甘情愿的给予,就像电影中那句“love yourself first”所说,是一种生意伙伴的关系。Mary和Max两个人像寒风中的两个人互相依偎着取暖一样,只是恰好的互取所需的生意伙伴关系而已。Mary为Max提供了一个能够放心交谈不会引起焦虑的伙伴,Max为Mary提供了一个讲述生活经验的老师。

可是生意的关系终有尽头,合同也有结束的那一天。终于有一天,Max的价值被Mary榨干了,Max无法再为Mary提供任何价值了;Mary也无法再作一个不引起焦虑和愤怒的交谈对象了。于是终于迎来了Mary和Max决裂的那一天。而Mary也不得不做出了妥协,给Max道歉让渡自己的一部分“利益”,Max也在是否接受这个妥协而思前想后犹豫不决。

不过两个人即使尝试维护这种关系,也需要面对这样一个问题:对方已经无法提供任何其他价值了,除了让自己堵心以外再无他用。既然如此,又何必不转向自己其他的朋友呢?试想一下,如果Mary的家庭都关心照顾她,而不是像电影中那样相继离他而去以至于将Mary逼上自绝的道路,Mary和Max又有多大的可能继续下去呢?

这么想的话,其实Max去世的时间也刚刚好:在Max刚刚原谅Mary之后。这也恰恰抹去了Max和Mary在和解之后再次发生冲突的可能性,让一切都显得更加童话。

这部电影之所以感人,就在于Max是一个特殊的例子——没有朋友的孤独的人,Mary也是一个特殊的例子——生长在冰冷家庭同样没有朋友的人。而特殊的例子在生活中不常见,所以更能引起人们的羡慕和感动。事实上,这种例子就像心灵鸡汤一样,虽然美味温馨,可是并不具有实际操作的意义。作为Max,原谅Mary之后Mary也终会有一天再一次伤害Max。两个人的所谓羁绊,就在那本书出版的一刻,已经彻底的消失了。而两个人的所谓羁绊,在他们认识的那一刹那就注定消失。

就像李志在那首歌中唱到的一样:我们生来就是孤独,我们生来就是孤单。

MC56F8257的ADC输出越限原因

MC56F8257的ADC是一个12位的ADC,而2^12=4096,所以按说只能输出0—4096范围内的值。但是在实际的使用过程中会发现,配置为12位的ADC会输出远大于4096的数字。

而ADC的转换结果会存储在ADC_RSLTn寄存器中。该寄存器的结构如下:

ADC_RSLTn

寄存器的0—2位为保留位;3—14位存储转换的结果;最高位15位为符号位,1表示为负,0表示为正。

而ADC的GetValue的函数中会将ADC_RSLTn的数值直接存在pValue中。返回的值包括第15位最高位的符号位。所以2^15=32768,实际输出的范围是0—32768。

byte AD1_GetValue(void* Values)
{
  register word *pValue=(word*)Values;

  if (!OutFlg) {
    return ERR_NOTAVAIL;
  }
  *pValue = getReg(ADC_RSLT0);
  return ERR_OK;
}

与GetValue相比GetValue16中则会将ADC_RSLTn的数值向左移一位,所以返回的值并不包括第15位最高位的符号位。而相应的,2^15=65536,所以实际的输出范围是0—65536。

byte AD1_GetValue16(word *Values)
{
  if (!OutFlg) {
    return ERR_NOTAVAIL;
  }
  *Values = (getReg(ADC_RSLT0) + 0x00U) &lt;&lt; 1U;
  return ERR_OK;
}

所以如果真的只想得到ADC_RSLTn中间那12位结果的话,对应函数中的语句应当进行如下改动:

对于GetValue:

*pValues = (getReg(ADC_RSLT0) &amp; 0x7FF8) &gt;&gt; 3;

对于GetValue16:

*Values = (getReg(ADC_RSLT0) &amp; 0x7FF8) &gt;&gt; 4;

如此的得到的结果的范围便是0—4096了。

但是实际上ADC在这之后还应当进行一次标度变换,而无论是否进行位移动,分辨率都不会有变化,对应的实际的物理意义也不会有变化,只是单纯的数字量的倍数关系而已。所以是否进行寄存器的位移动没有实际意义。

深淵

这首音乐来自增田俊郎的专辑《蟲師 オリジナル・サウンドトラック 蟲音 前》的第11首曲目《深淵》。

这首曲目无论是演奏的乐器、节奏还是旋律都很朴素,具有很强的安定能力。但是仔细听的话又会听出不一样的意味,仿佛一位僧人入定进入禅境一般,眼前一片黑暗,却又有一团绿色火焰不断跳动,静谧之余又有些迷幻引人继续靠近那团火焰。

这首曲目也一定程度上体现了这张专辑的特点,乐器节奏旋律都很简单,甚至有些原生态。为了配合虫师中那个“虫”和“人”共存的世界,勾勒的意境也都以幽静加神秘为主。

听这首音乐的时候会想起来初中的时候家里给买了一台入门级的天文望远镜。倍数并不是很高,很久没有动过已经忘记了。

虽然父母在买这台天文望远镜的时候是希望培养一下我对于科学的兴趣,最好是天文方面的。可是本人实在是懒,看着天上的一堆星星不仅分不清星座,也从来没有观察过星星的运动轨迹。前前后后将近半年的观察经历除了看到过一个人造卫星疑似物逢人便吹嘘以外,便再无所获。以至于虽然家里至今仍摆着这台望远镜,可我现在在夏天连仙后座在哪个位置都找不到。

不过当时带着那三分钟的热情,经常靠着失眠的特质或是可靠的闹钟半夜三点钟爬起来看星星。那个时候家乡的天空虽然也并不是很干净,倒也不像现在的雾霾这么严重,像是上帝遮住了帘忘了掀开。月光打在家属院的水泥地上,楼后的灯光全部都灭着,水泥地上的月光像水似在波动,就像漂浮在水面直视泳池的池底。再加上半夜三点的时候人半睡半醒,那感觉真的犹如进入了仙境一样。

摆好镜头,装好目镜,调整好目镜距离,便可以观察天空了。将眼睛凑近目镜,就可以从那个小小的玻璃片中看到无数密密麻麻的星,夜空也不再是肉眼观察到的蓝黑色,而是纯粹的黑,深不见底的黑。第一次用这台望远镜看星星的时候真的震撼很大,第一次直观的感受了无垠宇宙和人类的渺小。看着那条星河,虽然很想靠近,但却又心生畏惧,便只好抱着虔诚崇敬的态度仔细观察。

直到多年以后再看《虫师》的时候,听到了这段音乐,那片星空又浮现在了眼前。面对着这深渊,即使人类想去征服,却也不得不心怀崇敬吧。

Freescale家USB-TAP的使用方法

前几天要复习下Freescale家的56800E系列的MC56F8257控制BLDC,结果win7 64bit下不能用Codewarrior 8.3,被逼无奈只能去尝试着用之前没用过的Codewarrior 10.5。

把USB-TAP插上去之后没有动静,最后经过学长点拨发现在“FreescaleCW MCU v10.5MCUccsdriversusb”这个路径下还有个readme,打开一看果然是驱动的安装过程。

最后按着readme中的一步步做完之后,新建工程调试方法选择USB-TAP,在win7 64bit和CW10.5中测试发现是可以烧进去的。

而winxp在使用CW8.3时,使用USB-TAP烧录并不需要装驱动,只需要最基础的jungo驱动。在工程设置的Remote Debugging里的connection里选USB-TAP connection就行了。

在安装完jungo的驱动之后,将USB-TAP插入之后,这个时候USB-TAP的tx/rx灯应该是绿色的,会提示发现新硬件,这个时候所需要注意的就是千万不要点下一步,点击取消即可。而在自动安装完驱动之后则会变为红色,无法正常使用。

所以说对比下来,openSDA简直好用啊...