搜索
bottom↓
回复: 46

stm8s IIC从机,简单可用版代码

  [复制链接]

出0入0汤圆

发表于 2014-4-28 16:13:48 | 显示全部楼层 |阅读模式
官方IIC从机实在用不到,经过本人研究,写了个简单可通讯的从机版本。现在发出来分享下。


从机程序:
uchar u8_My_Buffer[8];   //存储要发送的值
/***IIC初始化****/
void Init_I2C (void)
{
        I2C_CR1 =0x81;//关闭时钟延展,启动IIC
        I2C_CR2=0x04;
        I2C_FREQR=1;
        I2C_OARL=0xa0;//设备地址
       
        I2C_OARH=0x40;
       
        I2C_ITR=0x06;
       
       
}

/***********IIC中断服务函数*********************/
@far @interrupt void I2C_Slave_check_event(void)
{

        static uchar sr1;                                       
        static uchar sr2;
        static uchar sr3;
        uchar tsr1,tsr2,tsr3;
       

if(I2C_SR1_ADDR)     // 地址匹配
{
  uchar erro=8;
        iict=0;
        I2C_DR=u8_My_Buffer[0];
        tsr1=I2C_SR1;
        tsr3=I2C_SR3;
        iict++;
        while(I2C_SR1_BTF&(erro--));
}
if(I2C_SR1_TXE)      //继续发送数据
{
        uchar erro=8;
        I2C_DR=u8_My_Buffer[iict++];
        while(I2C_SR1_BTF&(erro--));
}
if(I2C_SR2_AF)
{
        I2C_SR2 &= ~I2C_SR2_AF;
}


}
/*******************************************************/


主机读取数据(模拟):

@near uchar iictemp[7];//存储读取到的数据

void SDA_out(void)   //配置SDA引脚为输出

{

        PB_DDR|=0x20;//PB5

        PB_CR1|=0x20;//推挽输出

        PB_CR2&=0xdf;        

}

void SDA_in(void)   //配置SDA引脚为输入

{

        PB_DDR&=0xdf;//PB5

        PB_CR1|=0x20;//上拉输入

        PB_CR2&=0xdf;        

}

void SCL_out(void)  //配置SCL引脚为输出

{

        PB_DDR|=0x10;//PB4

        PB_CR1|=0x10;//推挽输出

        PB_CR2&=0xef;        

}

void SCL_in(void)   //配置SCL引脚为输入

{

        PB_DDR&=0xef;//PB5

        PB_CR1|=0x10;//上拉输入

        PB_CR2&=0xef;        

}




/*起始条件*/
void Start(void)
{
        SCL_out();
        SDA_out();
        SCL=1;
        SDA=1;
        Delay_us(1);
        SDA=0;
        Delay_us(1);
        SCL=0;
}       
/*停止条件*/
void Stop(void)
{
        SDA_out();
        SDA=0;
        Delay_us(1);
        SCL=1;
        Delay_us(1);
        SDA=1;
}

void IIC_w(uchar Idata)  //写一个字节
{
        uchar iici;
                for(iici=0;iici<8;iici++)
        {
                SCL=0;
                Delay_us(1);
                if(Idata&0x80)
                SDA=1;
                else
                SDA=0;
                Delay_us(1);
                SCL=1;
                Idata<<=1;
                Delay_us(1);
        }
        SCL=0;
}

void IIC_r(uchar* Idata)  //读一个字节
{
        uchar iici;
        SDA=1;
        SDA_in();
         for(iici=0;iici<8;iici++)
  {
                SCL=1;
                Delay_us(1);
                *Idata<<=1;
                if(SDAI)
                *Idata|=1;
                else
                *Idata|=0;
                Delay_us(1);
                SCL=0;
                Delay_us(1);
        }
}

void I2C_Send_Ack(void) //发送ACK
{
        SDA=0;
        SDA_out();
        SCL=0;
        Delay_us(1);
        SDA=0;
        Delay_us(1);
        SCL=1;
        Delay_us(1);
        SCL=0;
        }
       
