栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux裸机开发|I2C实验

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux裸机开发|I2C实验

I2C实验 一、I2C介绍 1.1 I2C简介

I2C使用两条线在主控制器和从机之间进行数据通信,一条串行时钟线(SCL),一条是串行数据线(SDA),这两条线需要接上拉电阻(阻值一般4.7K),总线空闲的时候SCL和SDA都处于高电平。I2C总线标准模式下速度可达100KB/s,快速模式下可达400KB/s

I2C支持多从机,这些不同的I2C从设备有不同的器件地址,I2C控制器可以通过从设备的器件地址访问指定的I2C设备

I2C总线工作是按照一定的协议来运行的,下面介绍I2C有关的术语

  • 起始位:SCL为高电平时,SDA出现下降沿表示起始位
  • 停止位:SCL为高电平时,SDA出现上升沿表示停止位
  • 数据传输:数据传输时要保证SCL高电平期间,SDA上的数据稳定;因此SDA上的数据变化只能发生在SCL低电平期间
  • 应答信号:I2C主机发送完8位数据后会将SDA设置为输入状态,等待I2C从机应答;应答信号由从机发出,通过将SDA拉低来发出应答信号,表示通信成功
  • I2C写时序:I2C总线单字节写时序如下图示

– 1. 开始信号
– 2. 发送I2C设备地址
– 3. 读写位,0表示写操作,1表示读操作
– 4. 从机发送的ACK应答信号
– 5. 重新发送开始信号
– 6. 发送要写入数据的寄存器地址
– 7. 从机发送的ACK应答信号
– 8. 发送要写入寄存器的数据
– 9. 从机发送的ACK应答信号
– 10. 停止信号

  • I2C读时序:I2C总线单字节读时序如下图示

– 1. 主机发送起始信号
– 2. 主机发送要读取的I2C从设备地址
– 3. 读写控制位,此时是向从设备发送数据,因此是写信号
– 4. 从机发送的ACK应答信号
– 5. 重新发送开始信号
– 6. 主机发送要读取的寄存器地址
– 7. 从机发送的ACK应答信号
– 8. 重新发送开始信号
– 9. 从新发送要读取的I2C从设备地址
– 10. 读写控制位,此时是从I2C从设备里读取数据,因此是读信号
– 11. 从机发送的ACK应答信号
– 12. 从I2C器件里读取到的数据
– 13. 主机发出NO ACK信号表示读取完成,不需要从机再发ACK信号了
– 14. 主机发出停止信号

1.2 IMX6U I2C介绍

IMX6U提供了4个I2C外设,通过这四个I2C外设即可完成与I2C从器件进行通信。IMX6U的I2C支持两种模式:标准模式(100KB/s)和快速模式(400KB/s)

I2C外设几个重要的寄存器

  • I2Cx_IADR 寄存器:I2C地址寄存器 (x = 1 ~ 4),用来保存从设备地址(bit7:1有效)
  • I2Cx_IFDR 寄存器:分频寄存器,用来设置波特率,通过IC位设置波特率
  • I2Cx_I2CR 寄存器:I2C控制寄存器

– IEN:I2C使能位,为1使能,为0关闭
– IIEN:I2C中断使能位,为1使能,为0关闭
– MSTA:主从模式选择位,为1时工作为主模式,为0时工作在从模式
– MTX:传输方向选择位,为0时接收,为1时发送
– TXAK:传输应答使能,为0发送ACK信号,为1发送NO ACK信号
– RSTA:重复开始信号,为1表示产生一个重新开始信号

  • I2Cx_I2SR 寄存器:I2C状态寄存器

– ICF:数据传输状态位,为0表示数据正在传输,为1表示数据传输完成
– IAAS:为1时表示I2C地址,即I2Cx_IADR寄存器中的地址是从设备地址
– IBB:I2C总线忙标志位,为0表示I2C总线空闲,为1表示总线忙
– IAL:仲裁丢失位,为1时表示发生仲裁丢失
– SRW:从机读写状态位,为0表示主机要向从机写数据,为1表示从从机读取数据
– IIF:I2C中断挂起标志位,为1时表示有中断挂起,此位需要软件清零
– RXAK:应答信号标志位,为0时表示接收到ACK应答信号,为1时表示NO ACK信号

  • I2Cx_I2DR 寄存器:I2C数据寄存器,低8位有效;当要发送数据的时候将要发送的数据写入到此寄存器,当要接收数据的话直接读取此寄存器即可得到接收到的数据
1.3 AP3216C传感器介绍

AP3216C传感器是一个支持环境光强度(ALS)、接近距离(PS)和红外强度(IR)的三合一环境传感器。该芯片可以通过I2C接口与主控制相连,并且支持中断

AP3216C常被用于手机、平板、导航设备等,其内置的接近传感器可以用于检测是由有物体接近,也可以使用环境光传感器检测光强度,可以实现自动背光亮度调节。AP3216C结构图如下示
AP3216的设备地址为0x1E,AP3216C内部也有一些寄存器,通过这些寄存器可以配置AP3216C的工作模式,并读取相应的数据,AP3216C内部寄存器如下表示:

综上所述,AP3216C的配置步骤如下:

  1. 初始化相应的IO,设置复用功能,若使用中断还需要设置中断IO
  2. 初始化I2C1,设置波特率
  3. 初始化AP3216C ,读取AP3216C的数据
二、硬件介绍

本例程需要用到的硬件资源:

  • LED0
  • RGB LCD接口
  • UART
  • AP3216C

AP3216C的原理图如下示

三、程序编写
  • 新建i2c文件夹,在文件夹中创建实时时钟驱动文件bsp_i2c.c和bsp_i2c.h
#define I2C_STATUS_OK				(0)
#define I2C_STATUS_BUSY				(1)
#define I2C_STATUS_IDLE				(2)
#define I2C_STATUS_NAK				(3)
#define I2C_STATUS_ARBITRATIONLOST	(4)
#define I2C_STATUS_TIMEOUT			(5)
#define I2C_STATUS_ADDRNAK			(6)

enum i2c_direction
{
    kI2C_Write = 0x0, 		
    kI2C_Read = 0x1,  		
} ;

struct i2c_transfer
{
    unsigned char slaveAddress;      	
    enum i2c_direction direction; 		
    unsigned int subaddress;       		
    unsigned char subaddressSize;    	
    unsigned char *volatile data;    	
    volatile unsigned int dataSize;  	
};

void i2c_init(I2C_Type *base);
unsigned char i2c_master_start(I2C_Type *base, unsigned char address, enum i2c_direction direction);
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction);
unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status);
unsigned char i2c_master_stop(I2C_Type *base);
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size);
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size);
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer);
void i2c_init(I2C_Type *base)
{
	
	base->I2CR &= ~(1 << 7); 

    
	base->IFDR = 0x15 << 0;

	
	base->I2CR |= (1<<7);
}


unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction)
{
	
	if(base->I2SR & (1 << 5) && (((base->I2CR) & (1 << 5)) == 0))		
		return 1;

	
	base->I2CR |=  (1 << 4) | (1 << 2);

	 
	base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read)? 1 : 0);
	
	return 0;
}


unsigned char i2c_master_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction)
{
	if(base->I2SR & (1 << 5))			
		return 1;

	
	base->I2CR |=  (1 << 5) | (1 << 4);

	 
	base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read)? 1 : 0);
	return 0;
}


unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status)
{
	
	if(status & (1<<4))
	{
		base->I2SR &= ~(1<<4);		

		base->I2CR &= ~(1 << 7);	
		base->I2CR |= (1 << 7);		
		return I2C_STATUS_ARBITRATIONLOST;
	} 
	else if(status & (1 << 0))     	
	{
		return I2C_STATUS_NAK;		
	}
	return I2C_STATUS_OK;
}


unsigned char i2c_master_stop(I2C_Type *base)
{
	unsigned short timeout = 0xffff;

	
	base->I2CR &= ~((1 << 5) | (1 << 4) | (1 << 3));

	
	while((base->I2SR & (1 << 5)))
	{
		timeout--;
		if(timeout == 0)	
			return I2C_STATUS_TIMEOUT;
	}
	return I2C_STATUS_OK;
}


void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size)
{
	
	while(!(base->I2SR & (1 << 7))); 
	
	base->I2SR &= ~(1 << 1); 	
	base->I2CR |= 1 << 4;		
	
	while(size--)
	{
		base->I2DR = *buf++; 	
		
		while(!(base->I2SR & (1 << 1))); 		
		base->I2SR &= ~(1 << 1);			

		
		if(i2c_check_and_clear_error(base, base->I2SR))
			break;
	}
	
	base->I2SR &= ~(1 << 1);
	i2c_master_stop(base); 	
}


void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size)
{
	volatile uint8_t dummy = 0;

	dummy++; 	
	
	
	while(!(base->I2SR & (1 << 7))); 
	
	base->I2SR &= ~(1 << 1); 				
	base->I2CR &= ~((1 << 4) | (1 << 3));	
	
	
	if(size == 1)
        base->I2CR |= (1 << 3);

	dummy = base->I2DR; 
	
	while(size--)
	{
		while(!(base->I2SR & (1 << 1))); 		
		base->I2SR &= ~(1 << 1);			

	 	if(size == 0)
        {
        	i2c_master_stop(base); 			
        }

        if(size == 1)
        {
            base->I2CR |= (1 << 3);
        }
		*buf++ = base->I2DR;
	}
}


unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
{
	unsigned char ret = 0;
	 enum i2c_direction direction = xfer->direction;	

	base->I2SR &= ~((1 << 1) | (1 << 4));			

	
	while(!((base->I2SR >> 7) & 0X1)){}; 

	
    if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
    {
        direction = kI2C_Write;
    }

	ret = i2c_master_start(base, xfer->slaveAddress, direction); 
    if(ret)
    {	
		return ret;
	}

	while(!(base->I2SR & (1 << 1))){};			

    ret = i2c_check_and_clear_error(base, base->I2SR);	
    if(ret)
    {
      	i2c_master_stop(base); 						
        return ret;
    }
	
    
    if(xfer->subaddressSize)
    {
        do
        {
			base->I2SR &= ~(1 << 1);			
            xfer->subaddressSize--;				
			
            base->I2DR =  ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器写入子地址
  
			while(!(base->I2SR & (1 << 1)));  	

            
            ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	i2c_master_stop(base); 				
             	return ret;
            }  
        } while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));

        if(xfer->direction == kI2C_Read) 		
        {
            base->I2SR &= ~(1 << 1);			
            i2c_master_repeated_start(base, xfer->slaveAddress, kI2C_Read); 
    		while(!(base->I2SR & (1 << 1))){};

            
			ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	ret = I2C_STATUS_ADDRNAK;
                i2c_master_stop(base); 		
                return ret;  
            }
           	          
        }
    }	


    
    if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0))
    {
    	i2c_master_write(base, xfer->data, xfer->dataSize);
	}

    
    if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0))
    {
       	i2c_master_read(base, xfer->data, xfer->dataSize);
	}
	return 0;	
}
  • 新建ap3216c文件夹,在文件夹中创建实时时钟驱动文件bsp_ap3216c.c和bsp_ap3216c.h
#define AP3216C_ADDR    	0x1E	

#define AP3216C_SYSTEMCONG	0x00	
#define AP3216C_INTSTATUS	0x01	
#define AP3216C_INTCLEAR	0x02	
#define AP3216C_IRDATALOW	0x0A	
#define AP3216C_IRDATAHIGH	0x0B	
#define AP3216C_ALSDATALOW	0x0C	
#define AP3216C_ALSDATAHIGH	0x0D	
#define AP3216C_PSDATALOW	0x0E	
#define AP3216C_PSDATAHIGH	0x0F	

unsigned char ap3216c_init(void);
unsigned char ap3216c_readonebyte(unsigned char addr,unsigned char reg);
unsigned char ap3216c_writeonebyte(unsigned char addr,unsigned char reg, unsigned char data);
void ap3216c_readdata(unsigned short *ir, unsigned short *ps, unsigned short *als);
unsigned char ap3216c_init(void)
{
	unsigned char data = 0;

	
	IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL, 1);
	IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA, 1);

	
	IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL, 0x70B0);
	IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA, 0x70B0);

	i2c_init(I2C1);		

	
	ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0x04);	
	delayms(50);													
	ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0x03);	
	data = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG);	
	if(data == 0x03)
		return 0;	
	else 
		return 1;	
}


unsigned char ap3216c_writeonebyte(unsigned char addr,unsigned char reg, unsigned char data)
{
    unsigned char status=0;
    unsigned char writedata=data;
    struct i2c_transfer masterXfer;
	
    
   	masterXfer.slaveAddress = addr; 			
    masterXfer.direction = kI2C_Write;			
    masterXfer.subaddress = reg;				
    masterXfer.subaddressSize = 1;				
    masterXfer.data = &writedata;				
    masterXfer.dataSize = 1;  					

    if(i2c_master_transfer(I2C1, &masterXfer))
        status=1;
        
    return status;
}


unsigned char ap3216c_readonebyte(unsigned char addr,unsigned char reg)
{
	unsigned char val=0;
	
	struct i2c_transfer masterXfer;	
	masterXfer.slaveAddress = addr;				
    masterXfer.direction = kI2C_Read;			
    masterXfer.subaddress = reg;				
    masterXfer.subaddressSize = 1;				
    masterXfer.data = &val;						
    masterXfer.dataSize = 1;					
	i2c_master_transfer(I2C1, &masterXfer);

	return val;
}


void ap3216c_readdata(unsigned short *ir, unsigned short *ps, unsigned short *als)
{
    unsigned char buf[6];
    unsigned char i;

	
    for(i = 0; i < 6; i++)	
    {
        buf[i] = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_IRDATALOW + i);	
    }
	
    if(buf[0] & 0x80) 	
		*ir = 0;					
	else 				
		*ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0x03); 			
	
	*als = ((unsigned short)buf[3] << 8) | buf[2];	  
	
    if(buf[4] & 0x40)	
		*ps = 0;    													
	else 				
		*ps = ((unsigned short)(buf[5] & 0x3F) << 4) | (buf[4] & 0x0F); 	
}

  • 主函数main.c中编写测试程序
int main(void)
{
	unsigned short ir, als, ps;
	unsigned char state = OFF;

	int_init(); 				
	imx6u_clkinit();			
	delay_init();				
	clk_enable();				
	led_init();					
	beep_init();				
	uart_init();				
	lcd_init();					

	tftlcd_dev.forecolor = LCD_RED;	
	lcd_show_string(30, 50, 200, 16, 16, (char*)"ALPHA-IMX6U IIC TEST");  
	lcd_show_string(30, 70, 200, 16, 16, (char*)"AP3216C TEST");  
	lcd_show_string(30, 90, 200, 16, 16, (char*)"ATOM@ALIENTEK");  
	lcd_show_string(30, 110, 200, 16, 16, (char*)"2019/3/26");  
	
	while(ap3216c_init())		
	{
		lcd_show_string(30, 130, 200, 16, 16, (char*)"AP3216C Check Failed!");
		delayms(500);
		lcd_show_string(30, 130, 200, 16, 16, (char*)"Please Check!        ");
		delayms(500);
	}	
	
	lcd_show_string(30, 130, 200, 16, 16, (char*)"AP3216C Ready!");  
    lcd_show_string(30, 160, 200, 16, 16, (char*)" IR:");	 
	lcd_show_string(30, 180, 200, 16, 16, (char*)" PS:");	
	lcd_show_string(30, 200, 200, 16, 16, (char*)"ALS:");	
	tftlcd_dev.forecolor = LCD_BLUE;	
	while(1)					
	{
		ap3216c_readdata(&ir, &ps, &als);		
		lcd_shownum(30 + 32, 160, ir, 5, 16);	
        lcd_shownum(30 + 32, 180, ps, 5, 16);	
        lcd_shownum(30 + 32, 200, als, 5, 16);	 
		delayms(120);
		state = !state;
		led_switch(LED0,state);	
	}
	return 0;
}
四、下载验证
  • 修改Makefile文件:修改TARGET为ap3216c,追加“bsp/ap3216c”和“bsp/i2c”文件夹
  • 使用imxdownload软件将bin文件下载到SD卡中
  • 烧写成功后,插入SD卡,复位开发板后,LCD屏幕上会显示环境光强度(ALS)、接近距离(PS)和红外强度(IR)的数值
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/338732.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号