21ic问答首页 - 中颖79F6442目标板TWI通讯测试
中颖79F6442目标板TWI通讯测试
rwf59562024-06-21
本帖最后由 rwf5956 于 2024-6-22 08:50 编辑
问题:主机发出START指令后,TWICON相应的中断标志位未产生,START发送不成功,主机一直在跑START发送检测,从机一直在等待
指令说明:
1、相应的寄存器配置
CLKCON |=0x08;
Delay();
CLKCON |=0x04;//时钟
TWITOUT = 0x02; //打开 SCL,SDA 上拉电阻
TWIBR=0x02; //配置发送波特率,禁止总线超时判断 f=fsys/(16+2*CR*TWIBR)
TWISTA=0x0; //64 分频
TWICON = 0x40; //ENTWI,禁止高电平超时
TWTFREE = 0xff; //最大超时配置
TWIAMR =0 ;//关闭TWI地址屏蔽
IEN0|=0X80;//使能所有中断允许开关
IEN1|=0X01;//使能TWI中断
INSCON |=0X40;
TWICR|=0X01;//使用默认管脚作为SCL、SDA//LCM功能配置SCL、SDA管脚
INSCON &= 0XBF;
2、代码说明
基于官方DEMOCODE
主机
/*******************************************************************************
TWI 主站发送START指令
*******************************************************************************/
bit M_TwiSendStart()
{
TWICON |=0x20; //TWICON=OX60 总线空闲时发送起始条件
//TWICON &= 0xdf;
while(1) //等待 TWI 中断(?是否初始化需要开启TWI中断允许IEN0 IEN1?)
{
if(TWICON&0x08) //TWICON bit3中断标志位=1,需软件复位
{
if(((TWISTA&0xF8)==0x08)||((TWISTA&0xF8)==0x10))
{
return OK; //成功发送开始条件或重复开始条件
}
else
{
return FAIL;
}
}
if(0x02 == (0x02 & TWICON))//TWICON bit1时钟线高电平超时,需软件复位
{
TWICON &= 0xdf;
return FAIL; //等待中断超时
}
}
}
/*******************************************************************************
(2)TWI 主站发送slave地址+W/R指令
*******************************************************************************/
UCHAR M_TwiSendCmd(UCHAR addr,UCHAR cmd)
{
UCHAR SlaveAddr;
UCHAR i=0;
if(cmd)
{
SlaveAddr=((addr&0x7f)<<1)|0x01; //读
}
else
{
SlaveAddr=((addr&0x7f)<<1); //写
}
TWICON &= 0xf7; //清除中断标志
TWIDAT=SlaveAddr;//执行发送指令
while(1) //等待 TWI 中断
{
i++;
if(TWICON&0x08)//主站自身对指令发送是否成功的反馈判断,根据是否产生TWI中断来判断的,该标志位需要再下一次判断前进行清零,复位
{
if(cmd) //发送的是读指令
{
if((TWISTA&0xF8)==0x40)//从站对指令发送是否成功的反馈判断,
{
return ACK; //成功发送 SLA+R
}
else if((TWISTA&0xF8)==0x48)
{
return NAK;
}
}
else //发送的是写指令
{
if((TWISTA&0xF8)==0x18)
{
return ACK; //成功发送 SLA+W
}
else if((TWISTA&0xF8)==0x20)
{
return NAK;
}
}
if((TWISTA&0xF8)==0x38)//反馈的是其他情况
{
return LOSEARBITRATION;//失去仲裁
}
else if((TWISTA&0xF8)==0x68)
{
return RCVCMDWRITE;
}
else if((TWISTA&0xF8)==0x78)
{
return RCVCMDREAD;
}
else if((TWISTA&0xF8)==0xB0)
{
return RCVADDRESS0;
}
else
{
return ERR;
}
}
if(i>=250)//尝试次数不超过250次
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(3)TWI 主站发送DATA数据
*******************************************************************************/
UCHAR M_TwiSendData(UCHAR byte)
{
UCHAR i=0;
TWICON &= 0xf7;//清除了中断标志位
TWIDAT=byte;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)//自身中断判断
{
if((TWISTA&0xF8)==0x28)
{
return ACK;
}
else if((TWISTA&0xF8)==0x30)
{
return NAK;
}
else if((TWISTA&0xF8)==0x38)
{
return LOSEARBITRATION;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*****************************************************************************************************
(4)Twi 主机发送结束指令
*****************************************************************************************************/
UCHAR M_TwiSendEnd()
{
UCHAR i=0;
TWICON=0x50;
while(1)
{
i++;
if((TWICON&0x10)==0)
{
if(TWISTA==0xF8)
{
return OK;
}
else
{
return FAIL;
}
}
if(i>=250)
{
return ERR; //等待终止位清除超时
}
}
}
/*******************************************************************************
(5)TWI 主站发送指令及数据给从站
*******************************************************************************/
bit M_SendDataToSlave()
{
UCHAR ret,i=0;
TwiInit();
H_Timeout_check; //使能总线超时,SCL 总线高电平超时判断
ret=M_TwiSendStart();//发送起始START
if(ret==OK) //send-STA OK
{
if(M_TwiSendCmd(0x2D,0x0)==ACK)//0X2D左移一位,对应从站地址0X5A
{
while(i < 0xff)
{
ret=M_TwiSendData(0x40+i);
i++;
if(ret==NAK)
{
return 1; //数据发送结束
}
else if((ret==LOSEARBITRATION)||(ret==ERR))
{
return 0;
}
}
}
else
{
return 0;
}
}
else //err process
{
return 0;
while(1);
}
}
从站
/*******************************************************************************
(1)从站等待接收指令
*******************************************************************************/
UCHAR S_TwiWaitRcvCmd()
{
TWIADR=0x5A; //从机地址设定
TWICON=0x44;
while(1)
{
// if(TWICON&0x08)
// {
if((TWISTA&0xF8)==0x60) //收到SLA+W
{
return CMD_WRITE;
}
else if((TWISTA&0xF8)==0xA8) //收到SLA+R
{
return CMD_READ;
}
else
{
return ERR;
}
// }
}
}
/*******************************************************************************
(2)从站等待接收数据
*******************************************************************************/
UCHAR S_TwiWaitRcvData()
{ UCHAR i=0;
TWIDAT=0;
TWICON=0x44;
while(1)
{
i++;
if(TWICON&0x08)
{
if(((TWISTA&0xF8)==0x80)||((TWISTA&0xF8)==0x90)) //收到1个byte数据
{
_nop_();
return ACK;
}
else
{
_nop_();
return ERR;
}
}
}
}
/*******************************************************************************
(3)从站接收最后1个byte数据
*******************************************************************************/
UCHAR S_TwiWaitRcvLastData()
{
UCHAR i=0;
TWIDAT=0;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)
{
if(((TWISTA&0xF8)==0x88)||((TWISTA&0xF8)==0x98)) //收到最后1个byte数据
{
return NAK;
}
else
{
return ERR;
}
}
}
}
/*******************************************************************************
(4)从站 发送数据
*******************************************************************************/
UCHAR S_TwiSendData(UCHAR byte)
{
UCHAR i=0;
TWIDAT=byte;
TWICON=0x44;
while(1)
{
i++;
if(TWICON&0x08)
{
if((TWISTA&0xF8)==0xB8)
{
return ACK;
}
else if((TWISTA&0xF8)==0xC0) //主机接收数据结束,从机切换至非寻址状态
{
return NAK;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(5)从站发送最后1byte数据
*******************************************************************************/
UCHAR S_TwiSendLastData(UCHAR byte)
{
UCHAR i=0;
TWIDAT=byte;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)
{
if((TWISTA&0xF8)==0xC8) //从机发送数据结束,切换至非寻址状态
{
return ACK;
}
else if((TWISTA&0xF8)==0xC0) //主机接收数据结束,从机切换至非寻址状态
{
return NAK;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(6)从站收发数据
*******************************************************************************/
bit SlaveTransfer()
{
UCHAR* rcv_data,i=0,ret;
TwiInit();
ret=S_TwiWaitRcvCmd();
if(ret==CMD_WRITE)
{
while(1)
{
if(S_TwiWaitRcvData()==ACK)//成功接收到1个byte
{
i++;
rcv_data[i-1]=TWIDAT;
if(i>=9)
{
if(S_TwiWaitRcvLastData()==NAK)
{
rcv_data=TWIDAT;
return 1; //接收数据结束
}
else
{
return 0; //接收最后1个byte数据过程中出错
}
}
}
else
{
return 0; //接收数据失败
}
}
}
else if(ret==CMD_READ)
{
while(1)
{
ret=S_TwiSendData(0x40+i);
if(ret==NAK) //主机接收数据结束
{
return 1;
}
else if(ret==ACK) //主机还可继续接收数据
{
i++;
if(i>=9)
{
if(S_TwiSendLastData(0x49)==ERR)
{
return 0; //发送最后1个byte数据过程中出错
}
else
{
return 1; //成功发送最后1个byte数据
}
}
}
else
{
return 0; //发送数据出错
}
}
}
else
{
return 0;
}
}
main函数
主站:
if(M_SendDataToSlave())
{
UCHAR M_TwiSendEnd();
}
从站
SlaveTransfer();
问题:主机发出START指令后,TWICON相应的中断标志位未产生,START发送不成功,主机一直在跑START发送检测,从机一直在等待
指令说明:
1、相应的寄存器配置
CLKCON |=0x08;
Delay();
CLKCON |=0x04;//时钟
TWITOUT = 0x02; //打开 SCL,SDA 上拉电阻
TWIBR=0x02; //配置发送波特率,禁止总线超时判断 f=fsys/(16+2*CR*TWIBR)
TWISTA=0x0; //64 分频
TWICON = 0x40; //ENTWI,禁止高电平超时
TWTFREE = 0xff; //最大超时配置
TWIAMR =0 ;//关闭TWI地址屏蔽
IEN0|=0X80;//使能所有中断允许开关
IEN1|=0X01;//使能TWI中断
INSCON |=0X40;
TWICR|=0X01;//使用默认管脚作为SCL、SDA//LCM功能配置SCL、SDA管脚
INSCON &= 0XBF;
2、代码说明
基于官方DEMOCODE
主机
/*******************************************************************************
TWI 主站发送START指令
*******************************************************************************/
bit M_TwiSendStart()
{
TWICON |=0x20; //TWICON=OX60 总线空闲时发送起始条件
//TWICON &= 0xdf;
while(1) //等待 TWI 中断(?是否初始化需要开启TWI中断允许IEN0 IEN1?)
{
if(TWICON&0x08) //TWICON bit3中断标志位=1,需软件复位
{
if(((TWISTA&0xF8)==0x08)||((TWISTA&0xF8)==0x10))
{
return OK; //成功发送开始条件或重复开始条件
}
else
{
return FAIL;
}
}
if(0x02 == (0x02 & TWICON))//TWICON bit1时钟线高电平超时,需软件复位
{
TWICON &= 0xdf;
return FAIL; //等待中断超时
}
}
}
/*******************************************************************************
(2)TWI 主站发送slave地址+W/R指令
*******************************************************************************/
UCHAR M_TwiSendCmd(UCHAR addr,UCHAR cmd)
{
UCHAR SlaveAddr;
UCHAR i=0;
if(cmd)
{
SlaveAddr=((addr&0x7f)<<1)|0x01; //读
}
else
{
SlaveAddr=((addr&0x7f)<<1); //写
}
TWICON &= 0xf7; //清除中断标志
TWIDAT=SlaveAddr;//执行发送指令
while(1) //等待 TWI 中断
{
i++;
if(TWICON&0x08)//主站自身对指令发送是否成功的反馈判断,根据是否产生TWI中断来判断的,该标志位需要再下一次判断前进行清零,复位
{
if(cmd) //发送的是读指令
{
if((TWISTA&0xF8)==0x40)//从站对指令发送是否成功的反馈判断,
{
return ACK; //成功发送 SLA+R
}
else if((TWISTA&0xF8)==0x48)
{
return NAK;
}
}
else //发送的是写指令
{
if((TWISTA&0xF8)==0x18)
{
return ACK; //成功发送 SLA+W
}
else if((TWISTA&0xF8)==0x20)
{
return NAK;
}
}
if((TWISTA&0xF8)==0x38)//反馈的是其他情况
{
return LOSEARBITRATION;//失去仲裁
}
else if((TWISTA&0xF8)==0x68)
{
return RCVCMDWRITE;
}
else if((TWISTA&0xF8)==0x78)
{
return RCVCMDREAD;
}
else if((TWISTA&0xF8)==0xB0)
{
return RCVADDRESS0;
}
else
{
return ERR;
}
}
if(i>=250)//尝试次数不超过250次
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(3)TWI 主站发送DATA数据
*******************************************************************************/
UCHAR M_TwiSendData(UCHAR byte)
{
UCHAR i=0;
TWICON &= 0xf7;//清除了中断标志位
TWIDAT=byte;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)//自身中断判断
{
if((TWISTA&0xF8)==0x28)
{
return ACK;
}
else if((TWISTA&0xF8)==0x30)
{
return NAK;
}
else if((TWISTA&0xF8)==0x38)
{
return LOSEARBITRATION;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*****************************************************************************************************
(4)Twi 主机发送结束指令
*****************************************************************************************************/
UCHAR M_TwiSendEnd()
{
UCHAR i=0;
TWICON=0x50;
while(1)
{
i++;
if((TWICON&0x10)==0)
{
if(TWISTA==0xF8)
{
return OK;
}
else
{
return FAIL;
}
}
if(i>=250)
{
return ERR; //等待终止位清除超时
}
}
}
/*******************************************************************************
(5)TWI 主站发送指令及数据给从站
*******************************************************************************/
bit M_SendDataToSlave()
{
UCHAR ret,i=0;
TwiInit();
H_Timeout_check; //使能总线超时,SCL 总线高电平超时判断
ret=M_TwiSendStart();//发送起始START
if(ret==OK) //send-STA OK
{
if(M_TwiSendCmd(0x2D,0x0)==ACK)//0X2D左移一位,对应从站地址0X5A
{
while(i < 0xff)
{
ret=M_TwiSendData(0x40+i);
i++;
if(ret==NAK)
{
return 1; //数据发送结束
}
else if((ret==LOSEARBITRATION)||(ret==ERR))
{
return 0;
}
}
}
else
{
return 0;
}
}
else //err process
{
return 0;
while(1);
}
}
从站
/*******************************************************************************
(1)从站等待接收指令
*******************************************************************************/
UCHAR S_TwiWaitRcvCmd()
{
TWIADR=0x5A; //从机地址设定
TWICON=0x44;
while(1)
{
// if(TWICON&0x08)
// {
if((TWISTA&0xF8)==0x60) //收到SLA+W
{
return CMD_WRITE;
}
else if((TWISTA&0xF8)==0xA8) //收到SLA+R
{
return CMD_READ;
}
else
{
return ERR;
}
// }
}
}
/*******************************************************************************
(2)从站等待接收数据
*******************************************************************************/
UCHAR S_TwiWaitRcvData()
{ UCHAR i=0;
TWIDAT=0;
TWICON=0x44;
while(1)
{
i++;
if(TWICON&0x08)
{
if(((TWISTA&0xF8)==0x80)||((TWISTA&0xF8)==0x90)) //收到1个byte数据
{
_nop_();
return ACK;
}
else
{
_nop_();
return ERR;
}
}
}
}
/*******************************************************************************
(3)从站接收最后1个byte数据
*******************************************************************************/
UCHAR S_TwiWaitRcvLastData()
{
UCHAR i=0;
TWIDAT=0;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)
{
if(((TWISTA&0xF8)==0x88)||((TWISTA&0xF8)==0x98)) //收到最后1个byte数据
{
return NAK;
}
else
{
return ERR;
}
}
}
}
/*******************************************************************************
(4)从站 发送数据
*******************************************************************************/
UCHAR S_TwiSendData(UCHAR byte)
{
UCHAR i=0;
TWIDAT=byte;
TWICON=0x44;
while(1)
{
i++;
if(TWICON&0x08)
{
if((TWISTA&0xF8)==0xB8)
{
return ACK;
}
else if((TWISTA&0xF8)==0xC0) //主机接收数据结束,从机切换至非寻址状态
{
return NAK;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(5)从站发送最后1byte数据
*******************************************************************************/
UCHAR S_TwiSendLastData(UCHAR byte)
{
UCHAR i=0;
TWIDAT=byte;
TWICON=0x40;
while(1)
{
i++;
if(TWICON&0x08)
{
if((TWISTA&0xF8)==0xC8) //从机发送数据结束,切换至非寻址状态
{
return ACK;
}
else if((TWISTA&0xF8)==0xC0) //主机接收数据结束,从机切换至非寻址状态
{
return NAK;
}
else
{
return ERR;
}
}
if(i>=250)
{
return ERR; //等待中断超时
}
}
}
/*******************************************************************************
(6)从站收发数据
*******************************************************************************/
bit SlaveTransfer()
{
UCHAR* rcv_data,i=0,ret;
TwiInit();
ret=S_TwiWaitRcvCmd();
if(ret==CMD_WRITE)
{
while(1)
{
if(S_TwiWaitRcvData()==ACK)//成功接收到1个byte
{
i++;
rcv_data[i-1]=TWIDAT;
if(i>=9)
{
if(S_TwiWaitRcvLastData()==NAK)
{
rcv_data=TWIDAT;
return 1; //接收数据结束
}
else
{
return 0; //接收最后1个byte数据过程中出错
}
}
}
else
{
return 0; //接收数据失败
}
}
}
else if(ret==CMD_READ)
{
while(1)
{
ret=S_TwiSendData(0x40+i);
if(ret==NAK) //主机接收数据结束
{
return 1;
}
else if(ret==ACK) //主机还可继续接收数据
{
i++;
if(i>=9)
{
if(S_TwiSendLastData(0x49)==ERR)
{
return 0; //发送最后1个byte数据过程中出错
}
else
{
return 1; //成功发送最后1个byte数据
}
}
}
else
{
return 0; //发送数据出错
}
}
}
else
{
return 0;
}
}
main函数
主站:
if(M_SendDataToSlave())
{
UCHAR M_TwiSendEnd();
}
从站
SlaveTransfer();
赞0
个人理解有限,我觉得基本可以按照IIC去理解,这个在论坛里有提到
评论
2024-06-24
赞0
评论
2024-06-23
赞0
1、主从站之间SCL和SDA引脚未连接前:
(1)主站 SCL和SDA均输出方波信号;
(2)从站 SCL和SDA均输出高电平信号;
2、主从站之间SCL和SDA引脚连接后:
SCL和SDA均输出掺杂高电平和半电平(2.5V左右)的方波信号;
评论
2024-06-21
您需要登录后才可以回复 登录 | 注册