unsigned char I2C_Get_Ack(void)  //读取ACK
{
        uchar ack;
        SDA=1;
        SDA_in();
        Delay_us(1);
        SCL=1;
        ack=SDAI;
        Delay_us(1);
        SCL=0;
        SDA_out();
        return ack;
       
}


void IICdata_Read(void)  //调用该函数会读取到从机数据
{
        uchar i;
        Start();
       
        IIC_w(0xa1);
        if(I2C_Get_Ack())
        {
                Stop();
                return;
        }
       
        for(i=0;i<8;i++)
        {
                Delay_us(1);
                IIC_r(&iictemp[i]);
                if(i<7)                    //这里很重要,最后一位不发送ACK,自动停止通讯
                I2C_Send_Ack();
        }
        Stop();
}



该程序存在较少的误码,加上校验位后可以稳定的通讯。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2014-4-28 19:29:07 来自手机 | 显示全部楼层
本帖最后由 o0pingu0o1 于 2014-4-28 19:30 编辑

学习了,太好了

出100入101汤圆

发表于 2014-4-28 21:00:59 | 显示全部楼层
i2c通信,应该“没有”误码才对。

出0入0汤圆

 楼主| 发表于 2014-4-28 22:07:46 | 显示全部楼层
stm8 IIC用起来胃疼

出0入0汤圆

 楼主| 发表于 2014-4-29 14:56:59 | 显示全部楼层
挂4个IIC测试通过,热拔插不死机。基本可以玩了

出0入0汤圆

发表于 2014-5-2 13:09:15 | 显示全部楼层
楼主,不行啊,我用你的代码测试从机,进去中断了,但是好像其他几个if都进不去。

出0入0汤圆

 楼主| 发表于 2014-5-4 17:46:35 | 显示全部楼层
本帖最后由 cvfl 于 2014-5-4 17:50 编辑
dhw5qq 发表于 2014-5-2 13:09
楼主,不行啊,我用你的代码测试从机,进去中断了,但是好像其他几个if都进不去。 ...


先检查地址匹配,然后把主机延时增加一些,地址能匹配之后,一切都好说了

出0入0汤圆

发表于 2014-5-4 18:19:10 | 显示全部楼层
好像停止检测到了,其他都没有检测到?
好奇怪啊

出0入0汤圆

 楼主| 发表于 2014-5-4 21:23:32 | 显示全部楼层
dhw5qq 发表于 2014-5-4 18:19
好像停止检测到了,其他都没有检测到?
好奇怪啊

代码里面根本没检测停止,是没有ACK就停止。你设置断点看I2C_SR1_ADDR   有没有置位

出0入0汤圆

发表于 2014-5-5 17:29:05 | 显示全部楼层
cvfl 发表于 2014-5-4 21:23
代码里面根本没检测停止,是没有ACK就停止。你设置断点看I2C_SR1_ADDR   有没有置位 ...

你从机在接收到数据就直接吧数据发给主机了么?
为什么我从机接收数据后,不能发数据给主机啊。

出0入0汤圆

发表于 2014-5-5 17:44:55 | 显示全部楼层
是两个STM8之间IIC通信吗?

出0入0汤圆

发表于 2014-5-5 17:59:37 | 显示全部楼层
现在从机数据发不出去啊!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-5-5 18:01:09 | 显示全部楼层
kxb 发表于 2014-5-5 17:44
是两个STM8之间IIC通信吗?

是两个stm8,同时通讯的还有stm32从机和51单片机主机。

出0入0汤圆

 楼主| 发表于 2014-5-5 18:09:49 | 显示全部楼层
