PIC24F之EEPROM读写中断事件处理函数要点及说明

2017-12-06 20:11:54来源: eefocus 关键字:PIC24F  EEPROM  读写中断事件  处理函数

/*----------------------------------------------------------------------
PIC24FEEPROM读写中断事件处理函数要点及说明 
注意: 这是一个通用的I2C/SMBUS通讯中断处理程序 
对于EEPROM来讲,从机后面需要跟EEPROM需要读写的地址(I2CRegs.RWAddr) 
对于SMBUS来说,从机后面需要跟SMBUS需要的命令(I2CRegs.RWAddr改为I2CRegs.CMD即可) 


由于PIC24F的I2C不太标准,I2C1STAT被搞得很倒塌!!!一点都没I2C的"大家闺秀"的样子~~~ 
不过它的STOP还能激活中断确实比LPCARM/AVR好一点点~~~ 

为什么I2C收发都用中断呢??? 
这主要是为了高低速灵活变化的总线通讯所做,主要是SMBUS总线的通信. 


如果为I2cExit()也配上钩子函数,那么任何错误都在手掌中~~~ 

这个PIC程序虽没SMBUS的PEC校验部分,但"异步"还是完美的. 
当然也要注意对写保护硬件管脚的控制时机的把握,原则是关保护的时间最短就更好~~~ 


主要看到人们编写MCU程序太死板~~~特别是I2C程序.网上收发全中断的很少,可以说几乎没有. 

随贴附老外倒塌的非中断I2C状态机读写程序i2cEmem.c~~~可以比较经典和非典的差异在何处~~~ 

菜农近期将整理出LPCARM和AVR的I2C/SMBUS/TWI/USI收发全中断实战例程供大家“游玩”~~~ 

如果精通DELPHI程序的人一定会为“事件驱动”机制而痴迷~~~为什么不在MCU上"声东击西"呢??? 

"有事件才处理"---这才是编程的硬道理~~~轮循的“痴迷等待”最终还是“单相思”~~~ 
-------------------------------------------------------------------------------------------------*/ 
#include "i2c.h" 

_PERSISTENT volatile I2CREGS I2CRegs; 
_PERSISTENT volatile I2CBITS I2CBits; 

void I2cInit(void) 

unsigned int i; 
    TRIS_WP   = PORTOUTMODE;//定义WP为输出IO 
    TRIS_SCL1 = PORTOUTMODE;//定义SCL为输出IO 
    TRIS_SDA1 = PORTINPUTMODE;//定义SDA为输出入IO 
    ODC_SCL1 = 1;//OC输出 
    ODC_SDA1 = 1;//OC输出 
    WP = 1;//写保护 
    I2CRegs.MaxCount = 0x200;//8KByte 
    I2CRegs.I2CAddr = 0xa0;//器件地址 
    I2CRegs.RWAddr = 0;//EEPROM读写地址 
    I2CRegs.TxCount = 0;//发送数据字节个数 
    I2CRegs.RxCount = 0;//接收数据字节个数 
    for (i = 0; i < 16; i ++) 
    { 
        I2CRegs.TxBuffer[i] = 0;//发送缓冲区清零 
    } 
    for (i = 0; i < 256; i ++) 
    { 
        I2CRegs.RxBuffer[i] = 0;//接收缓冲区清零 
    } 

    I2C1CON = 0; 
//    I2C1CONbits.A10M = 0;//7位地址模式 
    I2C1CONbits.SCLREL = 1; 
    I2C1MSK = 0; 
    I2C1STAT = 0; 
    _MI2C1IF = 0; 
    _SI2C1IF = 0; 
    I2C1BRG = (FCY / (2 * I2CBAUD)) - 1;//波特率计算 
/*------------------------------------------------------------------------ 
    定义I2C串口2中断优先级位1111) 
-------------------------------------------------------------------------*/ 
    IPC4bits.MI2C1P0 = 1; 
    IPC4bits.MI2C1P1 = 1; 
    IPC4bits.MI2C1P2 = 1; 

    I2C1CONbits.I2CEN = 1;//允许I2C功能 
    _MI2C1IE = 1;//允许主设备中断 

