本帖最后由 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;
}
|