📄 twi.c.svn-base
字号:
/* ****ROBOCON 2009 | BUPT TEAM******* * ------------------------------------------------------------------------ * FileName : twi.c * Version : 2.0 * Brief : * Code by : leaf * Date : Apr 28, 2009 * Note : 接收者不处理NACK后的数据。 * 发送者在收到NACK后发送一个0 * 主机接收如果没有收到足够的数据,应用程序应该处理这种情况 * * * ------------------------------------------------------------------------ */#include "lib_bupt.h"#ifdef TWI_H_INCLUDEDstatic TwiMode mode = TwiModeStop;inline void twiWait( void );static Mutex twiSignal;AVRX_SIGINT( TWI_vect ){ IntProlog(); AvrXIntSetSemaphore( &twiSignal ); Epilog();}void twiInit( UINT8 baud ){ cli(); AvrXResetSemaphore( &twiSignal ); TWBR = baud; PORTD |= 0x03; DDRD &= ~0x03; mode = TwiModeStop; sei();}/* 初始化Twi传输,如果成功,返回当前的模式,失败返回负数值 * 对应的四种模式 * MT-发送START, 发送SLA+W * MR-发送START, 发送SLA+R * ST-等待SLA+R * SR-等待SLA+W */inttwiOpen( TwiAddr addr, TwiMode m ){ /*Check Parameter */ if( m == TwiModeMT || m == TwiModeMR ) { TWCR = _BV(TWIE) | _BV(TWINT)|_BV(TWSTA)|_BV(TWEN); //发送START twiWait(); if( TW_STATUS != 0x08 && TW_STATUS != 0x10 ){ //START|REP_START没发出去 return TwiErrStart; } TWDR = (addr << 1) | (m & TWI_TR_MASK); //发送SLA+W或R( SLA<<1 + 0(或1) ) TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEN); twiWait(); if( TW_STATUS == TW_MT_SLA_ACK ){ //没有SLA+ACK,状态不对 mode = TwiModeMT; return TwiModeMT; } else if( TW_STATUS == TW_MR_SLA_ACK ){ mode = TwiModeMR; return TwiModeMR; } else{ return TwiErrSla; } } else if( m == TwiModeST || m == TwiModeSR ) { TWAR = (addr << 1) | _BV(TWGCE); //设置自己的地址,默认也接收广播 TWCR = _BV(TWIE) | _BV(TWEA) | _BV(TWEN); //TWEA使能地址匹配,TWEN使能TW模块 twiWait(); if( TW_STATUS == TW_SR_SLA_ACK ){ mode = TwiModeSR; return TwiModeSR; } else if( TW_STATUS == TW_ST_SLA_ACK ){ mode = TwiModeST; return TwiModeST; } else{ return TwiErrMatch; } } else{ return TwiErrOther; }}/* 主模式写入,遇到NACK认为文件结束,写入最后一个字节,返回不包括最后数据的实际写入字节数 */inline inttwiMasterWrite( const void *data, size_t sz){ int i = 0; const UINT8 *src = data; for( i = 0; i < sz; ++i ) { if( TW_STATUS == TW_MT_DATA_ACK || TW_STATUS == TW_MT_SLA_ACK ){ TWDR = src[i]; TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEN); twiWait(); } else if( TW_STATUS == TW_MT_DATA_NACK ){ TWDR = src[i]; TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEN); twiWait(); return i; } else{ return i; } } return i;}/* 遇到了NACK后认为文件结束,返回实际写入数 */inline inttwiSlaveWrite( const void *data, size_t sz ){ int i; const UINT8 *src = data; for( i = 0; i < sz; ++i ){ switch(TW_STATUS){ case TW_ST_SLA_ACK: case TW_ST_DATA_ACK: TWDR = src[i]; TWCR = _BV(TWIE) | _BV(TWEN) | _BV(TWEA) | _BV(TWINT); twiWait(); break; case TW_ST_DATA_NACK:/*主机希望停止传输*/ return i; break; /*case TW_ST_LAST_DATA: 是从机发送者主动停止了传输,此行为在close中执行 */ default: break; } } return i;}/* Twi发送数据,-1代表Twi没有正确的打开 */inttwiWrite( const void *data, size_t sz ){ if( mode == TwiModeMT){ return twiMasterWrite( data, sz ); } else if( mode == TwiModeST ){ return twiSlaveWrite( data, sz ); } else{ return TwiErrOpen; }}/* 主模式输入,SLA_NACK表示单字节传输,并不中止 * 在遇到DATA_NACK时(从机希望中止传输),读入最后数据,返回不包括最后数据的数据数 * 应用应该判断这种情况,作出反应(如 twiClose) */inline inttwiMasterRead( void *buf, size_t sz ){ UINT8 *dest = buf; int i; for( i = 0; i < sz; ++i ){ switch( TW_STATUS ) { case TW_MR_SLA_NACK: case TW_MR_SLA_ACK: --i; TWCR = _BV(TWIE) | _BV(TWEN) | _BV(TWEA) | _BV(TWINT); twiWait(); break; case TW_MR_DATA_ACK: dest[i] = TWDR; TWCR = _BV(TWIE) | _BV(TWEN) | _BV(TWEA) | _BV(TWINT); twiWait(); break; case TW_MR_DATA_NACK: dest[i] = TWDR; return i; break; default: return i; break; } } return i;}/* 从模式读入, * read应该在open之后调用 * 遇到SLA+W,则重新读入这一字节数据 * 如果遇到主机中止传输的情况,应该返回实际读入数,应用应该判断作出反应(如twiClose) */inline inttwiSlaveRead( void *buf, size_t sz){ int i; UINT8 *dest = buf; for( i = 0; i < sz; ++i ){ if( TW_STATUS == TW_SR_DATA_ACK ){ dest[ i ] = TWDR; TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN); twiWait(); } else if( TW_STATUS == TW_SR_SLA_ACK ){ -- i; TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN); twiWait(); continue; } else if( TW_STATUS == TW_SR_STOP ){ return i; } else{ break; } /*case TW_ST_DATA_NACK: 是从机接收者希望停止传输,此行为在close中执行 */ } return i;}/* twi读入 */inttwiRead( void *buf, size_t sz ){ if( mode == TwiModeMR){ return twiMasterRead( buf, sz ); } else if( mode == TwiModeSR ){ return twiSlaveRead( buf, sz ); } else{ return TwiErrOpen; }}inttwiClose( void ){ TwiMode md = mode; mode = TwiModeStop; if( md == TwiModeMR ){ //MR模式时要先发一个NACK使从机发送者停下来 TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEN); twiWait(); } if( md == TwiModeMT || md == TwiModeMR ) { TWCR = _BV(TWIE) | _BV(TWINT)|_BV(TWSTO)|_BV(TWEN); twiWait(); } else if( md == TwiModeSR || md == TwiModeSR ) //发送一个NACK { TWCR = _BV(TWIE) | _BV(TWEN) | _BV(TWINT); twiWait(); } return 0;}inline void twiWait( void ){ AvrXWaitSemaphore( &twiSignal ); while( bit_is_clear(TWCR, TWINT) );}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -