当前位置: 首页 > news >正文

硬件驱动——I.MX6ULL裸机启动(6)(i2c相关设置)

※重点:

1

i2c:i2c是一种双向的二线制同步串行总线协议,由飞利浦公司于1980年代开发,主要用于微控制器与外围设备之间的短距离,低速率通信,其核心特点是仅需两根信号线(SCL和SDA)即可实现多设备连接,支持主从架构和半双工通信

简述i2c发送一个字节的时序:先将SDA线置于低电平状态发送一个起始信号,然后将设备地址由高位到低位进行发送给从机,最后一位比特置于0,从机发送一个应答信号ACK,主机向从机发送一个寄存器地址,从机发送应答信号ACK,主机向从机发送一个数据,从机发送一个应答信号ACK,主机发送一个停止信号。

2

简述通过i2c写入某个设备的时序:先将SDA线置于低电平状态发送一个起始信号,然后将设备地址由高位到低位进行发送给从机,最后一个比特位置于0,从机发送一个应答信号ACK,主机向从机发送一个寄存器地址,从机发送一个应答信号ACK,主机向从机依次发送1个字节的数据,每发送一个数据,从机发送一个应答信号ACK,直到发完数据为止,主机发送一个停止信号。

3

简述通过i2c读取某个设备的时序:先将SDA数据线置于低电平状态发送一个起始信号,然后将设备地址由高到低进行发送给从机,最后一个比特置于0位,从机发送应答信号ACK,主机向从机发送一个寄存器地址,从机发送应答信号ACK,主机再次发送一个起始信号,再将设备地址发送给从机,最后一个比特位置于1,从机发送应答信号ACK,从机向主机每发送一个字节数据,主机发送应答信号ACK,发送到最后一个数据结束,主机发送信号NO ACK,主机发送一个停止信号。

4.

i2c在硬件设计时需要注意的问题:在SDA和SCL两条线上必须装两个上拉电阻(4.7~10kΩ),上拉电阻越小越强

一.i2c相关定义和概念

i2c通信主机时芯片与芯片之间,为半双工的通信方式

i2c连接方式为两根线SDA(数据线),SCL(时钟线),时钟线的作用是统一收发速率的

电路设置应注意的问题:在SDA和SCL两条线上必须装两个上拉电阻(4.7~10kΩ),上拉电阻越小越强

上拉电阻的作用是:保证SCL和SDA都在释放总线时,让SDA保持高电平

二.i2c的时序问题

空闲时:SCL和SDA都保持高电平状态

发数据时从左到右(MSB先行原则),SCL在高电平采样

接收方发送应答信号,每发完一个字节都要进行一次应答(答的低电平为ACK,高电平为NACK(默认))

停止信号:SCL为高电平时,SCL会将SDA拉成高电平然后处于空闲状态

i2c的发送频率由主机决定

i2c协议:按七个比特位来计算,第八个比特为0,表示主机发往从机,为1是表示从机发送给主机

第八个比特位为R/W数据流向位

三.AT24C08

大小为2k,256*8,有256个字节

波特率为:100khz~400khz

四.相关代码

#include "i2c.h"#include "fsl_iomuxc.h"
#include "delay.h"#define IEN     (7)
#define MSTA    (5)
#define MTX     (4)
#define TXAK    (3)
#define RSTA    (2)#define ICF     (7)
#define IBB     (5)
#define IAL     (4)
#define IIF     (1)void init_i2c1(void)
{IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL,1);      //配置SCL时钟总线的IO复用功能IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA,1);      //配置SDA数据总线的IO复用功能IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL,0xF0B0);      //配置SCL时钟总线的电气属性IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA,0xF0B0);      //配置SDA数据总线的电气属性I2C1->I2CR &= ~(1 << 7);            //在设置波特率之前将该位清零I2C1->IFDR = 0x15;                  //设置i2c的波特率I2C1->I2CR |= (1 << 7);             //在设置完波特率后将该位置1}
void i2c_write(I2C_Type *base, unsigned char device_address, unsigned short reg_address, int reg_len, const unsigned char *data, int len)
{base->I2SR &= ~((1 << IAL) | (1 << IIF));       //在启动通信之前需要将TAL和IIF位清零while((base->I2SR & (1 << ICF)) == 0);          //阻塞等待,判断数据是否在传输,当ICF位为1则传输完成base->I2CR |= (1 << MSTA) | (1 << MTX);         //将MSTA位置1,之后会发送一个起始位。发送从机地址时,MTX位总是为1base->I2CR &= ~(1 << TXAK);                     //在发送数据时表面是否监测应答,接收数据时表面是否回应应答,将TXAK位清零则开启应答base->I2SR &= ~(1 << IIF);                      //无论发送数据还是接收数据之前,都必须将IIF为清零base->I2DR = device_address << 1;               //将设备地址向左移一个比特,将最后一位比特置0while((base->I2SR & (1 << IIF)) == 0);          //若IIF位置1则发送完毕int i;for(i = 0; i < reg_len; ++i){base->I2SR &= ~(1 << IIF);                      //将IIF位清零base->I2DR = reg_address >> (reg_len - i - 1) * 8;                       //发送寄存器的地址while((base->I2SR & (1 << IIF)) == 0);          //判断IIF位是否为1}while(len--)                                    //发送的字节数--{base->I2SR &= ~(1 << IIF);                  //将IIF位清零base->I2DR = *data++;                       //将数据以一个字节为单位,依次进行发送while((base->I2SR & (1 << IIF)) == 0);      //判断IIF位是否为1}base->I2CR &= ~(1 << MSTA);                     //将MSTA位清零,主机会发送一个停止信号while((base->I2SR & (1 << IBB)) != 0)           //判断IBB位是否为0,为0则为已发送停止信号{delayus(100);                               //延时一毫秒}
}void i2c_read(I2C_Type *base, unsigned char device_address, unsigned short reg_address, int reg_len, unsigned char *data, int len)
{base->I2SR &= ~((1 << IAL) | (1 << IIF));       //在启动通信之前需要将TAL和IIF位清零while((base->I2SR & (1 << ICF)) == 0);          //阻塞等待,判断数据是否在传输,当ICF位为1则传输完成base->I2CR |= (1 << MSTA) | (1 << MTX);         //将MSTA位置1,之后会发送一个起始位。发送从机地址时,MTX位总是为1base->I2CR &= ~(1 << TXAK);                     //在发送数据时表面是否监测应答,接收数据时表面是否回应应答,将TXAK位清零则开启应答base->I2SR &= ~(1 << IIF);                      //将IIF位清零base->I2DR = device_address << 1;                       //发送寄存器的地址while((base->I2SR & (1 << IIF)) == 0);          //判断IIF位是否为1int i; //0x1234 reg_len = 2for(i = 0; i < reg_len; ++i){base->I2SR &= ~(1 << IIF);                      //将IIF位清零base->I2DR = reg_address >> (reg_len - i - 1) * 8;                       //发送寄存器的地址while((base->I2SR & (1 << IIF)) == 0);          //判断IIF位是否为1}base->I2CR |= (1 << RSTA);                      //当RSTA位为1时,主机重新发起起始信号base->I2SR &= ~(1 << IIF);                      //将IIF位清零base->I2DR = device_address << 1 | 1;                       //发送寄存器的地址while((base->I2SR & (1 << IIF)) == 0);          //判断IIF位是否为1base->I2CR &= ~(1 << MTX);                       //发送从机地址时,MTX位总是为1,接收数据时MTX位要为0base->I2SR &= ~(1 << IIF);                      //将IIF位清零if(1 == len){base->I2CR |= (1 << TXAK);                   //在发送数据时表面是否监测应答,接收数据时表面是否回应应答,将TXAK位清零则开启应答}*data = base->I2DR;                         //在数据传输之前需要假读一次while(len-- != 0){while((base->I2SR & (1 << IIF)) == 0);      //判断IIF位是否为1base->I2SR &= ~(1 << IIF);                      //将IIF位清零if(len == 0){base->I2CR &= ~((1 << MSTA) | (1 << TXAK));      //MSTA发送一个停止位while((base->I2SR & (1 << IBB)) != 0)           //判断IBB位是否为0,为0则为已发送停止信号{delayus(100);                               //延时一毫秒}}else if(len == 1){base->I2CR |= (1 << TXAK);                   //在发送数据时表面是否监测应答,接收数据时表面是否回应应答,将TXAK位清零则开启应答,置1则发送NO ACK}*data++ = base->I2DR;}
}void xfer(I2C_Type *base, struct I2C_MSG *msg)
{if(msg->driection == I2C_Write){i2c_write(base, msg->dev_address, msg->reg_address, msg->reg_len, msg->data, msg->len);}else{i2c_read(base, msg->dev_address, msg->reg_address, msg->reg_len, msg->data, msg->len);}}
#ifndef __I2C_H__
#define __I2C_H__
#include "MCIMX6Y2.h"
extern void init_i2c1(void);
extern void i2c_write(I2C_Type *base, unsigned char device_address, unsigned short reg_address, int reg_len, const unsigned char *data, int len);
extern void i2c_read(I2C_Type *base, unsigned char device_address, unsigned short reg_address, int reg_len, unsigned char *data, int len);
enum I2C_Driection
{I2C_Write = 0,I2C_Read = 1
};struct I2C_MSG
{unsigned char dev_address;unsigned short reg_address;int reg_len;unsigned char *data;int len;enum I2C_Driection driection;
};extern void xfer(I2C_Type *base, struct I2C_MSG *msg);
#endif

