stm8s 使用IO口模拟I2C

时间:2019-09-30
本文章向大家介绍stm8s 使用IO口模拟I2C,主要包括stm8s 使用IO口模拟I2C使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

刚入职不久,下面是使用stm8s005k6写的eeprom驱动程序。

#include "bsp_i2c.h"

/* 在stm8平台下移植,只需要改下面的宏定义即可 */
#define PORT_I2C_SCL                GPIOC
#define PIN_I2C_SCL                    GPIO_PIN_1

#define PORT_I2C_SDA                GPIOC        
#define PIN_I2C_SDA                    GPIO_PIN_2


static void i2c_Delay(void);
static void i2c_PinModeOutput(void);
static void i2c_PinModeInput(void);
static void i2c_SCL(uint8_t stat);
static void i2c_SDA(uint8_t stat);
static uint8_t i2c_ReadSDA(void);

/*
*    函 数 名: i2c_InitGpio
*    功能说明: 初始化IIC接口
*    形    参: 无
*    返 回 值: 无
*/
void i2c_InitGpio(void)
{
    GPIO_Init(PORT_I2C_SCL, PIN_I2C_SCL, GPIO_MODE_OUT_PP_LOW_FAST);
    GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);
    
    i2c_Stop();
}

/*
*    函 数 名: i2c_Delay
*    功能说明: 延时函数
*    形    参: 无
*    返 回 值: 无
*/
static void i2c_Delay(void)
{
    uint8_t time = 10;
    while (time--);
}

/*
*    函 数 名: i2c_PinModeOutput
*    功能说明: 将SDA线的端口设置为输出
*    形    参: 无
*    返 回 值: 无
*/
static void i2c_PinModeOutput(void)
{
    GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA,     GPIO_MODE_OUT_PP_LOW_FAST);
}

/*
*    函 数 名: i2c_PinModeOutput
*    功能说明: 将SDA线的端口设置为输入
*    形    参: 无
*    返 回 值: 无
*/
static void i2c_PinModeInput(void)
{
    GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_IN_FL_NO_IT);
}

/*
*    函 数 名: i2c_SCL
*    功能说明: 控制SCL线电平状态
*    形    参: stat:0 输出低电平,1 输出高电平
*    返 回 值: 无
*/
static void i2c_SCL(uint8_t stat)
{
    if (stat)
    {
        GPIO_WriteHigh(PORT_I2C_SCL, PIN_I2C_SCL);
    }
    else
    {
        GPIO_WriteLow(PORT_I2C_SCL, PIN_I2C_SCL);
    }
}

/*
*    函 数 名: i2c_SDA
*    功能说明: 控制SDA线电平状态
*    形    参: stat:0 输出低电平,1 输出高电平
*    返 回 值: 无
*/
static void i2c_SDA(uint8_t stat)
{    
    if (stat)
    {
        GPIO_WriteHigh(PORT_I2C_SDA, PIN_I2C_SDA);
    }
    else
    {
        GPIO_WriteLow(PORT_I2C_SDA, PIN_I2C_SDA);
    }
}



/*
*    函 数 名: i2c_ReadSDA
*    功能说明: 读取SDA线电平状态
*    形    参: 无
*    返 回 值: 0 或 1
*/

