打印
[STM8]

基于IAR开发环境的STM8S模拟IIC代码

[复制链接]
9759|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
owenli520|  楼主 | 2015-1-25 14:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 owenli520 于 2015-1-25 14:30 编辑

基于IAR STM8 2.10开发环境,STM8S005K6单片机,模拟IIC方式读写AT24C16或AT24C32,已验证可以正常对AT24C32进行读写数据,只是有个疑问,对于单片机接SDA脚的IO口进行方向控制反而引起时序不正常而读写不了数据,例程中是将此IO口始终设置为输出,不知道会不会有隐患,有待测试...  
以下是代码,完整代码请下载附件,包含完整工程!
#include "24Cxx.h"
#include "stm8s.h"
#include "stm8s_gpio.h"


#define AT24C32_SETSDAIN  GPIO_Init(AT24C32_SDA_PORT, GPIO_PIN_6, GPIO_MODE_IN_FL_NO_IT)
#define AT24C32_SETSDAOUT  GPIO_Init(AT24C32_SDA_PORT, GPIO_PIN_6, GPIO_MODE_OUT_OD_LOW_SLOW)

#define I2C_SLAW 0xA0        /*器件地址选择及写标志*/
#define I2C_SLAR 0xA1        /*器件地址选择及读标志*/


void nops(void)
{
//        asm("nop");
//        asm("nop");
        uint16_t i = 0;
        for (; i < 5; i++);
}


// 总线复位
void I2C_Reset(void)
{
        AT24C32_SCL_HIGH;
        AT24C32_SDA_HIGH;
}

// I2C操作严重错误
void I2C_Error(void)
{
        //复位I2C总线
        I2C_Reset();
        
        //进入死循环
        while (1)
        {
        }
}

// 发送起始条件
void I2C_Start_A(void) /*起始条件*/
{
        AT24C32_SCL_HIGH;
        nops();

        AT24C32_SDA_LOW;
        nops();

        AT24C32_SCL_LOW;
        nops();
}

// 停止条件
void I2C_Stop_A(void)
{
        AT24C32_SDA_LOW;
        nops();

        AT24C32_SCL_HIGH;
        nops();

        AT24C32_SDA_HIGH;
        nops();

        AT24C32_SCL_LOW;
        nops();
}

// 产生一个时钟信号
uint8_t I2C_GenerateClock(void)
{
        uint8_t bData = 0;
        uint16_t t = 0;
        
        AT24C32_SCL_HIGH;        
        nops();
        for (t = 0; t < 6; t++);
        
        if (AT24C32_READSDA)
        {
                bData = 1;
        }
        
        AT24C32_SCL_LOW;               
        nops();

        return bData;
}


// 应答位
void I2C_Ack(uint8_t bAckYes)
{
        if (bAckYes)
        {
                AT24C32_SDA_LOW;
        }
        else
        {
                AT24C32_SDA_HIGH;
        }
        
        I2C_GenerateClock();
        
        AT24C32_SDA_HIGH;
}

// 发送数据子程序, ucData为要求发送的数据
uint8_t I2C_Send(uint8_t ucData)
{
        uint8_t i;
        
        for (i = 0; i < 8; i++)
        {
                if (ucData & 0x80)
                {
                        AT24C32_SDA_HIGH;
                }
                else
                {
                        AT24C32_SDA_LOW;
                }
               
                ucData <<= 1;
               
                I2C_GenerateClock();
        }
        
        AT24C32_SDA_HIGH;
        
        return (!I2C_GenerateClock());
}

// 读一个字节的数据,并返回该字节值
uint8_t I2C_Read(void)
{
        uint8_t ucData = 0;
        uint8_t i;
        
        for (i = 0; i < 8; i++)
        {
                ucData <<= 1;
               
                if (I2C_GenerateClock())
                {
                        ucData |= 1;
                }
        }
        return ucData;
}

