| 
 
| /****************************************************************************<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 /> | 
 |