尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

ARM-IIC

发布时间:2026/9/29 15:08:01

资讯中心
01
ARTICLE

ARM-IIC

ARM-IIC
前面学完UART串口今天继续学习I2CIIC总线这是嵌入式里最常用的半双工同步串行总线。UART需要两根线TX/RX做点对点通信而I2C只需要SDA数据线 SCL时钟线一条总线上可以挂载多个从设备依靠从机地址来区分设备很适合外接EEPROM、温度传感器这类外设。本次实验同一根I2C总线挂载两个外设AT24C02 EEPROM存储器、LM75温度传感器。一、I2C基础原理1. 开漏输出与线与特性I2C的SDA、SCL引脚必须是开漏模式外部接上拉电阻4.7k~10k。开漏MOS管只能拉低电平高电平由外部上拉电阻提供多个设备挂载在同一根总线就形成线与逻辑只要任意一个设备把总线拉低整条总线就是低电平全部释放总线才是高电平。推挽输出可以主动输出高、低电平开漏输出只能拉低高电平依靠外部上拉I2C必须使用开漏才能实现多设备总线仲裁。2. I2C时序信号总线空闲时SDA和SCL全部为高电平。Start起始信号SCL保持高SDA由高→低代表通信开始Stop停止信号SCL保持高SDA由低→高结束本次通信数据传输SCL低电平期间主机修改SDASCL高电平期间从机采样SDA数据高位优先MSB先行应答位ACK/NACK每传输完一个字节接收方拉低SDA就是ACK应答0接收方保持高电平就是NACK无应答1。主机收到NACK就代表从机没有正常响应需要终止通信。I2C读操作有一个关键点重复起始信号Restart。读取从机内部寄存器数据流程是Start - 写从机地址(写方向) - 写寄存器地址 - Restart - 写从机地址(读方向) - 读取数据。中间不发送Stop直接发Restart重新发起起始切换读写方向LM75读取温度就使用这套流程。二、IMX6ULL硬件I2C控制器读写逻辑I2C写时序清除仲裁丢失标志I2SR_IAL、中断标志I2SR_IIF设置主机发送模式I2CR_MTX置位MSTA产生START信号I2DR写入从机地址方向位0写等待IIF中断标志判断RXAK应答发送要访问的寄存器地址等待应答循环写入多字节数据每字节等待应答清除MSTA产生STOP信号等待总线空闲I2C读时序初始化进入主机发送模式发送Start发送从机地址写方向发送内部寄存器地址发送RSTA重复起始信号Restart发送从机地址方向位1读切换为接收模式清除MTX提前设置TXAK应答最后一个字节要回复NACK前面字节回复ACK伪读操作触发硬件接收循环读取数据倒数第2字节时提前设置NACK读完所有数据发送Stop信号结束通信注意I2C接收的时候必须提前设置TXAK硬件是预加载应答。读到倒数第二个字节就要提前把TXAK置1告诉硬件最后一个字节回复NACK不能读完数据再设置。三、代码实现1、i2c.c —— I2C底层硬件驱动完成引脚初始化、底层读写函数、统一消息分发接口上层AT24C02、LM75全部调用这套底层API。#includei2c.h#includefsl_iomuxc.h//I2C1初始化引脚复用电气属性配置I2C控制器分频voidi2c_init(I2C_Type*base){//复用为I2C的SDA、SCLIOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA,1);IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL,1);//引脚电气配置IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA,0x10B0);IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL,0x10B0);base-I2CR~I2CR_IEN;//关闭I2C模块配置分频base-IFDR0x15;//设置I2C时钟分频base-I2CR|I2CR_IEN;//使能I2C控制器}//等待IIF中断标志并且判断是否收到NACKintwait_i2c_iif(I2C_Type*base){while((base-I2SRI2SR_IIF)0){//这里可以增加超时防止死等}base-I2SR~I2SR_IIF;//写0清除中断标志if((base-I2SRI2SR_RXAK)!0){return-1;//收到NACK通信失败}return0;}//I2C主机写函数写从机寄存器voidi2c_write(I2C_Type*base,unsignedchardev_addr,unsignedshortreg_addr,intreg_len,unsignedchar*data,intdata_len){intstat0;//0.清除标志位base-I2SR~(I2SR_IAL|I2SR_IIF);//1.设置为发送模式base-I2CR|I2CR_MTX;//2.发起STARTbase-I2CR|I2CR_MSTA;//3.发送从机地址方向0写base-I2DR(dev_addr1)|(00);statwait_i2c_iif(base);if(stat!0)gotostop;//4.发送寄存器地址支持1/2字节寄存器地址intireg_len-1;for(;i0;i--){base-I2DRreg_addr(i*8);statwait_i2c_iif(base);if(stat!0)gotostop;}//5.循环发送数据for(i0;idata_len;i){base-I2DRdata[i];statwait_i2c_iif(base);if(stat!0)gotostop;}stop://6.发送STOP等待总线空闲base-I2CR~I2CR_MSTA;while((base-I2SRI2SR_IBB)!0){//超时检测}}//I2C主机读函数带Restart重复起始voidi2c_read(I2C_Type*base,unsignedchardev_addr,unsignedshortreg_addr,intreg_len,unsignedchar*data,intdata_len){intstat0;//0.清除标志base-I2SR~(I2SR_IAL|I2SR_IIF);//1.发送模式base-I2CR|I2CR_MTX;//2.STARTbase-I2CR|I2CR_MSTA;//3.从机地址写方向base-I2DR(dev_addr1)|(00);statwait_i2c_iif(base);if(stat!0)gotostop;//4.发送寄存器地址intireg_len-1;for(;i0;i--){base-I2DRreg_addr(i*8);statwait_i2c_iif(base);if(stat!0)gotostop;}//5.重复起始 Restartbase-I2CR|I2CR_RSTA;//6.从机地址读方向1base-I2DR(dev_addr1)|(10);statwait_i2c_iif(base);if(stat!0)gotostop;//7.切换接收模式base-I2CR~I2CR_MTX;//8.设置应答多于1字节先发ACK最后一字节NACKif(data_len1){base-I2CR~I2CR_TXAK;}else{base-I2CR|I2CR_TXAK;}//9.伪读触发硬件接收data[0]base-I2DR;//10.循环接收for(i0;idata_len;i){statwait_i2c_iif(base);if(idata_len-2){base-I2CR|I2CR_TXAK;//倒数第二个提前设置NACK}if(idata_len-1){base-I2CR|I2CR_MTX;//读完切回发送模式准备stop}data[i]base-I2DR;if(stat!0)gotostop;}stop:base-I2CR~I2CR_MSTA;while((base-I2SRI2SR_IBB)!0){//超时等待总线空闲}}//统一消息分发接口根据读写方向调用i2c_write/i2c_readvoidtransfer(I2C_Type*base,structI2C_Msg*msg){if(NULLbase||NULLmsg){return;}if(I2C_writemsg-dir){i2c_write(base,msg-dev_addr,msg-reg_addr,msg-reg_len,msg-data,msg-data_len);}else{i2c_read(base,msg-dev_addr,msg-reg_addr,msg-reg_len,msg-data,msg-data_len);}}2、at24c02.c —— AT24C02 EEPROM上层驱动AT24C02是2Kbit I2C掉电存储芯片页写限制为8字节不能一次性写入超过8字节需要做分页处理写完要延时等待芯片内部烧写。读操作没有分页限制。依赖i2c.c提供的transfer接口。#includeat24c02.h#includegpt.hvoidat24c02_init(void){i2c_init(I2C1);}//分页写AT24C02按8字节一页拆分voidat24c02_write(I2C_Type*base,structI2C_Msg*msg){structI2C_Msg_at24c02*msg;unsignedstarmsg-reg_addr;unsignedendmsg-reg_addrmsg-data_len;inti;for(istar1;iend;i){if((i%8)0){_at24c02.reg_addrstar;_at24c02.data_leni-star;transfer(base,_at24c02);delay_ms(5);//等待EEPROM内部编程_at24c02.data_at24c02.data_len;stari;}}if(starend){_at24c02.reg_addrstar;_at24c02.data_lenend-star;transfer(base,_at24c02);delay_ms(5);}}//AT24C02读函数直接调用底层transfervoidat24c02_read(I2C_Type*base,structI2C_Msg*msg){transfer(base,msg);}3、lm75.c —— LM75温度传感器驱动LM75是I2C数字温度传感器从机地址0x48温度寄存器16bit分辨率0.5℃调用i2c.c的transfer接口读取原始数据并换算成摄氏度。#includelm75.h#includei2c.h#includestdio.h//读取原始温度值unsignedshortget_temp_vale(void){unsignedchardata[32]{0};//I2C消息结构体LM75从地址0x48寄存器地址0读2字节structI2C_Msg_lm75_msg{.dev_addr0x48,.reg_addr0,.reg_len1,.datadata,.data_len2,.dirI2C_read};transfer(I2C1,_lm75_msg);unsignedshortvalu((data[0]8)|(data[1]0));unsignedshorttempvalu7;//右移7位提取有效温度位returntemp;}//转换成浮点数温度单位℃floatget_temp(void){unsignedshorttempget_temp_vale();return(float)temp/2;}4、main.c 主测试代码复用之前时钟、GPT延时、UART串口驱动调用at24c02_init()完成I2C硬件初始化循环读取LM75温度串口打印温度AT24C02读写代码已经注释放开即可测试EEPROM。#includeMCIMX6Y2.h#includefsl_iomuxc.h#includeled.h#includebeep.h#includekey.h#includeinterrupt.h#includeclock.h#includeepit.h#includegpt.h#includeuart.h#includestdio.h#includestring.h#includei2c.h#includeat24c02.h#includelm75.hintmain(void){system_interrupt_init();clock_init();led_init();beep_init();key_init();//epit1_init();gpt1_init();uart1_init();at24c02_init();floattemp0;while(1){tempget_temp();intm0,n0;m(int)(temp*1000)/1000;n(int)(temp*1000)%1000;printf(temp %d.%d\n,m,n);//下面注释部分是AT24C02读写测试放开即可使用//scanf(%s, data);//_at24c02.data_len (int)strlen((char *)data);//i2c_write(I2C1, 0x50, 0, 1, data, size);//_at24c02.dir I2C_write;//at24c02_write(I2C1, _at24c02);delay_ms(100);//memset(data, 0, sizeof(data));//i2c_read(I2C1, 0x50, 0, 1, data, size);//_at24c02.dir I2C_read;//at24c02_read(I2C1, _at24c02);//printf(read %s\n, data);}return0;}学习小结代码分层思想i2c.c做硬件底层at24c02.c、lm75.c做设备业务层设备驱动不直接操作寄存器全部调用底层封装好的transfer接口。后续新增其他I2C外设只需要新增设备驱动文件底层不用改动。I2C是同步半双工串行总线SDASCL两根线开漏输出线与外部必须上拉电阻支持多从设备依靠从机地址区分。Start、Stop、Restart、ACK/NACK是I2C通信最核心的信号。IMX6ULL硬件I2C读操作难点Restart重复起始、提前设置TXAK应答位。硬件I2C是预加载应答不能读完字节再设置NACK。AT24C02重点注意页写8字节限制长数据要分页写写完增加延时等待芯片内部烧写否则写入失败LM75读取温度要处理原始寄存器数据换算成实际摄氏度。和UART做对比UART异步点对点通信TX/RXI2C同步支持多设备挂载SDA/SCL。I2C依靠SCL时钟线同步采样UART没有时钟线收发双方依靠预先约定的波特率。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。