3911|7

69

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

挂起中断 [复制链接]

请问各位高手:
为什么在读操作和写操作中两次挂起中断
具体代码如下:
DWORD IIC_Read(DWORD Handle, LPVOID pBuffer, DWORD dwNumBytes)
{
        UINT32 count, ret;
        uchar *pReadBuffer;

        if ((pBuffer == NULL) || (dwNumBytes <= 0))
                return 0;

        pReadBuffer = MapPtrToProcess(pBuffer, GetCallerProcess());

        // 设置从机地址及当前状态
        I2cCurSla = I2cSla | 0x01;
        I2cStatus = I2C_STATUS_SETADDR;
        StartI2C(I2cCurSla);

        ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT);                /* 挂起当前线程,直到IIC中断的产生 */   
        ResetEvent(gI2CEvent);       
        if ((IICError != I2C_ERROR_NO_ERR) || (ret != WAIT_OBJECT_0))
        {
                RETAILMSG(1, (TEXT("ERROR: IIC_Read: Send Slave Address fail! \r\n")));
                return 0;       
        }
       
        I2cStatus = I2C_STATUS_RECEIVE;                                                // 进入接收状态
        for (count = 0; count < dwNumBytes; count++)
        {
                if (count == (dwNumBytes - 1))
                        IIC_StartRecByteNA();
                else
                        IIC_StartRecByteA();       
               
                /* 挂起当前线程,直到IIC中断的产生 */
                ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT);
                ResetEvent(gI2CEvent);
                if (ret != WAIT_OBJECT_0)
                {
                        if (ret == WAIT_TIMEOUT)
                                RETAILMSG(1, (TEXT("ERROR: IIC read data time out! \r\n")));
                        else
                                RETAILMSG(1, (TEXT("ERROR: IIC read data fail! \r\n")));
                       
                        return count;
                }
       
                *pReadBuffer = IIC_RecByte();       
                pReadBuffer++;

                if (IICError != I2C_ERROR_NO_ERR)
                {
                        RETAILMSG(1, (TEXT("ERROR: IIC_Read: Receive data fail! \r\n")));
                        break;       
                }
        }
        StopI2C(0);
        return count;
}
1、为什么在读操作和写操作中两次挂起中断这样做的目的是什么呢??
2、还有ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT);其中#define I2C_RW_TIMEOUT                2000
是在等待gI2CEvent这个事件产生吗??,这个事件是在中断线程中被触发的,那么中断线程是怎么被触发的呢?(比如外部中断都是按键触发中断,IIC是如何触发中断呢)

最新回复

清晰了! shuiyan兄,您看是不是这个流程(单指IIC读的过程): 1、先设置从机地址,状态:         I2cCurSla = I2cSla | 0x01;                          I2cStatus = I2C_STATUS_SETADDR; 2、使能IIC    StartI2C(I2cCurSla);  这时CPU设置需要等待从机的应答 3、挂起中断 WaitForSingleObject,等待从机应答(主机设置开IIC后,从机做的回应),ACK或者NAK    2秒钟没有应答则说明开IIC失败 4、应答产生,开中断,使能事件SetEvent(gI2CEvent); 5、进入FOR循环体,先设置接收数据是否需要应答ACK或者不需要应答NAK         即:    if (count == (dwNumBytes - 1))                         IIC_StartRecByteNA();                 else                         IIC_StartRecByteA(); 6、接收数据前中断挂起 WaitForSingleObject,等待数据传送过来, 7、硬件接收到数据,触发中断,在中断中使能事件SetEvent(gI2CEvent);    程序开始接受数据,并将数据存在pReadBuffer中 这次理解应该对了吧 再问一下: 程序没有对ACK应答位进行判断,是硬件自己判断的吗?  详情 回复 发表于 2008-6-26 13:36
点赞 关注

回复
举报

85

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
顶一下
各位兄弟帮帮忙啊!
 
 

回复

62

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
1.
第一次只是在初始化配置,开始控制时的一次(只需要一次),所以这次是没有while,或者for之类的循环的。至于为什么要挂起等待中断。很显然,是为了释放CPU资源,避免阻塞。暴力的做法就是用while()循环读取某个bit位的值来判断初始化和握手是否成功。这样整个系统都被卡在这里了。

