tag 标签: 上位机

相关博文
  • 热度 3
    2023-5-18 22:40
    2542 次阅读|
    0 个评论
    上位机用来干什么 对于硬件工程师来说,上位机的主要作用就是提供一个良好的用户界面,方便用户使用硬件功能。另一个重要的优势是上位机的开发方式和开发环境相对下位机来说更加人性化。完善的IDE,丰富的硬件资源,大量的第三方库,使得做一个软件往往比做一个完善的硬件更容易。我们可以在计算机使用按钮,鼠标,键盘,下拉列表等作为输入信息的途径。用户的学习成本极低。同时也可以用文字输出框,波形显示控件,表格,声音作为信息的输出途径。信息获取直观,方便。本文将以我制作的模拟信号发生器上位机作为蓝本,介绍它的开发流程,难点,以及未来展望。 2. 介绍常用开发工具、语言。为什么用它 自身经历出发 我知道的常用上位机开发语言有Java、C++、C#、labview、python、html+js(electron)。很多的嵌入式开发工具就是Java开发的,比如stm32cubemx、RT-stdio、瑞萨电子的e2sIDE。Java常用来开发手机端的app。 C++常常配合QT来开发图形化界面,QT是一个跨平台的GUI框架,框架本身也是由C++编写的。纯的QT开发完全是用C++编写的,但是C++的学习难度大,对开发者要求较高。 C#也是上位机开发的常用语言,它以Vsstido作为开发IDE,所以比较适合Window下的软件开发,开发框架是WPF或者是Winform。说实话我最开始也考虑这个,问题在于我的电脑配置低,带不动IDE。 Labview是图形化编程的IDE,比较贴合硬件工程师的思维,所有的语法,功能,接口都以图形空间的方式展示,所见即所得。还是因为软件的体积过大,我不想用。 最后我选择的是Python+QT的方式进行上位机的开发,它可以说是解决我的需求的最优解。不需要庞大的IDE编写,类c的语法,强大的包管理器,丰富的代码案例。这里的QT的接口用python进行了封装,所以还是采用python的语法编写执行逻辑。 Electron实际上是把网页开发html+js+css的流程,封装一下用来开发客户端软件。由于和网页开发比较像,所以每个electron软件都内置一个chrome内核,故采用electron开发的软件都比较的大。Electron也有包管理npm为其提供第三方库拓展应用程序的功能。 Electron界面也比较美观,可移植性比较强。最重要的是我没学过网页开发。 总结一下,python作为一个胶水语言把GUI框架,信号处理,串口通信这些功能给融合到一起。虽然python应用程序打包后也很大,内置了python解释器,但是它第三方库多。 开发起来简单,快速。 3. 开发环境配置 下载python解释器 https://www.python.org/ftp/python/3.10.9/python-3.10.9-amd64.exe 或者,从清华大学开源软件镜像网站下载 安装好后如图 在cmd输入python 说明环境变量没有问题。 终端中输入exit()退出python程序。 Python的包管理器叫做pip,我们需要更新pip的版本以便支持最新的第三方库。 更新的命令python -m pip install --upgrade pip 接着换源,把网络上存放的包的网址替换成国内镜像。 阿里,腾讯,网易,清华….都可以。 地址 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple 换源的方式由临时换源和永久换源 临时换源的意思就是在下载第三方库时,手动指定下载的网站。 永久换源的意思是 建立一个配置文件存放下载第三方包的镜像地址 临时换源 pip install PyQt5 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com -i后面的参数是豆瓣源地址 永久换源 以Window为例 (1)windows环境下: 比如windows用户名是 admin 那么建立 admin主目录下的 pip子目录,在此pip子目录下建立pip的配置文件:pip.ini 在这c:\users\admin\pip\pip.ini # coding: GBK index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = https://pypi.tuna.tsinghua.edu.cn #清华大学:https://pypi.tuna.tsinghua.edu.cn/simple #阿里云:http://mirrors.aliyun.com/pypi/simple/ 换源后。 下载开发所需的工具。 编辑器geany,pycharm,vscode…都行 第三方包: PyQT5:python下的QT库,可以使用Qdesigner工具拖拽设计界面。 使用信号与槽功能设计交互事件。 Serial:串口通信库 Matplotlib:绘制图表 Pyqtgraph:绘制波形 PIL:图像处理 这个放在信号发生器的文章里写 Scipy:信号处理的库这个放在示波器的文章里写 pyuic5 -o ui_a.py serial.ui 把UI设计文件转换成py文件 4. 功能实现 事件响应 QT的事件响应通过信号与槽完成。按钮,菜单选项,滑块,文本框,下拉列表等在出现特定操作时,会发出信号,这个信号会触发其绑定的槽函数。槽函数会处理该信号要对应的操作。 类似于中断和中断服务函数。 不过在实现具体的事件响应前,应该指定相关控件的信号。比如按钮有单击信号,按下信号等。如图 例如 self.send=self.pushButton_2#获取按钮控件对象 def send_handl(self):#自定义槽函数send_handl 处理具体的按下操作,比如发送数据 self.send.clicked.connect(self.send_handl)#把按钮控件按下信号绑定到槽函数send_handl() #按下按钮执行send_handl函数 通信 我使用的是串口通信,python中通过serial库实现串口通信。 self.uart =serial.Serial(port, 9600)#串口对象构造参数 端口号(字符串),波特率(整型) self.uart.readline()#串口读取函数 self.uart.write(data.encode())#串口写入函数 data.encode()#表示对发送的信息进行编码,编码为utf-8 data.decode()#表示对接收的信息解码 为了保证能够及时发送和接收,这里有两种解决方案。1.使用定时器周期性的判断读取缓存区是否有数据,并把数据显示出来。2.使用多线程,把读取数据的任务单独放一个线程中,提高响应速度。 显示 波形 显示波形用的是Pyqtgraph,下位机发送的数据是一连串的数字。Value1:value2:…..等为了保证及时接收串口数据,使用PYQT里的Qtimer类创建了一个定时器,每隔20ms读取一次串口缓冲区的内容。并把内容记录在字符串data中,把data按照分隔符”:”的拆分,拆分成字符串数组x ,判断x的长度。如果x的长度不等于1,则说明缓冲区里面有内容。把字符串数组里每个元素转换成数值并保存在队列里。创建另一个定时器,用于界面绘制,定时器每个100ms读取一次队列,每次读取256个元素,把元素内容存入数组中,使用PyQtgraph库读取数组绘制图形 self.timer.timeout.connect(self.update)定时更新数据 self.timer.start(50) def init(self): win = pg.GraphicsLayoutWidget() win.setBackground("w") self.plot = self.widget.addPlot() self.plot.setMouseEnabled(x=False, y=False)#禁止鼠标拖动 self.plot.showAxes(True, showValues=(True, True, True, True), size=20)#显示坐标轴 vb = self.plot.getViewBox() vb.setBackgroundColor('w')#设置画布背景 self.curve = self.plot.plot(pen='black') win.show() def update(self):#更新数据 # a=range(0,1000,1) if(q.full()): #print("ok") for i in range(0, 256, 1): x=str(q.get()) try: a =int(re.sub("\D","",x)) except ValueError: print(a ) self.curve.setData(a)#把数据填入图表中 self.curve.setPos(self.ptr, 0) self.ptr += 1 5 . 项目案例 做一个简易的串口助手 点击这里创建一个主界面。 界面分成三部分第一部分控件区,提供按钮、列表、文本框控件,布局。 第二部分界面设计区,可以把控件拖拽到此区域。 第三部分,对象查看器,通过树状图展示了从视图到空间的关系。下方的数学编辑器可以编辑设计区的任何对象的属性。例如,位置,是否可见… 这里用到了button,list,label,textview控件。 在Qdesiger内可以设置控件发出的信号类型,但是一般不在这里设置。不过我们可以通过在这的信号与槽工具看看,相关的控件有哪些信号。 左击选中一个控件,拖拽出一条线再松手。 设计好后保存成xxx.ui文件 使用pyuic5 -o ui_a.py xxx.ui把ui文件转换成py文件。 也可使用vscode插件,自行百度。 接下来需要在主文件导入界面文件。 在此之前需要导入pyqt5的一些库。 之后附上代码这里就不加了。 from ui_a import Ui_MainWindow#导入ui转py文件 class MyWindow(QtWidgets.QMainWindow,Ui_MainWindow):#继承父类QWidget 这个MyWindow就是我们设计功能的主类,所以需要继承PyQT和MainWindow类。以便操作他们派生的对象。 在MyWindow构造函数中,初始化父类对象和界面组件对象。 在def ini_ui(self):初始化控件 self.com=self.comboBox获取控件对象 把控件的信号绑定到槽函数comfun上, self.com.activated.connect(self.comfun) 编写槽函数 def comfun(self): global ser, serialPort serialPort=self.com.currentText()#获取当前的串口号 print(serialPort) ser.port=serialPort#设置串口对象的串口号 其他控件都差不多 发送槽函数 def sendhand(self): global serialPort, ser if self.pushButton.text() == '断开'and serialPort != None: send_str=self.textEdit.toPlainText() ser.write(send_str.encode('utf-8')) 定时器定时监控接收缓冲区 def time_out(self): global ser, timer_value data = ser.read_all() txt=str(data.decode()) if (len(txt)!=0): self.textBrowser.append(txt) self.timer.start(timer_value) 要在打开串口后,开启定时器,并且在回调函数执行末尾开启定时器。 重复执行回调函数 app=QApplication(sys.argv) timer_value=100#间隔100ms读一次串口 baudRate = 115200 ser=serial.Serial(timeout=0.5) ############ com_list=get_com_list() if com_list!= #默认为第一个端口 else: serialPort = None w.show_dialog(str='请先打开串口') ############ #开启图形化界面 w=MyWindow() w.show()#w-ui-show ui里有布局 #w.show_dialog("123456") #程序进行循环等待状态 app.exec() 6 . 其他资料 Python学习: https://www.educoder.net/paths/85 交互式python学习,适合有编程基础的。 PyQT学习: https://www.bilibili.com/video/BV15R4y1s7JD/?vd_source=9030595337abea343e2125e65d245d46 Pyqtgraph绘制波形教程:https://gitee.com/zsbyg/pyqtgraph_my_cookbook/tree/master 我会把我的学习时的代码打包,供其下载。
  • 热度 11
    2023-3-29 12:01
    2396 次阅读|
    2 个评论
    以前使用 VB 做串口上位机,现在试用 QT 来做,顺便学习一下,入个门。看看有多大区别。 QT 上编程用的是 C++ ,所以 Class (类)的概念(公有、私有、继承、多态、构造、析构、重载这些名词)一定要搞明白。 QT 专有的信号和槽的概念。 开发用的是开源的 QT Creator ,具体下载,安装方法可以上 B 站看看大牛们的讲解。界面和使用方法,新建一个工程的方法,同样也可以看 B 站。 串口编程在 VB 中使用 comm 控件。在现在的这个 QT 版本中没有这个 comm 控件。不过可以使用两个类来完成同样的工作。 #include #include 在 MainWindow 的类定义中,私有成员增加 QSerialPort * serial ; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pbConnect_clicked(); void readData(); private: Ui::MainWindow *ui; QSerialPort *serial; // 私有QSerialPort成员 }; 记得一定要在 MainWindow 的构造函数中对 serial 进行实例化。也就是需要让 serial 指向的一个实体,用于操作。 serial = new QSerialPort ; //new 的作用相当于 malloc ,分配一个实体 QSerialPort 需要的内存。 严格的说,在析构函数中应该 delete serial ; 以释放内存。 第一次编程时,没有实例化 serial ,空指针操作 serial ,结果程序一运行就崩溃退出。 MainWindow :: MainWindow ( QWidget * parent ) : QMainWindow ( parent ) , ui ( new Ui :: MainWindow ) { ui setupUi ( this ); const auto infos = QSerialPortInfo :: availablePorts (); for ( const QSerialPortInfo & info : infos ){ ui cbCom addItem ( info . portName ()); } serial = new QSerialPort ; // 实例化 serial connect ( serial , & QSerialPort :: readyRead , this , & MainWindow :: readData ); } 在连接用的按键点击可以打开或关闭串口了。方法是判断按键上的文字。神奇的是,经常用的 strcmp 不存在,不过可以这样用: if ( ui pbConnect text () == QString ( " 连接 " )) 直接判断字符串相等,不比 strcmp 香么?判断字符串相等肯定还是得一个字节一个字节比较。我想这个 QString 类一定把 “ == ” 做了重载(新定义了 == 作为字符串比较的运算符)。 void MainWindow :: on_pbConnect_clicked () { if ( ui pbConnect text () == QString ( " 连接 " )){ serial setPortName ( ui cbCom currentText ()); serial setBaudRate ( QSerialPort :: Baud115200 ); serial setDataBits ( QSerialPort :: Data8 ); serial setStopBits ( QSerialPort :: OneStop ); serial setParity ( QSerialPort :: NoParity ); if (! serial open ( QIODevice :: ReadWrite )){ QMessageBox :: information ( this , " 错误提示 " , " 不能打开串口 " , QMessageBox :: Ok ); } else { ui cbCom setEnabled ( false ); ui pbConnect setText ( " 关闭 " ); } } else { serial close (); ui cbCom setEnabled ( true ); ui pbConnect setText ( " 连接 " ); } } 关于串口号的获取,在用 VB 时,用的是穷举法,捕获错误,非法的 COM 号会产生错误剔除 , 获得合法串口号。在 QT 里可以用 QSerialPortInfo 类,获取可用串口。这个 for 循环也很有意思。不是常规的 ;; 结构,感觉像是使用 : 对集合里的元素做一个遍历。可以在窗口构造函数中,或者其它地方把可用串口号送到 combox 里,方便选取。 const auto infos = QSerialPortInfo :: availablePorts (); for ( const QSerialPortInfo & info : infos ){ ui cbCom addItem ( info . portName ()); } 为了从串口获取数据,需要连接一个串口取数的槽函数。 connect ( serial , & QSerialPort :: readyRead , this , & MainWindow :: readData ); 当串口产生 readyRead 信号时,调用 readData 函数处理。而 readData ,当然需要定义到 private slots 里面。 class MainWindow : public QMainWindow { Q_OBJECT public : MainWindow ( QWidget * parent = nullptr ); ~ MainWindow (); private slots : void on_pbConnect_clicked (); void readData (); private : Ui :: MainWindow * ui ; QSerialPort * serial ; }; 每产生一次 readyRead , readData 就被执行,程序中直接把所有接收到的内容存放到 QString data 里面。对于格式化数据,先前可以用 sscanf 读取分别放到数据或字符串里。 QT 里面没有 sscanf , 感觉不爽是吧。 QStringList datlist = data . split ( "," , QString :: SkipEmptyParts ); 这个 split 一下就把字符串分好了,直接使用 datlist ); ui lcdNumber2 display ( datlist ); } 程序运行,结果满意。效率又提升了。 So easy! 好文赏现金!2023面包板社区原创奖励活动进行中: https://mbb.eet-china.com/forum/topic/125238_1_1.html
  • 热度 4
    2021-3-21 14:07
    17347 次阅读|
    1 个评论
    实战项目 -- 做一个舵机控制上位机
    实战项目旨在交流学习,项目相关资料请在 关注大鸟科创空间微信公众号后 回复项目关键字 ———“舵机控制” 以获取,欢迎在评论区交流意见。 简介:设计舵机控制的上位机和运行在舵机控制板中的下位机代码,实现联动控制舵机。 先展示效果: 项目开发环境: Visual Studio 2017/ Arduino IDE 开发语言: C#/C demo功能: 1:设计上位机,使得用户在其界面拖动滑条,可以通过串口发送指令到单片机控制板 2:设计单片机控制板中的固件程序,接收上位机发过来的串口指令并解析,根据指令控制舵机运动 3:这里单片机控制板采用一块自己设计的arduino板,其他单片机板也可以,主要理解其通信原理。 PS:这个上位机设计在前期的博文中有介绍,详细设计过程可参考前期内容,下面上源码截图: 上位机部分源码截图: 还有下位机部分源码截图: 上位机要注意串口的设置, demo 设计的比较简单,仅仅实现了原理,在舵机控制方面,有很多玩法,包括将指定动作写入控制板内并保存在芯片 flash 中,实现重播;也可以在线编辑动作组;而舵机控制板还可以用 stm32 或者 51 等单片机设计电路和程序,这些内容将在后期陆续分享开源。 至此项目介绍完毕,本项目旨在开源,想要获取源码资料的朋友,关注大鸟科创空间微信公众号后,回复项目关键字 ———“舵机控制” ,即可获得源码资料下载链接。 微信扫描下方二维码,关注“大鸟科创空间”微信公众号
  • 热度 24
    2015-3-24 13:56
    1066 次阅读|
    0 个评论
      随着现代科学技术的发展和计算机技术的普及,高速数据采集系统已应用于越来越多的场合,如通信、雷达、生物医学、机器人、语音和图像处理等领域。本文介绍的数据采集处理系统采用CPLD控制ADS8364完成数据的A/D转换,转换后的数据预先存储到FIFO中,再经DSP进行前端的数字信号处理后,通过USB总线传给上位机,并在上位机上进行存储、显示和分析等。该系统完全可以满足信号采集处理对高精度及实时性的要求。   1 系统原理   数据采集处理系统主要由前端信号调理电路、ADC芯片ADS8364、CPLD芯片EPM3128A、DSP芯片TMS320F2812、USB芯片CY7C68013及其外围电路组成。系统原理框图如图l所示。   系统主要完成的任务为:DSP接收上位机通过USB总线发送的命令,完成系统工作参数的设置,并通过模拟地址/数据总线与CPLD进行通信,向CPLD发送控制命令;对外部的多路模拟量输入进行信号调理,在CPLD控制下进行单通道或多通道A/D转换,将采集到的数据存储在一片FIFO芯片中;当FIFO中存储的数据半满时,对DSP产生一个中断信号,DSP收到此中断信号 后,取出FIFO中的部分数据,进行前端数字信号处理,将处理完毕的数据通过USB总线传给上位机;上位机实现各种图形界面操作和后端信号处理,对所采集的信号进行分析。系统可对输入的多路模拟信号进行同步采样,这就使得采集到的数据不仅含有模拟信号的幅度特性,同时还保持不同模拟信号之间的相位差异;采样频率可以预置,以适应不同速率的采样要求。    2 系统硬件   系统硬件包括信号调理模块、A/D转换模块、DSP处理器模块、CPLD逻辑控制模块以及USB通信模块。    2.1 信号调理模块的设计   外部的多路模拟量输入信号往往是微弱的传感器信号,信号的幅值较小,为了方便且不失一般性,假定其幅值范围为O~25mV。ADS8364待转换的模拟输入电压范围应保持在AGND-0.3V和AVDD+O.3V之间。这里选用低功率变增益仪表放大器INAl29对模拟量输入信号进行调理放大,将其放大为0~5V之间。   INAl29是BURR-BROWM公司的一种小功率通用仪表放大器,具有优异的精度和很宽的带宽,在增益高达100时,带宽达200kHz。它可用单一外部电阻器调节其增益,调节范围为l~10000,其放大倍数计算公式为:   从而使放大输出电压在O~5V之间。信号调理模块原理图如图2所示。    2.2 A/D转换模块的设计   该模块采用了TI公司的高速、低功耗、六通道同步采样模/教转换器ADS8364,它采用+5V工作电压,其6个模拟输入通道分为三组(A,B和C),每组都有一个ADCs保持信号(HOLDA,HOLDB和HOLDC),用来启动各组的AID转换,6个通道可以进行同步并行采样和转换。ADS8364采用具有80dB共模抑制能力的全差分输入通道,将其REFin和REFout引脚接到一起,为差分电路提供2.5V的参考电压。这里模拟量采用单端输入,将-IN端接共模电压2.5V,+IN端接前端信号调理模块的输出。   ADS8364的时钟信号由外部提供,最高频率为5MHz,对应的采样频率是250kHz。这里由CPLD提供时钟信号,主要是考虑到CPLD可以灵活地改变时钟频率,进而改变系统的采样频率。A/D转换完成后产生转换结束信号EOC。将ADS8364的。BYTE引脚接低电平,使转换结果以16位的方式输出。地址/模式信号(A0,Al,A2)决定ADS8364的数据读取方式,可以选择的方式包括单通道、周期或FIFO模式。将ADD引脚置为高电平,使得读出的数据中包含转换通道信息。考虑到数据采集处理系统的采样频率一般较高,如果用DSP直接控制ADS8364的访问,将占用DSP较多的资源,同时对DSP的实时性要求也较高。因此在本系统设计中,用CPLD实现ADS8364的接口控制电路,并将转换结果存储在FIFO芯片中,用DSP实现FIFO芯片的输出接口。   DSP、CPLD、ADS8364及FIFO之间的接口设计如图3所示。    2.3 DSP处理器模块的设计   DSP主要负责与USB通信模块交换数据、以模拟地址/数据总线的方式与CPLD通信,实现对数据采集的控制,完成与FIFO芯片的输出接口以及对采样后的数据进行前端数字信号处理(FIR低通滤波)。这里选用TI公司的32位定点DSP TMS320F2812 (以下简称F2812),它采用1.8V的内核电压,具有3.3V的外围接口电压,最高频率150MHz,片内有18K字的RAM,128K字的高速Flash。 .        2.4 CPLD逻辑控制模块的设计   在该数据采集处理系统中,CPLD是一个重要的组成部分。由CPLD组成的逻辑控制模块接收DSP传送过来的动作命令,控制A/D转换模块进行数据采集,并提供对FIFO的接口时序,实现转换数据的存储。这里选用Altem公司的EPM3128A芯片,它共有128个宏单元,2500个可用门。   CPLD作为一个单独的控制执行结构.通过编写相应的Verilog HDL代码,即可生成相应的操作电路,实现对各种输入信号的锁存、判断和处理以及对各种命令信号的执行和输出信号的控制。    2.5 USB通信模块的设计   这里选用CYPRESS公司的EZ-USB FX2系列中的CY7C68013作为USB通信控制器芯片,它内含增强型8051微控制器,支持USB2.0传输协议,同时也向下兼容USBl.1规范。该芯片把USB2.0收发器、SIE(串行接口引擎)、增强型8051微控制器、I2C总线接口以及GPIF(通用可编程接口)集成于一体。CY7C68013提供了SlaveFIFO和GPIF两种接口模式,Slave FIFO模式是从机模式,外部控制器可以像对普通FI FO存储器一样对FX2的多层缓冲FIFO存储器进行读写;GPIF模式是主机模式,可以由软件设置读写的控制波形,灵活性很大。这里采用的是Slave FIFO模式。   3 系统软件设计   系统软件设计包括DSP程序设计、USB固件程序设计、USB驱动程序设计和上位机应用程序设计。    3.1 DSP程序设计   DSP编程的主要任务是初始化、管理板上的资源和实现前端数字信号处理的算法。这里以TI公司提供的功能强大的CCS(Code Composer Studio)为集成开发环境。系统上电复位后。首先完成F2812自身的初始化,包括配置RAM块,设置I/O模式、定时器模式、中断等;然后程序进人循环状态,等待USB及FIFO的中断。F2812主程序流程图如图4所示。   在F2812的程序存储器中存储常用的数字信号处理算法,F2812在收到上位机通过USB总线发送的控制信息后,在中断函数中选择某种处理算法,同时向CPLD发出动作命令,控制A/D转换模块完成信号的采集并将采集到的数据存入FIFO中。当FIFO中数据达到半满时,向F2812提出中断申请,F2812响应此中断,在中断函数中实现对部分采样数据的读取,在主循环程序中根据上位机选定的处理算法完成数据的前端处理,然后将数据打包,通过USB总线传输给上位机。对于常用的数字信号处理算法在DSP上的实现,这里不再赘述。   3.2 USB固件程序设计   固件负责辅助硬件让设备双向交换数据,其主要功能是:接收并处理USB驱动程序的请求及应用程序的控制指令。CYPRESS公司针对EZ-USB FX2系列芯片给出了一个Firmware库和Firmware框架(Frame Works),均采用Kei C5l开发。Firmware库提供了一些常量、数据结构、宏定义、函数来简化用户对芯片的使用。用户只需要在源程序中包含进fx2.h、fx2regs.h和fx2sdly.h,并且把Ezusb.1ib和UsBJmpTB.obj添加进项目即可。Firmware框架实现了初始化芯片、处理USB标准设备请求以及挂起状态下的电源管理等功能。该框架无需添加任何代码,将编译后产生的*.hex文件载入芯片就能与主机进行基本的USB通信,只是不能完成特定的任务。在本系统中,需要选择适当的传输方式,添加需要使用的端点(Endpoint),在框架预留的地方(如TD_Init()、TD_Poll()等函数中)添加初始化代码和完成特定功能的代码。   USB共有四种数据传输方式:控制传输、中断传输、块传输及同步传输,本系统中使用了控制传输和块传输。控制传输主要用来完成主机对设备的各种控制操作,即用来实现位于主机上的USB总线驱动程序以及编写的功能驱动程序对设备的各种控制操作;块传输主要用来完成主机和设备间的大批量数据传输以及对传输的数据进行错误检测(支持“错误重传”功能)。    3.3 USB驱动程序设计   CYPRESS FX2开发包中提供了一个通用的设备驱动程序Ezusb.sys,可用于基于EZ-USB FX2系列的芯片,能够完成基本的USB通信任务。本系统设计中,利用DDK对上述驱动程序进行了修改,将不常用的函数删除,同时添加了自己定义的函数。         3.4 上位机应用程序设计   上位机应用程序主要实现与数据采集处理系统间的USB通信、向系统发送控制命令以及接收系统传送过来的数据并进行存储、处理与显示。在Win32系统中,各个设备被抽象为文件,应用程序通过文件操作API函数实现与驱动程序中某个设备的通信。USB通信常用的API函数有;CreateFile(),WriteFile(),ReadFile(),DeviceloControl(),CloseFile()等。在应用程序中,只需将上述函数添加到相应的功能模块中便可完成应用程序对USB设备的打开、读、写等操作,从而实现两者的通信。采用LabVIEW语言实现USB通信及仪器界面,而对于后端的信号处理算法则在VC++环境下实现并生成动态链接库文件(*.d11),方便LabVIEW的调用。图5为上位机上层应用程序的流程图。   本文将TMS320F2812与ADS8364相结合,设计了一套数据采集处理系统。该系统采用uSB总线与上位机通信,充分发挥了USB2.O方便、快捷的优点;考虑到对实时性的要求,将某些特定的数字信号处理算法(如FIR滤波、快速FFT等)放到数据采集处理卡上由DSP快速完成。该系统采集精度高,速度快,并可同时采集多路信号。实践证明,该数据采集处理系统可适用于高精度、实时性信号的数据采集和处理,具有广泛的实用价值。
  • 热度 3
    2013-10-22 02:37
    3180 次阅读|
    1 个评论
    所谓的花里挑花,也即一直选型的——上位机软件开发,从VB到VC++,在到C++Builder,在到QT,再到LabView等等,最后选中了CVI(LabWindows/CVI),感觉良好,所以大家都懂得。因为是刚开始,所以好多知识点可能还做的不到位,望各位高手别拍砖,而是多多指教,先谢。 由于自己爱好和出书的缘故,必须的搞定上位机的开发,所以先来个2小时的成果,望能和大家共勉。                                            说明:界面有点丑,没夜月狼丑,望包涵哈! 先介绍一下,所谓下位机是MGMC-V1.0实验板,核心器件:单片机+LM75A温度传感器,实时采集当前温度,并通过串口打印到PC机上,最后结合自己编写的上位机软件,演示效果如上,说明此时温度也不高(18.125)啊。其实自己也想睡在被窝里,可是既然选择了这条路,没有退路,所以必须得搞起,呵呵。。。 最后来上整个上位机的源码,该源码自己当然能理解,也会写,但是还没真正吃透,因为才学了2个小时嘛,所以望理解,不过相信自己很快就能搞定,之后再给大家详细的注释和说明,若喜欢请等待,若不喜欢,请轻轻的走开,不要带走一点点“孤独”,也不要留下一丝丝“恶意”。 /* =============================================================== */   #include rs232.h #include ansi_c.h #include "sample5.h"   static int panelHandle; int ComSelect=0; int status; char info ; // 字符型数组,用于存放发送、接收的字符串   int CVIFUNC DimObject(int stat) //设置页面控件状态,stat=0表示串口关闭,1串口打开 {     SetCtrlAttribute(panelHandle,PANEL_COMSELECT,ATTR_DIMMED ,stat);     SetCtrlAttribute(panelHandle,PANEL_BTLSELECT,ATTR_DIMMED ,stat);     SetCtrlAttribute(panelHandle,PANEL_JYSELECT,ATTR_DIMMED ,stat);     SetCtrlAttribute(panelHandle,PANEL_LONGSELECT,ATTR_DIMMED ,stat);     SetCtrlAttribute(panelHandle,PANEL_STOPSELECT,ATTR_DIMMED ,stat);       SetCtrlAttribute(panelHandle,PANEL_OPEN_COM,ATTR_DIMMED ,stat);      SetCtrlAttribute(panelHandle,PANEL_CLOSE_COM,ATTR_DIMMED ,!stat);      SetCtrlAttribute(panelHandle,PANEL_SEND,ATTR_DIMMED ,!stat);      SetCtrlAttribute(panelHandle,PANEL_CLEARSEND,ATTR_DIMMED ,!stat);      SetCtrlAttribute(panelHandle,PANEL_RECIEVE,ATTR_DIMMED ,!stat);      SetCtrlAttribute(panelHandle,PANEL_CLEARRECIVE,ATTR_DIMMED ,!stat);      return 0; }   int main (int argc, char *argv ='\0';             SetCtrlVal(PANEL,PANEL_RECIVETEXT,info);             //SetActiveCtrl(PANEL,PANEL_RECIVETEXT); // 考虑中!         break;     }     return 0; }   int CVICALLBACK Quit (int panel, int control, int event,         void *callbackData, int eventData1, int eventData2) {     switch (event)     {         case EVENT_COMMIT:             if(ComSelect)             {                 CloseCom(ComSelect);                 ComSelect=0;                 DimObject(0);             }             QuitUserInterface (0);         break;     }     return 0; }   int CVICALLBACK ComOpen (int panel, int control, int event,         void *callbackData, int eventData1, int eventData2) {     int comValue,btlValue,jhValue,longValue,stopValue;     switch (event)     {         case EVENT_COMMIT:             GetCtrlVal(PANEL,PANEL_COMSELECT,comValue);     //选择串口             GetCtrlVal(PANEL,PANEL_BTLSELECT,btlValue);          //选择波特率             GetCtrlVal(PANEL,PANEL_JYSELECT,jhValue);              //选择奇偶校验             GetCtrlVal(PANEL,PANEL_LONGSELECT,longValue);  //选择数据位             GetCtrlVal(PANEL,PANEL_STOPSELECT,stopValue);   //选择停止位             //设置和打开串口             status=OpenComConfig(comValue,"",btlValue,jhValue,                 longValue,stopValue,512,512);             if(status!=0)             {                 MessagePopup("Error","config failed!");                 return 0;             }             SetCTSMode(comValue,LWRS_HWHANDSHAKE_OFF);             FlushInQ(comValue);             //清空输入和输出缓冲区             FlushOutQ(comValue);             ComSelect=comValue;             DimObject(1);             break;     }     return 0; }   int CVICALLBACK ComClose (int panel, int control, int event,         void *callbackData, int eventData1, int eventData2) {     switch (event)     {         case EVENT_COMMIT:             CloseCom(ComSelect);             ComSelect=0;             DimObject(0);             break;     }     return 0; }   int CVICALLBACK ClearTextBox (int panel, int control, int event,         void *callbackData, int eventData1, int eventData2) {     switch (event)     {         case EVENT_COMMIT:             if(control==PANEL_CLEARRECIVE)                 ResetTextBox(PANEL,PANEL_RECIVETEXT,"\0");//清空接收文本框              else                 ResetTextBox(PANEL,PANEL_SENDTEXT,"\0");//清空发送文本框                   break;     }     return 0; } 演示完毕,一点“滚蛋”和一把实验板电源开关,上位机软件、实验板、自己统统睡觉,因为时间不早了啊(午夜2:40),大家都累了,晚安、好梦。。。
相关资源