dhw5qq 发表于 2014-5-5 17:59
现在从机数据发不出去啊!

   看看我的图

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 20:30:00 | 显示全部楼层
[code]@far @interrupt void iic_irq(void)
{

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 20:30:15 | 显示全部楼层
  1. @far @interrupt void iic_irq(void)
  2. {                                
  3.                         if((I2C_SR1&(1<<1)))         // 地址匹配
  4.                         {
  5.                                  
  6.                                         temp1=I2C_SR1;
  7.                                         temp2=I2C_SR3;         //地址匹配清除标志位       
  8.                         }       
  9.                         if(I2C_SR1&(1<<6))         //接收到数据
  10.                         {       
  11.                                         temp=I2C_DR;                       
  12.                 //                while((I2C_SR1 & 0x80));                //等待发送寄存器为空                       
  13.                                                  switch(temp)
  14.                                         {
  15.                                                  case 0x11:
  16.                                                  I2C_DR = 0x02;                                                                        //发送要写入的数据
  17.                                                          while((I2C_SR1 & 0x04));                //等待发送完成                 
  18.                                                         break;
  19.                                                  case 0x12:
  20.                                                  I2C_DR = 0x04;                                                                        //发送要写入的数据
  21.                                                  break;
  22.                                                  default:
  23.                                                  break;
  24.                                         }                                                       
  25.                                
  26.                                 }
  27.                                
  28.                                 if((I2C_SR1&0x10))                                //停止位侦测
  29.                         {
  30.                          
  31.                                                  temp1=I2C_SR1;
  32.                                                  I2C_CR2|=(1<<1);
  33.                         }
  34. }
复制代码

出0入0汤圆

 楼主| 发表于 2014-5-5 20:51:12 | 显示全部楼层

while()语句很容易造成死机,最好加上超时检测。我的代码加的8个周期,比较快,所以要求主机时钟切换快一点,否则就给过掉了。

,stm8s从机发送过程最后需要一个NA才能正常停止发送数据,经我实验,只需要nack就可以停止,不需要检测停止条件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 20:56:45 | 显示全部楼层
你的怎么没有接受缓冲区数据判断啊,

出0入0汤圆

发表于 2014-5-5 21:01:44 | 显示全部楼层
cvfl 发表于 2014-5-5 20:51
while()语句很容易造成死机,最好加上超时检测。我的代码加的8个周期,比较快,所以要求主机时钟切换快 ...

           我主机是软件模拟的,50us的速率,你说从机发送完成后要发NA,

是不是我图片上的这个位,

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-5-5 21:03:51 | 显示全部楼层
dhw5qq 发表于 2014-5-5 21:01
我主机是软件模拟的,50us的速率,你说从机发送完成后要发NA,

是不是我图片上的这个位, ...

你看我主机读取函数,里面专门注释了最后一位不发送ACK

出0入0汤圆

发表于 2014-5-5 21:09:10 | 显示全部楼层
   哦,我说错了,  是AF。我现在主机读取的数据是0xab,奇怪?
我主机发的0xab啊

出0入0汤圆

发表于 2014-5-5 21:12:46 | 显示全部楼层
谢谢,调出来了,居然要读2遍,奇怪了,在研究下
  1. u8 read_gasgauge(void)
  2. {
  3.      u8 temp=0,a;
  4.      I2C_start();       
  5.           delay_us(1);
  6.          I2C_write(bq3050_read_address);          
  7.          a=I2C_read(1);         
  8.           temp=I2C_read(0);
  9.          I2C_stop();
  10.          return temp;
  11. }
复制代码

出0入0汤圆

 楼主| 发表于 2014-5-5 21:13:50 | 显示全部楼层
dhw5qq 发表于 2014-5-5 21:09
哦,我说错了,  是AF。我现在主机读取的数据是0xab,奇怪?
我主机发的0xab啊 ...

你要先把主机发的数据读了,再启动从机发送,然后往DR里面填数据

出0入0汤圆

发表于 2014-5-5 21:15:30 | 显示全部楼层
cvfl 发表于 2014-5-5 21:13
你要先把主机发的数据读了,再启动从机发送,然后往DR里面填数据

     我记得上次avr硬件iic的时候也是这样,连续读的时候,非要多读一次,这次也是一样,奇怪
  1. @far @interrupt void iic_irq(void)
  2. {                                
  3.                         if((I2C_SR1&(1<<1)))         // 地址匹配
  4.                         {
  5.                                  
  6.                                         temp1=I2C_SR1;
  7.                                         temp2=I2C_SR3;         //地址匹配清除标志位
  8.                                        
  9.                         }       
  10.                         if(I2C_SR1&(1<<6))         //接收到数据
  11.                         {       
  12.                                         temp=I2C_DR;                       
  13.                 //                while((I2C_SR1 & 0x80));                //等待发送寄存器为空                       
  14.                                                  switch(temp)
  15.                                         {
  16.                                                  case 0x11:
  17.                                                 // while((I2C_SR1 & 0x80));                //等待发送完成                 
  18.                                                  I2C_DR = 0x02;                                                                        //发送要写入的数据
  19.                                                          while((I2C_SR1 & 0x04));                //等待发送完成                 
  20.                                                                  
  21.                                                         break;
  22.                                                  case 0x12:
  23.                                         //         while((I2C_SR1 & 0x80));                //等待发送完成                 
  24.                                                  I2C_DR = 0x04;                                                                        //发送要写入的数据
  25.                                                          while((I2C_SR1 & 0x04));                //等待发送完成               
  26.                                                                   
  27.                                         //         I2C_DR = 0x04;                                                                        //发送要写入的数据
  28.                                                  break;
  29.                                                  default:
  30.                                                  break;
  31.                                         }                                                       
  32.                                
  33.                                 }
  34.                                
  35.                  if(I2C_SR2&(1<<2))
  36.          {
  37.                         I2C_SR2&=~(1<<2);
  38.          }
  39. }
复制代码

出0入0汤圆

发表于 2014-7-1 11:03:23 | 显示全部楼层
楼主stm8l的 7硬件iic有玩过没

出0入0汤圆

发表于 2014-10-10 11:13:16 | 显示全部楼层
从STM32到AVR再到430,硬件和模拟IIC都用到过了,除了AVR有唯一一次模拟不行换了硬件,其他都没有网上说的一大堆问题。是,那个while是容易死机,但是问题也是在自己编写的程序上,底层驱动没有问题。马上就用STM8的IIC 了,有没有这样那样的问题,we will see~

出0入8汤圆

发表于 2014-10-11 16:31:42 | 显示全部楼层
还有热插拔,这么高端~

出0入95汤圆

发表于 2014-10-12 00:14:31 | 显示全部楼层
不错,学习下

出0入0汤圆

发表于 2014-10-12 00:17:26 | 显示全部楼层
支持楼主~

出0入0汤圆

发表于 2014-10-12 13:56:22 | 显示全部楼层
为何不用STM8S的内部IIC,我做过,确实可以用的。硬件中断驱动方式。

出0入0汤圆

发表于 2014-10-12 14:01:27 | 显示全部楼层
谢谢分享,顶一下

出0入0汤圆

 楼主| 发表于 2014-10-28 08:24:25 | 显示全部楼层
s1j2h3 发表于 2014-10-12 13:56
为何不用STM8S的内部IIC,我做过,确实可以用的。硬件中断驱动方式。

主机为什么不用内部IIC呢?主要是因为在速度要求不高的情况下,模拟的代码可移植性强,写从机也是为了让别人读取使用,不管什么单片机,只要写好start,stop,ack,nack等几个函数,后面的读取函数可以直接复制。而且几行所有单片机那几个函数网上都可以下载下来直接使用。

出0入0汤圆

发表于 2014-10-28 11:42:06 | 显示全部楼层
谢谢楼主,这个刚好用得着

出0入0汤圆

发表于 2014-10-30 15:18:26 | 显示全部楼层
学习了         

出0入0汤圆

发表于 2015-3-2 19:31:14 | 显示全部楼层
我想问下,这种iic 交互的程序, 能不能保证大量数据通讯, 或者说 稳定性怎么样!

出0入0汤圆

 楼主| 发表于 2015-3-23 18:46:28 | 显示全部楼层
dhw5qq 发表于 2015-3-2 19:31
我想问下,这种iic 交互的程序, 能不能保证大量数据通讯, 或者说 稳定性怎么样! ...

稳定性不错,有上批量产品

出0入0汤圆

发表于 2015-3-23 19:04:11 | 显示全部楼层
mark  stm8s IIC从机

出0入0汤圆

发表于 2015-3-23 23:25:31 | 显示全部楼层
也就用iiC读过一个EEPROM,进一步学习了

出0入0汤圆

发表于 2015-8-19 19:53:26 | 显示全部楼层
楼主呀,我的stm8s005 IIC从机地址一直不匹配呀,进不去中断,不知道为什么呀,地址一直是对的呀

出0入0汤圆

发表于 2015-11-17 23:10:57 | 显示全部楼层
明天测试下

出0入0汤圆

 楼主| 发表于 2015-11-19 09:02:42 | 显示全部楼层
chinamaken 发表于 2015-8-19 19:53
楼主呀,我的stm8s005 IIC从机地址一直不匹配呀,进不去中断,不知道为什么呀,地址一直是对的呀 ...

如果中断映射、初始化都没问题,就看看延时

出0入0汤圆

发表于 2016-2-28 21:58:11 | 显示全部楼层
学习了,正在整两单片机:从机接收主机的数据

出0入0汤圆

发表于 2016-3-1 16:53:34 | 显示全部楼层
赞赞赞  ! 收下了 
谢啦

出0入0汤圆

发表于 2016-3-2 08:18:01 | 显示全部楼层
学习了~~

出0入0汤圆

发表于 2016-4-11 14:51:06 | 显示全部楼层
本帖最后由 华仔 于 2016-4-11 14:52 编辑

    if(I2C->SR1&I2C_SR1_ADDR)     // 地址匹配
    {
      unsigned char erro=8;
      iict=0;
      I2C->DR=u8_My_Buffer[0];
      tsr1=I2C->SR1;
      tsr3=I2C->SR3;
      iict++;
      while(I2C->SR1&I2C_SR1_BTF&(erro--));
    }
    if(I2C->SR1&I2C_SR1_TXE)      //继续发送数据
    {
      unsigned char erro=8;
      I2C->DR=u8_My_Buffer[iict++];
      while(I2C->SR1&I2C_SR1_BTF&(erro--));
    }
    if(I2C->SR2&I2C_SR2_AF)
    {
      I2C->SR2 &= ~I2C_SR2_AF;
    }


修改了一下if判断语句就可以了
#define I2C_SR1_TXE      ((uint8_t)0x80)  /*!< Data Register Empty (transmitters) */
#define I2C_SR1_RXNE     ((uint8_t)0x40)  /*!< Data Register not Empty (receivers) */
#define I2C_SR1_STOPF    ((uint8_t)0x10)  /*!< Stop detection (Slave mode) */
#define I2C_SR1_ADD10    ((uint8_t)0x08)  /*!< 10-bit header sent (Master mode) */
#define I2C_SR1_BTF      ((uint8_t)0x04)  /*!< Byte Transfer Finished */
#define I2C_SR1_ADDR     ((uint8_t)0x02)  /*!< Address sent (master mode)/matched (slave mode) */
#define I2C_SR1_SB       ((uint8_t)0x01)  /*!< Start Bit (Master mode) */
这些并不是寄存器而是具体的值。

出0入0汤圆

发表于 2016-4-13 21:03:57 | 显示全部楼层
mark stm8s IIC从机

出0入0汤圆

发表于 2020-8-3 11:52:59 | 显示全部楼层
楼主,有没有完整的工程,从机的那些IO设置,CLK_CKDIVR是否要设置?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 06:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表