第二次是真正的有效数据通讯,所以这次是有for循环的,挂起会在每次的发出之后,需要等待设备的ACK/NAK应答。同样也是避免占用CPU资源的。


2. #define I2C_RW_TIMEOUT 2000 是设置等待超时值,就是如果超过2秒,就说明此次通讯失败,没有正确的返回值。

的确是在等待gI2CEvent这个事件。

这个事件对应的中断是由CPU的IIC Controller产生的,是硬件层面的,你既然明白按键能触发外部中断,那么也应该能理解串口、IIC、SPI之类的通讯端口,会产生数据发送完毕中断、数据发送失败中断、FIFO清空中断、FIFO过半中断、接收到数据中断,等等等等,都是可以触发中断的。
 
 
 

回复

78

帖子

0

TA的资源

一粒金砂(初级)

4
 
非常非常感谢!
是不是这样的:
程序在执行这条语句StartI2C(I2cCurSla)(开IIC)后进入中断挂起状态,等待中断,此时在中断线程中的CASE语句中找到I2cStatus = I2C_STATUS_SETADDR(判断一下从机地址后)就使能事件gI2CEvent,如果这些执行是在2秒内,则继续执行ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT)的下一条语句,即ResetEvent(gI2CEvent);
使事件恢复到原来的状态,然后令I2cStatus = I2C_STATUS_RECEIVE; 进入for 循环调用IIC_StartRecByteA(需要应答位)或IIC_StartRecByteNA(无需应答)接收数据。
在一组数据接收结束之后(FOR循环结束)又一次进入中断挂起,这次挂起结束后调用了IIC_RecByte(),这个函数的作用是:IIC总线上接收一个字符这个函数定义如下:
BYTE IIC_RecByte(void)
{
        return (v_pIICPregs->IICDS);
}
中断线程如下:DWORD I2C_IntrThread(PVOID pArg)
{
        DWORD ret;

        // 创建I2C中断中断事件
        gI2CIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

        // 初始化 I2C 中断: 注册中断事件, 允许 I2C 中断
        if (!(InterruptInitialize(g_I2CSysIntr, gI2CIntrEvent, 0, 0)))
        {
                CloseHandle(gI2CIntrEvent);
                RETAILMSG(1, (TEXT("ERROR: I2C Bus: Interrupt initialize failed.\r\n")));
                return 0;
        }

        // IIC 中断线程开始运行
        while (1)
        {
                ret = WaitForSingleObject(gI2CIntrEvent, INFINITE);
                if ((ret != WAIT_OBJECT_0) || (g_bKillIST == TRUE))                                        /* 驱动卸载或错误发生 */
                {               
                        CloseHandle(gI2CIntrEvent);
                        RETAILMSG(1, (TEXT("INFO: I2C Bus Driver DeInit or Error Occur. \r\n")));
                        return 0;                                                                                                                /* 线程退出 */
                }

                switch(I2cStatus)
                {       
                    // Start IIC Status
                    case I2C_STATUS_SETADDR:                                               
                                if((v_pIICPregs->IICSTAT & 0x09) == 0)                                                // 发送地址成功
                                {
                                        SetEvent(gI2CEvent);               
                                        IICError = I2C_ERROR_NO_ERR;
                                }
                                else
                                {
                                        if (I2cCurSla & I2C_READ)
                                                v_pIICPregs->IICSTAT = (2 << 6) | (0<<5) | (1<<4);        // 读终止
                                        else               
                                                v_pIICPregs->IICSTAT = (3 << 6) | (0<<5) | (1<<4);        // 写终止
                                       
                                        IICCON_DACK(v_pIICPregs->IICCON);
                                        Sleep(1);                                                                                                // 等待结束信号产生完毕       
                                       
                                        SetEvent(gI2CEvent);
                                        IICError = I2C_ERROR_SETADDR;
                                }
                        break;
   
                    // Send Bytes Status
                    case I2C_STATUS_SEND:       
                            if((v_pIICPregs->IICSTAT & 0x09) == 0)                                                // 数据成功发送
                            {
                                        IICError = I2C_ERROR_NO_ERR;
                                        SetEvent(gI2CEvent);
                            }
                            else
                            {
                                    v_pIICPregs->IICSTAT = (3 << 6) | (0 << 5) | (1 << 4);
                                   
                                        IICCON_DACK(v_pIICPregs->IICCON);       
                                        Sleep(1);                                                                                                // 等待结束信号产生完毕                  
                                   
                                        IICError = I2C_ERROR_SEND;
                                        SetEvent(gI2CEvent);
                                }
                     break;
                           
                    // Receive Bytes
                    case I2C_STATUS_RECEIVE:
                            if((v_pIICPregs->IICSTAT & 0x08) == 0)
                            {
                                       
                                        IICError = I2C_ERROR_NO_ERR;       
                                        SetEvent(gI2CEvent);
                            }
                            else
                            {
                                           // 发送结束信号       
                                        v_pIICPregs->IICSTAT = (2 << 6) | (0 << 5) | (1 << 4);       
                                        IICCON_DACK(v_pIICPregs->IICCON);
                                        Sleep(1);                                                                                        // 等待结束信号产生完毕
                               
                                        IICError = I2C_ERROR_RECEIVE;
                                        SetEvent(gI2CEvent);
                            }
                    break;
   
                        default:
                          break;       
                }
       
                InterruptDone(g_I2CSysIntr);
        }      
}
我理解的是不是不对?2楼怎么说是在第二次挂起后才进入FOR循环(第二次是真正的有效数据通讯,所以这次是有for循环的)??
还有第2次挂起结束后
*pReadBuffer = IIC_RecByte();
pReadBuffer++;
是什么意思啊??作用是什么??
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

