[资料分享] DSP 2812: 使用C++封装SCI

Aguilera   2017-7-23 18:47 楼主
使用SCI模块进行通信,是装置与外界的主要方式。比如与上位机通信,接入GPRS模块,接入485电度表,或者板间通信等等。

SCI的控制应该说还是比较简单的,但是也是非常灵活的。支持FIFO模式,支持测试模式,支持中断模式,而且还有各种通信参数的设置等。

DSP2812有两个SCI模块。其实DSP28335这样的片子的很多外设和2812是一样使用的,程序都是可以通用的。这里我们只对2812进行封装。


先定义一个基类:CSci,然后为SCI-A和SCI-B分别定义子类CScia,CScib.


基类定义如下:

namespace NF281x{

/**
* SCI基类
*/
class CSci{
public:
        CSci( volatile unsigned int& ccr,
                        volatile unsigned int& ctl1,
                        volatile unsigned int& ctl2,
                        volatile unsigned int& lbaud,
                        volatile unsigned int& hbaud,
                        volatile unsigned int& rxst,
                        volatile unsigned int& rxbuf,
                        volatile unsigned int& txbuf,
                        volatile unsigned int& fftx,
                        volatile unsigned int& ffrx,
                        volatile unsigned int& ffct);
private:
        volatile unsigned int& m_ccr;
        volatile unsigned int& m_ctl1;
        volatile unsigned int& m_ctl2;
        volatile unsigned int& m_lbaud;
        volatile unsigned int& m_hbaud;

        volatile unsigned int& m_rxst;
        volatile unsigned int& m_rxbuf;
        volatile unsigned int& m_txbuf;

        volatile unsigned int& m_fftx;
        volatile unsigned int& m_ffrx;
        volatile unsigned int& m_ffct;
};


一看基类的构造函数这么复杂,其实没关系,应用程序使用时没有这些的。
应用程序时不会直接使用基类的构造函数的,这在我们定义子类的时候传入相应的寄存器即可。

其实也说明了一点,SCI的使用还是有点复杂,不说难,也是容易出错的。所以,封装成简洁的接口是很有必要的。


看看子类的接口:

namespace NF281x{

class CScia:public CSci{
public:
        CScia();
};

}

namespace NF281x{
class CScib:public CSci{
public:
        CScib();
};
}
也就是说应用程序使用SCI-B对象时,只需要定义一个CScib的对象,而且构造时不需要任何参数。
接下来是通讯参数的相关接口

        /**
         * 获取停止位数
         * @return
         * - 0x00 1bit停止位
         * - 0x80 2bits停止位
         */
        inline unsigned int getStop()const{
                return NDm::getBit(m_ccr);
        }

        /**
         * 是否是1位停止位
         * @return
         */
        inline bool isStop_1()const{
                return getStop()==0;
        }

        /**
         * 是否是2位停止位
         * @return
         */
        inline bool isStop_2()const{
                return getStop()!=0;
        }

        /**
         * 设置停止位
         * @param st
         * @see getStop()
         */
        inline void setStop( const unsigned int& st ){
                if( st==0 )
                        setStop_1();
                else
                        setStop_2();
        }

        /**
         * 设置1位停止位
         */
        inline void setStop_1(){
                NDm::bitClr(m_ccr);
        }

        /**
         * 设置2位停止位
         */
        inline void setStop_2(){
                NDm::bitSet(m_ccr);
        }

        /**
         * 获取校验方式
         * @return
         * - 0x40: 奇校验
         * - 0x60: 偶校验
         * - 其他: 无校验
         */
        inline unsigned int getParity()const{
                return m_ccr & 0x60;        // bit 6-5
        }

        /**
         * 是否奇校验
         * @return
         */
        inline bool isParity_odd()const{
                return getParity()==0x40;
        }

        /**
         * 是否偶校验
         * @return
         */
        inline bool isParity_even()const{
                return getParity()==0x60;
        }

        /**
         * 是否无校验
         * @return
         */
        inline bool isParity_none()const{
                return (getParity())&0x20==0;
        }

        /**
         * 设置校验方式
         * @param p
         * @see getParity();
         */
        inline void setParity( const unsigned int& p ){
                if( p==0x60 )
                        setParity_even();
                else if( p==0x40 )
                        setParity_odd();
                else
                        setParity_none();
        }

        /**
         * 设置无校验
         */
        inline void setParity_none(){
                NDm::bitClr(m_ccr);
        }

        /**
         * 设置为偶校验
         */
        inline void setParity_even(){
                m_ccr |= 0x60;
        }

        /**
         * 设置为奇校验
         */
        inline void setParity_odd(){
                m_ccr = (m_ccr&0xDF) | 0x20;
        }

        /**
         * 获取字符长度
         * @return 0~7:1~8
         */
        inline unsigned int getChar()const{
                return m_ccr&0x07;        // bit 0~3
        }

