pic模拟iic通讯开发中所遇重点难点总结

转行做程序员来的第一个任务,就是用模拟iic给板子加上lmp91000,小公司嘛中间经历了好多事情再加上纯粹新手,调了两个多月才基本完成功能,回过头来总结,其实模拟iic很简单,多看数据手册多用示波器就行。下面总结下本次项目遇到的问题和解决方法。

第一个问题是io口操作问题,本次项目使用的是pic单片机,和stm32系列区别挺大的。最开始我只百度了pic的io口操作,以及pic数据手册的io章节,以为只需要操作TRISA和PORTA两个寄存器就可以完成输出高低电平的操作,后来有遇到连续两个问题,sda无法拉高,解决后sda拉高出现弧线。第一个问题分析应该是引脚复用功能没有完全关闭,每次需要使用sda引脚时我都把复用功能再关闭一次,好在基本上只需要开机初始化时通讯一次就够了,所以不太占用cpu资源。除了复用功能之外,看网上有的大佬分析是LATA寄存器需要设置,老实讲这个寄存器和PORTA寄存器的区别我还没有弄清楚,但是双管齐下之后sda拉高就再也没有问题了。第二个问题,拉高sda示波器里看这个过程是段弧线,查阅91000数据手册发现需要接上拉电阻,接上上拉电阻后问题解决。所以说,数据手册很重要!!!

第二个问题是iic时序问题,没啥好说的网上一大堆程序,copy下来根据数据手册和示波器调一调就好了,当然第一次接触的我也调了好久,现在再调一个全新的模拟iic估计一两天就行了吧哈哈。这里不得不再次强调,数据手册真的很重要!!调时序一定要根据数据手册来调,要不然就是无头苍蝇,像我们这种没师傅带的野生程序员,仔细读数据手册太重要了。

第三个问题是ad转换问题,属于历史遗留问题,和iic通讯关系不大其实。正常设置的ad转换参考电压是2.5和0,对应ad值为4095和0,但是一旦91000开始工作,零点电压时ad值为1365,并且特别稳定,给电测试时从0到0.6v都没有反应,大于0.6时ad值才开始上升,直到给电3.2v左右时上升至5460,再给电则跳到1开始继续走数。一开始从5460-1635=4095上入手,怀疑是ad转换设置问题,更改了参考电压,问题解决,但是同样带来另一个问题,就是电压为0时ad值为4.8k左右,给电到0.4v走到两百左右,按理来说其实已经可以使用了,但是我对于原本程序里的ad转换部分不够熟悉,直接更改参考电压怕有隐患,所以没有采用这种方法。后面逐项排查测试发现时sda引脚问题,原本板子sda这个引脚和另一个引脚并一起用于ad转换,经测试91000通讯后将sda拉低即可。

下面附上本次模拟iic代码,实测能用,不过由于没有调通读取从机寄存器数据,所以只上传驱动部分

void LMP_SDA_IN(void)  
{
    TRISAbits.TRISA1=1;
}
void LMP_SDA_OUT(void)  
{
    ANSELAbits.ANSA1 = 0;
    TRISAbits.TRISA1=0;
}


void LMP_IIC_SCL (unsigned char num)//高电平用输入,低电平用输出
{
	if(num)
	{ 
		TRISAbits.TRISA5=0;
        PORTAbits.RA5=1;
	}
	else
	{
        TRISAbits.TRISA5=0;
		PORTAbits.RA5=0;
	}
}
void LMP_IIC_SDA (unsigned char num)
{
	if(num)
	{   
        ANSELAbits.ANSA1 = 0;
        TRISAbits.TRISA1 = 0;
        LATAbits.LATA1 = 1;
        PORTAbits.RA1=1;
	}
	else
	{
        ANSELAbits.ANSA1 = 0;
        TRISAbits.TRISA1 = 0;
        LATAbits.LATA1 = 0;
		PORTAbits.RA1=0;
	}
}
unsigned char LMP_READ_SDA (void)
{
	return PORTAbits.RA1;
}
void LMP_IIC_Start(void)
{
	LMP_SDA_OUT();     //sda???
	LMP_IIC_SDA(1);                    
	LMP_IIC_SCL(1);
	NOP();NOP();NOP();NOP();NOP();
	LMP_IIC_SDA(0);    //START:when CLK is high,DATA change form high to low
	NOP();NOP();
	LMP_IIC_SCL(0);    //??I2C??,?????????
}  
void LMP_IIC_Stop(void)      
{
	LMP_SDA_OUT(); 
    LMP_IIC_SCL(0);    
	LMP_IIC_SDA(0);     //STOP:when CLK is high DATA change form low to high
	NOP();NOP();
	LMP_IIC_SCL(1);
    NOP();NOP();NOP();NOP();
	LMP_IIC_SDA(1);     //??I2C??????
	NOP();NOP();NOP();NOP();                                                             
}
void dlay(unsigned char val)
{
    while(val--)
    {
        NOP();NOP();NOP();NOP();
    }
}
unsigned char LMP_IIC_Wait_Ack(void)
{
	unsigned short errTime=0;
    PORTAbits.RA1=1; 
    TRISAbits.TRISA1=1;
    PORTAbits.RA5=1;
	NOP();NOP();   
	while(LMP_READ_SDA())
	{
		errTime++;
		if(errTime>2000)
		{
			LMP_IIC_Stop();
			return 1;
		}
	}
	LMP_IIC_SCL(0);//????0  
//    LMP_IIC_SDA(1);
	return 0;  
}

void LMP_IIC_Send_Byte(unsigned char byte)
{                        
	unsigned char i; 
	unsigned char temp;
	LMP_SDA_OUT();            
	LMP_IIC_SCL(0);
	for(i=0;i<8;i++)
	{
        temp = (byte&0x80)>>7;
		LMP_IIC_SDA(temp);
		byte<<=1; 
		NOP();
		LMP_IIC_SCL(1);
		NOP();NOP();NOP();NOP();  
		LMP_IIC_SCL(0);        

	}   
    NOP();NOP();NOP();NOP();
    LMP_IIC_SDA(0); 
//	LMP_IIC_SDA(1);               
}  

void I2C_WriteByte(unsigned char slaveAddr, unsigned char byte, unsigned char writeAddr)
{
		LMP_IIC_Start();
		LMP_IIC_Send_Byte(slaveAddr);
		if(LMP_IIC_Wait_Ack())
		{
				return;
		}
		LMP_IIC_Send_Byte(writeAddr);
		if(LMP_IIC_Wait_Ack())
		{
				return;
		}
		LMP_IIC_Send_Byte(byte);
		if(LMP_IIC_Wait_Ack())
		{
				return;
		}
		LMP_IIC_Stop();
		NOP();NOP();NOP();NOP();NOP();
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值