原创 [原创]TWI硬件中断模式读写

2007-6-19 17:57 7881 9 11 分类: MCU/ 嵌入式

这个不是我自己发明也是参考了网上的一些例子,不过大部分都是轮询模式这样单片机效率比较低。我感觉还是中断模式的好一些,这样不会浪费很多时间在查询上。以下是部分代码,在M16和M48上读写PCF8563测试通过:


#include
#include


// TWI主机模式读写操作步骤预定义
#define TWI_MRW_STEP_START   1   //  发送完START
#define TWI_MRW_STEP_SLAW   2   //  发送完SLA+W
#define TWI_MRW_STEP_DATAADDR  3   // 发送完数据地址
#define TWI_MRW_STEP_REPSTART  4   // 发送完REPSTART
#define TWI_MRW_STEP_SLAR   5   // 发送完SLA+R
#define TWI_MRW_STEP_DATAR   6   // 读取完一字节数据
#define TWI_MRW_STEP_DATAW   7   // 发送完一字节数据
#define TWI_MRW_FAIL    9   // TWI操作失败
// TWI主机模式读写操状态及结果宏定义 
#define TWI_MRW_BUSY   1   // TWI操作忙碌
#define TWI_MRW_NOBUSY   0   //  TWI操作空闲 
#define TWI_MRW_OK    0   //  TWI操作成功


#define TWI_MRW_FAIL_MAX  20   // TWI操作失败最大次数 


struct TWI_MRW_STEP_MASTER    // 定义TWI_MRW_STEP主机模式结构体
 {
  volatile unsigned char uchResult; //  TWI_MRW_STEP操作结果
           // 0成功 1失败
  volatile unsigned char uchBusy;  // TWI_MRW_STEP操作忙碌状态
           // 0空闲 1忙碌
  volatile unsigned char uchSla;  // 从设备的器件地址
  volatile unsigned char uchByteAddr; // 从设备的数据地址
  volatile unsigned char *puchByte; // 字节数据指针
  volatile unsigned int uiByteLen; // 读写字节长度
  volatile unsigned char uchStep;  // TWI_MRW_STEP读写操作步骤
  volatile unsigned char uchFailCount;// 操作失败次数
 };

struct TWI_MRW_STEP_MASTER g_TwiMasterRW;  

******************************** ****************************************
*名称: ISR(TWI_vect)             * 
*功能: TWI中断服务程序 主机中断模式读写数据       *
*参数: 无                               *
*返回: 无                                     *
*************************************************************************
*/


