• PCB 钻孔补偿那点事


     没有优秀的个人,只有优秀的团队,在团队共同的协作下,PCB CAM自动化【net处理】与【钻孔处理】 第一阶段开发项完成了,,后续工作可以转向PCB规则引擎开发了。这里说说PCB工程钻孔补偿的那点事,身为一个PCB工程开发人员,有必要知其然,而且还要知其所以然,这里将钻孔补偿的知识点分享一下。

     

    一.为什么对钻孔进行补偿?

         客户来的PCB文件中的孔径一般指成品孔径,而PCB生产会在孔内镀上铜(或表面处理:喷锡,沉金,OSP,沉锡),这样一下来孔径就会缩小;为了满足成品孔径大小符合要求,工程CAM会进行钻孔补偿,进行孔径大小的校正.

           实际例子:成品孔径是1.00mm,表面处理:沉金 (镍厚:2.54um,金厚:0.0254um),IPC标准II级(平均孔铜:20um),孔径按0.10mm补偿,那么工程会选取1.10mm钻刀钻孔

           

    二.如何进行钻孔也补偿?

        先得说说钻孔补偿3个关键参数【钻刀的进制】,【补偿值】,【进阶值】这3个参数决定了钻孔如何补偿了.

       【钻刀的进制】---由公司采购钻刀决定,行业常规为50um进制

        一般钻刀大小范围在:0.1mm到6.35mm之间,而常规钻刀最小相邻间隔是0.05mm,那么钻刀库钻刀为: 0.10mm,0.15mm,0.20mm,0.25mm  等等。。。。

        【补偿值】---由工艺部结合工厂生产能力测试结果制定补偿值规则, 其实整个行业钻孔补偿值差了多少,大同小异

         通常:喷锡板:补偿0.15mm, 非喷锡板(沉金,镀金,沉锡,OSP等):补偿:0.10mm.

       【进阶值】---由工艺部结合工厂生产能力测试结果制定选取钻刀的策略.

        进阶值类似四舍五入,比如:进制值按是20um,那么钻孔补偿后的余数是>=20um,则向上进50um,否则不进按0um 。

       例如:成品孔径是:1.025mm,补偿值:0.10mm,钻孔补偿后是 :1.125mm,实际钻刀库中没有1.125mm,那得就得进阶值发挥作用了。

                 1.125mm余数为25um,此25um>20um,那么向上进50um,钻孔选取1.15mm

     实际钻孔补偿例子:

          

         选取钻刀大小的计算过程,将补偿后的钻孔,分解为整数部份与余数部份

          1.125mm整数部份: 1.125 / 0.05 =  22.5 向下取整为22,接着 22*0.05 = 1.10mm 

          1.125mm余数部份   1.125 % 0.05 = 0.025mm

         通过判断:余数部份是否大于20um,如果大于那么按 整数部份+0.05mm,否则按:整数部份+0mm.

       

        【进阶值】小结:

                  当钻刀进制为50um 【进阶值】对于钻刀选取至关重要,因为这个值是对钻孔补偿的又一个钻刀尺寸效正,【进阶值】决定是钻刀是进还是舍,

                【进阶值】变化也决定了钻刀大小也发生了变化,看看下面这个例子

                 

               上面例子可见【进阶值】直接决定了钻刀大小的选择, 那么【进阶值】设为多少合适也是一个研究的课题了

                对【进阶值】设定多少合适的个人看法:

                1.通过利蔽分析:假如钻孔补偿,导致PCB成品孔径尺寸大了或孔径尺寸小了,可以评估对客户插件哪个影响最大,

                                            成品孔径尺寸大了至少还是可以插件的,如果孔径尺寸小了插元件器插不进去.                   

                                            所以:【进阶值】一般定在20um,而不是25um,当然这也得跟据不同工艺决定补偿值决定,

                2.钻孔【补偿值】: 拿喷锡板工艺来说,钻孔补偿值为0.15mm,其实这个补偿值是多补偿了,会导致成品孔径尺寸大一点

                                     比如:1.0mm孔,钻刀:1.15mm,那么这个孔会比实际客户要求孔径大一点,

                                      所以:当钻孔【补偿值】存在本身多补偿了,那么【进阶值】可以设在25um也没问题,就近取刀

    三.如何保证钻孔补偿后成品孔径符合要求

         方法1.采购特殊钻刀

              PCB钻孔进制常规是50um,即相邻钻刀间隔0.05mm, 如1.00mm,1.05mm.1.10mm,1.15mm

             一般PTH公差+/-3mil公差采用50um进制钻刀可以保障成品公差要求了,但孔径公差小于这个值时,可以采用特殊钻刀。

              例1:50um与25um进制选刀对比

               原始孔径 0.922mm 钻孔补偿 0.10mm,补偿后是1.022mm

               

              差值对比 1.050-1.022 =0.028mm

                              1.025-1.022=0.003mm

               差值越小;钻刀选取越合理,那么这里选用1.025mm最佳

              例2:50um与特殊钻刀 选刀对比

              原始孔径 0.611mm 钻孔补偿 0.10mm,补偿后是0.711mm

            

              差值对比 0.700-0.711 =0.011mm

                              0.711-0.711 =0.000mm

               差值越小;钻刀选取越合理,那么这里选用0.711mm最佳

         方法2.工艺与设备改进

             1.增加二次板镀,减少图镀时间,减少图形分布不均造成电镀厚度不均的影响

              2.改负片直蚀工艺, 全部采用整板镀铜,减少图形分布不均造成电镀厚度不均的影响

              3.电流密度减少,通常电流密度 19ASF,适当降低电流密度电镀效果越好,但电镀时间延长了

               4.更新更先进的水平电镀线,常规的垂直电镀线对于高厚径比,表面或孔边缘铜厚比孔壁中心铜厚要厚.

          方法3.工程CAM改进

              1..独立孔区域钻孔,钻刀多补偿一个进制钻刀

                    独立区域,铜比较少,电镀时是高电流区域,镀上铜会比其它区域的铜会厚一些,就会导致孔小了

               2.一边密集线路,而另一边稀疏线路(记得电源板经常这样设计), 稀疏的线路朝板内,而密集的线路朝板外, 进行倒扣拼板

                    整个PNL电镀时,越靠近PNL板边单位电流密度越大,所以越靠近板边镀上去的铜厚越多.

               3. TOP与BOTTOM面 铜面积相差大,进行阴阳拼板. 

                    对钻孔的影响会行成喇叭孔,当板厚与孔铜越厚时,孔侧面形状越明显,采用阴阳拼板改善两边铜面积分布不均

               4.独立区域钻孔,当靠近板边或锣槽较近的,可以在板边或锣槽中心,铺抢电铜皮或抢电铜PAD

                   独立区域钻孔会孔铜越厚,孔会变小, 允许的情况下周边增加铜皮或PAD,可以减少独立区域的高电流.

    四.钻孔要补偿多少,如何得出来的.

         经过测试结果评估得出来的,看一组钻孔补偿后,在经过各工序后;钻孔大小变化(报告摘自百度文库)

    工艺流程:

    工艺参数:

    测试PNL数量与切边位置:

     钻孔后---孔径变化:

     

    图形电镀后---孔铜变化:

     

     图形电镀后---孔径变化:

     喷锡后---孔径变化:

     孔径变化情况:

     

      可以测试结果得出结论:

       喷锡板钻孔补偿:0.15mm,是多补偿了,会导致成品孔径偏大一点,所以最佳补偿因该是补偿0.125mm

    五.钻孔补偿代码实现.

        1.补偿值与进阶值规则:

        2.特殊刀径(公差小于3mil  采用特殊刀径与25um进制刀径,就近取刀原则)

        List<double> ContainDrillToolList = new List<double>();
        ContainDrillToolList.AddRange(new double[] { 610, 635, 711, 838, 914, 1016, 1320, 3120 });

        3.补偿钻孔代码

    /// <summary>
    /// 通过钻孔补偿参数计算钻孔刀径
    /// </summary>
    /// <param name="ToolInfo"></param>
    /// <param name="UpParam"></param>
    ///<param name="ContainDrillToolList"></param>
    /// <returns></returns>
    public static int getDrillUpSize(Mod_tool ToolInfo, gToolUpParam UpParam, List<double> ContainDrillToolList)
    {
        if (ContainDrillToolList == null) ContainDrillToolList = new List<double>();
        gToolUpParamHole UpParamHole = new G_Helper.gToolUpParamHole();
        switch (ToolInfo.type)
        {
            case "via":
                UpParamHole = UpParam.Via;
                break;
            case "plate":
                UpParamHole = UpParam.Pth;
                break;
            case "nplate":
                UpParamHole = UpParam.Npth;
                break;
        }
        ToolInfo.max_tol = Math.Round(UpParamHole.Max_Tol, 0);
        ToolInfo.min_tol = Math.Round(UpParamHole.Min_Tol, 0);
        if (ToolInfo.finish_size < 50)
        {
            ToolInfo.finish_size = ToolInfo.drill_size;
        }
        double DrillSlotLevel = (ToolInfo.shape == "slot") ? UpParam.SlotLevel : UpParam.DrillLevel;  //钻孔阶级距   圆孔有2类阶级25 50  槽孔有一类阶级:50
        double UpLevel;
        if (UpParam.DrillLevel > 49) //进制为50时,不取特殊钻刀
        {
            ContainDrillToolList = new List<double>();
            UpLevel = UpParamHole.UpLevel;
        }
        else
        {
            UpLevel = UpParam.DrillLevel * 0.5;  //通过进制的一半取刀
        }
    
        double Drillfinish_size = ToolInfo.finish_size + (ToolInfo.max_tol - ToolInfo.min_tol) * 0.5;  //上限下限公差平分
        int DrillLevelCount = (int)(Math.Floor((Drillfinish_size + UpParamHole.UpVal) / DrillSlotLevel)); //孔阶数
        double DrillsizeInt = DrillLevelCount * DrillSlotLevel; //化整钻孔
        double DrillsizeFloat = (Drillfinish_size + UpParamHole.UpVal) % DrillSlotLevel;//余数钻孔
        double DrillsizeLevel = (DrillsizeFloat > UpLevel) ? DrillSlotLevel : 0;//余数是否进舍
                                                                                //包含特殊钻刀
        int ContainDrillIndex = ContainDrillToolList.FindIndex(tt => (int)(Math.Floor(tt / DrillSlotLevel)) == DrillLevelCount);
        if (ContainDrillIndex > -1)
        {
            double ContainDrillFloat = ContainDrillToolList[ContainDrillIndex] % DrillSlotLevel;//特殊钻孔--余数钻孔
            if (DrillsizeFloat > UpLevel) // 38 > 20
            {
                double diff1 = Math.Abs(DrillsizeFloat - DrillSlotLevel);  //40-50
                double diff2 = Math.Abs(DrillsizeFloat - ContainDrillFloat);  //40-38
                DrillsizeLevel = (diff1 < diff2) ? DrillSlotLevel : ContainDrillFloat;
            }
            else //if (ContainDrillFloat < UpLevel)
            {
                double diff1 = Math.Abs(DrillsizeFloat - 0);  //12-0
                double diff2 = Math.Abs(DrillsizeFloat - ContainDrillFloat);  //12-16
                DrillsizeLevel = (diff1 < diff2) ? 0 : ContainDrillFloat;
            }
        }
        ToolInfo.drill_size = DrillsizeInt + DrillsizeLevel;
    
        double DiffDrillSizeUp = ToolInfo.drill_size - ToolInfo.finish_size;
        if (ToolInfo.shape == "slot") //槽长补偿
        {
            if (UpParam.isSlotUpLevel) //槽长是否进制化
            {
                Drillfinish_size = ToolInfo.slot_len + (ToolInfo.max_tol - ToolInfo.min_tol) * 0.5;  //上限下限公差平分
                DrillLevelCount = (int)(Math.Floor((Drillfinish_size + UpParamHole.UpVal + UpParam.SlotLengthUp) / DrillSlotLevel)); //孔阶数
                DrillsizeInt = DrillLevelCount * DrillSlotLevel; //化整钻孔   50
                DrillsizeFloat = (Drillfinish_size + UpParamHole.UpVal + UpParam.SlotLengthUp) % DrillSlotLevel;//余数钻孔
                DrillsizeLevel = (DrillsizeFloat > UpParamHole.UpLevel) ? DrillSlotLevel : 0;//余数是否进舍
                ToolInfo.slot_len = DrillsizeInt + DrillsizeLevel;
            }
            else
            {
                DrillsizeInt = Math.Floor((ToolInfo.slot_len + DiffDrillSizeUp) / 10) * 10; //化整钻孔  10 
                ToolInfo.slot_len = DrillsizeInt;
            }
            ToolInfo.drill_size += UpParam.SlotEndNumber;  //Slot槽分刀  加尾数
        }
        ToolInfo.bit = Math.Round((ToolInfo.drill_size * 0.001), 3).ToString();
        return 1;
    }
    public class gToolUpParam
    {
        /// <summary>
        /// VIA孔补偿值参数
        /// </summary>
        public gToolUpParamHole Via { get; set; } = new gToolUpParamHole();
        /// <summary>
        /// PTH孔补偿值参数
        /// </summary>
        public gToolUpParamHole Pth { get; set; } = new gToolUpParamHole();
        /// <summary>
        /// NPTH孔补偿值参数
        /// </summary>
        public gToolUpParamHole Npth { get; set; } = new gToolUpParamHole();
        /// <summary>
        /// 钻孔阶级距
        /// </summary>
        public double DrillLevel { get; set; } = 50;
        /// <summary>
        /// Slot槽孔阶级距
        /// </summary>
        public double SlotLevel { get; set; } = 50;
        /// <summary>
        /// Slot槽尾数(用于分刀)
        /// </summary>
        public int SlotEndNumber { get; set; } = 0;
        /// <summary>
        /// Slot槽多补偿值(微米)
        /// </summary>
        public double SlotLengthUp { get; set; } = 0;
        /// <summary>
        /// Slot槽长是否进制化
        /// </summary>
        public bool isSlotUpLevel { get; set; } = false;
    }
    public class gToolUpParamHole
    {
        /// <summary>
        /// 补偿值(微米)
        /// </summary>
        public double UpVal { get; set; } = 100;
        /// <summary>
        /// 进制(微米)
        /// </summary>
        public double UpLevel { get; set; } = 25;
        /// <summary>
        ///正公差(微米)
        /// </summary>
        public double Max_Tol { get; set; } = 76;
        /// <summary>
        /// 负公差(微米)
        /// </summary>
        public double Min_Tol { get; set; } = 76;
    
    }
    
    /// <summary>
    /// Mod_layer 层类型
    /// </summary>
    public class Mod_tool
    {
        public int num { get; set; }
        public double finish_size { get; set; }
        public double drill_size { get; set; }
        public string bit { get; set; } = "";
        public double slot_len { get; set; }
        public double min_tol { get; set; }
        public double max_tol { get; set; }
        public int count { get; set; }
        public string shape { get; set; }
        /// <summary>
        /// via 改via non_plated 改nplate plated 改plate
        /// </summary>
        public string type { get; set; }
        public string type2 { get; set; }
    }

    六.为什么钻孔补偿和板厚有关呢

            这个问题之前我也没明白,主要是因为高【厚径比】会导致孔中心的孔铜薄一些,而孔边缘铜厚厚一些,会形成如下图片所示效果,

            要计算出【厚径比】需要板厚这个值,所以板厚也参与到了,钻孔补偿的规则中来了,当高【厚径比】(如12:1)的钻孔补偿会多补偿一些.

            

  • 相关阅读:
    BeanFactory not initialized or already closed
    点击程序不弹出界面,但有后台服务
    python获取一年所有的日期
    keepalived实现高可用
    解决docker镜像pull超时问题
    docker容器的操作
    docker小结
    docker概述
    docker镜像操作
    python批量下载
  • 原文地址:https://www.cnblogs.com/pcbren/p/9840500.html
Copyright © 2020-2023  润新知