5
 
发现你对这个流程有点误解,稍微解释一下。不过首先建议你细细看一下“线程相关”的知识,还有IIC协议的知识。尤其是IIC的通讯状态机一定要弄清楚。

ResetEvent(gI2CEvent); 是释放事件(envnet)标志,这个是线程的概念,并不是“使事件恢复到原来的状态”。相关的资料很多,你google或者baidu一下线程编程,就可以明白。


StartI2C(I2cCurSla);  //这个是开始IIC,也就是硬件接口上,发出一个“IIC_START"信号,并且向对应地址的从设备发出一个基本的读写控制指令,等待回应。具体可以查看IIC协议。

ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); /* 挂起当前线程,直到IIC中断的产生 */  
//这个Wait中断的意思,就是当前一步发出IIC_START信号(命令)后,需要等待一个中断,这个中断是由于对应地址(I2cCurSla)的从设备,接收到基本的读写控制指令后,发回ACK(成功应答)或者NAK(无应答),CPU的IIC Controller会根据两种状态,产生两种中断。

而2秒的超时设置,就是为了防止无限等待造成IIC线程锁死。因为再慢的通讯,2秒的时间也肯定有结果了。

这是第一次等待中断的作用。
--------------------------------------------------

第二次中断是在for里面进行的,目的也是为了等待IIC的通讯中断。CPU发出“读”某个寄存器的命令后,需要等待设备将数据发送过来,这个发送过程是需要时间的。所以,CPU发出命令后,就等待中断,线程挂起,自己做别的事情去。一旦硬件的IIC Controller接收到数据后,会产生中断,重新唤醒这个线程,将这次的数据保存,并进行下一次的 (发送“读”命令->线程挂起,等待中断->接收到数据,产生中断->线程唤醒,保存数据) 流程。

-------------------------------------------------
还有第2次挂起结束后
*pReadBuffer = IIC_RecByte();   // 将从设备传过来的数据读取保存在pReadBuffer的当前地址
pReadBuffer++;                  // 将pReadBuffer的地址+1(字节)。
是什么意思啊??作用是什么??       // 其实就是从设备传送过来很多数据,按顺序保存在pReadBuffer对应的内存空间中,等待全部传送完毕后,进行处理。