static uint8_t i2c_ReadSDA(void)
{
    if (GPIO_ReadInputPin(PORT_I2C_SDA, PIN_I2C_SDA))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/*
*    函 数 名: i2c_Start
*    功能说明: IIC总线起始信号
*    形    参: 无
*    返 回 值: 无
*/
void i2c_Start(void)
{
    i2c_PinModeOutput();
    
    i2c_SDA(1);
    i2c_Delay();
    i2c_SCL(1);
    i2c_Delay();
    
    i2c_SDA(0);
    i2c_Delay();
    
    i2c_SCL(0);
    i2c_Delay();
}

/*
*    函 数 名: i2c_Stop
*    功能说明: IIC总线停止信号
*    形    参: 无
*    返 回 值: 无
*/
void i2c_Stop(void)
{
    i2c_PinModeOutput();
    
    i2c_SCL(0);
    i2c_SDA(0);
    i2c_Delay();
    
    i2c_SCL(1);
    i2c_Delay();
    i2c_SDA(1);
    i2c_Delay();
}

/*
*    函 数 名: i2c_WriteByte
*    功能说明: IIC总线写数据
*    形    参: _ucByte:写入的一个字节数据
*    返 回 值: 无
*/
void i2c_WriteByte(uint8_t _ucByte)
{
    uint8_t i;
    
    i2c_PinModeOutput();
    
    i2c_SCL(0);
    i2c_Delay();
    
    for (i = 0; i < 8; i++)
    {
        if (_ucByte & 0x80)
        {
            i2c_SDA(1);
        }
        else
        {
            i2c_SDA(0);
        }
        
        _ucByte = _ucByte << 1;
        
        i2c_SCL(1);
        i2c_Delay();
        i2c_SCL(0);
        i2c_Delay();
    }
    
    i2c_SDA(1);
}

/*
*    函 数 名: i2c_ReadByte
*    功能说明: IIC总线读数据
*    形    参: 无
*    返 回 值: recv:读取的一个字节数据
*/
uint8_t i2c_ReadByte(void)
{
    uint8_t i;
    uint8_t recv = 0;
    
    i2c_PinModeOutput();
    
    i2c_SDA(1);
    i2c_Delay();
    
    i2c_PinModeInput();
    
    for (i = 0; i < 8; i++)
    {
        recv = recv << 1;
        
        i2c_SCL(1);
        i2c_Delay();
            
        if (i2c_ReadSDA())
        {
            recv |= 0x01;
        }
        else
        {
            recv |= 0x00;
        }

        i2c_SCL(0);
        i2c_Delay();
    }
    
    return recv;
}

/*
*    函 数 名: i2c_Ack
*    功能说明: IIC总线主机主动应答
*    形    参: 无
*    返 回 值: 无
*/
void i2c_Ack(void)
{
    i2c_PinModeOutput();
    
    i2c_SCL(0);
    i2c_SDA(0);
    i2c_Delay();
    
    i2c_SCL(1);
    i2c_Delay();
    
    i2c_SCL(0);
}

/*
*    函 数 名: i2c_NAck
*    功能说明: IIC总线主机主动非应答
*    形    参: 无
*    返 回 值: 无
*/
void i2c_NAck(void)
{
    i2c_PinModeOutput();
    
    i2c_SCL(0);
    i2c_SDA(1);
    i2c_Delay();
    
    i2c_SCL(1);
    i2c_Delay();
    
    i2c_SCL(0);
}

/*
*    函 数 名: i2c_CheckAck
*    功能说明: IIC总线检测应答信号
*    形    参: 无
*    返 回 值: 0 应答信号,1 非应答信号 
*/
uint8_t i2c_CheckAck(void)
{
    uint8_t time = 0;

    i2c_PinModeOutput();

    i2c_SDA(1);
    i2c_Delay();
    i2c_SCL(1);
    i2c_Delay();
    
    i2c_PinModeInput();
    
    while (i2c_ReadSDA())
    {
        time++;
        if (time >= 100)
        {
            return 1;
        }
    }
    
    i2c_SCL(0);
    
    return 0;
}
bsp_i2c.c
#ifndef __BSP_I2C_H__
#define __BSP_I2C_H__

#include "stm8s.h"

#define I2C_WR            ((uint8_t) 0)        /* 写控制bit */
#define I2C_RD            ((uint8_t) 1)        /* 读控制bit */

#define ACK                ((uint8_t) 0)
#define NOACK            ((uint8_t) 1)

void i2c_InitGpio(void);
void i2c_Start(void);
void i2c_Stop(void);
void i2c_WriteByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(void);
void i2c_Ack(void);
void i2c_NAck(void);
uint8_t i2c_CheckAck(void);

#endif /* __BSP_I2C_H__ */
bsp_i2c.h
#include "m24256_driver.h"
#include "bsp_i2c.h"
#include "modbus_driver.h"


//uint8_t g_ucIsEEPROMBusy;


/*
*    函 数 名: M24256_Init
*    功能说明: 初始化
*    形    参: 无
*    返 回 值: 无
*/
void M24256_Init(void)
{
    i2c_InitGpio();
}

/*
*    函 数 名: M24256_WriteByte
*    功能说明: 写一个字节
*    形    参: _usAddress:地址
*                        _ucByte:数据
*    返 回 值: 无
*/
uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte)
{
    uint16_t i;
    
    for (i = 0; i < 3000; i++)
    {
        i2c_Start();
        i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */
        if (i2c_CheckAck() == ACK)
        {
            break;
        }
    }
    if (i >= 3000)
    {
        i2c_Stop();
        return 0;
    }
    
    /* 发送地址 */
    i2c_WriteByte((_usAddress & 0xFF00) >> 8);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 2;
    }
    i2c_WriteByte(_usAddress & 0x00FF);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 3;
    }
    
    /* 读数据 */
    i2c_WriteByte(_ucByte);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 4;
    }
    
    i2c_Stop();
    
    return 5;
}