//    I2cStop(); 


/*------------------------------------------------------------------ 
    EEPROM读块函数(只能在回调函数I2CReadCallBack中得到读出的数据) 
-------------------------------------------------------------------*/ 
void I2CReadBuffers(unsigned int E2RomAddr, unsigned int ReadSize) 

    if (ReadSize && (ReadSize <= 256)) 
    { 
        I2CRegs.TxCount = 0; 
        I2CRegs.RxCount = ReadSize; 
        I2CRegs.RWAddr = E2RomAddr; 
        I2CRegs.I2CAddr |= 1;//0xa1 
        I2cStart(); 
    } 


void I2CReadByte(unsigned int E2RomAddr) 

    I2CRegs.TxCount = 0; 
    I2CRegs.RxCount = 1; 
    I2CRegs.RWAddr = E2RomAddr; 
    I2CRegs.I2CAddr |= 1;//0xa1 
    I2cStart(); 


/*------------------------------------------------------------------ 
    EEPROM写块函数 
-------------------------------------------------------------------*/ 
void I2CWriteBuffers(unsigned int E2RomAddr, unsigned int WriteSize) 

    if (WriteSize && (WriteSize <= 16)) 
    { 
        I2CRegs.TxCount = WriteSize; 
        I2CRegs.RxCount = 0; 
        I2CRegs.RWAddr = E2RomAddr; 
        I2CRegs.I2CAddr &= 0xfe;//0xa0 
        I2cStart(); 
    } 


void I2CWriteByte(unsigned int E2RomAddr, unsigned char cData) 

    I2CRegs.TxBuffer[0] = cData; 
    I2CRegs.TxCount = 1; 
    I2CRegs.RxCount = 0; 
    I2CRegs.RWAddr = E2RomAddr; 
    I2CRegs.I2CAddr &= 0xfe;//0xa0 
    I2cStart(); 


/*------------------------------------------------------------------ 
    用户读回调函数 
-------------------------------------------------------------------*/ 
void I2CReadCallBack(void) 

    if ((I2CRegs.RWAddr + I2CRegs.RxCount) <= I2CRegs.MaxCount)  
    { 
//        I2CRegs.RWAddr += I2CRegs.RxCount; 
//        I2CReadBuffers(I2CRegs.RWAddr, I2CRegs.RxCount);//继续读 
    } 


/*------------------------------------------------------------------ 
    用户写回调函数 
-------------------------------------------------------------------*/ 
void I2CWriteCallBack(void) 

    if ((I2CRegs.RWAddr + I2CRegs.TxCount) <= I2CRegs.MaxCount)  
    { 
//        I2CRegs.RWAddr += I2CRegs.TxCount; 
//        I2CWriteBuffers(I2CRegs.RWAddr, I2CRegs.TxCount);//继续写 
    } 



/*------------------------------------------------------------------ 
    EEPROM读写启动函数 
-------------------------------------------------------------------*/ 
void I2cStart(void) 

/*------------------------------------------------------------------------ 
//本程序在状态I2C_MT_ADDRL_ACK下进行瞬间打开,也可在此打开,不过安全不好 
    if (I2CRegs.TxCount)//需要写入字节 
    { 
        WP = 0;//不写保护 
    } 
    else 
    { 
        WP = 1;//写保护 
    } 
--------------------------------------------------------------------------*/ 
    I2C1STATbits.IWCOL = 0; 
    I2CBits.BusyFlag = 1; 
    I2CRegs.State = I2C_START;//主机准备发送启始位 
    I2CRegs.Count = 0;//发送数据个数 
    I2CBits.I2CFlag = 0; 
    I2C1CONbits.SEN = 1;//发送Start信号 


/*------------------------------------------------------------------ 
    EEPROM读再启动函数 
-------------------------------------------------------------------*/ 
void I2cReStart(void) 

    I2C1STATbits.IWCOL = 0; 
    I2CBits.BusyFlag = 1; 
    I2CRegs.State = I2C_REP_START;//主机准备发送重新启始位 
    I2CRegs.Count = 0;//发送数据个数 
    I2C1CONbits.RSEN = 1;//发送ReStart信号 
    I2C1CONbits.ACKEN = 0; 


