单片机交流
直播中

赵敏

7年用户 1061经验值
私信 关注
[问答]

如何用arm内核的mcu模拟IIC通讯?

如何用arm内核的mcu模拟IIC通讯?

回帖(1)

陈华

2021-11-5 11:00:21
摘要

之前写过51内核系列的IO口模拟IIC通讯,最近用arm内核的mcu模拟IIC通讯,发现与51内核有些区别(arm内核不支持位寻址)
IIC的信号:开始信号(SCL保持高,拉低SDA)、应答信号(第九个时钟,SDA为低)、非应答信号(第九个时钟,SDA为低)、结束信号(SCL保持高,拉高SDA)
(非)应答信号: 有应答信号才可以进行下一步,非应答信号会结束通讯
IIC写数据设置三个信号:起始信号、从地址+写(如:addr为0x18(00011000),左移1位后为0x30(00110000),最后一位是0表示写)、寄存器
IIC读数据设置五个信号:起始信号、从地址+写、寄存器、起始信号、从地址+读(如:addr为0x18(00011000),左移1位后为0x30(00110000)与上1后为0x31,最后一位是1表示读(上个图帮助理解)





看下代码吧
一、IO宏定义

51内核定义方式:


#define         IIC_SCL     P04//SCL输出模式
#define         IIC_SDA     P03 //SDA输出模式         
#define         READ_SDA    P03//读取应答信号SDA 输入模式

arm内核定义方式:


//IIC IO定义
#define         IIC_SCL(x)    GPIO_output(0, 2, x)//SCL输出模式
#define         IIC_SDA(x)    GPIO_output(0, 3, x) //SDA输出模式         
#define         READ_SDA()    gpio_input(0,2)//读取应答信号SDA 输入模式
#define         READ_SCL()    gpio_input(0,3)//读取应答信号SDA 输入模式

//SDA线输入输出设置
#define         SET_SDA_IN()  GPIO_config(0,2,0)
#define         SET_SDA_OUT() GPIO_config(0,2,1)
//SCL线输入输出设置
#define         SET_SCL_IN()  GPIO_config(0,3,0)
#define         SET_SCL_OUT() GPIO_config(0,3,1)

二、写数据



/**************************************************************
函数名:                IIC_SendNByte
功能:                发送Nbyte数据
输入参数:        ADDR从机地址,REG寄存器地址 待发送数据dat,n数据大小
返回值:                成功写了多少个
函数类型:        void
-------------------------------------------------------------*/       
unsigned char        IIC_WriteNByte(unsigned char        addr,unsigned char        reg_addr,unsigned char        *dat,unsigned char n)
{
    unsigned char        i;
       
        IIC_Start();//一个起始信号
        addr <<= 1; //左移1位,最低位为0 表示写
        IIC_Write1Byte(addr);//一个从机地址信号
        IIC_Write1Byte(reg_addr);//一个寄存器地址信号
//下面可以连续写啦         
        for(i = 0;i         {
                 IIC_Write1Byte(dat);
                if(IIC_Ack())
                        {
                                IIC_Stop();
                                return i;
                        }
        }
       
        IIC_Stop();
       
        return i;
}
硬件IIC内部有地址自增功能,所以一直读就可以了


三、读数据

/**************************************************************
函数名:                IIC_ReadNByte
功能:                接收Nbyte数据
输入参数:        是否需要发送应答信号 1:需要 0:不需要
返回值:                接收到的数据
函数类型:        u8
-------------------------------------------------------------*/       
void IIC_ReadNByte(unsigned char        addr,unsigned char        reg_addr,unsigned char        *dat,unsigned char n)
{
    unsigned char        i;
       
        IIC_Start();//一个起始信号
        addr <<= 1; //左移1位,最低位为0 表示写
        IIC_Write1Byte(addr);//一个从机地址信号
        IIC_Write1Byte(reg_addr);//一个寄存器地址信号
       
        IIC_Start();//restart信号
        IIC_Write1Byte(addr|1);//从机地址+读
//下面就可以读啦
        for(i = 0;i         {
                dat=IIC_Read1Byte();
                if(i<(n-1))
                IIC_SendAck();
                       
        }
       
        IIC_NoSendAck();//发送非应答
  IIC_Stop();


}


四,读和写的区别


1、写数据要接收应答或非应答信号、读数据发送应答或非应答信号
2、写数据:start、addr+w、reg; 读数据:start、addr+w、reg、start、addr+r   多了start、addr+r





举报

更多回帖

×
20
完善资料,
赚取积分