ISR(TWI_vect)
 {


    
  switch(g_TwiMasterRW.uchStep)
   {
    case TWI_MRW_STEP_START:    // START发送完毕 
     {
      if(TW_STATUS == TW_START)  // START发送成功
       {
        TWDR = g_TwiMasterRW.uchSla&0xFE; 
        TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWIE);
              // 发送sla
              
       }
      else       // START发送失败
       {
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
       }
      break; 
     }
    case TWI_MRW_STEP_SLAW:     // slaw发送完毕 
     { 
      if(TW_STATUS == TW_MT_SLA_ACK  ) // slaw发送成功
       {
        TWDR = g_TwiMasterRW.uchByteAddr; 
        TWCR = (1 << TWINT)|(1 << TWEN)|(1<< TWIE );
              //  发送数据地址
       }
      else        // sla发送失败  
       { 
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;  
       }
      break; 
     }
    case TWI_MRW_STEP_DATAADDR:    // 数据地址发送完毕  
     {
      if(TW_STATUS == TW_MT_DATA_ACK) // 数据地址发送成功
       {
        if((g_TwiMasterRW.uchSla&0x01) == TW_READ)
              // 读模式
         {
          
          TWCR =_BV(TWINT)|_BV(TWSTA)|_BV(TWEN)
           |_BV(TWIE); //发送REP_START 
         }
        else if((g_TwiMasterRW.uchSla&0x01)
          == TW_WRITE) // 写模式            //  写模式  
         {
          TWDR = *g_TwiMasterRW.puchByte++; 
          g_TwiMasterRW.uchStep
          = TWI_MRW_STEP_DATAW -1;
           // 下一次将跳入TWI_DATA_W步骤
          TWCR = _BV(TWINT)|_BV(TWEN)
           |_BV(TWIE); // 发送写入数据
           
         }
        
       }
      else        // 数据地址发送失败
       { 
        
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;    
       }
      break; 
     }
    case TWI_MRW_STEP_REPSTART:   // RESTART发送完毕
     {
      if(TW_STATUS == TW_REP_START)// REP_START发送完毕
       {
        TWDR = g_TwiMasterRW.uchSla; 
        TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWIE); 
             // 发送sla地址
       }
      else      //  REP_START发送失败
       {
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
       }
      break;        
     } 
    case TWI_MRW_STEP_SLAR:    // slar发送完毕
     {
      if(TW_STATUS == TW_MR_SLA_ACK )// slar发送成功
       {
        if(g_TwiMasterRW.uiByteLen--)//继续接收数据
         {
          TWCR=_BV(TWINT)|_BV(TWEN)|_BV(TWEA)
          |_BV(TWIE); // 发送ACK应答
         }
        else    // 数据接收完毕
         {
          TWCR = (1<         } 
       }
      else      // slar发送失败
       {
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
       }
      break;        
     }
    case TWI_MRW_STEP_DATAR:   // 接收完一字节数据
     {
      g_TwiMasterRW.uchStep--;
      if(TW_STATUS == TW_MR_DATA_ACK) // 继续接收数据
       {
        *g_TwiMasterRW.puchByte++ = TWDR;         
        if(g_TwiMasterRW.uiByteLen--)
              // 数据没有接收完
         {
          TWCR = _BV(TWINT)|_BV(TWEN)
          |_BV(TWEA)|_BV(TWIE);// 发送ACK应答
         }
        else // 准备接收最后一个字节数据
         {            
          TWCR = _BV(TWINT)
          |_BV(TWEN)|_BV(TWIE);// 不发送ACK应答
         }
       }
      else if(TW_STATUS==TW_MR_DATA_NACK)
          // 接收最后一个字节数据
       {
        *g_TwiMasterRW.puchByte++ = TWDR;
        TWCR = _BV(TWSTO)|_BV(TWINT)|_BV(TWEN)
         |_BV(TWIE);  // 发送STOP信号
        g_TwiMasterRW.uchBusy = TWI_MRW_NOBUSY;
        g_TwiMasterRW.uchResult = TWI_MRW_OK;
       } 
      else   // 接收数据失败   
       {
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
       }
      break; 
     }  
    case TWI_MRW_STEP_DATAW :    // 发送完一字节数据
     {     
      g_TwiMasterRW.uchStep--; // 循环发送指定长度的数据                 
      if(TW_STATUS==TW_MT_DATA_ACK) // 发送数据发送成功
       {
        if(g_TwiMasterRW.uiByteLen--)// 数据没有发送完    
         {
          TWDR = *g_TwiMasterRW.puchByte++;
          TWCR = _BV(TWINT)|_BV(TWEN)
          |_BV(TWIE); // 发送数据
         } 
        else    // 发送完数据  
         {
          TWCR = _BV(TWSTO)|_BV(TWINT)
          |_BV(TWEN)|_BV(TWIE);// 发送STOP信号
          g_TwiMasterRW.uchResult
              = TWI_MRW_OK;
          g_TwiMasterRW.uchBusy
              = TWI_MRW_NOBUSY;
          
         } 
       }
      else     //  发送数据失败  
       {
        g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
       }
      break; 
     }
    default :      //  错误状态 
     {
      g_TwiMasterRW.uchStep = TWI_MRW_FAIL;
      break;
     }
   }
   
  if(g_TwiMasterRW.uchStep == TWI_MRW_FAIL)
   { 
    g_TwiMasterRW.uchFailCount++;
    if(g_TwiMasterRW.uchFailCount >= TWI_MRW_FAIL_MAX)
        // 失败超过最大次数
     {
      TWCR = _BV(TWSTO)|_BV(TWINT)|_BV(TWEN)|_BV(TWIE);  
        // 发送STOP信号
      
      g_TwiMasterRW.uchResult = TWI_MRW_FAIL;
      g_TwiMasterRW.uchBusy = TWI_MRW_NOBUSY;      
     }
    else   // 失败没有超过最大次数
     {
      TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN)|_BV(TWIE);
        // 发送START
      g_TwiMasterRW.uchStep = TWI_MRW_STEP_START;
     }
   }
  else // 进入下一步操作
   {
    g_TwiMasterRW.uchStep++;
   } 
 
 }