/*------------------------------------------------------------------ 
    EEPROM读写正确停止函数 
-------------------------------------------------------------------*/ 
void I2cStop(void) 

    I2C1STATbits.IWCOL = 0; 
    I2CBits.BusyFlag = 0; 
    I2CRegs.State = I2C_SUCCEEDED;//通讯成功 
    I2C1CONbits.PEN = 1;//发送Stop信号 
    WP = 1;//写保护 



/*------------------------------------------------------------------ 
    EEPROM读写错误退出函数 
-------------------------------------------------------------------*/ 
void I2cExit(void) 

    I2C1STATbits.IWCOL = 0; 
    I2CBits.BusyFlag = 0; 
    I2CRegs.State = I2C_FAILED; 
    I2C1CONbits.PEN = 1;//发送Stop信号 
    WP = 1;//写保护 


/*------------------------------------------------------------------ 
     EEPROM读写中断事件处理函数(说明见文件头部) 
-------------------------------------------------------------------*/ 
void I2CExec(void) 

    if (I2C1STATbits.S)//收到Start过信号 
    { 
        switch (I2CRegs.State) 
        { 
            case I2C_START://收到Start信号 
                I2C1TRN = I2CRegs.I2CAddr & 0xfe;//发送器件写地址(通知从机只能听) 
                I2CRegs.State = I2C_MT_SLA_ACK;//下次应该接收器件写地址应答信号 
                break; 
            case I2C_MT_SLA_ACK://收到器件写地址应答信号 
                if (!I2C1STATbits.ACKSTAT)//收到Ack信号 
                { 
                    if (I2CRegs.MaxCount > 0x100)//EEPROM容量超过256个字节,EEPROM地址需要两次发送 
                    { 
                        I2C1TRN = I2CRegs.RWAddr >> 8;//发送EEPROM写高8位地址 
                        I2CRegs.State = I2C_MT_ADDRH_ACK;//下次应该接收EEPROM写高8位地址应答信号 
                    } 
                    else//小容量只需一次发送!!! 
                    { 
                        I2C1TRN = I2CRegs.RWAddr;//发送EEPROM写低8位地址 
                        I2CRegs.State = I2C_MT_ADDRL_ACK;//下次应该接收EEPROM写低8位地址应答信号 
                        I2CRegs.Count = 0;//清空发送缓冲计数器 
                    } 
                }     
                else//收到NAck信号 
                { 
                    I2cExit();//错误的ACK信号     
                }     
                break; 
            case I2C_MT_ADDRH_ACK://收到EEPROM写高8位地址应答信号 
                if (!I2C1STATbits.ACKSTAT)//收到Ack信号 
                { 
                    I2C1TRN = I2CRegs.RWAddr & 0xff;//发送EEPROM写低8位地址 
                    I2CRegs.State = I2C_MT_ADDRL_ACK;//下次应该接收EEPROM写低8位地址应答信号 
                    I2CRegs.Count = 0;//清空发送缓冲计数器 
                }     
                else//收到NAck信号 
                { 
                    I2cExit();//错误的ACK信号     
                }     
                break; 
            case I2C_MT_ADDRL_ACK://收到EEPROM写高低8位地址应答信号 
                if (I2CRegs.TxCount)//写保护只在写入期间不保护,增加了对误写入的安全防护能力!!! 
                { 
                     WP = 0;//不写保护 
                } 
            case I2C_MT_DATA_ACK://收到应答信号 
                if (!I2C1STATbits.ACKSTAT)//收到Ack信号 
                { 
                    if (I2CRegs.Count < I2CRegs.TxCount)//缓冲区未空 
                    { 
                        I2C1TRN = I2CRegs.TxBuffer[I2CRegs.Count ++];//继续发送数据     
                    } 
                    else if (I2CRegs.Count == I2CRegs.TxCount)//缓冲区已空 
                    { 
                        if (I2CRegs.I2CAddr & 1)//应该开始接收数据 
                        { 
                            I2cReStart();//发送重复位命令 
                        } 
                        else//只写退出 
                        { 
                            I2cStop();//正常发送结束 
                        } 
                    } 
                    else//干扰出错 
                    { 
                        I2cExit();//错误 
                    } 
                }     
                else//收到NAck信号(可能被写保护) 
                { 
                    I2cExit();//错误的ACK信号     
                }     
                break; 
            case I2C_REP_START://收到ReStart信号 
                I2C1TRN = I2CRegs.I2CAddr | I2C_READ;//发送器件读地址(通知从机可以说话) 
                I2CRegs.State = I2C_MR_SLA_ACK;//下次应该接收器件写读地址应答信号 
                break; 
            case I2C_MR_SLA_ACK://收到器件读地址应答信号 
                if (!I2C1STATbits.ACKSTAT)//收到Ack信号 
                { 
                    I2C1CONbits.RCEN = 1;//开始接收数据 
                    I2CRegs.State = I2C_MR_DATA;//下次应该收接收数据 
                }     
                else//收到NAck信号 
                { 
                    I2cExit();//错误的ACK信号     
                }     
                break; 
            case I2C_MR_DATA://收到接收数据 
                if (I2CRegs.Count < I2CRegs.RxCount) 
                { 
//                    I2C1STATbits.I2COV = 0; 
                    I2CRegs.RxBuffer[I2CRegs.Count ++] = I2C1RCV; 
                    if (I2CRegs.Count < I2CRegs.RxCount) 
                    { 
                         I2C1CONbits.ACKDT = 0;//应答子机 
                        I2CRegs.State = I2C_MR_DATA_EN;//下次应该收到器件允许继续读信号 
                    } 
                    else 
                    { 
                        I2C1CONbits.ACKDT = 1;//非应答子机     
                        I2CRegs.State = I2C_MR_DATA_STOP;//下次应该收到退出信号 
                    } 
                     I2C1CONbits.ACKEN = 1;//向从机发送(非)应答信号 
                } 
                else//正确的状态已分支到I2C_MR_DATA_STOP 
                { 
                    I2cExit();//错误 
                } 
                break; 
            case I2C_MR_DATA_EN://收到器件允许继续读信号 
                I2C1CONbits.RCEN = 1;//开始接收数据 
                I2CRegs.State = I2C_MR_DATA;//下次应该继续接收数据 
                break; 
            case I2C_MR_DATA_STOP://收到器件退出信号 
                I2cStop();//正常接收结束 
                break; 
            default://其他不可预料的错误 
                I2cExit();//错误 
        } 
    } 
    else if (I2C1STATbits.P)//收到Stop信号 
    { 
        if (I2CRegs.State == I2C_SUCCEEDED)//成功,回调 
        { 
            if (I2CRegs.I2CAddr & 1)//读 
            { 
                I2CBits.ReadFlag = 1;//激活用户读回调函数I2CReadCallBack() 
            } 
            else//写 
            { 
                I2CBits.WriteFlag = 1;//激活用户写回调函数I2CWriteCallBack() 
            } 
        } 
    } 
    else//无法确认的复杂错误  
    { 
        I2cExit();//错误出错退出 
    } 

关键字:PIC24F  EEPROM  读写中断事件  处理函数

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/article_2017120636622.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:PIC单片机PWM模块应用实验程序
下一篇:最后一页

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利
推荐阅读
全部
PIC24F
EEPROM
读写中断事件
处理函数

小广播

独家专题更多

东芝在线展会——芯科技智社会创未来
东芝在线展会——芯科技智社会创未来
2017东芝PCIM在线展会
2017东芝PCIM在线展会
TI车载信息娱乐系统的音视频解决方案
TI车载信息娱乐系统的音视频解决方案
汇总了TI汽车信息娱乐系统方案、优质音频解决方案、汽车娱乐系统和仪表盘参考设计相关的文档、视频等资源

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2017 EEWORLD.com.cn, Inc. All rights reserved