// 设置下一步操作的地址(一字节地址)
uint8_t I2C_SetAddress(uint16_t u16Addr)
{
        // 发送启动信号
        I2C_Start_A();

        // 发送访问地址
        return (I2C_Send(I2C_SLAW) && I2C_Send(u16Addr));
}

// 设置下一步操作的地址(两字节地址)
uint8_t I2C_SetAddress16(uint16_t u16Addr)
{
        // 发送启动信号
        I2C_Start_A();
        // 发送从器件地址

        // 发送访问地址        
        return (I2C_Send(I2C_SLAW) && I2C_Send(u16Addr >> 8) && I2C_Send(u16Addr & 0xff));
}

// 向8位地址的器件( 如:24C02 )写数据  bAddressIs16bit = 0
// 向16位地址的器件( 如:24C32 )写数据 bAddressIs16bit = 1
void Write_Byte_24c32(uint8_t *pDat, uint16_t u16Addr, uint8_t ucNbyte, uint8_t bAddressIs16bit)
{
        uint8_t bWriteError = FALSE;        //写数据出错标志位
        uint8_t i;
        uint8_t ucDataBuf = 0;
        uint32_t Cnt = 0;

        for (i = 0; i < ucNbyte; i++)
        {
                if (bAddressIs16bit)
                {
                        if (I2C_SetAddress16(u16Addr + i) == 0)
                        {
                                bWriteError = TRUE;
                                break;
                        }
                }
                else
                {
                        if (I2C_SetAddress(u16Addr + i) == 0)
                        {
                                bWriteError = TRUE;
                                break;
                        }
                }

                ucDataBuf = *(pDat + i);

                if (I2C_Send(ucDataBuf) == 0)
                {
                        bWriteError = TRUE;
                        break;
                }
               
                I2C_Stop_A();
               
                ucDataBuf = 12;
               
                do
                {
                        I2C_Start_A();
                } while ((++Cnt < 500000) && I2C_Send(I2C_SLAW) == 0);
               
                //如果50mS内还没有响应,则进入保护性报警状态
                if (Cnt == 500000)
                {
                        bWriteError = TRUE;
                        break;
                }
               
                I2C_Stop_A();
        }
        
        if (bWriteError)
        {
                I2C_Error();
        }
}

// 从8位地址的器件( 如:24C02 )读数据  bAddressIs16bit = 0
// 从16位地址的器件( 如:24C32 )读数据 bAddressIs16bit = 1
void Read_nByte_24c32(uint8_t *pDat, uint16_t u16Addr, uint8_t ucNbyte, uint8_t bAddressIs16bit)
{
        uint8_t bReadError标志寄存器 = FALSE;        //读EEPROM错误标志位
        uint8_t i;
        uint8_t ucDataBuf = 0;

        if (bAddressIs16bit)
        {
                if (I2C_SetAddress16(u16Addr) == 0)
                {
                        bReadError = TRUE;
                }
        }
        else
        {
                if (I2C_SetAddress(u16Addr) == 0)
                {
                        bReadError = TRUE;
                }
        }

        if (bReadError)
        {
                I2C_Error();
        }

        I2C_Start_A();

        if (I2C_Send(I2C_SLAR) == 0)
        {
                bReadError = TRUE;
        }

        if (bReadError)
        {
                I2C_Error();
        }

        for (i = 0; i < ucNbyte; i++)
        {
                ucDataBuf = I2C_Read();

                *(pDat + i) = ucDataBuf;
                I2C_Ack(i != (ucNbyte - 1));
        }
        
        I2C_Stop_A();
}

uint8_t Read_Byte_24c32(uint16_t u16Addr)
{
        uint8_t EepromDataBuf = 0xFF;
        //从16位地址的器件( 如:24C32 )读数据 bAddressIs16bit = 1

        Read_nByte_24c32(&EepromDataBuf, u16Addr, 1, DEVICE_ADDR);
               
        return EepromDataBuf;
}

