DSP 2812: 使用C++封装SCI

11 篇文章 0 订阅

使用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<volatile unsigned int,7,unsigned int>(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<volatile unsigned int,7,unsigned int>(m_ccr);
	}

	/**
	 * 设置2位停止位
	 */
	inline void setStop_2(){
		NDm::bitSet<volatile unsigned int,7,unsigned int>(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<volatile unsigned int,5,unsigned int>(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<volatile unsigned int,7,unsigned int>(m_ctl2);
	}

	/**
	 * 发送线路空闲
	 * @return
	 */
	inline bool isTxEmpty()const{
		return NDm::isBitSet<volatile unsigned int,6,unsigned int>(m_ctl2);
	}

	/**
	 * 接收缓冲区可读
	 * @return
	 */
	inline bool isRxRdy()const{
		return NDm::isBitSet<volatile unsigned int,6,unsigned int>(m_rxst);
	}

定义操作相关接口

inline bool isTxEn()const{
		return NDm::isBitSet<volatile unsigned int,1,unsigned int>(m_ctl1);
	}

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

	inline void enTx(){
		NDm::bitSet<volatile unsigned int,1,unsigned int>(m_ctl1);
	}

	inline void disTx(){
		NDm::bitClr<volatile unsigned int,1,unsigned int>(m_ctl1);
	}

	inline bool isRxEn()const{
		return NDm::isBitSet<volatile unsigned int,0,unsigned int>(m_ctl1);
	}

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

	inline void enRx(){
		NDm::bitSet<volatile unsigned int,0,unsigned int>(m_ctl1);
	}

	inline void disRx(){
		NDm::bitClr<volatile unsigned int,0,unsigned int>(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<volatile unsigned int,7,unsigned int>(m_rxst);
	}

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

	/**
	 * 没有收到正确的停止位
	 * @return
	 */
	inline bool isRxErr_frame()const{
		return NDm::isBitSet<volatile unsigned int,4,unsigned int>(m_rxst);
	}

	/**
	 * 校验没通过
	 * @return
	 */
	inline bool isRxErr_parity()const{
		return NDm::isBitSet<volatile unsigned int,2,unsigned int>(m_rxst);
	}

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

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

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

定义中断相关的接口


	/**
	 * 接收错误时产生中断
	 * @return
	 */
	inline bool isIntEn_rxErr()const{
		return NDm::isBitSet<volatile unsigned int,6,unsigned int>(m_ctl1);
	}

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

	inline void enInt_rxErr(){
		NDm::bitSet<volatile unsigned int,6,unsigned int>(m_ctl1);
	}

	inline void disInt_rxErr(){
		NDm::bitClr<volatile unsigned int,6,unsigned int>(m_ctl1);
	}

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

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

	inline void enInt_rxRdyOrBreak(){
		NDm::bitSet<volatile unsigned int,1,unsigned int>(m_ctl2);
	}

	inline void disInt_rxRdyOrBreak(){
		NDm::bitClr<volatile unsigned int,1,unsigned int>(m_ctl2);
	}

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

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

	inline void enInt_txRdy(){
		NDm::bitSet<volatile unsigned int,0,unsigned int>(m_ctl2);
	}

	inline void disInt_txRdy(){
		NDm::bitClr<volatile unsigned int,0,unsigned int>(m_ctl2);
	}

定义FIFO相关的接口

	inline bool isEnFifo()const{
		return NDm::isBitSet<volatile unsigned int,14,unsigned int>(m_fftx);
	}

	inline void enFifo(){
		NDm::bitSet<volatile unsigned int,14,unsigned int>(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<volatile unsigned int,15,unsigned int>(m_ffrx);
	}

	/**
	 * 清除接收队列溢出标志
	 */
	inline void clrRxFfOverFlow(){
		NDm::bitSet<volatile unsigned int,14,unsigned int>(m_ffrx);
	}

	/**
	 * 使能发送队列中断
	 */
	inline void enInt_txFf(){
		NDm::bitSet<volatile unsigned int,5,unsigned int>(m_fftx);
	}

	/**
	 * 使能接收队列中断
	 */
	inline void enInt_rxFf(){
		NDm::bitSet<volatile unsigned int,5,unsigned int>(m_ffrx);
	}

	/**
	 * 禁用发送队列中断
	 */
	inline void disInt_txFf(){
		NDm::bitClr<volatile unsigned int,5,unsigned int>(m_fftx);
	}

	/**
	 * 禁用接收队列中断
	 */
	inline void disInt_rxFf(){
		NDm::bitClr<volatile unsigned int,5,unsigned int>(m_ffrx);
	}

	/**
	 * 发送队列中断是否使能
	 * @return
	 */
	inline bool isIntEn_txFf()const{
		return NDm::isBitSet<volatile unsigned int,5,unsigned int>(m_fftx);
	}

	/**
	 * 接收队列中断是否使能
	 * @return
	 */
	inline bool isIntEn_rxFf()const{
		return NDm::isBitSet<volatile unsigned int,5,unsigned int>(m_ffrx);
	}

	/**
	 * 是否有发送队列中断
	 * @return
	 */
	inline bool isInt_txFf()const{
		return NDm::isBitSet<volatile unsigned int,7,unsigned int>(m_fftx);
	}

	/**
	 * 是否有接收队列中断
	 * @return
	 */
	inline bool isInt_rxFf()const{
		return NDm::isBitSet<volatile unsigned int,7,unsigned int>(m_ffrx);
	}

	/**
	 * 清除发送队列中断
	 */
	inline void clrInt_txFf(){
		NDm::bitSet<volatile unsigned int,6,unsigned int>(m_fftx);
	}

	/**
	 * 清除接收队列中断
	 */
	inline void clrInt_rxFf(){
		NDm::bitSet<volatile unsigned int,6,unsigned int>(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的普遍用法,或者说几种比较实用的用法。






  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值