PCB CAM 鉆孔補償那點事
沒有優秀的個人,只有優秀的團隊,在團隊共同的協作下,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; } }
六.為什麽鉆孔補償和板厚有關呢
這個問題之前我也沒明白,主要是因為高厚徑比了,會導致孔中心的孔銅薄一些,而孔邊緣銅厚厚一些,會形成如下圖片所示效果,
要計算出厚徑比需要板厚的參數,所以板厚也參與到鉆孔補償的規則中來了,當高厚徑比的鉆孔補償會多補償一點.
PCB CAM 鉆孔補償那點事