这个处理,在所有的数据交换处理中都会应用,见多了就知道。
 
 
 

回复

81

帖子

0

TA的资源

一粒金砂(初级)

6
 
我按我的思路一时转不过来

我还想问一下:
1、ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT);
这个函数返回失败后执行哪条语句???

2、第一次ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); /* 挂起当前线程,直到IIC中断的产生 */  
中断产生后,进入中断线程处理函数,执行
case I2C_STATUS_RECEIVE:
                            .......
                        break;
中断返回后,不是直接就进入       
        I2cStatus = I2C_STATUS_RECEIVE;                                                // 进入接收状态
        for (count = 0; count < dwNumBytes; count++)
        {
                if (count == (dwNumBytes - 1))
                        IIC_StartRecByteNA();
                else
                        IIC_StartRecByteA();               
这个FOR循环操作了吗???
3、第二次ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); /* 挂起当前线程,直到IIC中断的产生 */  
中断产生后也只是执行这句下面的程序:
                   ResetEvent(gI2CEvent);
                if (ret != WAIT_OBJECT_0)
                {
                        if (ret == WAIT_TIMEOUT)
                                RETAILMSG(1, (TEXT("ERROR: IIC read data time out! \r\n")));
                        else
                                RETAILMSG(1, (TEXT("ERROR: IIC read data fail! \r\n")));
                       
                        return count;
                }
       
                *pReadBuffer = IIC_RecByte();       
                pReadBuffer++;

                if (IICError != I2C_ERROR_NO_ERR)
                {
                        RETAILMSG(1, (TEXT("ERROR: IIC_Read: Receive data fail! \r\n")));
                        break;       
                }
        }
怎么还能执行FOR循环呢??
不解!!
谢谢shuiyan兄!
 
 
 

回复

79

帖子

0

TA的资源

一粒金砂(初级)

7
 
SORRY我看错了
没看清第二个ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); /* 挂起当前线程,直到IIC中断的产生 */  
是在FOR循环体内部
那现在清楚了
是不是这样:
1、第一次ret = WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); /* 挂起当前线程,直到IIC中断的产生 */  
2、中断产生后
   进入中断SetEvent(gI2CEvent);
3、然后进入FOR循环体
   在循环体中首先判断是ACK应答模式还是NOACK
   如果是NOACK则直接执行IIC_StartRecByteNA();
4、如果是ACK模式则挂起中断WaitForSingleObject(gI2CEvent, I2C_RW_TIMEOUT); 等待ACK应答
   ACK应答到来则进入中断SetEvent(gI2CEvent);
5、然后接收数据存到pReadBuffer
  *pReadBuffer = IIC_RecByte();       
                pReadBuffer++;

这样对了吧??
问题:ACK应答不是在接收完数据之后由从机发给主机的吗
这个程序怎么好象是先接收到了ACK应答,才发的数据呢??


再次感谢shuiyan兄!
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

8
 
清晰了!
shuiyan兄,您看是不是这个流程(单指IIC读的过程):
1、先设置从机地址,状态:         I2cCurSla = I2cSla | 0x01;
                         I2cStatus = I2C_STATUS_SETADDR;
2、使能IIC
   StartI2C(I2cCurSla);  这时CPU设置需要等待从机的应答
3、挂起中断 WaitForSingleObject,等待从机应答(主机设置开IIC后,从机做的回应),ACK或者NAK
   2秒钟没有应答则说明开IIC失败
4、应答产生,开中断,使能事件SetEvent(gI2CEvent);
5、进入FOR循环体,先设置接收数据是否需要应答ACK或者不需要应答NAK
        即:    if (count == (dwNumBytes - 1))
                        IIC_StartRecByteNA();
                else
                        IIC_StartRecByteA();
6、接收数据前中断挂起 WaitForSingleObject,等待数据传送过来,
7、硬件接收到数据,触发中断,在中断中使能事件SetEvent(gI2CEvent);
   程序开始接受数据,并将数据存在pReadBuffer中
这次理解应该对了吧
再问一下:
程序没有对ACK应答位进行判断,是硬件自己判断的吗?
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表