找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 1204|回复: 0
打印 上一主题 下一主题
收起左侧

STM32单片机模拟IIC通用驱动程序

[复制链接]
跳转到指定楼层
楼主
要用到IIC程序网上找了许多参考大多不完整,或不完善,不尽如意。参考他人程序写了一份模拟程序,通用性强,略做修改引脚即可移植到51单片机平台,测试可使用多种芯片,功能完善可单个程序读写一个数据,也可连续读写一组数据,速度快,具有速度调节。可靠具有超时检测,故障重启功能。目前使用它驱动4线OLED显示和读写时钟,达到设计目标,使用过程可以任意通断一条线,线路恢复,显示和时钟读写恢复正常。有需要高可靠性读写EEPRAM的可以,进一步采用写后复读比对。   

单片机代码
//=====================MRI2C.h===========================
#ifndef __MRI2C_H
#define __MRI2C_H
#include "stm32f10x.h"

#include "wei_bit.h" //位带操作

#define W_SCL     PBout(8)   // 定义输出SCL引脚
#define W_SDA     PBout(9)   //定义输出SDA引脚
#define R_SDA     PBin(9)    //定义SDA输入用于读取状态

// 如果要启用高速 I2C,则定义 IIC_HS 注释掉下面一行降速
#define IIC_HS

// 条件编译的代码
#ifdef IIC_HS    //电平改变后无延时 最高速度 约300Khz
    #define W_SCL_H   W_SCL=1
    #define W_SCL_L   W_SCL=0
          #define W_SDA_H   W_SDA=1
    #define W_SDA_L   W_SDA=0                        
#else    //电平改变后延时达到减低速度目的 约100Khz
          #define W_SCL_H   W_SCL=1 ; IIc_Delay(10)     //SCL拉高 并延时
    #define W_SCL_L   W_SCL=0 ; IIc_Delay(10)     //SCL拉低 并延时
          #define W_SDA_H   W_SDA=1 ; IIc_Delay(5)      //SDA拉高 加延时
    #define W_SDA_L   W_SDA=0        ; IIc_Delay(5)      //SDA拉低 并延时
#endif

#define PCF8575_ADDRESS                0x40                //IIC的I2C从机地址
#define PCF8574_ADDRESS                0x4E                //IIC的I2C从机地址
#define PCF2129_ADDRESS           0xA2   //pcf2129
#define PCF8563_ADDRESS           0xA2   //pcf8563
#define R8025_ADDRESS             0x64   //R8025

extern  uint8_t   IIC_EEr ;       //错误标志

extern void I2C1_Init(void);                // IIC初始化
extern void I2C1_Reset(void);               //I2C故障重启

extern void I2C1_Read (uint8_t ADDRESS        , uint8_t addr,uint8_t *pData,uint8_t len);
extern void I2C1_Write(uint8_t ADDRESS        , uint8_t addr,uint8_t *pData,uint8_t len);

#endif
//====================MRI2C.c========================
//***************模拟IIC程序************************************
/*无延时,最高速度,时钟脉宽1.25us,间歇2.5us */
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "MRI2C.h"

#include "stm32f10x_i2c.h"


uint8_t   IIC_EEr = 0;          //错误标志。
uint16_t  EER_coner   = 0;     //错误计数器

//*********************************************************
void IIc_Delay(uint16_t ys)
{ uint16_t ystm;
            ystm=ys;
                                while(ystm--){}                        
}

//产生IIC起始信号
void MyI2C_Start(void)
{
W_SDA_H;
W_SCL_H;
W_SDA_L;
W_SCL_L;
}
//产生IIC停止信号
void MyI2C_Stop(void)
{
W_SDA_L;
W_SCL_H;
W_SDA_H;
        
}
/**
  * 函    数:I2C发送一个字节
  * 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
        uint8_t i;
        for (i = 0; i < 8; i ++)
        {
     W_SDA=(Byte&0x80)>>7;
     Byte<<=1;
                 W_SCL_H;
                 W_SCL_L;
        }
}
/**
  * 函    数:I2C接收一个字节
  * 参    数:无
  * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF
  */
uint8_t MyI2C_ReceiveByte(void)
{
        uint8_t i, Byte = 0x00;
         W_SDA_H;
        for (i = 0; i < 8; i ++)
        {
                W_SCL_H;
        Byte<<=1;
        if(R_SDA)
                        Byte|= 0x01;   
                W_SCL_L;
    }        
        return Byte;
}
/**
  * 函    数:I2C发送应答位
  * 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)
{
         W_SDA=AckBit;
         W_SCL_H;
         W_SCL_L;
}

//============================================================
//等待应答信号到来
//返回值:0,接收应答失败 报错IIC_EEr
//        1,接收应答成功
u8 IIC_Wait_Ack(void)
{
        u16 ucErrTime=0;         
          W_SDA_H;
         W_SCL_H;
        while(-R_SDA)
        {  
                  ucErrTime++;
                  if(ucErrTime>10000)
                                      {  
                                              IIC_EEr = 1;     //错误标志 重启IIC
                                                          EER_coner++;   //错误计数器用于调试
                                              MyI2C_Stop();
                                              return 0;
                                       }
         }
        W_SCL_L;           
        return 1;  
}
/**
  * 函    数:I2C连续写一组数据
  * 参    数:ADDRESS 器件码, addr 起始寄存地址,*pData 要写的数组,len 写入字数
  * 返 回 值:无
  */
