智汇工业-智慧工业、智能制造及工业智能、工业互联门户网站,专业的工业“互联网+”传媒

Android提高應用篇之模擬信號示波器

來源:網絡

點擊:2096

A+ A-

所屬頻道:新聞中心

關鍵詞: Android手機,模擬信號示波器

        本文結合SurfaceView實現一個Android版的手機模擬信號示波器(PS:以前也講過J2ME版的手機示波器)。最近物聯網炒得很火,作為手機軟件開發者,如何在不修改手機硬件電路的前提下實現與第三方傳感器結合呢?麥克風就是一個很好的ADC接口,通過麥克風與第三方傳感器結合,再在軟件里對模擬信號做相應的處理,就可以提供更豐富的傳感化應用。

        先來看看本文程序運行的效果圖(屏幕錄像速度較慢,真機實際運行起來會更加流暢):

     

           本文程序使用8000hz的采樣率,對X軸方向繪圖的實時性要求較高,如果不降低X軸的分辨率,程序的實時性較差,因此程序對X軸數據縮小區間為8倍~16倍。由于采用16位采樣,因此Y軸數據的高度相對于手機屏幕來說也偏大,程序也對Y軸數據做縮小,區間為1倍~10倍。在SurfaceView的OnTouchListener方法里加入了波形基線的位置調節,直接在SurfaceView控件上觸摸即可控制整體波形偏上或偏下顯示。

    main.xml源碼如下:

    view plaincopy to clipboardprint?
    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="vertical" android:layout_width="fill_parent" 
        android:layout_height="fill_parent"> 
        <LinearLayout android:id="@+id/LinearLayout01" 
            android:layout_height="wrap_content" android:layout_width="fill_parent" 
            android:orientation="horizontal"> 
            <Button android:layout_height="wrap_content" android:id="@+id/btnStart" 
                android:text="開始" android:layout_width="80dip"></Button> 
            <Button android:layout_height="wrap_content" android:text="停止" 
                android:id="@+id/btnExit" android:layout_width="80dip"></Button> 
            <ZoomControls android:layout_width="wrap_content" 
                android:layout_height="wrap_content" android:id="@+id/zctlX"></ZoomControls> 
            <ZoomControls android:layout_width="wrap_content" 
                android:layout_height="wrap_content" android:id="@+id/zctlY"></ZoomControls> 
        </LinearLayout> 
        <SurfaceView android:id="@+id/SurfaceView01" 
            android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView> 
    </LinearLayout> 
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical" android:layout_width="fill_parent"
     android:layout_height="fill_parent">
     <LinearLayout android:id="@+id/LinearLayout01"
      android:layout_height="wrap_content" android:layout_width="fill_parent"
      android:orientation="horizontal">
      <Button android:layout_height="wrap_content" android:id="@+id/btnStart"
       android:text="開始" android:layout_width="80dip"></Button>
      <Button android:layout_height="wrap_content" android:text="停止"
       android:id="@+id/btnExit" android:layout_width="80dip"></Button>
      <ZoomControls android:layout_width="wrap_content"
       android:layout_height="wrap_content" android:id="@+id/zctlX"></ZoomControls>
      <ZoomControls android:layout_width="wrap_content"
       android:layout_height="wrap_content" android:id="@+id/zctlY"></ZoomControls>
     </LinearLayout>
     <SurfaceView android:id="@+id/SurfaceView01"
      android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView>
    </LinearLayout>
     

    ClsOscilloscope.java是實現示波器的類庫,包含AudioRecord操作線程和SurfaceView繪圖線程的實現,兩個線程同步操作,代碼如下:

    view plaincopy to clipboardprint?
    package com.testOscilloscope;  
    import java.util.ArrayList;  
    import android.graphics.Canvas;  
    import android.graphics.Color;  
    import android.graphics.Paint;  
    import android.graphics.Rect;  
    import android.media.AudioRecord;  
    import android.view.SurfaceView;  
    public class ClsOscilloscope {  
        private ArrayList<short[]> inBuf = new ArrayList<short[]>();  
        private boolean isRecording = false;// 線程控制標記  
        /** 
         * X軸縮小的比例 
         */ 
        public int rateX = 4;  
        /** 
         * Y軸縮小的比例 
         */ 
        public int rateY = 4;  
        /** 
         * Y軸基線 
         */ 
        public int baseLine = 0;  
        /** 
         * 初始化 
         */ 
        public void initOscilloscope(int rateX, int rateY, int baseLine) {  
            this.rateX = rateX;  
            this.rateY = rateY;  
            this.baseLine = baseLine;  
        }  
        /** 
         * 開始 
         *  
         * @param recBufSize 
         *            AudioRecord的MinBufferSize 
         */ 
        public void Start(AudioRecord audioRecord, int recBufSize, SurfaceView sfv,  
                Paint mPaint) {  
            isRecording = true;  
            new RecordThread(audioRecord, recBufSize).start();// 開始錄制線程  
            new DrawThread(sfv, mPaint).start();// 開始繪制線程  
        }  
        /** 
         * 停止 
         */ 
        public void Stop() {  
            isRecording = false;  
            inBuf.clear();// 清除  
        }  
        /** 
         * 負責從MIC保存數據到inBuf 
         *  
         * @author GV 
         *  
         */ 
        class RecordThread extends Thread {  
            private int recBufSize;  
            private AudioRecord audioRecord;  
            public RecordThread(AudioRecord audioRecord, int recBufSize) {  
                this.audioRecord = audioRecord;  
                this.recBufSize = recBufSize;  
            }  
            public void run() {  
                try {  
                    short[] buffer = new short[recBufSize];  
                    audioRecord.startRecording();// 開始錄制  
                    while (isRecording) {  
                        // 從MIC保存數據到緩沖區  
                        int bufferReadResult = audioRecord.read(buffer, 0,  
                                recBufSize);  
                        short[] tmpBuf = new short[bufferReadResult / rateX];  
                        for (int i = 0, ii = 0; i < tmpBuf.length; i++, ii = i  
                                * rateX) {  
                            tmpBuf[i] = buffer[ii];  
                        }  
                        synchronized (inBuf) {//  
                            inBuf.add(tmpBuf);// 添加數據  
                        }  
                    }  
                    audioRecord.stop();  
                } catch (Throwable t) {  
                }  
            }  
        };  
        /** 
         * 負責繪制inBuf中的數據 
         *  
         * @author GV 
         *  
         */  


        class DrawThread extends Thread {  
            private int oldX = 0;// 上次繪制的X坐標  
            private int oldY = 0;// 上次繪制的Y坐標  
            private SurfaceView sfv;// 畫板  
            private int X_index = 0;// 當前畫圖所在屏幕X軸的坐標  
            private Paint mPaint;// 畫筆  
            public DrawThread(SurfaceView sfv, Paint mPaint) {  
                this.sfv = sfv;  
                this.mPaint = mPaint;  
            }  
            public void run() {  
                while (isRecording) {  
                    ArrayList<short[]> buf = new ArrayList<short[]>();  
                    synchronized (inBuf) {  
                        if (inBuf.size() == 0)  
                            continue;  
                        buf = (ArrayList<short[]>) inBuf.clone();// 保存  
                        inBuf.clear();// 清除  
                    }  
                    for (int i = 0; i < buf.size(); i++) {  
                        short[] tmpBuf = buf.get(i);  
                        SimpleDraw(X_index, tmpBuf, rateY, baseLine);// 把緩沖區數據畫出來  
                        X_index = X_index + tmpBuf.length;  
                        if (X_index > sfv.getWidth()) {  
                            X_index = 0;  
                        }  
                    }  
                }  
            }  
            /** 
             * 繪制指定區域 
             *  
             * @param start 
             *            X軸開始的位置(全屏) 
             * @param buffer 
             *            緩沖區 
             * @param rate 
             *            Y軸數據縮小的比例 
             * @param baseLine 
             *            Y軸基線 
             */ 
            void SimpleDraw(int start, short[] buffer, int rate, int baseLine) {  
                if (start == 0)  
                    oldX = 0;  
                Canvas canvas = sfv.getHolder().lockCanvas(  
                        new Rect(start, 0, start + buffer.length, sfv.getHeight()));// 關鍵:獲取畫布  
                canvas.drawColor(Color.BLACK);// 清除背景  
                int y;  
                for (int i = 0; i < buffer.length; i++) {// 有多少畫多少  
                    int x = i + start;  
                    y = buffer[i] / rate + baseLine;// 調節縮小比例,調節基準線  
                    canvas.drawLine(oldX, oldY, x, y, mPaint);  
                    oldX = x;  
                    oldY = y;  
                }  
                sfv.getHolder().unlockCanvasAndPost(canvas);// 解鎖畫布,提交畫好的圖像  
            }  
        }  

    package com.testOscilloscope;
    import java.util.ArrayList;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.media.AudioRecord;
    import android.view.SurfaceView;
    public class ClsOscilloscope {
     private ArrayList<short[]> inBuf = new ArrayList<short[]>();
     private boolean isRecording = false;// 線程控制標記
     /**
      * X軸縮小的比例
      */
     public int rateX = 4;
     /**
      * Y軸縮小的比例
      */
     public int rateY = 4;
     /**
      * Y軸基線
      */
     public int baseLine = 0;
     /**
      * 初始化
      */
     public void initOscilloscope(int rateX, int rateY, int baseLine) {
      this.rateX = rateX;
      this.rateY = rateY;
      this.baseLine = baseLine;
     }
     /**
      * 開始
      *
      * @param recBufSize
      *            AudioRecord的MinBufferSize
      */
     public void Start(AudioRecord audioRecord, int recBufSize, SurfaceView sfv,
       Paint mPaint) {
      isRecording = true;
      new RecordThread(audioRecord, recBufSize).start();// 開始錄制線程
      new DrawThread(sfv, mPaint).start();// 開始繪制線程
     }
     /**
      * 停止
      */
     public void Stop() {
      isRecording = false;
      inBuf.clear();// 清除
     }
     /**
      * 負責從MIC保存數據到inBuf
      *
      * @author GV
      *
      */
     class RecordThread extends Thread {
      private int recBufSize;
      private AudioRecord audioRecord;
      public RecordThread(AudioRecord audioRecord, int recBufSize) {
       this.audioRecord = audioRecord;
       this.recBufSize = recBufSize;
      }
      public void run() {
       try {
        short[] buffer = new short[recBufSize];
        audioRecord.startRecording();// 開始錄制
        while (isRecording) {
         // 從MIC保存數據到緩沖區
         int bufferReadResult = audioRecord.read(buffer, 0,
           recBufSize);
         short[] tmpBuf = new short[bufferReadResult / rateX];
         for (int i = 0, ii = 0; i < tmpBuf.length; i++, ii = i
           * rateX) {
          tmpBuf[i] = buffer[ii];
         }
         synchronized (inBuf) {//
          inBuf.add(tmpBuf);// 添加數據
         }
        }
        audioRecord.stop();
       } catch (Throwable t) {
       }
      }
     };
     /**
      * 負責繪制inBuf中的數據
      *
      * @author GV
      *
      */
     class DrawThread extends Thread {
      private int oldX = 0;// 上次繪制的X坐標
      private int oldY = 0;// 上次繪制的Y坐標
      private SurfaceView sfv;// 畫板
      private int X_index = 0;// 當前畫圖所在屏幕X軸的坐標
      private Paint mPaint;// 畫筆
      public DrawThread(SurfaceView sfv, Paint mPaint) {
       this.sfv = sfv;
       this.mPaint = mPaint;
      }
      public void run() {
       while (isRecording) {
        ArrayList<short[]> buf = new ArrayList<short[]>();
        synchronized (inBuf) {
         if (inBuf.size() == 0)
          continue;
         buf = (ArrayList<short[]>) inBuf.clone();// 保存
         inBuf.clear();// 清除
        }
        for (int i = 0; i < buf.size(); i++) {
         short[] tmpBuf = buf.get(i);
         SimpleDraw(X_index, tmpBuf, rateY, baseLine);// 把緩沖區數據畫出來
         X_index = X_index + tmpBuf.length;
         if (X_index > sfv.getWidth()) {
          X_index = 0;
         }
        }
       }
      }


      /**
       * 繪制指定區域
       *
       * @param start
       *            X軸開始的位置(全屏)
       * @param buffer
       *            緩沖區
       * @param rate
       *            Y軸數據縮小的比例
       * @param baseLine
       *            Y軸基線
       */
      void SimpleDraw(int start, short[] buffer, int rate, int baseLine) {
       if (start == 0)
        oldX = 0;
       Canvas canvas = sfv.getHolder().lockCanvas(
         new Rect(start, 0, start + buffer.length, sfv.getHeight()));// 關鍵:獲取畫布
       canvas.drawColor(Color.BLACK);// 清除背景
       int y;
       for (int i = 0; i < buffer.length; i++) {// 有多少畫多少
        int x = i + start;
        y = buffer[i] / rate + baseLine;// 調節縮小比例,調節基準線
        canvas.drawLine(oldX, oldY, x, y, mPaint);
        oldX = x;
        oldY = y;
       }
       sfv.getHolder().unlockCanvasAndPost(canvas);// 解鎖畫布,提交畫好的圖像
      }
     }
    }
     

    testOscilloscope.java是主程序,控制UI和ClsOscilloscope,代碼如下:

    view plaincopy to clipboardprint?
    package com.testOscilloscope;  
    import android.app.Activity;  
    import android.graphics.Color;  
    import android.graphics.Paint;  
    import android.media.AudioFormat;  
    import android.media.AudioRecord;  
    import android.media.MediaRecorder;  
    import android.os.Bundle;  
    import android.view.MotionEvent;  
    import android.view.SurfaceView;  
    import android.view.View;  
    import android.view.View.OnTouchListener;  
    import android.widget.Button;  
    import android.widget.ZoomControls;  
    public class testOscilloscope extends Activity {  
        /** Called when the activity is first created. */ 
        Button btnStart,btnExit;  
        SurfaceView sfv;  
        ZoomControls zctlX,zctlY;  
          
        ClsOscilloscope clsOscilloscope=new ClsOscilloscope();  
          
        static final int frequency = 8000;//分辨率  
        static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
        static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
        static final int xMax = 16;//X軸縮小比例最大值,X軸數據量巨大,容易產生刷新延時  
        static final int xMin = 8;//X軸縮小比例最小值  
        static final int yMax = 10;//Y軸縮小比例最大值  
        static final int yMin = 1;//Y軸縮小比例最小值  
          
        int recBufSize;//錄音最小buffer大小  
        AudioRecord audioRecord;  
        Paint mPaint;  
        @Override 
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            //錄音組件  
            recBufSize = AudioRecord.getMinBufferSize(frequency,  
                    channelConfiguration, audioEncoding);  
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,  
                    channelConfiguration, audioEncoding, recBufSize);  
            //按鍵  
            btnStart = (Button) this.findViewById(R.id.btnStart);  
            btnStart.setOnClickListener(new ClickEvent());  
            btnExit = (Button) this.findViewById(R.id.btnExit);  
            btnExit.setOnClickListener(new ClickEvent());  
            //畫板和畫筆  
            sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);   
            sfv.setOnTouchListener(new TouchEvent());  
            mPaint = new Paint();    
            mPaint.setColor(Color.GREEN);// 畫筆為綠色    
            mPaint.setStrokeWidth(1);// 設置畫筆粗細   
            //示波器類庫  
            clsOscilloscope.initOscilloscope(xMax/2, yMax/2, sfv.getHeight()/2);  
              
            //縮放控件,X軸的數據縮小的比率高些  
            zctlX = (ZoomControls)this.findViewById(R.id.zctlX);  
            zctlX.setOnZoomInClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateX>xMin)  
                        clsOscilloscope.rateX--;  
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
            zctlX.setOnZoomOutClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateX<xMax)  
                        clsOscilloscope.rateX++;      
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
            zctlY = (ZoomControls)this.findViewById(R.id.zctlY);  
            zctlY.setOnZoomInClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateY>yMin)  
                        clsOscilloscope.rateY--;  
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
              
            zctlY.setOnZoomOutClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateY<yMax)  
                        clsOscilloscope.rateY++;      
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
        }  
        @Override 
        protected void onDestroy() {  
            super.onDestroy();  
            android.os.Process.killProcess(android.os.Process.myPid());  
        }  
          
        /** 
         * 按鍵事件處理 
         * @author GV 
         * 
         */ 
        class ClickEvent implements View.OnClickListener {  
            @Override 
            public void onClick(View v) {  
                if (v == btnStart) {  
                    clsOscilloscope.baseLine=sfv.getHeight()/2;  
                    clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);  
                } else if (v == btnExit) {  
                    clsOscilloscope.Stop();  
                }  
            }  
        }  
        /** 
         * 觸摸屏動態設置波形圖基線 
         * @author GV 
         * 
         */ 
        class TouchEvent implements OnTouchListener{  
            @Override 
            public boolean onTouch(View v, MotionEvent event) {  
                clsOscilloscope.baseLine=(int)event.getY();  
                return true;  
            }  
              
        }  

    (審核編輯: 智匯小新)

    聲明:除特別說明之外,新聞內容及圖片均來自網絡及各大主流媒體。版權歸原作者所有。如認為內容侵權,請聯系我們刪除。

    主站蜘蛛池模板: 徐州电动垃圾车|三轮快速保洁车|电动高压冲洗车|江苏大卫王环保科技有限公司 | 湖北大洋塑胶有限公司|AGR|PPR|RTP|HDPE|e-PSP钢塑复合压力管道生产厂家 | 领先的一站式_专利申请代理知识产权服务平台_乐知网 | 首页-青特集团官方网站 | 永磁变频空压机-无油空压机-螺杆式空压机热能回收-空压机配套-空压机合同能源管理-维修保养-北京斯特兰压缩机有限公司 | 油气回收设备厂家_加油站/化工厂油气回收装置解决方案-金辉环保 油漆颜料砂磨机,油墨水砂磨机,水性涂料砂磨机-常州市奥能达机械设备有限公司 | 云德律师事务所_全国律师服务咨询服务企业 | 陶瓷靶材_氧化铌靶材_合金靶材_专注河北氧化铌靶材批发-河北东同光电科技有限公司 | 实验室冷水机-冷却循环水系统-深圳市达沃西制冷设备厂 | 湖南净声源环保科技有限公司是一家专业从事噪声治理和建筑声学设计生态环境综合治理服务的企业,专业从事株洲电梯隔音治理,湘潭中央空调降噪处理,衡阳邵阳冷却塔噪音治理,岳阳常德大型风机噪声隔音降噪,张家界空压机噪声治理,益阳配电房变压器噪声治理,专业郴州永州工厂企业车间噪声治理,怀化娄底专业机械设备减振降治理,武汉噪音治理隔音降噪公司,孝感噪音治理,立式球磨机的噪声控制,专业隔音降噪公司,、以及各类机械动力设备减振降噪噪声治理的公司,同时为客户提供咨询与解决方案 | 无线对讲系统-海能达对讲机-广州中达慧通科技有限公司 | 豪美陶瓷|陶瓷十大品牌|佛山陶瓷放心消费品牌 | 蒸汽流量计_涡轮流量计_涡街流量计_雷达液位计_污水流量计_分体式_大口径工业流量计-江苏长顺仪表 | 潍坊沃林机械设备有限公司-牵引式风送果园打药机,悬挂式风送果园喷雾机,自走式果树喷药机,车载式风送远程喷雾机-潍坊沃林机械设备有限公司-牵引式风送果园打药机,悬挂式风送果园喷雾机,自走式果树喷药机,车载式风送远程喷雾机 潍坊网络推广,临沂360推广,东营360推广,枣庄360推广,潍坊网站建设,潍坊网络公司,潍坊360搜索,潍坊APP开发,潍坊360推广,潍坊360代理,潍坊点睛网络科技有限公司 | 深圳展厅设计_产业园区展馆设计_展馆设计公司_健康产业展馆设计_展厅设计哪家好_华竣国际 | 景县泉兴永塔业有限公司-广播电视塔、通信塔、电力塔、交通设施、监控杆塔、气象塔、森林防火瞭望塔、避雷塔、烟筒塔、训练塔 | 浙江创洁卫生消杀有限公司-浙江杀虫公司,温州消杀公司,温州灭鼠公司,灭蟑螂,灭蚊蝇,灭跳蚤,灭书虱,灭臭虫,灭螨虫,白蚁防治,房间消毒除味等专业服务 | 金酱酒_金酱酒代理加盟招商_OEM贴牌企业定制! – 金酱酒代理加盟!茅台镇较早的酿酒烧坊,年产优质酱香白酒5000余吨,仁怀市十强白酒企业,主营主品:金酱酒、金酱陈香酒、酱香老酒等系列品牌产品 | 景德镇星瑞陶瓷有限公司--官网-景德镇星瑞陶瓷有限公司 | 实验升降炉-箱式管式炉- 台车真空炉-熔块旋转炉-推板隧道窑-洛阳鲁威窑炉有限公司 | 实验反应釜,高压反应釜,玻璃反应釜,不锈钢反应釜-烟台招远松岭化工设备有限公司 | 真空上料机_加料机_天津自动上料机_投料站_包装机加料_吸料机_粉体称重-天津市飞云粉体设备有限公司 | 亚洲一区日韩一区欧美一区a,中文字幕乱妇无码AV在线,欧美日韩免费在线观看,国产精品一区二区三区免费,日韩精品免费一线在线观看,日韩一本在线,国产呦精品一区二区三区下载,国产日韩精品一区二区在线观看,欧美日韩高清一区二区三区,日韩在线免费观看视频,欧美日韩一区在线观看 | 无锡新源润不锈钢官网|304不锈钢平板|316L冷轧宽幅|2米卷分条开平 | 组合包装箱,折叠包装箱,烟台木箱,烟台包装箱-烟台顺达包装有限责任公司 | 上海机械加工-机械加工-精密机械加工-上海欧野精工机械有限公司 上海慧泰仪器制造有限公司_一体型马弗炉-可控真空干燥箱-强光稳定性试验箱 | 正拓夏令营官网-中小学生军事夏令营-研学军旅训练拓展夏令营 | 慢直播摄像头厂家,监控直播摄像机厂家,景区慢直播设备,rtmp推流直播摄像头,实时摄像头监控直播-监控慢直播厂家:专注监控慢直播系统解决方案 | 全自动包装机械设备_液体灌装机-迈驰日化包装流水线厂家 | 视频监控|安防监控|智能防火|智慧城市-浩海科技 | 绝缘纸板-3240环氧板-酚醛布板-FR4环氧板-沈阳友达绝缘材料有限公司 | 全彩LED显示屏厂家_室内户外电子屏-深圳华邦瀛光电有限公司 | 泰安铭德机械有限公司,有机肥设备,山东有机肥设备厂家,铭德机械 泰安华特玻璃钢有限公司|泰安玻璃钢|泰安华特玻璃钢 | 长焦监控摄像机-热成像夜视仪-激光云台-深圳红阳信息科技有限公司 | 济南手板_山东快速成型-山东嘉瑞杰机械科技有限公司 | 模型公司|沙盘公司|优选杭州景文模型设计有限公司 | 紫外线光疗仪|白癜风光疗仪|牛皮癣治疗仪|308纳米led|SIGMA|上海希格玛高技术有限公司 | 长沙广告设计公司|长沙广告制作|湖南户外广告制作|商业美陈就找湖南盛翔文化传媒有限公司老品牌高品质 | 上海前 傲信息技术有限公司-企业信息化建设及品牌推广服务商 | 全自动拆包机,自动拆包机,全自动逐层拆包机,全自动吨袋拆包机,吨袋拆包机,管链输送机,气流分级机 | 酒店设计_建筑设计_室内装修装饰-北极点酒店设计公司 |