        /**
         * 设置字符长度
         * @param len
         * @see getChar();
         */
        inline void setChar( const unsigned int& len ){
                m_ccr = (m_ccr&0xF8) | (len&0x07);
        }

        /****************  通信参数  **************/

        inline unsigned long getBps( const CClocking& clk )const{
                return clk.getClk_sci()/(( getBrr()+1 ) * 8);
        }

        inline void setBps( const unsigned long& bps,const CClocking& clk ){
                setBrr(clk.getClk_sci()/(8*bps) -1 );
        }

        void init( const unsigned int& ch=8,const unsigned int& stop=1,const unsigned int& parity=0 );
定义丰富的接口查看运行状态


       
        /**
         * 发送缓冲区可写
         * @return
         */
        inline bool isTxRdy()const{
                return NDm::isBitSet(m_ctl2);
        }

        /**
         * 发送线路空闲
         * @return
         */
        inline bool isTxEmpty()const{
                return NDm::isBitSet(m_ctl2);
        }

        /**
         * 接收缓冲区可读
         * @return
         */
        inline bool isRxRdy()const{
                return NDm::isBitSet(m_rxst);
        }

定义操作相关接口
inline bool isTxEn()const{
                return NDm::isBitSet(m_ctl1);
        }

        inline void enTx( const bool& en ){
                if( en )
                        enTx();
                else
                        disTx();
        }

        inline void enTx(){
                NDm::bitSet(m_ctl1);
        }

        inline void disTx(){
                NDm::bitClr(m_ctl1);
        }

        inline bool isRxEn()const{
                return NDm::isBitSet(m_ctl1);
        }

        inline void enRx( const bool& en ){
                if( en )
                        enRx();
                else
                        disRx();
        }

        inline void enRx(){
                NDm::bitSet(m_ctl1);
        }

        inline void disRx(){
                NDm::bitClr(m_ctl1);
        }

        inline void tx( const unsigned char& c ){
                m_txbuf = c;
        }

        inline void rx( unsigned char& c )const{
                c = m_rxbuf&0xFF;
        }

        /**
         * 复位模块状态机
         * 该操作不会修改参数
         * @param delay 处于复位时常
         */
        void reset(  const unsigned int& delay=100 );

定义错误检测的接口
        /**
         * 接收错误
         * 这是一个总的接收错误标志。
         * 一般程序测试错误,都应该测试该标志
         * 当有错误标志时,必须使用reset来进行复位。
         * @return
         */
        inline bool isRxErr()const{
                return NDm::isBitSet(m_rxst);
        }

        /**
         * 接收信号至少有10bit的低电平
         * @return
         */
        inline bool isRxErr_break()const{
                return NDm::isBitSet(m_rxst);
        }

        /**
         * 没有收到正确的停止位
         * @return
         */
        inline bool isRxErr_frame()const{
                return NDm::isBitSet(m_rxst);
        }

        /**
         * 校验没通过
         * @return
         */
        inline bool isRxErr_parity()const{
                return NDm::isBitSet(m_rxst);
        }

        /**
         * 程序或者DMA没有及时取走接收到的数据
         * @return
         */
        inline bool isRxErr_overrun()const{
                return NDm::isBitSet(m_rxst);
        }

        /**
         * FIFO顶层数据有帧错误
         * @note 只在FIFO模式下有效
         * @return
         */
        inline bool isFFErr_frame()const{
                return NDm::isBitSet(m_rxbuf);
        }

        /**
         * FIFO顶层数据有校验错误
         * @note 只在FIFO模式下有效
         * @return
         */
        inline bool isFFErr_parity()const{
                return NDm::isBitSet(m_rxbuf);
        }

定义中断相关的接口

        /**
         * 接收错误时产生中断
         * @return
         */
        inline bool isIntEn_rxErr()const{
                return NDm::isBitSet(m_ctl1);
        }

        inline void enInt_rxErr( const bool& en ){
                if( en )
                        enInt_rxErr();
                else
                        disInt_rxErr();
        }

        inline void enInt_rxErr(){
                NDm::bitSet(m_ctl1);
        }

        inline void disInt_rxErr(){
                NDm::bitClr(m_ctl1);
        }

        /**
         * 可以读取接收缓冲区或者检测到Break时产生中断
         * @return
         */
        inline bool isIntEn_rxRdyOrBreak()const{
                return NDm::isBitSet(m_ctl2);
        }

        inline void enInt_rxRdyOrBreak( const bool& en ){
                if( en )
                        enInt_rxRdyOrBreak();
                else
                        disInt_rxRdyOrBreak();
        }

        inline void enInt_rxRdyOrBreak(){
                NDm::bitSet(m_ctl2);
        }

        inline void disInt_rxRdyOrBreak(){
                NDm::bitClr(m_ctl2);
        }