#include "i2c.h"
#include "MCIMX6Y2.h"float lm75_get_temperature(void)
{unsigned char buffer[2] = {0};short s;struct I2C_MSG msg ={.driection = I2C_Read,.dev_address = 0x48,.reg_address = 0,.reg_len = 1,.data = buffer,.len = 2};xfer(I2C1, &msg);//i2c_read(I2C1,0x48,0,1,buffer,2);s = buffer[0] << 8;s |= buffer[1];s >>= 7;return s * 0.5;}
#include "beep.h"
#include "led.h"
#include "key.h"
#include "core_ca7.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "stdio.h"
#include "i2c.h"
#include "string.h"
#include "lm75.h"int main(void)
{init_clock();system_interrupt_init();init_beep();init_led();
//    init_key();
//    init_epit1();init_gpt1();init_uart1();init_i2c1();// const char *s = "Hello";// i2c_write(I2C1, 0x50, 0, (unsigned char *)s, 5);// printf("I2C Write OK");// delayms(500);// unsigned char buffer[16] = {0};// i2c_read(I2C1, 0x50, 0, buffer, 5);// puts((char *)buffer);while(1){// char s1[16];// scanf("%s",s1);// i2c_write(I2C1, 0x50, 0, (unsigned char *)s1, strlen(s1));// printf("ok\n");// delayms(500);// char s2[16] = {0};// i2c_read(I2C1, 0x50, 0, (unsigned char *)s2, strlen(s1));// puts((char *)s2);delayms(500);float f = lm75_get_temperature();int i = f * 10;int n = i / 10;int m = i % 10;printf("%d.%d",n,m);}return 0;
}


文章转载自:

http://SBbCLIDu.nshhf.cn
http://4z0px13D.nshhf.cn
http://yaI2R1mC.nshhf.cn
http://kn5OlUsb.nshhf.cn
http://5dFPBUCC.nshhf.cn
http://nM5isDMd.nshhf.cn
http://2LiNhhmP.nshhf.cn
http://C9GEl9T1.nshhf.cn
http://Dndc1HKF.nshhf.cn
http://3B0KuqI3.nshhf.cn
http://AotT3V14.nshhf.cn
http://GMbjSskX.nshhf.cn
http://BgzYqMbi.nshhf.cn
http://2Fyx0FIR.nshhf.cn
http://6N4foZL4.nshhf.cn
http://sNSFaRb6.nshhf.cn
http://Lvx7TWsc.nshhf.cn
http://KikgXpJo.nshhf.cn
http://E6LlEO7W.nshhf.cn
http://nIJxiRGg.nshhf.cn
http://Xa3tjSH6.nshhf.cn
http://rfd7rtDx.nshhf.cn
http://dHIyjhCU.nshhf.cn
http://u2ntJZVn.nshhf.cn
http://FKCWektJ.nshhf.cn
http://oALK9YtE.nshhf.cn
http://TOQFgoeK.nshhf.cn
http://imPTBt8q.nshhf.cn
http://IJKRbcu9.nshhf.cn
http://Yv4C2rwk.nshhf.cn
http://www.dtcms.com/a/387977.html

相关文章:

  • 9.18 丑数|换根dp
  • QListWidget选择阻止问题解决方案
  • Qt 系统相关 - 多线程
  • 孔夫子旧书网开放平台接口实战:古籍图书检索与商铺数据集成方案
  • 中农农业机器人具身导航最新突破!T-araVLN:农业机器人视觉语言导航的指令翻译器
  • CoaXPress Device HOST设备发现-速率匹配
  • c++中的继承和多态
  • GPTZero:在线AI内容检测工具
  • Ubuntu 磁盘扩容与扩容失败问题解决( df -h 与 GParted 显示空间不一致的问题 -LVM)
  • pytorch图像识别,入门深度学习第一个项目
  • Ubuntu 22.04 使用 Docker 部署 Redis 6.2(带密码与持久化)
  • Termux 安装 Trilium 笔记,全平台同步的好用开源 Markdow 笔记,超大型双链接笔记
  • CVAT工具的详细使用教程(视频标注)
  • 【一周AI资讯】Claude自动抓取网页;美团发布生活Agent;阿里通义发布双模型
  • [视图功能4] 视图共享与外部链接权限管理:安全又灵活的数据展示
  • 20250917在荣品RD-RK3588-MID开发板的Android13系统下使用tinyplay播放wav格式的音频
  • PAT 1013 Battle Over Cities
  • 自动驾驶车辆的网络安全威胁及防护技术
  • 《基于uni-app构建鸿蒙原生体验:HarmonyOS NEXT跨平台开发实战指南》
  • 数学_向量投影相关
  • 【完整源码+数据集+部署教程】传统韩文化元素分割系统: yolov8-seg-GFPN
  • hybrid实验
  • Prompt Engineering 技术文档
  • 《我看见的世界》- 李飞飞自传
  • TPS54302开关电源启动 1s 后输出电压掉电排查笔记 — TPS54302 5V→2.8V 案例
  • 具身智能数据采集方案,如何为机器人打造“数据燃料库”?
  • Prism模块化和对话服务
  • nas怎么提供给k8s容器使用
  • 【第五章:计算机视觉-项目实战之图像分类实战】1.经典卷积神经网络模型Backbone与图像-(8)多标签图像分类理论
  • 认知语义学中的意象图式对人工智能自然语言处理深层语义分析的影响与启示