首页 > 技术文章 > 九齐MCU io口模拟I2C

logicexpression 2020-06-13 22:11 原文

IO口模拟I2C的要点:

  1. 数据帧符合标准的I2C协议
  2. 分的清楚ACK与NACK的区别,是那个设备下拉。
  3. 数据位时间符合要求

项目合作开发,吹牛扯蛋、交朋友 ,请联系:18665321219

SaiOneC -mcu交流群群二维码

#include "iic_p.h"
 #include <ny8.h>
 #include "main.h"
 #include <ny8_constant.h>
 #include <stdint.h>


 #define sda_out()  IOSTA=(IOSTA & ((uint8_t)(~ C_PA6_Input)))  //输出
#define sda_in()   IOSTA=(IOSTA | C_PA6_Input)  //输入

#define sda   PORTAbits.PA6   //sda输出高  
 #define scl   PORTAbits.PA4   //scl输出高,写程序注意默认让其保持高电平

void delayus(uint8_t tim)  
 {
     while(tim--)    //2.4us周期 clk_8M
     {
         NOP();
         NOP();
         NOP();
         NOP();
         
         NOP();
         NOP();
         NOP();
         NOP();
     }
 }

void i2c_stop(void) 
 {
     scl = 0;
     delayus(1);
     sda = 0;
     sda_out();
     delayus(2);
     scl = 1;
     delayus(1);
     sda = 1;
 }

void i2c_start(void)
 { 
     sda = 1;    //
     delayus(1);
     scl = 1;    //发送停止位后将SCL及SDA置位
     delayus(1);
     sda = 0;
     delayus(1);
 }

//测试ok
void trandata(uint8_t data)
 {
     //IOSTB=(IOSTB & ((uint8_t)(~ C_PB2_Input)));  //输出
     uint8_t i;
     
     //scl = 0;
     for( i = 0;i<8;i++ )
     {
         scl = 0;
         delayus(1);
         if((data & 0x80) == 0x80)
         {
             sda = 1;
         }
         else
         {
             sda = 0;
         }
         data <<=1;
         delayus(2);
         scl = 1;
         delayus(3);
     } 
     //scl = 0;
     //delayus(3);
     //sda = 0;   //因该把IO输出禁止,不然slaver无法下拉
}

//测试ok
void revdata(uint8_t *data)
 {
     uint8_t i;
     //sda_in();
     
     for(i=0;i<8;i++)
     { 
         scl = 0;
         delayus(3);
         scl = 1;
         delayus(1);
         *data <<= 1;
         if(sda==1)
         {
             *data |= 0x01;    //首位置为一
         }
         else
         {
             *data &= 0xfe;
         }  
         delayus(2);
     }
 }

//测试ok
void i2c_nack(void)
 {
     scl = 0;
     delayus(1);
     sda = 1;
     sda_out();
     delayus(2);
     scl = 1;
     delayus(3);
 }


 //测试ok
 uint8_t i2c_dectack(void)
 {
     uint8_t ackflg;
     
     scl = 0;
     delayus(1);
     sda_in();
     delayus(2);
     scl = 1;
     delayus(1);
     
     if(sda ==1)
     {
        ackflg = 0;  //为接收到应答
     }
     else
     {
        ackflg = 1;  //接收到应答
     }
     delayus(2);
     return ackflg;
 }

//测试ok   3ms
 uint8_t i2c_wtdata(uint8_t address,uint8_t data)
 {
     uint8_t temp,errflg=0;
     i2c_start();
     temp = 0xa0;      //地址位赋值1010add(R/W)
     
     trandata(temp);
     if(i2c_dectack() == 0)
     {
         errflg = 1;    //未接收到应答数据
     } 
     scl = 0;
     delayus(1);
     sda = 1;
     sda_out();
     
     temp = address;
     trandata(temp);
     if(i2c_dectack() == 0)
     {
         errflg = 1;    //未接收到应答数据
     } 
     scl = 0;
     delayus(1);
     sda = 1;
     sda_out();
     
     trandata(data);
     if(i2c_dectack() == 0)
     {
         errflg = 1;    //未接收到应答数据
     } 
  // scl = 0;
  // delayus(3);
  // sda = 0;
  // sda_out();
     
     i2c_stop();
     return errflg;
 }

//测试ok //测试不稳定
uint8_t curddata(uint8_t *data)
 {
      uint8_t temp,errflg=0;
      i2c_start();
      temp = 0xa1;   //地址位赋值1010add(R/W)
     
      trandata(temp);
      if(i2c_dectack() == 0)
      {
          errflg = 1;    //未接收到应答数据
      } 
      
      //sda_out();
      revdata(data);
      i2c_nack();
      
      i2c_stop();
      return errflg;
 }

//测试ok  4ms
 uint8_t i2c_rddata(uint8_t address,uint8_t *pdata) 
 {
      uint8_t temp,errflg=0;
      
      i2c_start();
      temp = 0xa0;   //地址位赋值1010000(R/W)
     
      trandata(temp);
      if(i2c_dectack() == 0)
      {
          errflg = 1;   //未接收到应答数据
      } 
      scl = 0;
      delayus(1);
      sda = 1;          //默认为上拉
      sda_out();
      
      temp = address;
      trandata(temp);
      if(i2c_dectack() == 0)
      {
         errflg = 1;    //未接收到应答数据
      } 
      scl = 0;
      delayus(1);
      sda = 1;
      sda_out();
      
      if(curddata(pdata) == 1)
      {
          errflg = 1;
      }
      return errflg;
 }

/*
 //写数据遵守写入读出
void i2cbus_wt(uint8_t address,uint8_t data)
 {
     uint8_t temp;
     
     do
     {
         while(i2c_wtdata(address,data) == 1);  //写入数据
         while(curddata(&temp) == 1);  //读出数据
         
     } while(data != temp);  //比较通过视为写入成功
}
 */

推荐阅读