这个不是我自己发明也是参考了网上的一些例子,不过大部分都是轮询模式这样单片机效率比较低。我感觉还是中断模式的好一些,这样不会浪费很多时间在查询上。以下是部分代码,在M16和M48上读写PCF8563测试通过:
#include
#include
// TWI主机模式读写操作步骤预定义
#define TWI_MRW_STEP_START 1 // 发送完START
#define TWI_MRW_STEP_SLAW 2 // 发送完SLA+W
#define TWI_MRW_STEP_DATAADDR 3 // 发送完数据地址
#define TWI_MRW_STEP_REPSTART 4 // 发送完REPSTART
#define TWI_MRW_STEP_SLAR 5 // 发送完SLA+R
#define TWI_MRW_STEP_DATAR 6 // 读取完一字节数据
#define TWI_MRW_STEP_DATAW 7 // 发送完一字节数据
#define TWI_MRW_FAIL 9 // TWI操作失败
// TWI主机模式读写操状态及结果宏定义
#define TWI_MRW_BUSY 1 // TWI操作忙碌
#define TWI_MRW_NOBUSY 0 // TWI操作空闲
#define TWI_MRW_OK 0 // TWI操作成功
#define TWI_MRW_FAIL_MAX 20 // TWI操作失败最大次数
struct TWI_MRW_STEP_MASTER // 定义TWI_MRW_STEP主机模式结构体
{
volatile unsigned char uchResult; // TWI_MRW_STEP操作结果
// 0成功 1失败
volatile unsigned char uchBusy; // TWI_MRW_STEP操作忙碌状态
// 0空闲 1忙碌
volatile unsigned char uchSla; // 从设备的器件地址
volatile unsigned char uchByteAddr; // 从设备的数据地址
volatile unsigned char *puchByte; // 字节数据指针
volatile unsigned int uiByteLen; // 读写字节长度
volatile unsigned char uchStep; // TWI_MRW_STEP读写操作步骤
volatile unsigned char uchFailCount;// 操作失败次数
};
struct TWI_MRW_STEP_MASTER g_TwiMasterRW;
******************************** ****************************************
*名称: ISR(TWI_vect) *
*功能: TWI中断服务程序 主机中断模式读写数据 *
*参数: 无 *
*返回: 无 *
*************************************************************************
*/
ISR(TWI_vect)
{
switch(g_TwiMasterRW.uchStep)
{
case TWI_MRW_STEP_START: // START发送完毕
{
if(TW_STATUS == TW_START) // START发送成功
{
TWDR = g_TwiMasterRW.uchSla&0xFE;
TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWIE);
// 发送sla
}
else // START发送失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_SLAW: // slaw发送完毕
{
if(TW_STATUS == TW_MT_SLA_ACK ) // slaw发送成功
{
TWDR = g_TwiMasterRW.uchByteAddr;
TWCR = (1 << TWINT)|(1 << TWEN)|(1<< TWIE );
// 发送数据地址
}
else // sla发送失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_DATAADDR: // 数据地址发送完毕
{
if(TW_STATUS == TW_MT_DATA_ACK) // 数据地址发送成功
{
if((g_TwiMasterRW.uchSla&0x01) == TW_READ)
// 读模式
{
TWCR =_BV(TWINT)|_BV(TWSTA)|_BV(TWEN)
|_BV(TWIE); //发送REP_START
}
else if((g_TwiMasterRW.uchSla&0x01)
== TW_WRITE) // 写模式 // 写模式
{
TWDR = *g_TwiMasterRW.puchByte++;
g_TwiMasterRW.uchStep
= TWI_MRW_STEP_DATAW -1;
// 下一次将跳入TWI_DATA_W步骤
TWCR = _BV(TWINT)|_BV(TWEN)
|_BV(TWIE); // 发送写入数据
}
}
else // 数据地址发送失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_REPSTART: // RESTART发送完毕
{
if(TW_STATUS == TW_REP_START)// REP_START发送完毕
{
TWDR = g_TwiMasterRW.uchSla;
TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWIE);
// 发送sla地址
}
else // REP_START发送失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_SLAR: // slar发送完毕
{
if(TW_STATUS == TW_MR_SLA_ACK )// slar发送成功
{
if(g_TwiMasterRW.uiByteLen--)//继续接收数据
{
TWCR=_BV(TWINT)|_BV(TWEN)|_BV(TWEA)
|_BV(TWIE); // 发送ACK应答
}
else // 数据接收完毕
{
TWCR = (1< }
}
else // slar发送失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_DATAR: // 接收完一字节数据
{
g_TwiMasterRW.uchStep--;
if(TW_STATUS == TW_MR_DATA_ACK) // 继续接收数据
{
*g_TwiMasterRW.puchByte++ = TWDR;
if(g_TwiMasterRW.uiByteLen--)
// 数据没有接收完
{
TWCR = _BV(TWINT)|_BV(TWEN)
|_BV(TWEA)|_BV(TWIE);// 发送ACK应答
}
else // 准备接收最后一个字节数据
{
TWCR = _BV(TWINT)
|_BV(TWEN)|_BV(TWIE);// 不发送ACK应答
}
}
else if(TW_STATUS==TW_MR_DATA_NACK)
// 接收最后一个字节数据
{
*g_TwiMasterRW.puchByte++ = TWDR;
TWCR = _BV(TWSTO)|_BV(TWINT)|_BV(TWEN)
|_BV(TWIE); // 发送STOP信号
g_TwiMasterRW.uchBusy = TWI_MRW_NOBUSY;
g_TwiMasterRW.uchResult = TWI_MRW_OK;
}
else // 接收数据失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
case TWI_MRW_STEP_DATAW : // 发送完一字节数据
{
g_TwiMasterRW.uchStep--; // 循环发送指定长度的数据
if(TW_STATUS==TW_MT_DATA_ACK) // 发送数据发送成功
{
if(g_TwiMasterRW.uiByteLen--)// 数据没有发送完
{
TWDR = *g_TwiMasterRW.puchByte++;
TWCR = _BV(TWINT)|_BV(TWEN)
|_BV(TWIE); // 发送数据
}
else // 发送完数据
{
TWCR = _BV(TWSTO)|_BV(TWINT)
|_BV(TWEN)|_BV(TWIE);// 发送STOP信号
g_TwiMasterRW.uchResult
= TWI_MRW_OK;
g_TwiMasterRW.uchBusy
= TWI_MRW_NOBUSY;
}
}
else // 发送数据失败
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
}
break;
}
default : // 错误状态
{
g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
break;
}
}
if(g_TwiMasterRW.uchStep == TWI_MRW_FAIL)
{
g_TwiMasterRW.uchFailCount++;
if(g_TwiMasterRW.uchFailCount >= TWI_MRW_FAIL_MAX)
// 失败超过最大次数
{
TWCR = _BV(TWSTO)|_BV(TWINT)|_BV(TWEN)|_BV(TWIE);
// 发送STOP信号
g_TwiMasterRW.uchResult = TWI_MRW_FAIL;
g_TwiMasterRW.uchBusy = TWI_MRW_NOBUSY;
}
else // 失败没有超过最大次数
{
TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN)|_BV(TWIE);
// 发送START
g_TwiMasterRW.uchStep = TWI_MRW_STEP_START;
}
}
else // 进入下一步操作
{
g_TwiMasterRW.uchStep++;
}
}
/*
*************************************************************************
*函数: unsigned char TwiMasterRW(unsigned char uchSla, *
* unsigned char uchByteAddr, unsigned char *puchByte, *
* unsigned int uiByteLen ) *
*功能: TWI主机模式读写数据 *
* *
*参数: uchSla 从器件地址 uchByteAddr 数据地址 *
* *puchByte 数据指针 uiByteLen 数据长度 *
*返回: 1 操作成功 0 操作失败 *
*************************************************************************
*/
unsigned char TwiMasterRW(unsigned char uchSla, unsigned char uchByteAddr,
unsigned char *puchByte, unsigned int uiByteLen )
{
g_TwiMasterRW.uchResult = TWI_MRW_FAIL;
g_TwiMasterRW.uchBusy = TWI_MRW_BUSY;
g_TwiMasterRW.uchSla = uchSla;
g_TwiMasterRW.uchByteAddr = uchByteAddr;
g_TwiMasterRW.puchByte = puchByte;
g_TwiMasterRW.uiByteLen = uiByteLen;
g_TwiMasterRW.uchStep = TWI_MRW_STEP_START;
g_TwiMasterRW.uchFailCount = 0;
TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN)|_BV(TWIE);// 启动总线START状态
while(g_TwiMasterRW.uchBusy == TWI_MRW_BUSY); // 等待操作完成
if(g_TwiMasterRW.uchResult == TWI_MRW_OK)
{
return TWI_MRW_OK; // 如果操作成功返回1
}
else // 如果操作失败返回0
{
return TWI_MRW_FAIL;
}
}
用户1447181 2009-7-30 23:53
网上都是轮询方式,最近我也在研究中断方式
用户1053025 2007-6-25 16:08
支持一下:D