/****************************************************************************<br />* 文件名:I2CINT.C<br />* 功能:硬件I2C软件包,利用中断方式操作。<br />* 说明:主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)<br />****************************************************************************/<br />#include "config.h" <br />#include "I2C.h"<br />volatile uint8 I2C_sla; // 从机地址(即器件地址)<br />volatile uint8 I2C_suba; // 子地址<br />volatile uint8 *I2C_buf; // 数据缓冲区指针 (读操作时会被更改)<br />volatile uint8 I2C_num; // 操作数据个数 (会被更改)<br />volatile uint8 I2C_end; // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)<br />volatile uint8 I2C_suba_en; // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)<br /><br />uint8 I2C_Init(uint32 fi2c)<br />{ <br /> if(fi2c>400000) fi2c = 400000;<br /><br /> PINSEL0 = (PINSEL0&0xFFFFFF0F) | 0x50; // 设置I2C控制口有效<br /><br /> I2SCLH = (Fpclk/fi2c + 1) / 2; // 设置I2C时钟为fi2c<br /> I2SCLL = (Fpclk/fi2c) / 2;<br /> I2CONCLR = 0x6C;<br /> I2C_end=0;<br /> I2cWrite_sem=OSSemCreate(1);<br /> //I2CONSET = 0x40; // 使能主I2C<br /> <br /> <br /> // I2cMbox = OSMboxCreate(NULL); /* 消息邮箱用于中断向任务传递操作结果 */<br />// I2cWrite = OSMboxCreate((void *)0);<br /> // I2cRead = OSMboxCreate(NULL);<br /> /* if (I2cMbox == NULL)<br /> {<br /> return 0;<br /> }<br /> */ // 使能I2C中断 <br />}<br /><br />/****************************************************************************<br />* 名称:IRQ_I2C()<br />* 功能:I2C中断,通过判断I2C状态字进行相应的操作。<br />* 入口参数:无<br />* 出口参数:无<br />****************************************************************************/<br />void I2c_Exception(void)<br />{ uint8 sta,err;<br /> OS_ENTER_CRITICAL();<br /> sta = I2STAT; // 读出I2C状态字<br /> switch(sta)<br /> { case 0x08: // 己发送起始条件<br /> if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址<br /> else I2DAT = I2C_sla; // 否则直接发送从机地址<br /> I2CONCLR = 0x28; // SI=0<br /> break;<br /> <br /> case 0x10:<br /> I2DAT = I2C_sla; // 重启动总线后,发送从地址<br /> I2CONCLR = 0x28; // SI=0<br /> break;<br /> <br /> case 0x18: // 已发送SLA+W,并已接收应答<br /> if(0==I2C_suba_en) // 无子地址,则直接发送数据<br /> { if(I2C_num>0)<br /> { I2DAT = *I2C_buf++;<br /> I2CONCLR = 0x28; <br /> I2C_num--;<br /> }<br /> else<br /> { I2CONSET = 0x10; // 无数据发送,结束总线<br /> I2CONCLR = 0x28;<br /> I2C_end = 1; // 设置总线操作结束标志<br /> // OSMboxPost(I2cMbox, (void *)I2C_WRITE_END);<br /> }<br /> break;<br /> }<br /> if(1==I2C_suba_en) // 发送子地址<br /> { I2DAT = I2C_suba;<br /> I2CONCLR = 0x28;<br /> }<br /> if(2==I2C_suba_en)<br /> { I2DAT = I2C_suba;<br /> I2CONCLR = 0x28;<br /> I2C_suba_en = 0; // 子地址己处理<br /> }<br /> break;<br /> <br /> case 0x28: // 已发送I2C数据,并接收到应答<br /> if(0==I2C_suba_en) // 无子地址,则直接发送数据<br /> { if(I2C_num>0)<br /> { I2DAT = *I2C_buf++;<br /> I2CONCLR = 0x28; <br /> I2C_num--;<br /> }<br /> else<br /> { I2CONSET = 0x10; // 无数据发送,结束总线<br /> I2CONCLR = 0x28;<br /> I2C_end = 1; //此处是为了测试之用<br /> <br /> err=OSMboxPost(I2cWrite,(void *)1);<br />/////////问题是邮箱发送消息之后在中断程序结束时进入取数据中止,不知是何原因,不通过邮箱发送消息而直接通过全局变量就没任何问题.敬请周工及各位大侠指点.<br /> VICIntEnClr = 1 << 9; // 禁止能I2c中断 <br /> }<br /> break;<br /> }<br /> if(1==I2C_suba_en) // 若是指定地址读,则重新启动总线<br /> { I2CONSET = 0x20;<br /> I2CONCLR = 0x08;<br /> I2C_suba_en = 0; // 子地址己处理<br /> }<br /> break;<br /> <br /> <br /> case 0x20:<br /> case 0x30:<br /> case 0x38:<br /> I2CONCLR = 0x28; // 总线进入不可寻址从模式<br /> I2C_end = 0xFF; // 总线出错,设置标志<br /> // OSMboxPost(I2cMbox, (void *)I2C_err);<br /> break;<br /> <br /> <br /> case 0x40: // 己发送SLA+R,并已接收到应答<br /> if(1==I2C_num) // 最后一字节,接收数据后发送非应答信号<br /> { I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答<br /> }<br /> else // 接收数据并发送应答信号<br /> { I2CONSET = 0x04; // AA=1,接收到数据后产生应答<br /> I2CONCLR = 0x28;<br /> }<br /> break;<br /> <br /> case 0x50:<br /> *I2C_buf++ = I2DAT; // 读取数据<br /> I2C_num--;<br /> if(1==I2C_num)<br /> { I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答<br /> }<br /> else<br /> { I2CONSET = 0x04; // AA=1,接收到数据后产生应答<br /> I2CONCLR = 0x28;<br /> }<br /> break;<br /> <br /> case 0x58:<br /> *I2C_buf++ = I2DAT; // 读取最后一字节数据<br /> I2CONSET = 0x10; // 结束总线<br /> I2CONCLR = 0x28;<br /> I2C_end = 1; <br /> // OSMboxPost(I2cMbox, (void *)I2C_READ_END);<br /> break;<br /> <br /> case 0x48:<br /> I2CONCLR = 0x28; // 总线进入不可寻址从模式<br /> I2C_end = 0xFF; <br /> // OSMboxPost(I2cMbox, (void *)I2C_err);<br /> break;<br /> <br /> default: <br /> break;<br /> }<br /> <br /><br /> VICVectAddr = 0x00; // 中断处理结束<br /> OS_EXIT_CRITICAL();<br />}<br /><br /><br /><br />/****************************************************************************<br />* 名称:ISendByte()<br />* 功能:向无子地址器件发送一字节数据。<br />* 入口参数:sla 器件地址<br />* dat 要发送的数据<br />* 出口参数:返回值为0时表示出错,为1时表示操作正确。<br />* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式<br />****************************************************************************/<br />uint8 ISendByte(uint8 sla, uint8 dat)<br />{ <br /> uint8 err;<br /> unsigned int Rt;<br /> /* 参数设置 */<br /> I2C_sla = sla; // 写操作的器件地址<br /> I2C_buf = &dat; // 待发送的数据<br /> I2C_num = 1; // 发送1字节数据<br /> I2C_suba_en = 0; // 无子地址<br /> I2C_end = 0;<br /> <br /> I2CONCLR = 0x2C;<br /> I2CONSET = 0x60; // 设置为主机,并启动总线<br /> <br /> /* Rt=(unsigned int)OSMboxPend(I2cMbox, 0, &err);<br /> if(Rt==I2C_WRITE_END)<br /> {<br /> return 1;<br /> }<br /> else <br /> return 0;*/<br /> while(I2C_end==0);<br /> if(1==I2C_end) return(1);<br /> else return(0);<br />}<br /><br /><br /><br />/****************************************************************************<br />* 名称:ISendStr()<br />* 功能:向有子地址器件发送多字节数据。<br />* 入口参数:sla 器件从机地址<br />* suba 器件子地址<br />* s 数据发送缓冲区指针<br />* no 发送数据个数<br />* 出口参数:返回值为0时表示出错,为1时表示操作正确。<br />* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式<br />****************************************************************************/<br />uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)<br />{ <br /> uint8 err;<br /><br /> // unsigned int Rt;<br /> uint8 *Rt;<br /> //I2cWrite = OSMboxCreate((void *)0);<br /><br /> /* 参数设置 */<br /> I2C_sla = sla; // 写操作的器件地址<br /> I2C_suba = suba; // 子地址<br /> I2C_buf = s; <br /> I2C_num = no; <br /> I2C_suba_en = 2; // 有子地址写<br /> I2C_end = 0;<br /> <br /> I2CONCLR = 0x2C;<br /> I2CONSET = 0x60; // 设置为主机,并启动总线<br /><br /> /* Rt=(unsigned int)OSMboxPend(I2cMbox, 0, &err);<br /> Rt=(uint8 *)OSMboxPend(I2cWrite, 0, &err);<br /><br /> if(Rt[0]==1)<br /> {<br /> return 1;<br /> }<br /> else <br /> return 0;*/<br /> while(I2C_end==0);<br /> if(1==I2C_end) return(1);<br /> else return(0);<br /> OSSemPend(I2cWrite_sem,0,&err);<br /> /* Rt=(uint8 *)OSMboxPend(I2cWrite, 0, &err);<br /><br /> if(Rt[0]==1)<br /> {<br /> return 1;<br /> }<br /> else <br /> return 0;*/<br />}<br /><br /><br /><br />/****************************************************************************<br />* 名称:IRcvByte()<br />* 功能:向无子地址器件读取一字节数据。<br />* 入口参数:sla 器件地址<br />* dat 接收数据的变量指针<br />* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。<br />* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式<br />****************************************************************************/<br />uint8 IRcvByte(uint8 sla, uint8 *dat)<br />{ <br /> uint8 err;<br /> unsigned int Rt;<br /> /* 参数设置 */<br /> I2C_sla = sla+1; // 读操作的器件地址<br /> I2C_buf = dat;<br /> I2C_num = 1;<br /> I2C_suba_en = 0; // 无子地址<br /> I2C_end = 0;<br /> <br /> I2CONCLR = 0x2C;<br /> I2CONSET = 0x60; // 设置为主机,并启动总线<br /> <br />/* Rt=(unsigned int)OSMboxPend(I2cMbox, 0, &err);<br /> if(Rt==I2C_READ_END)<br /> {<br /> return 1;<br /> }<br /> else <br /> return 0;*/<br /> while(0==I2C_end);<br /> if(1==I2C_end) return(1);<br /> else return(0);<br />}<br /><br /><br /><br />/****************************************************************************<br />* 名称:IRcvStr()<br />* 功能:向有子地址器件读取多字节数据。<br />* 入口参数:sla 器件地址<br />* suba 器件子地址<br />* s 数据接收缓冲区指针<br />* no 读取数据个数<br />* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。<br />* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式<br />****************************************************************************/<br />uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)<br />{ <br /> uint8 err;<br /> unsigned int Rt;<br /> if(0==no) return(0);<br /> <br /> /* 参数设置 */<br /> I2C_sla = sla+1; // 读操作的器件地址<br /> I2C_suba = suba; <br /> I2C_buf = s;<br /> I2C_num = no;<br /> I2C_suba_en = 1; // 有子地址读<br /> I2C_end = 0;<br /> <br /> I2CONCLR = 0x2C;<br /> I2CONSET = 0x60; // 设置为主机,并启动总线<br /> <br />/* Rt=(unsigned int)OSMboxPend(I2cMbox, 0, &err);<br /> if(Rt==I2C_READ_END)<br /> {<br /> return 1;<br /> }<br /> else <br /> return 0;*/<br /> while(0==I2C_end);<br /> if(1==I2C_end) return(1);<br /> else return(0);<br />}<br /><br /><br />//////////////////////////////////////////////////////////////<br /> I2C_end = 1; //此处是为了测试之用<br /> <br /> err=OSMboxPost(I2cWrite,(void *)1);<br />/////////问题是邮箱发送消息之后在中断程序结束时进入取数据中止,不知是何原因,不通过邮箱发送消息而直接通过全局变量就没任何问题.敬请周工及各位大侠指点.<br /><br /> |
|