//时间:20200610 //作者:郝爽 //功能:测量线程 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SmartSEMControl; using MeasureData; namespace MeasureThread { public enum FMode { Manual, Auto } public enum ImageMode { FIB, SEM } public class Measure { //全局只有一个fatorySEM static FactoryHardware factorySEM = FactoryHardware.Instance; ISEMControl iSEM = factorySEM.ISEM; const String ImageName1 = @"ImageSEM600X.tif"; //传给客户 const String ImageName2 = @"ImageFIB600X1.tif";//传给客户 const String ImageName3 = @"ImageFIB600X2.tif"; const String ImageName4 = @"ImageSEM300X.tif";//传给客户 const String ImageName5 = @"ImageSEM6000X.tif";//传给客户 const float fMin = (float)0.0000002; //单位是米 //测量文件 private MeasureFile m_measureFile; public MeasureFile MeasureFile { get { return this.m_measureFile; } set { this.m_measureFile = value; } } //测量的切割孔 private List m_cutHoles; public List cutHoles { get { return this.m_cutHoles; } set { this.m_cutHoles = value; } } //工作文件夹 private string m_WorkingFolder; public string WorkingFolder { get { return this.m_WorkingFolder; } set { this.m_WorkingFolder = value; } } //线程状态 private ThreadStatus m_ThreadStatus; public ThreadStatus TStatus { get { return this.m_ThreadStatus; } set { this.m_ThreadStatus = value; } } //对焦模式 private FMode m_bFocusMode; public FMode FocusMode { get { return this.m_bFocusMode; } set { this.m_bFocusMode = FocusMode; } } //// SEM data general //CSEMDataGnrPtr m_pSEMDataGnr; ////MeasureAppFormName //CString m_strMAppFormName; //HWND m_hWnd; //构造函数 public Measure() { Init(); } public void Init() { FocusMode = FMode.Manual; } //初始化测量业务, 读测量文件,判断是否有可测试的切孔 public bool InitMeas(MeasureFile a_measureFile) { m_measureFile = a_measureFile; List listHoles = m_measureFile.ListCutHole; foreach (CutHole h in listHoles ) { if (h.SWITCH == true) { m_cutHoles.Add(h); } } if(m_cutHoles.Count == 0) return false; return true; } //测量流程 public void DoMeasure() { //创建线程的测量状态的更新 this.TStatus.ComputeTime(THREAD_TIME_TYPE.START); //将这个开始时间传递给主界面 //检查硬件连接是否正常 if (!ConnectHardware()) { return; } //设置工作文件夹 if (!SetWorkingFolderStr()) { return; } //第一个孔的测试 FirstHole(); //非第一个孔的测试 OtherHole(); } //检查硬件连接是否正常 public bool ConnectHardware() { //返回硬件的连接状态 return iSEM.ConnectStatus(); } //设置工作文件夹 public bool SetWorkingFolderStr() { //获取工作文件路径 string pathName = m_measureFile.FilePath; //判断工作文件路径是否为空或无效 if (string.IsNullOrEmpty(pathName)) { return false; } //文件未保存 else if (pathName.CompareTo(MeasureFile.UNTITLED_FILE_NAME) == 0) { return false; } //获取工作文件所在文件夹 string folder = System.IO.Path.GetDirectoryName(pathName); if (string.IsNullOrEmpty(folder)) { return false; } WorkingFolder += @"\\"; return false; } //第一个孔的测试过程 public void FirstHole() { MeasureData.CutHole firstHole = m_cutHoles[0]; //12.根据样品类型参数确定是否需要PT沉积,控制PT针插入 if (firstHole.PT == true) { if (!iSEM.InsertPT()) { return; } } //13.自动定位切割 { //1.控制SEM放大600X if (!iSEM.SetMagnification(600)) { return; } //2.控制SEM自动对焦、亮度、对比度 if (FocusMode == FMode.Manual) { //弹出手动对焦的窗口 } else if (FocusMode == FMode.Auto) { //调用自动对焦模块 } else { return; } //3.设置SEM进行角度补偿54度 if (!TiltCorrection(54)) { return; } //4.控制SEM拍照 //5.保存照片 { //1. 创建目录,已经完成 //2. 设置图片名称 //3. 保存图片1 String fileName1 = WorkingFolder + ImageName1; if (!GetImage(ImageMode.SEM, fileName1)) { return; } } //6.设置FIB拍照参数——扫描时间、束流等 //7.控制FIB自动亮度、对比度 //8.控制FIB拍照 //9.保存照片 { //1. 设置图片名称 //2. 保存图片2 String fileName2 = WorkingFolder + ImageName2; if (!GetImage(ImageMode.FIB, fileName2)) { return; } } //10.将照片传给客户,返回梯形位置坐标,及样品类型参数(是否需要PT沉积,PT坐标位置,PT宽度、PT高度、梯形上、下边及深度、扫描时间、束流、样品放大倍数1、样品放大倍数2等切割参数) //11.自动工具样品类型参数确定是否需要PT沉积 { //1. 根据客户PT沉积坐标控制FIB调整到中心位置 //2. 验证移动准确性:获取当前FIB中心位置坐标,与客户返回坐标对比,验证是否一定正确 //3. 根据坐标进行PT沉积 } //模拟为客户返回的坐标值 float x0 = 0, y0 = 0; //12.根据梯形坐标控制FIB调整到中心位置 if (!iSEM.MoveStageXY(x0, y0)) { return; } //13.验证移动准确性:获取当前FIB中心位置坐标,与客户返回坐标对比,验证是否移动正确 float x1 = iSEM.GetStageAtX(); float y1 = iSEM.GetStageAtY(); if (Math.Abs(x0 - x1) > fMin && Math.Abs(y0 - y1) > fMin) { return; } //14.保存样品1第1号孔中心位置6轴坐标1 XYZMRT到数据库,保存客户返回值信息到数据库 float[] firstPosition = iSEM.GetStagePosition(); } //14.自动控制FIB切割 { //1.根据参数设置FIB草率时间(使图清晰),设置梯形上下边及深度、设置束流 //2.控制FIB进行切割 //3.控制FIB拍照600X //4.保存图片 { //1.设置图片名称 //2.保存图片3 String fileName3 = WorkingFolder + ImageName3; if (!GetImage(ImageMode.FIB, fileName3)) { return; } } //5.验证切割准确性:与切割前对比,如果对比误差大,则停止自动执行,进行报警 //6.设置FIB解冻:先读取状态,如果冻结状态则进行解冻 } //15.根据样品类型决定是否撤出PT针 if (firstHole.PT == false) { if (!iSEM.OutputPT()) { return; } } //16.自动调整SEM找到切割位置 { //1.控制SEM放大到300倍 if (!iSEM.SetMagnification(300)) { return; } //2.控制SEM自动对焦、亮度、对比度-接口 if (FocusMode == FMode.Manual) { //弹出手动对焦的窗口 } else if (FocusMode == FMode.Auto) { //调用自动对焦模块 } else { return; } //3.控制SEM拍照 String fileName4 = WorkingFolder + ImageName4; if (!GetImage(ImageMode.SEM, fileName4)) { return; } //4.将照片传给客户,获取偏移坐标,以及偏移角度 float x4 = 0, y4 = 0; float angle = 0; //5.根据坐标控制SEM移动到切孔位置,居中 if (!iSEM.MoveStageXY(x4, y4)) { return; } if (!iSEM.SetScanRotation(angle)) { return; } //6.验证移动准确性:获取当前SEM中心位置坐标,与客户返回坐标对比,验证是否移动正确 float x5 = iSEM.GetStageAtX(); float y5 = iSEM.GetStageAtY(); if (Math.Abs(x5 - x4) > fMin && Math.Abs(y5 - y4) > fMin) { return; } } //17.自动控制SEM拍截面照 { //1.控制SEM放大到指定参数大小范围,6000x if (!iSEM.SetMagnification(6000)) { return; } //2.控制SEM自动对焦、消像散、亮度、对比度 if (FocusMode == FMode.Manual) { //弹出手动对焦的窗口 } else if (FocusMode == FMode.Auto) { //调用自动对焦模块 } else { return; } //3.设置SEM角度补偿cos36度 if (!TiltCorrection(36)) { return; } //4.控制SEM拍照 //5.保存照片4 String fileName5 = WorkingFolder + ImageName5; if (!GetImage(ImageMode.SEM, fileName5)) { return; } //6.将照片传给客户,获取偏移坐标 float x6 = 0, y6 = 0; float angle1 = 0; float mage = 0; //7.根据坐标控制SEM移动到分析位置 if (!iSEM.MoveStageXY(x6, y6)) { return; } //8.验证移动准确性:获取当前SEM中心位置坐标,与客户返回坐标对比,验证是否移动正确 float x7 = iSEM.GetStageAtX(); float y7 = iSEM.GetStageAtY(); if (Math.Abs(x6 - x7) > fMin && Math.Abs(y6 - y7) > fMin) { return; } //9.控制SEM平行校正,并记录校正前初始值 if (!iSEM.SetScanRotation(angle1)) { return; } //10.控制SEM放大到指定参数大小范围 //11.控制SEM自动对焦、消像散、亮度、对比度 //12.控制SEM对分析位置拍照 //13.保存照片 //14.控制SEM取消电子束校正,回到初始值 } //18.自动层高分析 { //1.获取SEM Pixel Size给客户传入参数 //2.将照片传给客户,客户进行层高分析(返回分析后的图像、相对坐标、分辨率、各层编号以及各层对应的层高数据),如果客户自行出分析报告则无需返回数据 } //19.自动能谱分析 { //1. 确定能谱位置 //2. 控制牛津打能谱 //3. 能谱分析——面扫+线扫描 } } //非第一个孔的测试过程 public void OtherHole() { } //角度补偿 public bool TiltCorrection(float a_fAngle) { //记录原来电镜的状态 bool bTilt = false; float fOldTilt = iSEM.GetTiltCorrection(); if (fOldTilt == float.NaN) { return false; } else if (fOldTilt == 1) { bTilt = true; } else if (fOldTilt == 0) { bTilt = false; } float fOldAngle = iSEM.GetTiltAngle(); if (fOldAngle == float.NaN) { return false; } //开启校正 if (!iSEM.SetTiltCorrectionOn()) { return false; } //设置校正角度 if (!iSEM.SetTiltAngle(fOldAngle)) { return false; } //恢复原始状态 if (!iSEM.SetTiltAngle(a_fAngle)) { return false; } if (bTilt) { if (!iSEM.SetTiltCorrectionOn()) { return false; } } else { if (!iSEM.SetTiltCorrectionOff()) { return false; } } return true; } //拍图 public bool GetImage(ImageMode a_mode, String a_fileName) { //1. 图像解冻 float foldFrozen = iSEM.GetImageFrozen(); if (foldFrozen == float.NaN) { return false; } if (!iSEM.ImageLive()) { return false; } //2. 确认图像模式 if (ImageMode.SEM == a_mode) { if (!iSEM.CmdFIBModeSEM()) { return false; } } else if (ImageMode.FIB == a_mode) { if (!iSEM.CmdFIBModeFIB()) { return false; } } else { return false; } //3. 获取分辨率 int[] ImageSize = iSEM.GetImageStore(); if (ImageSize[0] == 0 || ImageSize[1] == 0) { return false; } short width = (short)ImageSize[0]; short height = (short)ImageSize[1]; //4. 抓图 if (!iSEM.GrabImage(a_fileName, 0, 0, width, height, 0)) { return false; } //5. 恢复初始状态 if (foldFrozen == 0) { if (!iSEM.ImageLive()) { return false; } } else if (foldFrozen == 1) { if (!iSEM.ImageFrozen()) { return false; } } return true; } } }