OpenGL和pcDuino搭建数字示波器

pc朵拉 发布于 2014/01/02 10:56
阅读 976
收藏 9

一:前言
看到很多人用Arduino、AVR做示波器,感觉很好玩,于是有人问pcDuino能不能做到呢?现在我们就用pcDuino来搭建示波器。

二:硬件清单
1.pcDuino一块;
2.杜邦线若干。

三:软件环境

1、pcDuino板载ubuntu
2、GCC 4.6
3、QT 4.8.5:http://qt-project.org/downloads
4、OpenGL:qt library自带
5、Arduino SDK(c_enviroment):https://github.com/pcduino/c_enviroment

照例先来捋一下思路,由于手头没有LCD模块,只能用显示器来充当示波器的屏幕了(27寸的示波器)。因为涉及到绘图,这里我使用OpenGL作为绘图工具。
实现原理很简单,通过pcDuino的analogRead函数读取信号源的电压变化,再用OpenGL构建一个坐标系,X轴代表时间,Y轴代表电压,持续绘制电压随时间的变化曲线,就得到我们需要的波形图像了。
QT和OpenGL的环境搭建请参照这个帖子在pcduino安装Qt,这里不再赘述
下面来看关键的GLWidget类代码:

#include “OpenGLwidget.h”
#include <QTimer>
#include <QKeyEvent>
#include <math.h>
#include <iostream>
#include <GL/glu.h>
#include <Arduino.h>
#include <Serial.h>
#include <wiring_private.h>

//出于性能考虑宏定义一些必要的常量计算
//step定义opengl的x轴步长,即把x轴的-1到1均分成窗口的宽度(像素)

#define STEP 2/800.0

//units定义了窗口的x轴有800个点

#define UNITS 800

//pcduino的12bits ADC范围是0~4095,正负各4095

#define ANALOGVALUE 4095*2

//定义opengl的顶点二维数组,800个点,每个点由两个float组成

GLfloat ver[UNITS][2];

//定义了x轴的起步值,-1.0即屏幕的最左边

GLfloat xstep = -1.0;

//openglwidget的构造器,设置了窗口大小、窗口标题和更新opengl画布的signal

OpenGLWidget::OpenGLWidget( QWidget* parent)
: QGLWidget(parent){
setGeometry( 0, 30, 800, 600 );
setWindowTitle(“Joker’s OpenGL Framework”);
t = new QTimer(this);
connect(t, SIGNAL(timeout()), this, SLOT(updateGL()));
t->start(0);
}

OpenGLWidget::~OpenGLWidget(){

}

//opengl的初始化函数

void OpenGLWidget::initializeGL(){
glShadeModel( GL_SMOOTH );

//设置颜色清空颜色,参数依次为RGBA,这里是一个我觉得比较帅气的灰色:)

glClearColor( 0.3, 0.3, 0.3, 1.0 );
glClearDepth( 1.0 );

//开启深度测试

glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

//开启opengl的反锯齿

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

}

//opengl的绘制函数,调用一次绘制一帧画面

void OpenGLWidget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

//清空颜色缓冲区

glClear(GL_COLOR_BUFFER_BIT);

//定义视点、原点和视角俯仰,由于这个例子只是2d绘图,可以忽略

gluLookAt (0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

//绘制两条直线代表x和y坐标轴

glBegin(GL_LINES);
glColor3f(0.5,0.5,0.5);

//这两个点可以画x轴

glVertex2f(-1.0f, 0.0f);
glVertex2f(1.0f, 0.0f);

//这两个点可以画y轴

glVertex2f(0.0f, -1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();

//绘制波形,用opengl的一个line strip定义,line strip其实就是一组点连成的线

glBegin(GL_LINE_STRIP);

//定义line strip的颜色,这里也是我认为比较帅气的绿色,哈哈

glColor3f(0.0,1.0,0.0);

//这个循环会通过analogRead取得电压数值,并把这个电压值转换成波形的y值,写入顶点数组

for(int i=0;i<UNITS;i++){
*(ver[i]) = xstep+=STEP;
*(ver[i]+1) = analogRead(5)/ANALOGVALUE;
glVertex2fv(ver[i]);
}
//std::cout<<analogRead(5)/4095.0*2<<std::endl;
glEnd();

//把顶点数据压入opengl的渲染管道,开始绘图

glFlush();
}

//窗口大小变化的回调函数

void OpenGLWidget::resizeGL( int width, int height ){
//std::cout<<width<<”*”<<height<<std::endl;
if ( height == 0 )
{
height = 1;
}
glViewport(0,0,(GLint)width,(GLint)height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
//gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}

//键盘按键的回调函数,按esc退出

void OpenGLWidget::keyPressEvent(QKeyEvent *e){
switch ( e->key() ){
case Qt::Key_Escape:
close();
}
}

编译运行,由于手头没有信号发生器,我就拿pcduino的PWM信号简单测试一下:

PWM输出的200Hz的方波,似乎很工整
7
我们加快频率到800,缩短占空比
9

实测只能支持2kHz左右的带宽,
看腻了方波工整的信号,我索性输入一个音频信号:

10



  Linksprite学习中心

加载中
返回顶部
顶部