        /**
         * 可以写数据到发送缓冲区时产生中断
         * @return
         */
        inline bool isIntEn_txRdy()const{
                return NDm::isBitSet(m_ctl2);
        }

        inline void enInt_txRdy( const bool& en ){
                if( en )
                        enInt_txRdy();
                else
                        disInt_txRdy();
        }

        inline void enInt_txRdy(){
                NDm::bitSet(m_ctl2);
        }

        inline void disInt_txRdy(){
                NDm::bitClr(m_ctl2);
        }

定义FIFO相关的接口
        inline bool isEnFifo()const{
                return NDm::isBitSet(m_fftx);
        }

        inline void enFifo(){
                NDm::bitSet(m_fftx);
        }

        /**
         * 复位
         * 复位FIFO与SCI模块
         * @param wait
         */
        void resetFf( const unsigned int& wait=1000 );

        /**
         * 复位发送队列
         * @param wait
         */
        void resetTxFf( const unsigned int& wait=100 );

        /**
         * 复位接收队列
         * @param wait
         */
        void resetRxFf( const unsigned int& wait=100 );

        /**
         * 发送字符延时
         * @return
         */
        inline unsigned int getFfTxDelay()const{
                return m_ffct & 0x00FF;
        }

        inline void setFfTxDelay( const unsigned int& delay=0 ){
                m_ffct = (m_ffct&0xFF00)| (delay&0x00FF);
        }

        int tx( const unsigned char* buf,const int& size );
        int rx( unsigned char* buf,const int& size )const;

        /**
         * 发送队列数据个数
         * @return
         */
        inline unsigned int txFfState()const{
                return (m_fftx&0x1F00)>>8;
        }

        /**
         * 接收队列数据个数
         * @return
         */
        inline unsigned int rxFfState()const{
                return (m_ffrx&0x1F00)>>8;
        }

        /**
         * 接收队列溢出
         * @return
         */
        inline bool isRxFfOverFlow()const{
                return NDm::isBitSet(m_ffrx);
        }

        /**
         * 清除接收队列溢出标志
         */
        inline void clrRxFfOverFlow(){
                NDm::bitSet(m_ffrx);
        }

        /**
         * 使能发送队列中断
         */
        inline void enInt_txFf(){
                NDm::bitSet(m_fftx);
        }

        /**
         * 使能接收队列中断
         */
        inline void enInt_rxFf(){
                NDm::bitSet(m_ffrx);
        }

        /**
         * 禁用发送队列中断
         */
        inline void disInt_txFf(){
                NDm::bitClr(m_fftx);
        }

        /**
         * 禁用接收队列中断
         */
        inline void disInt_rxFf(){
                NDm::bitClr(m_ffrx);
        }

        /**
         * 发送队列中断是否使能
         * @return
         */
        inline bool isIntEn_txFf()const{
                return NDm::isBitSet(m_fftx);
        }

        /**
         * 接收队列中断是否使能
         * @return
         */
        inline bool isIntEn_rxFf()const{
                return NDm::isBitSet(m_ffrx);
        }

        /**
         * 是否有发送队列中断
         * @return
         */
        inline bool isInt_txFf()const{
                return NDm::isBitSet(m_fftx);
        }

        /**
         * 是否有接收队列中断
         * @return
         */
        inline bool isInt_rxFf()const{
                return NDm::isBitSet(m_ffrx);
        }

        /**
         * 清除发送队列中断
         */
        inline void clrInt_txFf(){
                NDm::bitSet(m_fftx);
        }

        /**
         * 清除接收队列中断
         */
        inline void clrInt_rxFf(){
                NDm::bitSet(m_ffrx);
        }

        /**
         * 获取发送队列中断级别
         * @return
         */
        inline unsigned int getTxFfIntLevel()const{
                return m_fftx & 0x001F;
        }

        /**
         * 获取接收队列中断级别
         * @return
         */
        inline unsigned int getRxFfIntLevel()const{
                return m_ffrx & 0x001F;
        }

        /**
         * 设置发送队列中断级别
         * @param level
         */
        inline void setTxFfIntLevel( const unsigned int& level=0 )const{
                m_fftx = ((m_fftx&0xFFE0)|(level&0x001F));
        }

        /**
         * 设置发送队列中断级别
         * @param level
         */
        inline void setRxFfIntLevel( const unsigned int& level=16 )const{
                m_ffrx = ((m_ffrx&0xFFE0)|(level&0x001F));
        }

这里我还定义了一个为将来扩展使用的函数,用于一般性的串口使用初始化过程函数
        /**
         * 默认的初始化参数
         * 这个函数给后续简单使用做封装
         * 默认设置使用FIFO模式,但是参数不对通信速率初始化
         */
        void defaultInit();

也就是说,面对SCI这么灵活的使用方法,这么多接口,应用程序使用起来还是比较麻烦的。将来要抽象出SCI的普遍用法,或者说几种比较实用的用法。

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复