开发背景 一直一来,在开发完新样品做样机的时候,手工贴片非常痛苦,板子简单还好,如果板子复杂且样机数量又多(一般10台以内),那真是贴的眼疼胳膊酸啊,在贴片过程中最耗费时间的就是在密密麻麻的丝印图上找元件座位号了,所以如果有什么工具能一下子找到并能图形化标注出来位置,那将大大加快贴片的速度,也不用闻那么长时间的锡膏散发出来的有毒气体了。
灵感来源 之前在用Kicad设计板子的时候,有一款插件不得不提一下,就是InteractiveHtmlBom,这款插件可以生成一个交互式BOM的文件,可以在浏览器里打开,图形化展示出来各个元件位置,手工贴片非常方便
这正是我想要的效果,但是这个插件只适合用在Kicad或者LCEDA里,其它软件使用不了,而且还得是源代码才能生成交互式BOM,只能自己开发了,于是就有了这个软件
实现原理 由于没有源文件,要实现这种效果,需要有BOM表,Gerber,及坐标文件,这些是工厂批量生产的最基本的东西,都会提供的。 原理:根据BOM表获取同一种元件的座位号,再从坐标里件里获取每一个元件的坐标,然后生成每一个元件的gerber绘图语句,最后就是渲染gerber丝印图并在上边标识出来
Gerber文件解析 Gerber文件要是自己写,还是比较复杂的,网上已有很多开源的Gerber文件解析的库,就不重复造轮子了,这里使用了GerberVS库,我测试了一下,已经相当完善了,测试了一些产品的gerber 基本没问题。GerberVS
BOM解析 BOM是excel格式的,这里使用NPOI进行BOM表的读取,还是比较简单的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 workBook = new XSSFWorkbook(tbx_bom.Text); ISheet sheet = workBook.GetSheetAt(0 ); int lastNum = sheet.LastRowNum;Console.WriteLine("总行数:" + lastNum); dataGridView1.Rows.Clear(); for (int i = 2 ; i < lastNum; i++){ if (sheet.GetRow(i) != null ) { dataGridView1.Rows.Add(); for (int j = 0 ; j < 10 ; j++) { if (sheet.GetRow(i).GetCell(j) != null ) { if (sheet.GetRow(i).Cells.Count > 10 ) { switch (sheet.GetRow(i).GetCell(j).CellType) { case CellType.Numeric: dataGridView1.Rows[i - 2 ].Cells[j].Value = sheet.GetRow(i).GetCell(j).NumericCellValue; break ; case CellType.String: dataGridView1.Rows[i - 2 ].Cells[j].Value = sheet.GetRow(i).GetCell(j).StringCellValue; break ; } } else { Console.WriteLine(i + " ---> cells < 10" ); } } } } } dataGridView1.AutoResizeRows();
坐标文件解析 坐标文件就是普通的文本文件,按照坐标格式进行读取就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 StreamReader sr = File.OpenText(tbx_rep.Text); pst = new List<Placement>(); while ((temp = sr.ReadLine()) != null ){ if (temp.Contains("Total Number of SMD Components on Top" )) { string s = temp.Remove(0 , temp.IndexOf(':' ) + 1 ); line = int .Parse(s); sr.ReadLine(); sr.ReadLine(); for (int i = 0 ; i < line; i++) { temp = sr.ReadLine(); string str = temp.Substring(0 , 10 ).Trim(); string x = temp.Substring(10 , 10 ).Trim(); string y = temp.Substring(20 , 10 ).Trim(); string r = temp.Substring(30 , 7 ).Trim(); if (i == 0 ) { label_first_smd.Text = string .Format("{0}--->X:{1} Y:{2}" , str, x, y); } Placement p = new Placement(); p.Symbol = str; p.X_pos = x; p.Y_pos = y; p.Rotation = r; pst.Add(p); } } }
在图形中渲染位置 根据坐标生成对应的gerber绘图语句,比如画一个圆点,能标识出即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 Console.WriteLine(dataGridView1.Rows[e.RowIndex].Cells[7 ].Value); string location = (string )dataGridView1.Rows[e.RowIndex].Cells[7 ].Value;string [] loc;StringBuilder sb = new StringBuilder(); sb.Append("G04 Sonavox auto mark smd commpent helper *\r\n" ); sb.Append("G04 Draw by:101367 *\n" ); sb.Append("%MOIN*%\n" ); sb.Append("%FSLAX55Y55*%\n" ); sb.Append(string .Format("%ADD11C,{0}*%\n" , numericUpDown_size.Value.ToString())); sb.Append("\nG54D11*\n" ); if (location != "" ){ loc = location.Split(',' ); bool find = false ; foreach (string s in loc) { find = false ; foreach (Placement p in pst) { if (s == p.Symbol) { find = true ; Int32 xpos = Int32.Parse(p.X_pos) + (Int32)numericUpDown_x.Value; Int32 ypos = Int32.Parse(p.Y_pos) + (Int32)numericUpDown_y.Value; xpos = xpos * 100 ; ypos = ypos * 100 ; sb.Append(string .Format("X{0}Y{1}D03*\n" , xpos, ypos)); Console.WriteLine(string .Format("Top SMD:{0}--->X:{1} Y:{2} R:{3}" , s, p.X_pos, p.Y_pos, p.Rotation)); continue ; } } if (find == false ) { foreach (Placement p in psb) { if (s == p.Symbol) { find = true ; Int32 xpos = Int32.Parse(p.X_pos) + (Int32)numericUpDown_x.Value; Int32 ypos = Int32.Parse(p.Y_pos) + (Int32)numericUpDown_y.Value; xpos = xpos * 100 ; ypos = ypos * 100 ; sb.Append(string .Format("X{0,0.00}Y{1,0.00}D03*\n" , xpos, ypos)); Console.WriteLine(string .Format("Bottom SMD:{0}--->X:{1} Y:{2} R:{3}" , s, p.X_pos, p.Y_pos, p.Rotation)); continue ; } } } if (find == false ) { MessageBox.Show(s + "的坐标未找到,请确认!!!\r\n可能是座位号不正确或者在MI部分" ); return ; } } sb.Append("M02*\n" ); richTextBox1.Text = sb.ToString(); StreamWriter sw = new StreamWriter(@"Auto-Generate-Gerber.gbx" ); sw.Write(sb.ToString()); sw.Flush(); sw.Close(); reload_event(0 ); }
软件界面 图形标记目前只支持加点,可以很容易添加方框,箭头等符号
软件以坐标文件中第一个位置为参照来计算偏移量的,需要填入实际坐标才可以计算出偏移量,如果坐标没有偏移,则无需计算,贴完的可以标记为绿色背景,取消即为默认背景
源码如下 目前代码只适合解析我们公司cadstar导出的文件,这个EDA国内用的不多,这里给出源码,简单修改下就可以解析其它格式的BOM及坐标文件了点击下载源码
视频演示