DSP 2812: 使用C++实现的SCI主动站程序框架
来源:互联网 发布:origin8.5软件下载 编辑:程序博客网 时间:2024/05/17 01:05
控制器与外界通讯,一般都会使用一些约定的通讯协议,或者使用类似于linux控制台的字符终端交互。
大体上有两种通讯模式。一种是接收上位机之类的主机的命令,并执行和输出命令的执行结果或状态。在这种被动模式,开发板称为从动站;另外一种是定时发送命令给其他控制板或者仪表,读取或者控制其他设备。在这种主动模式,开发板被称为主动站。
我们创建了这两张模式下的程序框架。
这里介绍的是做为主动站的程序框架。
应用程序的编写
首先展示一下应用程序中是如何使用这个驱动的:
第一步初始化串口设备
scia().setBps(9600,board.clock());
我们这里使用的SCIA,设置通讯速率是9600.其他参数使用默认值。
第二步定义Scia主站类对象,并设置收发缓冲区:
unsigned char sciRxBuf[256];unsigned char sciTxBuf[256];NDm::NApp::NF281x::CSciAMaster& sciaMaster = NDm::NApp::NF281x::CSciAMaster::ins();sciaMaster.setRxBuf(sciRxBuf,256);sciaMaster.setTxBuf(sciTxBuf,256);sciaMaster.reset();
第三步在应用程序中实现报文处理的业务程序。
基本就是这样的循环:发送数据,然后接收数据,处理数据。
我的例子程序使用调试助手,接收DSP发来的start后,就发数据,然后DSP回复发送的数据,再发数据,再回复这样的循环。
unsigned char buf[10] = "start\n";int num = 6;sciaMaster.send(buf,num);while( true ){num = sciaMaster.recv(buf,10);if( num>0 ){sciaMaster.send(buf,num);}}
驱动程序的设计
驱动程序时设计一个基类,然后为各串口实现子类。在子类中设定中断向量和相应的处理串口类。
基类的设计
namespace NF281x {/** * SCI主模块驱动 * 由作为主动站的程序调用本类接口。 */class CSciMaster {public:typedef TRingBuf<unsigned char,unsigned int,unsigned int> CRingBuf;typedef CRingBuf::CRingPos CRingPos;public:CSciMaster( NDm::NHw::NF281x::CSci& sci );
private:CRingBuf m_rx;CRingPos m_rxPos;CRingBuf m_tx;CRingPos m_txPos;NDm::NHw::NF281x::CSci& m_sci;NDm::NApp::NF281x::CPieCtl& m_pie;};} /* namespace NF281x */
这个类使用了两个循环缓冲区,用于缓存接收到的数据和要发送的数据。
定义了简单使用的接口函数
void reset();bool isError()const;inline NDm::NHw::NF281x::CSci& sci(){return m_sci;}inline const NDm::NHw::NF281x::CSci& sci()const{return m_sci;}inline void setTxBuf( unsigned char* buf,const unsigned int& size ){m_tx.setBuf(buf,size);}inline void setRxBuf( unsigned char* buf,const unsigned int& size ){m_rx.setBuf(buf,size);}inline bool ifTxEmpty()const{return m_tx.getPos()==m_txPos;}inline bool ifRxEmpty()const{return m_rx.getPos()==m_rxPos;}int send( const unsigned char* buf,const int& size );int recv( unsigned char* buf,const int& size );
应用程序主要使用的函数就是send和recv函数。
因为驱动程序自带缓冲区,所以应用程序调用收发函数后,可以立即返回去处理其他业务,而不用等到串口数据发送完成。
/** * 中断处理函数 * 这些函数应该在中断函数中被调用执行 * 用户程序应该执行PIE级别的ACK操作 */void irsRx();void irsTx();inline NDm::NHw::NF281x::CPie& pie(){return m_pie;}
真正的在SCI设备上收发数据在irsRx()和irsTx()中实现。这两个函数由中断调用。
这块可以详细看看收发函数是如何实现的。
void CSciMaster::irsRx(){unsigned char buf[16];unsigned int size;if( m_sci.isInt_rxFf() ){// 接收中断,将接收到的数据保存到缓存中size = m_sci.rx(buf,16);if( size>0 )m_rx.push(buf,size);m_sci.clrInt_rxFf();}else{reset();}}
可以看出来,接收中断中,只是将RXFIFO中的数据转移到接收的循环缓冲区中,并清除接收中断标志。
而对于发送的过程可能要复杂一些。
因为发送数据是由中断之外触发的。
int CSciMaster::send( const unsigned char* buf,const int& size ){int rt = m_tx.getSize() - m_tx.getLen(m_txPos);if( rt>size )rt = size;if( rt<=0 )return 0;m_tx.push(buf,rt);m_sci.disInt_txFf();// 禁用发送中断startTx();return rt;}
发送函数将要发送的数据存入发送缓冲区中。在这个过程中,如果有发送中断到来,是不会影响send函数的正确性的,因为发送缓冲区,使用了两个pos对象,一个是写,一个是读。
但是真要发送数据时,是必须要禁止发送中断的。然后将缓冲区中的数据写到TXFIFO中,这个过程由startTx()函数实现。
为什么要有startTx()函数,因为这个过程在发送中断中也使用了。
void CSciMaster::irsTx(){startTx();// 如果队列为空,则停止中断if( ifTxEmpty() )m_sci.disInt_txFf();}
startTx()函数做了什么?
void CSciMaster::startTx(){unsigned char buf[16];unsigned int size;size = m_tx.getData(buf,16,m_txPos);if( size>0 ){size = m_sci.tx(buf,size);m_txPos += size;}// 清除中断标志m_sci.clrInt_txFf();// 如果队列为空,则停止中断if( ifTxEmpty() )m_sci.disInt_txFf();elsem_sci.enInt_txFf();}
这样的话,我将recv()函数的实现也展示出来:
int CSciMaster::recv( unsigned char* buf,const int& size ){int rt = m_rx.getLen(m_rxPos);if( rt>size )rt = size;if( rt<=0 )return 0;m_rx.getDataAndMovePos(buf,rt,m_rxPos);return rt;}
这样的话,这个驱动就算是完整了。
其实这样的程序要考虑清楚各种并非事件之间的关系,成员变量是否会受影响,是否会影响程序的正确性,也不是一件容易的事情。
还好,这块的代码经过测试和使用,是没问题的。
其实Ti的实时操作系统SYSBIOS中的DEV模型也是非常好的框架,我在28335平台上就是实现了一个DEV的驱动。
子类的实现
以Scia为例
namespace NF281x {class CSciAMaster:public CSciMaster{CSciAMaster();public:static CSciAMaster& ins();};
在其构造函数中需要对其进行特殊化处理
CSciAMaster::CSciAMaster():CSciMaster(NDm::NApp::NF281x::CSciaCtl::ins()){CCpu::dint();pie().setIrs_rxAInt(irsDm281xSciAMasterRx);pie().setIrs_txAInt(irsDm281xSciAMasterTx);CCpu::eint();CCpu::ertm();}CSciAMaster& CSciAMaster::ins(){static CSciAMaster i;return i;}
可以看出,还需要两个中断函数进行封装
extern "C" interrupt void irsDm281xSciAMasterRx(){CSciAMaster& sci = CSciAMaster::ins();sci.irsRx();sci.pie().ack_rxAInt();}extern "C" interrupt void irsDm281xSciAMasterTx(){CSciAMaster& sci = CSciAMaster::ins();sci.irsTx();sci.pie().ack_txAInt();}
中断函数的处理也比较简单,只需要将执行权传递给相应的中断处理成员函数即可。
- DSP 2812: 使用C++实现的SCI主动站程序框架
- DSP 2812: 使用C++实现的SCI从动站程序框架
- DSP 2812: 使用C++封装SCI
- 使用C/C++语言编写基于DSP程序的注意事项
- 【28系列DSP小结-3】通过SCI更新Flash程序
- 使用C语言操作DSP的寄存器
- Android程序主动点亮&解锁屏幕的实现
- Android程序主动点亮&解锁屏幕的实现
- DSP—2812、28335串行通信接口SCI
- 编写一个以C 语言为基础的DSP程序
- 编写一个以C 语言为基础的DSP程序
- DSP 实现模式识别小程序
- DSP多目标板程序下载方案的实现
- 在Ti的DSP程序中使用C++编程
- AlertDialog的第一次主动使用
- 借助移动飞信及网友吕昆的主动防御大师实现脱离.net框架
- C程序的实现
- C程序:使用 googletest 测试框架
- Cannot proceed with delivery: an existing transporter instance is currently uploading this package
- java----会动的方块
- mysql分表和表分区详解
- 几个容器
- 寒假刷题—栈和队列
- DSP 2812: 使用C++实现的SCI主动站程序框架
- 自动查询友链(普通链接也行)机器人
- [leetcode 318]Maximum Product of Word Lengths--判断两个字符串是否有相同的字符
- mysql索引总结
- Android开发之蓝牙详解(三)
- innodb_flush_log_at_trx_commit
- 按钮也能随单机变化(ImageButton选择特效)
- socket.io搭建分布式web推送服务器
- 给bootstrap-treeview增加点击事件,单击菜单也能展开和折叠