📄 twi._c
字号:
/*********************************************************************************************************
** TWI 驱动程序
** (c) Copyright 2006-2008, limaokui
** All Rights Reserved
**
** V1.0.0
**
**
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名:TWI.h
**创 建 人: 李茂奎
**最后修改日期: 2006年8月29日
**描 述: TWI驱动程序
**
**--------------历史版本信息----------------------------------------------------------------------------
** 创建人: 李茂奎
** 版 本: V1.00
** 日 期: 2006年8月29日
** 描 述: 原始版本
**
**------------------------------------------------------------------------------------------------------
** 修改人: 李茂奎
** 版 本:
** 日 期:
** 描 述:
**
**--------------当前版本修订------------------------------------------------------------------------------
** 修改人: 李茂奎
** 日 期: 2006年9月1日
** 描 述:
**
**------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
/*
说明:1、本驱动程序已经实现了TWI中断通讯的四种模式:MT、MR、ST、SR。
2、MT方式调用Twi_MasterSend()函数,用到了Twi_SendBuffer队列,
最大单次发送255Btye,理论上两次发送间隔5MS以上。
3、MR方式调用Twi_MasterRecive()函数,用到了Twi_ReceiveBuffer队列,
最大单次发送255Btye,理论上两次发送间隔5MS以上。
4、SR方式用户不必关心何时中断,在中断结束后,调用Twi_SlaveReceiveService()函数,
此函数将接收到的数据传给上层缓冲区Twi_LocalBuffer,用到了Twi_ReceiveBuffer、Twi_LocalBuffer队列,
最大单次发送255Btye。上层程序仅需检测Twi_LocalBuffer中的status即可,即若status值
TWI_DATA_READY,就可以读取数据,读完后设置LocalBuffer的Status为TWI_DATA_FREE。
5、ST方式用户不必关心何时中断,在中断结束后,调用Twi_TransmintReceiveService()函数S玫搅薚wi_ReceiveBuffer、Twi_LocalBuffer队列,
如果想使能从机发送则可将要发数据传入LocalBuffer中并设置Status为TWI_DATA_SEND,在写
LocalBuffer之前,应检测STATUS是否为Status为TWI_DATA_FREE。
6、非中断模式的接收发送没有经过验证。使用时请注意。
7、使用时首先调用TwiInit()进行初始化,(循环队列的长度可以自己修改对应的数组和结构中的queuesize),
然后打开中断即可。对于不同的单片机,此驱动中通过定义CPU_TYPE实现切换。对应的定义在config中。
*/
#include "config.h"
// Twi标准波特率:
// 低速 100KHz
// 高速 400KHz
// Twi_ 状态和地址变量
static volatile eTwi_StateType Twi_State; // 用于独占TWI的资源分配的信号量机制
static volatile uint8 Twi_DeviceAddrRW;
// 发送缓冲区
uint8 Twi_SendData[TWI_SEND_DATA_BUFFER_SIZE];
CirQueue Twi_SendBuffer={0,0,0,Twi_SendData,TWI_SEND_DATA_BUFFER_SIZE,QUEUE_OK,TWI_DATA_FREE,0};
// 接收缓冲区
uint8 Twi_ReceiveData[TWI_RECEIVE_DATA_BUFFER_SIZE];
CirQueue Twi_ReceiveBuffer={0,0,0,(uint8 *)Twi_ReceiveData,TWI_RECEIVE_DATA_BUFFER_SIZE,QUEUE_OK,TWI_DATA_FREE,0};
//本地缓冲区,当为从机时,与TWI接口
static uint8 LocalBuffer[TWI_LOCAL_DATA_BUFFER_SIZE];
CirQueue Twi_LocalBuffer={0,0,0,LocalBuffer,TWI_LOCAL_DATA_BUFFER_SIZE,QUEUE_OK,TWI_DATA_FREE,0};
//错误代码
static volatile uint8 TwiErrorCode;
// 指向接收处理函数的指针,当本机被选中从接收时调用函数:Twi_SlaveReceive
static void (*Twi_SlaveReceive)(uint8 receiveDataLength, uint8* recieveData);
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:ITwi_SlaveTransmit
static uint8 (*Twi_SlaveTransmit)(uint8 transmitDataLengthMax, uint8* transmitData);
/*************************************************************************************
**延时公式
** i*500-100 US (8>i>2)
** i*500 (255>i>8)
** i=1精确延时100us
** i=2 精确延时660US
** i=6 精确延时2.9ms
** i=10 精确延时5ms
** i=20 10ms
** i=100 50ms
** i=200 100ms
** i=255 128ms
**************************************************************************************/
void Delay(uint8 n)
{
uint8 i;
for(i=36;n!=0;n--)
{
while(--i);
WDR(); //喂狗;
}
}
/*********************************************************************************************************
** 函数名称:Twi_SetBitrate
** 功能描述:设置TWI总线的速率
** 输 入: bitrateKHZ : 总线速率
** 输 出:
** 全局变量:
** 调用模块: 无
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
void Twi_SetBitrate(uint16 bitrateKHz){
uint8 bitrate_div;
WDR(); //喂狗;
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
// 对于用速率分频的AVR (mega128)
// SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
// set TWPS to zero
TWSR&=~(1<<TWPS0);
TWSR&=~(1<<TWPS1);
#endif
// 计算分频
bitrate_div = ((F_CPU/1000)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
TWBR = bitrate_div;
}
/*********************************************************************************************************
** 函数名称:Twi_MasterSend
** 功能描述:主发送
** 输 入: deviceAddr:从机地址
** length:数据长度
** * data:发送缓冲区指针
**
** 输 出: 发送的字节数
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
uint8 Twi_MasterSend(uint8 deviceAddr, uint8 length, uint8* data)
{
uint8 i,result=0;
WDR(); //喂狗;
// 等待总线准备完成
while(Twi_State); //此处为独占TWI的信号量机制
// 设置状态
Twi_State = TWI_MASTER_TX;
// 准备数据
Twi_DeviceAddrRW = (deviceAddr & 0xFE); // RW 为0: 写操作
if(Twi_SendBuffer.status==TWI_DATA_FREE)
{
InitQueue(&Twi_SendBuffer); //清空上次发送的信息
Twi_SendBuffer.status=TWI_DATA_SEND;
}
for(i=0; (i<length)&&(Twi_SendBuffer.errorcode!=QUEUE_OVERFLOW); i++)
EnQueue(&Twi_SendBuffer,*data++);
result=i;
// 发送开始条件
Twi_Start();
WDR(); //喂狗;
while(Twi_State);
WDR(); //喂狗;
i=0;
while(((TwiErrorCode==TW_MT_SLA_NACK)||(TwiErrorCode==TW_MT_ARB_LOST)||(TwiErrorCode==TW_MT_DATA_NACK))&&i<TWI_FAIL_MAX) //器件不响应或总线仲裁失败
{
i++;
if((TwiErrorCode==TW_MT_DATA_NACK)&&(Twi_SendBuffer.count==0))
{
break;
}
Delay(255);
Twi_State = TWI_MASTER_TX;
Twi_Start();
WDR(); //喂狗;
while(Twi_State);
WDR(); //喂狗;
}
Twi_SendBuffer.status=TWI_DATA_FREE;
if(i>=TWI_FAIL_MAX)
{
return (FALSE);
}
else
{
return (result-Twi_SendBuffer.count);
}
}
/*********************************************************************************************************
** 函数名称:Twi_MasterReceive
** 功能描述:主模式接收
** 输 入: deviceAddr:从机地址
** length:数据长度
** * data 缓冲区指针
**
** 输 出: 返回接收到的字节数
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
uint8 Twi_MasterReceive(uint8 deviceAddr, uint8 length, uint8* data)
{
uint8 i,result;
WDR(); //喂狗;
// 等待总线准备完成
while(Twi_State);
// 设置状态
Twi_State = TWI_MASTER_RX;
// 保存数据
Twi_DeviceAddrRW = (deviceAddr|0x01); // RW 为1 : 读操作
if(Twi_ReceiveBuffer.status==TWI_DATA_FREE)
{
InitQueue(&Twi_ReceiveBuffer); //清空上次发送的信息
Twi_ReceiveBuffer.status=TWI_DATA_RECEIVE;
Twi_ReceiveBuffer.memo=length;
}
// 发送开始条件
Twi_Start();
WDR(); //喂狗;
//等待数据准备好
while(Twi_State); //注意有可能引起死循环
WDR(); //喂狗;
i=0;
while(((TwiErrorCode==TW_MR_SLA_NACK)||(TwiErrorCode==TW_MR_ARB_LOST)||(TwiErrorCode==TW_MR_DATA_NACK))&&i<TWI_FAIL_MAX) //器件不响应或总线仲裁失败
{
i++;
if((TwiErrorCode==TW_MR_DATA_NACK)&&(Twi_ReceiveBuffer.count>=length))
{
break;
}
//Twi_Stop();
Delay(255);
Twi_State = TWI_MASTER_RX;
Twi_Start();
WDR(); //喂狗;
while(Twi_State);
WDR(); //喂狗;
}
// 取数据
for(result=0; (result<length)&&(Twi_ReceiveBuffer.count>0); result++)
*data++ = DeQueue(&Twi_ReceiveBuffer);
Twi_ReceiveBuffer.status=TWI_DATA_FREE;
if(i>=TWI_FAIL_MAX)
{
return (FALSE);
}
else
{
return (result); //返回接收到的字节数;
}
}
/*********************************************************************************************************
** 函数名称:Twi_MasterSendNI
** 功能描述:主模式非中断发送
** 输 入: deviceAddr:从机地址
** length:数据长度
** * data 缓冲区指针
** 输 出:
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
uint8 Twi_MasterSendNI(uint8 deviceAddr, uint8 length, uint8* data)
{
uint8 retval = TWI_OK;
WDR(); //喂狗;
// 关Twi_中断
TWCR&=~(1<<TWIE);
WDR(); //喂狗;
// 发送开始条件
Twi_Start();
WDR(); //喂狗;
Twi_WaitForComplete();
// 发送器件写地址
Twi_SendByte( deviceAddr & 0xFE );
Twi_WaitForComplete();
// 检查器件是否可用
if( TWSR == TW_MT_SLA_ACK)
{
// 发送数据
while(length)
{
Twi_SendByte( *data++ );
Twi_WaitForComplete();
length--;
WDR(); //喂狗;
}
}
else
{
// 如未回应器件地址,停止发送,返回错误
retval = TWI_ERROR_NODEV;
}
// 发送停止条件,保持TWEA以便从接收
Twi_Stop();
while( !(TWCR&(1<<TWSTO)) );
// 开Twi_中断
TWCR|=(1<<TWIE);
return retval;
}
/*********************************************************************************************************
** 函数名称:主模式非中断接收
** 功能描述:
** 输 入: deviceAddr:从机地址
** length:数据长度
** * data 缓冲区指针
** 输 出:
** 全局变量:
** 调用模块:
** 说明:
** 注意:
** 日 期: 2006年8月29日
********************************************************************************************************/
uint8 Twi_MasterReceiveNI(uint8 deviceAddr, uint8 length, uint8 *data)
{
uint8 retval = TWI_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -