Linux 学习记录59(ARM篇)

Linux 学习记录59(ARM篇)

本文目录

  • [Linux 学习记录59(ARM篇)](#Linux 学习记录59(ARM篇))
  • 一、IIC总线
    • [1. 概念](#1. 概念)
    • [2. IIC总线硬件连接](#2. IIC总线硬件连接)
  • 二、系统框图
  • 三、IIC时序
    • [1. 起始信号 / 停止信号](#1. 起始信号 / 停止信号)
    • [2. 数据传输信号](#2. 数据传输信号)
    • [3. 应答信号 / 非应答信号](#3. 应答信号 / 非应答信号)
    • [4. 寻址信号](#4. 寻址信号)
  • 四、IIC协议
    • [1. 主机给从机发送一个字节(写)](#1. 主机给从机发送一个字节(写))
    • [2. 主机给从机发送多个连续字节](#2. 主机给从机发送多个连续字节)
    • [3. 从机给主机发送一个字节(读)](#3. 从机给主机发送一个字节(读))
    • [4. 从机给主机发送多个连续字节](#4. 从机给主机发送多个连续字节)
  • 五、软件模拟IIC
    • [1. IIC的GPIO初始化](#1. IIC的GPIO初始化)
    • [2. 宏定义及函数声明](#2. 宏定义及函数声明)
    • [3. 切换SDA的GPIO模式](#3. 切换SDA的GPIO模式)
    • [4. 起始信号](#4. 起始信号)
    • [5. 停止信号](#5. 停止信号)
    • [6. 等待应答信号](#6. 等待应答信号)
    • [7. ACK应答](#7. ACK应答)
    • [8. 发送/读取一个字节](#8. 发送/读取一个字节)

一、IIC总线

1. 概念

  1. I2C总线是PHLIPS公司在八十年代初推出的一种串行半双工同步总线,主要用于连接整体电路
  1. 两个芯片之间通讯 SOC(stm32mp157a)<------- IIC总线 ------->温湿度传感器(si7006)
  2. 两个设备之间通讯 PC<------ UART总线 ------>开发板
  1. I2C总线为两线制,只有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL
  1. SDA数据线作用:完成数据传输
  2. SCL时钟线作用:完成数据收发同步
  1. IIC传输速率
  1. 低速:100K
  2. 中速:400K
  3. 高速:3.4M
  1. I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用
  2. 、IIC总线外接两个上拉电阻作用:在总线处于空闲状态时,SCL线和SDA线处于高电平状态

2. IIC总线硬件连接

c 复制代码
1. IIC总线支持多主机多从机模式,在同一时刻,只能与一个从机进行通讯
2. 在实际使用过程中,大多数都使用单主机多从机模式
3. 挂接到IIC总线上的每个从机设备,都有自己唯一的7位从机地址(从对应的芯片手册中进行查找从机地址)
4. 主动发起数据的叫做主机(起始信号),只能被动接收数据的叫做从机
5. 在总线上,发送数据叫做发送器,接收数据的叫做接收器
6. 起始信号、时钟信号、停止信号都是由主机产生
7. 时钟信号只能由主机产生,作用给从机,完成数据收发同步

二、系统框图

三、IIC时序

1. 起始信号 / 停止信号

c 复制代码
1、起始信号:在SCL为高电平期间,SDA从高到低的变化(下降沿)
2、停止信号:在SCL为高电平期间,SDA从低到高的变化(上升沿)
3、起始信号和停止信号由主机产生
4、起始信号产生之后,总线处于占用状态
5、停止信号产生之后,总线处于空闲状态

2. 数据传输信号

c 复制代码
1、在SCL为高电平期间,数据线上数据保持稳定,接收器从数据线上读取数据
2、在SCL为低电平期间,数据线上数据允许发生变化,发送器向数据线上写入数据

3. 应答信号 / 非应答信号

c 复制代码
1、每一个字节必须保证是8位长度,数据传输时,先传送最高位,在传送低位
	每一个被传送的字节后面都必须跟随一位应答位,一帧数据 = 8位数据位 + 1位应答位 = 9位
	
2、发送器在发送完8位数据之后,接收器在第九个时钟周期,返回一个应答信号(0)/非应答信号(1)
第九个时钟周期,接收器向数据线上写入应答/非应答信号
第九个时钟周期,发送器从数据线上读
读0:应答信号
读1:非应答信号

4. 寻址信号

c 复制代码
1、IIC总线上数据传输是广义的,包括从机地址,传输数据信号
2、在起始信号产生之后,寻址从机,需要发送7位从机地址 + 读(1)/写(0)
3、从总线上读取数据:7位从机地址 + 读(1)
4、向总线上写入数据:7位从机地址 + 写(0)

四、IIC协议

1. 主机给从机发送一个字节(写)

主机作为 "发送器" 从机作为"接收器"

c 复制代码
IIC_Start();//起始信号
/*add_RH 为从机地址例如0x40 或上0表示要写入数据*/
IIC_Send_Byte((add_RH << 1) | 0);//发送从机地址
IIC_Wait_Ack();//等待回应
/*USER_W表示要写入的寄存器或命令*/
IIC_Send_Byte(USER_W);//发送从机地址
IIC_Wait_Ack();//等待回应
/*start_M表示要写入该寄存器的数据*/
IIC_Send_Byte(start_M);//发送从机地址
IIC_Wait_Ack();//等待回应
IIC_Stop();

2. 主机给从机发送多个连续字节

每发送一个8位数据后寄存器地址自动偏移

3. 从机给主机发送一个字节(读)

c 复制代码
uint8_t buf;
IIC_Start();//起始信号
/*add_RH 为从机地址例如0x40 或上0表示要写入数据*/
IIC_Send_Byte(add_RH << 1);//发送从机地址
IIC_Wait_Ack();//等待回应
/*USER_R表示要读取的寄存器或命令*/
IIC_Send_Byte(USER_R);//发送从机命令
IIC_Wait_Ack();//等待回应
/*从机开始作为发送方*/
IIC_Start();//起始信号
/*add_RH 为从机地址例如0x40 或上1表示要读取数据*/
IIC_Send_Byte((add_RH << 1) |1);//发送从机地址
IIC_Wait_Ack();//等待回应
/*IIC_R_NACK 表示不读取后续数据*/
buf= IIC_Read_Byte(IIC_R_NACK);//IIC读取一个字节
IIC_Stop();

4. 从机给主机发送多个连续字节

五、软件模拟IIC

1. IIC的GPIO初始化

c 复制代码
//初始化IIC
void IIC_Init(void)
{			
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_MP_AHB4_ENSETR |= (0x1 << 1);//使能GPIO F-E时钟;//使能GPIOB时钟

    //GPIOB8,B9初始化设置
    GPIO_InitStructure.GPIO_Pin = IIC_SCL_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(IIC_GPIOx, &GPIO_InitStructure);//初始化

    GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
    GPIO_Init(IIC_GPIOx, &GPIO_InitStructure);//初始化

    IIC_SCL_H;//将时钟线和数据线拉高
    IIC_SDA_H;
}

2. 宏定义及函数声明

c 复制代码
#define IIC_GPIOx GPIOF

#define IIC_R_ACK 1
#define IIC_R_NACK 0

#define IIC_SCL_Pin 14
#define IIC_SDA_Pin 15

#define IIC_SCL_H   GPIO_SetBits(IIC_GPIOx,IIC_SCL_Pin)
#define IIC_SDA_H   GPIO_SetBits(IIC_GPIOx,IIC_SDA_Pin)

#define IIC_SCL_L   GPIO_ResetBits(IIC_GPIOx,IIC_SCL_Pin)
#define IIC_SDA_L   GPIO_ResetBits(IIC_GPIOx,IIC_SDA_Pin)

#define READ_SDA	GPIO_ReadInputDataBit(IIC_GPIOx,IIC_SDA_Pin)


//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(uint8_t txd);			//IIC发送一个字节
uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
uint8_t IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

3. 切换SDA的GPIO模式

c 复制代码
void SDA_OUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    //GPIOB8,B9初始化设置
    GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(IIC_GPIOx, &GPIO_InitStructure);//初始化
}

void SDA_IN(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    //GPIOB8,B9初始化设置
    GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输出模式
    GPIO_Init(IIC_GPIOx, &GPIO_InitStructure);//初始化
}

4. 起始信号

c 复制代码
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
    IIC_SDA_H;
	IIC_SCL_H;
	delay_us(4);
 	IIC_SDA_L;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL_L;//钳住I2C总线,准备发送或接收数据 
}

5. 停止信号

c 复制代码
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL_L;
	IIC_SDA_L;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL_H;
    IIC_SDA_H;//发送I2C总线结束信号
	delay_us(4);							   	
}

6. 等待应答信号

c 复制代码
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA_H;delay_us(1);	   
	IIC_SCL_H;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL_L;//时钟输出0 	   
	return 0;  
}

7. ACK应答

c 复制代码
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL_L;
	SDA_OUT();
	IIC_SDA_L;
	delay_us(2);
	IIC_SCL_H;
	delay_us(2);
	IIC_SCL_L;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL_L;
	SDA_OUT();
	IIC_SDA_L;
	delay_us(2);
	IIC_SCL_H;
	delay_us(2);
	IIC_SCL_L;
}

8. 发送/读取一个字节

c 复制代码
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
	SDA_OUT(); 	    
    IIC_SCL_L;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        if((txd&0x80)>>7){
            IIC_SDA_H;
        }else{
            IIC_SDA_L;
        }
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL_H;
		delay_us(2); 
		IIC_SCL_L;	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL_L; 
        delay_us(2);
		IIC_SCL_H;
        receive<<=1;
        if(READ_SDA)
            receive |= 1;   
        else 
            receive |= 0; 

		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}
相关推荐
brave and determined10 小时前
接口通讯学习(day05):智能手机的内部高速公路:揭秘MIPI CSI与DSI技术
学习·智能手机·软件工程·制造·csi·mipi·dsi
nuoxin11410 小时前
GSV1011-富利威-HDMI芯片选型
arm开发·驱动开发·fpga开发·ffmpeg·射频工程
云计算练习生10 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
虚伪的空想家12 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
Tonya4313 小时前
测开学习DAY37
学习
t1987512818 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816318 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
晚风吹人醒.19 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件
Hard but lovely19 小时前
linux: pthread库的使用和理解
linux