//修改EEPROM数据
void ModifData_24c32(uint16_t u16Addr, uint8_t *pDat, uint16_t uclen)
{
        //向16位地址的器件( 如:24C32 )写数据 bAddressIs16bit = 1
        Write_Byte_24c32(pDat, u16Addr, uclen, DEVICE_ADDR);
}

STM8S005K6_24Cxx_IIC_Test_Simulator.zip (301.58 KB)


沙发
zh113214| | 2015-1-25 17:07 | 只看该作者
为啥对于单片机接SDA脚的IO口进行方向控制反而引起时序不正常而读写不了数据,这个我也看的不是很懂

使用特权

评论回复
板凳
VDeveloper| | 2015-5-19 17:27 | 只看该作者
测试通过,谢谢楼主……

使用特权

评论回复
地板
309030106| | 2015-5-19 20:26 | 只看该作者
感谢分享

使用特权

评论回复
5
zdaly| | 2015-5-20 09:54 | 只看该作者
用软件模拟是因为什么呢?STM8自己的硬件I2C不能用吗?

使用特权

评论回复
6
paier_tt| | 2015-5-20 11:42 | 只看该作者
完全看不懂,不过还是支持你一下

使用特权

评论回复
7
owenli520|  楼主 | 2015-5-21 08:39 | 只看该作者
zdaly 发表于 2015-5-20 09:54
用软件模拟是因为什么呢?STM8自己的硬件I2C不能用吗?

硬件I2C能用就不用模拟了,折腾很久硬件I2C就是不行

使用特权

评论回复
8
wowow| | 2015-5-21 08:55 | 只看该作者
STM32下是设成开集电极输出的,STM8没试过,应该也可以。

使用特权

评论回复
9
周董| | 2015-5-21 09:38 | 只看该作者
楼主怎么解决的啊,可以分享下吗

使用特权

评论回复
10
zdaly| | 2015-5-28 09:47 | 只看该作者
owenli520 发表于 2015-5-21 08:39
硬件I2C能用就不用模拟了,折腾很久硬件I2C就是不行

硬件I2C还是可以用的,目前我遇到的问题只是不能连续读,其他的都还好。

使用特权

评论回复
11
linlulu| | 2015-12-8 12:00 | 只看该作者
正在调试STM051的,用得着!多谢!!

使用特权

评论回复
12
tianyu22| | 2016-5-19 13:39 | 只看该作者
遇到个问题。。stm8s005无法调试,借你代码一用

使用特权

评论回复
13
shizaigaole| | 2016-5-20 10:27 | 只看该作者
有时间的话,
还是建议把硬件IIC模块用起来。

否则每次有点困难,就退缩回去,
不是好习惯。

使用特权

评论回复
14
大好大| | 2016-8-22 16:06 | 只看该作者
为什么下载来附件不完整打不开啊楼主

使用特权

评论回复
15
Glory分享| | 2016-11-2 16:23 | 只看该作者
楼主 我下载的为啥打不开呢?

使用特权

评论回复
16
干掉9527| | 2017-3-29 21:43 | 只看该作者
谢谢分享,刚好试一下

使用特权

评论回复
17
feelhyq| | 2017-3-30 09:18 | 只看该作者
针对楼主的疑问,将IO方向改变出现异常。  在改变IO方向之前,将SDA线释放掉,即将SDA拉高,原因是 SDA是开漏的,一旦被拉低之后,SDA就直接接地了,从器件是无法将SDA拉高的,也就无法传输数据。

使用特权

评论回复
18
simonliu009| | 2017-5-7 11:47 | 只看该作者
谢谢,早就听说STM8的I2C有bug,有个模拟的就好多了

使用特权

评论回复
19
10299823| | 2017-5-7 17:22 | 只看该作者
模拟iic好调试。

使用特权

评论回复
20
10299823| | 2017-5-7 17:28 | 只看该作者
iic读取EEPROM的代码很多。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

57

帖子

0

粉丝