void I2C1_Write(uint8_t ADDRESS        , uint8_t addr,uint8_t *pData,uint8_t len)
{
        uint8_t i;
                MyI2C_Start();          //I2C起始
        MyI2C_SendByte(ADDRESS);  //发送从机地址,读写位为0,表示即将写入
        if(IIC_Wait_Ack())                                //接受应答出错跳过  
        MyI2C_SendByte(addr);     //发送寄存器地址
        if(IIC_Wait_Ack())                                //接受应答出错跳过
        for(i=len;i>0;i--){        
                            MyI2C_SendByte(*pData);pData++;//发送要写入寄存器的数据
                            IIC_Wait_Ack();                //接受应答
                     }
        MyI2C_Stop();                                                //I2C终止
        }

        
/**
  * 函    数:I2C连续读一组数据
  * 参    数:ADDRESS 器件码, addr 起始寄存地址,*pData 保存数组位置,len 读出字数
  * 返 回 值:无
  */               
void I2C1_Read(uint8_t ADDRESS, uint8_t addr,uint8_t *pData,uint8_t len)
        {
//        uint8_t i;
        MyI2C_Start();                                                //I2C起始
        MyI2C_SendByte(ADDRESS);        //发送从机地址,读写位为0,表示即将写入
        if(IIC_Wait_Ack())                                        //接受应答出错退出
        MyI2C_SendByte(addr);                        //发送寄存器地址
        if(IIC_Wait_Ack())                                //接受应答出错退出
                      {  MyI2C_Start();                                                        //I2C重复起始
                         MyI2C_SendByte(ADDRESS | 0x01);        //发送从机地址,读写位为1,表示即将读取
                         }
        if(IIC_Wait_Ack()){                                        //接受应答出错退出
          while (len)
        {
          *pData = MyI2C_ReceiveByte();                        //接收指定寄存器的数据
          if(len == 1)
                      MyI2C_SendAck(1);         //发送非应答,终止从机的数据输出
          else
                      MyI2C_SendAck(0);        //发送应答, 继续从机的数据输出
          pData++;
          len--;
         }
                                         }
   MyI2C_Stop();                                                //I2C终止
}


// IIC初始化
void I2C1_Init(void) {
        /*开启时钟*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);        //开启GPIOB的时钟        
        /*GPIO初始化*/
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);                                        //将PB8和PB9引脚初始化为开漏输出
        /*设置默认电平*/
        GPIO_SetBits(GPIOB, GPIO_Pin_8 | GPIO_Pin_9);                        //设置PB8和PB9引脚初始化后默认为高电平(释放总线状态)        
}
//---------------------------------------------------------------------------------------


void I2C1_Reset(void)     //I2C故障重启
{ uint8_t i;
    // 手动操作SCL和SDA
            W_SDA_L;
    for (i = 0; i < 9; i++)
          {
     W_SCL_H;
                        Delay_us(1); // 延时
     W_SCL_L;
                        Delay_us(1); // 延时
    }           
      W_SDA_L; // l拉低SDA
                Delay_us(1); // 延时
                 W_SCL_H;
          Delay_us(1); // 延时   
      W_SDA_H;           // 释放SDA   产生停止信号  必须 用于消除重启后I2C->SR .BUSY 位
          Delay_us(1);// 延时
IIC_EEr = 0;      //清除错误标志
}


/*************************例子:main.c *********************************

uint8_t buffer[7]={0,0,0,0,0,0,0};

int main(void)
{   
    uint8_t  Data=0;

             // IIC初始化
    I2C1_Init();
       //I2C故障重启 消除异常状态
    I2C1_Reset();
    I2C1_Write(PCF8563_ADDRESS,0,buffer, 7);    // 将缓冲区数据写入PCF8563寄存器 时钟清零
       //OLED初始化
    OLED_Init();

  while
  {
    I2C1_Read(R8025_ADDRESS,0,buffer, 7);   //读取时钟

    I2C1_Write(0x78,0x40,&Data,1);    Data++;    // 写一个数据  oled显示屏驱动测试
                        
                 if (IIC_EEr == 0)    //错误标志{
                                        { disp_p(dis);}     //IIC4线oled显示驱动程序
                       else {   
                              I2C1_Reset();     //I2C故障重启                                             
                                                       OLED_Init();//OLED初始化
                                                       num_REST++;                        //错误计数
                              }
        }
   }
}
************************************************************************/



以上3个文件下载: 3个文件.7z (3.4 KB, 下载次数: 13)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶1 踩
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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