/*
*************************************************************************
*函数: unsigned char TwiMasterRW(unsigned char uchSla,      *
*    unsigned char uchByteAddr, unsigned char *puchByte,  *
*           unsigned int uiByteLen )         *
*功能: TWI主机模式读写数据            *
*                       *
*参数: uchSla 从器件地址  uchByteAddr  数据地址       *
*       *puchByte 数据指针 uiByteLen   数据长度       *
*返回: 1 操作成功 0 操作失败           *
*************************************************************************
*/
unsigned char TwiMasterRW(unsigned char uchSla, unsigned char uchByteAddr,
      unsigned char *puchByte, unsigned int uiByteLen )
 {
  g_TwiMasterRW.uchResult = TWI_MRW_FAIL;
  g_TwiMasterRW.uchBusy = TWI_MRW_BUSY;
  g_TwiMasterRW.uchSla = uchSla;
  g_TwiMasterRW.uchByteAddr = uchByteAddr;
  g_TwiMasterRW.puchByte = puchByte;
  g_TwiMasterRW.uiByteLen = uiByteLen;
  g_TwiMasterRW.uchStep = TWI_MRW_STEP_START;
  g_TwiMasterRW.uchFailCount = 0;
  TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN)|_BV(TWIE);// 启动总线START状态
  while(g_TwiMasterRW.uchBusy == TWI_MRW_BUSY); // 等待操作完成  
  
  if(g_TwiMasterRW.uchResult == TWI_MRW_OK)      
   {
    return TWI_MRW_OK;     // 如果操作成功返回1
   }
  else          // 如果操作失败返回0 
   {
    return TWI_MRW_FAIL;
   }
 }

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户1447181 2009-7-30 23:53

网上都是轮询方式,最近我也在研究中断方式

用户1053025 2007-6-25 16:08

支持一下:D

相关推荐阅读
用户1079511 2009-07-10 16:08
Mega16读取SD卡内的FAT16文件
最近一直在学习FAT文件系统,在网络上找了一些资料加上参考别人写的程序,现在已经可以读取SD/MMC卡指定的文件,有些东西自己也不是很懂,回头还得慢慢研究。程序比较简单,就是读取SD卡的基本信息和初始...
用户1079511 2009-04-14 08:38
[原创]AVR M16热敏电阻测温LCM12864显示
https://static.assets-stash.eet-china.com/album/old-resources/2009/4/14/d085d878-6d8f-4245-acdb-cf44...
用户1079511 2009-04-08 11:34
Mega16 Bootloader+PC端上位机
AVR的Bootloader功能很方便产品的在线升级,以前参考网上的资料写过下位机的程序,标准的XMODEM协议,用超级终端来升级程序。最近在学习C#,所以用C#写个简单的上位机软件,配合以前的boo...
用户1079511 2009-01-22 16:15
Mega16热敏电阻测温上位机曲线显示
最近在一直学习用C#做上位机,把以前的做的m16热敏电阻测温的程序翻出来,稍加修改通过串口发给PC;PC端用c#2008写程序,接收数据后通过ZedGraph绘图控件实时显示出曲线图。ZedGraph...
用户1079511 2009-01-09 09:25
[原创]c#的Hex转Bin小程序
最近在搞AVR的bootloader,程序已经写好了,参考网上的代码用的是XMODEM协议用XP自带的超级终端。问题是xmodem支持bin格式的文件,一般用编译器生成的是hex文件不用直接使用,需要...
用户1079511 2008-12-31 10:42
[学习]用595驱动LED实现灰度调节
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />前一段时间在ouravr论坛里闲逛的...
EE直播间
更多
我要评论
2
9
关闭 站长推荐上一条 /3 下一条