/*
*    函 数 名: M24256_ReadByte
*    功能说明: 读一个字节
*    形    参: _usAddress:地址
*    返 回 值: recv:读取到的一个字节数据
*/
uint8_t M24256_ReadByte(uint16_t _usAddress)
{
    uint8_t recv = 0;
    uint16_t i;
    
    for (i = 0; i < 3000; i++)
    {
        i2c_Start();
        i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */
        if (i2c_CheckAck() == ACK)
        {
            break;
        }
    }
    if (i >= 3000)
    {
        i2c_Stop();
        return 0;
    }
    
    /* 发送地址 */
    i2c_WriteByte((_usAddress & 0xFF00) >> 8);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    i2c_WriteByte(_usAddress & 0x00FF);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    
    i2c_Start();
    i2c_WriteByte(EE_DEV_ADDR | I2C_RD);  /* 选中器件 + 读 */
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    
    recv = i2c_ReadByte();
    i2c_NAck();
    i2c_Stop();
    
 return recv;
}


/*
*    函 数 名: M24256_ReadBlock
*    功能说明: 从串行EEPROM指定地址处开始读取若干数据
*    形    参:  _usAddress : 起始地址
*                                 _usSize : 数据长度,单位为字节
*                           _pReadBuf : 存放读到的数据的缓冲区指针
*    返 回 值: 0 表示失败,1表示成功
*/
unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress)
{
    uint16_t i;
    
    for (i = 0; i < 3000; i++)
    {
        i2c_Start();
        i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */
        if (i2c_CheckAck() == ACK)
        {
            break;
        }
    }
    if (i >= 3000)
    {
        i2c_Stop();
        return 0;
    }
    
    /* 发送地址 */
    i2c_WriteByte((_usAddress & 0xFF00) >> 8);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    i2c_WriteByte(_usAddress &0x00FF);
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    
    i2c_Start();
    i2c_WriteByte(EE_DEV_ADDR | I2C_RD);  /* 选中器件 + 读 */
    if (i2c_CheckAck() == NOACK)
    {
        i2c_Stop();
        return 0;
    }
    
    /* 循环读取数据 */
    for (i = 0; i < _usSize; i++)
    {
        _pReadBuf[i] = i2c_ReadByte();
        
        if (i != _usSize - 1)
        {
            i2c_Ack();
        }
        else
        {
            i2c_NAck(); /* 读完最后一个字节,主机发送非应答 */
        }
    }
    
    i2c_Stop();
    return 1;
}


/*
*    函 数 名: M24256_WriteBlock
*    功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
*    形    参:  _usAddress : 起始地址
*                                 _usSize : 数据长度,单位为字节
*                          _pWriteBuf : 存放读到的数据的缓冲区指针
*    返 回 值: 0 表示失败,1表示成功
*/
unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress)
{
    uint16_t i, m;
    uint16_t usAddr;
    
    usAddr = _usAddress;
    for (i = 0; i < _usSize; i++)
    {
        if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0)
        {
            i2c_Stop();
            
            /* 重复发送起始信号,eeprom要重新开始写要等待10ms左右 */
            for (m = 0; m < 3000; m++)
            {
                i2c_Start();
                i2c_WriteByte(EE_DEV_ADDR | I2C_WR);
                if (i2c_CheckAck() == ACK)
                {
                    break;
                }
            }
            if (m >= 3000)
            {
                i2c_Stop();   /* 写eeprom超时 */
                return 0;
            }
            
            /* 发送地址 */
            i2c_WriteByte((usAddr & 0xFF00) >> 8);
            if (i2c_CheckAck() == NOACK)
            {
                i2c_Stop();
                return 0;
            }
            i2c_WriteByte(usAddr & 0x00FF);
            if (i2c_CheckAck() == NOACK)
            {
                i2c_Stop();
                return 0;
            }
        }
        
        /* 写入数据 */
        i2c_WriteByte(_pWriteBuf[i]);
        if (i2c_CheckAck() == NOACK)
        {
                i2c_Stop();
                return 0;
        }
        
        usAddr++;
    }
    
    i2c_Stop();
    
    return 1;
}
bsp_eeprom.c
#ifndef __M24256_DRIVER_H__
#define __M24256_DRIVER_H__

#include "stm8s.h"


#define EE_MODEL_NAME        "M24256"
#define EE_DEV_ADDR            0xA0        /* 设备地址 */
#define EE_PAGE_SIZE        64            /* 页面大小(字节) */
#define EE_SIZE                  (32*1024)    /* 总容量(字节) */
#define EE_ADDR_BYTES        1            /* 地址字节个数 */


extern unsigned char g_ucIsEEPROMBusy;


void M24256_Init(void);
uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte);
uint8_t M24256_ReadByte(uint16_t _usAddress);

unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress);
unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress);

void ee_Test(void);

#endif /* __M24256_DRIVER_H__ */
bsp_eeprom.h

原文地址:https://www.cnblogs.com/laoyou12138/p/11611079.html