打印
[STM8]

搞得快自闭了...STM8使用I2C从机反应奇特(有响应,没数据..

[复制链接]
2308|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zgjzgjkyo 于 2019-5-8 17:37 编辑


环境为 IAR for STM8。使用寄存器(因为考虑到使用速度和flash有限,只能用寄存器版了)(即使寄存器版本,日常应用程序都快10K了)
主从机使用 STM8L152K4
目前情况是,主机能正常发送地址,也有从机的响应,有时突然能发送数据过去。但从机那边却没有没有产生任何的中断(按理一但响应add地址会产生一个中断的啊),更不用说收到数据了。

首先关键设置是有的,也开了总中断(asm("rim");


奇怪在,地址对时有产生一相关的回复


但会突然的置0(按理说要读了SR1再读SR3时,ADDR才会置0,我曾经怀疑过是仿真时先读了寄存器产生了误操作,但我试过不仿真,也会一样突然置0的(用放led程序在里面,没有运行))


如果发送错误的地址,SR2是会有AF没响应置位的。(也就是上面的操作没错阿?)
这里也要说一下,明明是开启了接收广播响应,但下面输入00地址还是没响应,太奇怪了........



主机这边的怪异问题先不说,至少能正常的产生中断,而且发送地址正常得到响应......
但从机那边就要命多了,直接说就是没有任何的响应,按理说主机是收到ACK的,也就是从机那边对了地址,SR1的ADDR会置1并产生中断的阿......事实上没有。
我也试过直接用循环查询SR1、2、3状态寄存器了,除了SR3 检测到有总线外,其余全为0。这下我也真的不知怎么回事了........




这东西我搞了三天了,结果还是完全的一样。主机能正常产生中断,也算能发送地址有回复响应。但从机就完全绝了......

在这里真心求教各位了。


下面程序主从机共用,方便大家查看。(删除大量不相干的,我测试过是可以用的,就是从机没有反应,但主机能收到地址的响应回复.......(如果改成其它地址就没有回复了...证明地址那边是可以的吧?))
#include<iostm8l152k4.h>

/*延时ms*/
void delay(unsigned int ms)
{
        unsigned int x , y;
        for(x = ms; x > 0; x--)           /*  通过一定周期循环进行延时*/
                for(y = 3000 ; y > 0 ; y--);
}


/*    主函数    */
int main(void)
{
        
        asm("sim");                              //关闭系统总中断
        CLK_CKDIVR = 0x00;                   //采用内部16M高速晶振

        
        /*——————I2C模块初始化——————*/
        CLK_PCKENR1_bit.PCKEN13 = 1;            //使能I2C1时钟                 

        I2C1_CR2_bit.SWRST = 1;                     //复位I2C1寄存器
        asm("nop");
        asm("nop");
        asm("nop");
        asm("nop");
        I2C1_CR2_bit.SWRST = 0;               //清除复位设置
        
        I2C1_FREQR_bit.FREQ = 16;              //Freq = 16M
        
        //标准速度
        I2C1_CCRL = 0x50;        //即为80d,在标准速度100KHz下。1/100,000即为10微秒(含Tlow+Thigh)。
                                                        //因此在1/16MHz=0.0625微秒,乘以80=5微秒
        I2C1_TRISER_bit.TRISE = 0x11;                //即为17d。标准速度下最大允许上升时间为1000ns(1微秒)。
                                                                                                //因此在16MHz下,1/0.0625=16+1=17d
        
        I2C1_OARH_bit.ADDMODE = 0;                        //设置7位地址响应
        I2C1_OARH_bit.ADDCONF = 1;                        //软件必须配置该位(只能配置成1)
        I2C1_OARL = 0xAE;                                                //设置7位地址为AE

        I2C1_ITR = 0x07;                                                //开启ITBUFEN、ITEVTEN、ITERREN所有事件中断(这里没反应啊~~~~!!!!?)
        
        I2C1_CR2_bit.ACK = 1;                                //应答使能
               
        I2C1_CR1_bit.ENGC = 1;                                //设置为广播呼叫模式(设置了也没有用?主机发送00h地址没响应??)
        I2C1_CR1_bit.PE = 1;                              //打开I2C(使能I2C)
        /*——————I2C模块初始化——————*/
        
        //Key1 按键输入设置(这里根据自己的开发板来写按键检测)
        PD_DDR_bit.DDR4 = 0;      //GPD->PIN4 设置为输入模式
        PD_CR1_bit.C14 = 1;       //GPD->PIN4 带上拉电阻输入
        PD_CR2_bit.C24 = 0;       //GPD->PIN4  禁止外部中断
        
        asm("rim");                                                    //打开系统总中断
        
        while(1)                        //进入死循环,等待发送接收
        {
                if(PD_IDR_bit.IDR4 == 0)                        //判断按钮1是否被按下
                {
                        delay(10);                                //先延时进行消抖
                        while(PD_IDR_bit.IDR4 == 0);        //等待按钮1被松开
                        delay(10);                                              //再次延时消抖
                        
                        I2C1_CR2_bit.START = 1;            //I2C发送起始信号
                }
        }
}



/*    I2C中断事件服务函数(目前情况就是发送有产生中断,接收就什么反应也没有)    */
#pragma vector = I2C_ADDR_vector                //设置I2C中断事件向量号 = 0x1F(相关事件中断向量的地址是一样的?)
__interrupt void I2C_ITEVFEN(void)
{         

        if(I2C1_SR1_bit.SB == 1);                        //产生起始信号
        {
                I2C1_DR = 0xAE;                                        //发送器件地地址,并清除SB标志位(试了一下,AE和AF均有反应(主机发送和主机接收))
        }
               

        if (I2C1_SR1_bit.ADDR == 1)                //等待器件地址发送完成(主机神奇在这里有收到应答,如果上面地址填写不正确,这里因addr=0变成无限循环死机的)
        {
                if (I2C1_SR3_bit.MSL == 1)                //主模式
                {
                        unsigned char i2cSRtemp;        //这里会出现一个“was set but never used”警告,不用理。
                        i2cSRtemp = I2C1_SR1;
                        i2cSRtemp = I2C1_SR3;                                //读状态寄存器1和状态寄存器3清除发送器件地址标志位
                        
                        while(!(I2C1_SR1_bit.TXE == 1));        //等待“发送的数据寄存器”变空
                        
                        I2C1_DR = 'A';                                                        //发送字符给从机(但没有反应,动作都完成。从机没发生中断,也没收到数据)

                        I2C1_CR2_bit.STOP = 1;                           //发送停止信号结束数据传输
                        
                        return;
                        
                }else        //从模式
                {
                        //从机就不写了,能进入中断就算成功了,但目前没反应.........
               
                }
        }
        
        

        if (I2C1_SR1_bit.STOPF == 1)        //检测到停止位
        {
          I2C1_CR2_bit.STOP = 1;        //清除停止位
        }
        
        /*------ 错误处理 ------*/
        if (I2C1_SR2_bit.BERR == 1)                //总线错误
        {
          I2C1_SR2_bit.BERR = 0;        //清零
        }
        else if(I2C1_SR2_bit.ARLO == 1)        //仲裁失败
        {
          I2C1_SR2_bit.ARLO = 0;        //清零
        }
        else if(I2C1_SR2_bit.AF)                        //应答失败
        {
          I2C1_SR2_bit.AF = 0;                //清零
        }
        else if(I2C1_SR2_bit.OVR)                        //上溢、下溢
        {
          I2C1_SR2_bit.OVR =0;                //清零
        }

        I2C1_CR2_bit.STOP = 1;
        
}





使用特权

评论回复
沙发
zgjzgjkyo|  楼主 | 2019-5-8 17:40 | 只看该作者
或者那位朋友能提供个主从机的I2C通讯(寄存器版)。我目前网上找到的都是库版(事实我上面的程序基本上就是从库版转过来的)
有试过在I2C的器件正常使用(AT24C02)...但主从机数据传输就不行了......(说实在还真的没搞过从机,以前用IO口模拟I2C也很好做的,想不到这次坑在从机身上了......)

使用特权

评论回复
板凳
zgjzgjkyo|  楼主 | 2019-5-8 17:46 | 只看该作者
另外接错线这事应该是没有可能的,我有用万用表测过。PC1接PC1(scl),PC0接PC0(sda)吧....(又不是串口反着接........)

使用特权

评论回复
地板
lein2006| | 2019-5-8 21:00 | 只看该作者
请把
unsigned char i2cSRtemp;            // 这里会出现一个“was set but never used”警告,不用理。
改成
volatile unsigned char i2cSRtemp;   // 试一下

使用特权

评论回复
5
zgjzgjkyo|  楼主 | 2019-5-15 10:00 | 只看该作者
靠~~!!!!终于找到原因了!!!!!!!要不是有官方函数库,我也不知道原来是那个坑!!!
我猜大家一定是用函数库来写stm8的I2C吧?所以没碰到这个问题。因为我是用寄存器编写的所以才碰到这个问题。
其实问题说白了就是寄存器的输入顺序问题,在PE未置位前,CR1和CR2有部分参数是无法置位的!!!(虽然手册上有说明,但我一直以为是PE产生复位动作那些寄存器才会自动复位,原来是理解错了!!!!)

使用特权

评论回复
6
蝴蝶泉2018| | 2019-5-15 10:30 | 只看该作者
在这里提个小建议,建议大家初始化时还是用官方的标准外设库(或STM32 的CUBE 库)。如楼上所说,有些设置的细节一开始未必注意到,所以用库就可以避免走弯路。其次,对于代码简化来说,先调通外设,能工作,再参考外设库的代码简化函数至寄存器操作。 再次,注意所使用的编译器的优化设置。这样才能少走弯路,提高效率,少加一点班

使用特权

评论回复
7
zgjzgjkyo|  楼主 | 2019-5-15 10:35 | 只看该作者
蝴蝶泉2018 发表于 2019-5-15 10:30
在这里提个小建议,建议大家初始化时还是用官方的标准外设库(或STM32 的CUBE 库)。如楼上所说,有些设置 ...

对阿,第一次搞这个程序搞到有心理阴影........以后都是用官方例程运行通过再转寄存器好了。

使用特权

评论回复
8
antusheng| | 2019-5-15 22:20 | 只看该作者
还是用库吧,至少那是官方验证过的程序

使用特权

评论回复
9
wangjiahao88| | 2019-5-16 08:11 | 只看该作者
模拟IIC可以吗?

使用特权

评论回复
10
zgjzgjkyo|  楼主 | 2019-5-18 14:28 | 只看该作者

模拟主机这个容易搞,有非常多的例程搞这个,甚至IO口模拟主机也有的。
但模拟从机的,我查过就相当的少了.....

使用特权

评论回复
评论
joketinnle 2019-9-8 00:25 回复TA
可以看着I2C协议 自己写一个 XDD 
11
磨砂| | 2019-6-12 09:04 | 只看该作者
也有可能不是真正的相应 只是一种干扰波

使用特权

评论回复
12
晓伍| | 2019-6-12 09:08 | 只看该作者
用示波器看看波形

使用特权

评论回复
13
八层楼| | 2019-6-12 09:13 | 只看该作者
说明极有可能时序不满足要求

使用特权

评论回复
14
观海| | 2019-6-12 09:22 | 只看该作者
用普通的io口模式试试看

使用特权

评论回复
15
LiuChenghu| | 2019-9-6 22:33 | 只看该作者
你好版主,我也是同样的问题,从机返回的数据一直是FF,请问你是怎么调试通过的呢,我用的是库函数版本的,能不能发一个例程呢

使用特权

评论回复
16
zgjzgjkyo|  楼主 | 2019-9-29 09:55 | 只看该作者
LiuChenghu 发表于 2019-9-6 22:33
你好版主,我也是同样的问题,从机返回的数据一直是FF,请问你是怎么调试通过的呢,我用的是库函数版本的, ...

已经不搞I2C了。一怒之下,干脆自己写私有通讯协议,保证其独有的加密性!!!!

使用特权

评论回复
17
zjq985062714| | 2019-10-3 13:21 | 只看该作者
这个官方Demo没有例程吗?应该可以参考一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

213

帖子

4

粉丝