ARM.7(UART,I2C)

1.UART

1.1IMX6ULL的UART(通用异步收发传输器)模块框图UART(通用异步收发传输器)模块的框图

数据终端设备和数据电路终接设备

底板原理图:

1.2UART寄存器

1.2.1UARTx_URXD接受寄存器

1.2.2UARTx_UTXD发送寄存器

1.2.3UARTx_UCR1控制寄存器 1

1.2.4UARTx_UCR2控制寄存器 2

1.2.5UARTx_UCR3控制寄存器 3

1.2.6UART_xUFCRFIFO 控制寄存器

1.2.7UARTx_USR2状态寄存器

1.2.8UARTx_UBIR波特率整数部分寄存器

1.2.9UARTx_UBMR波特率小数部分寄存器

1.3配置UART

复制代码
void init_uart1()
{
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);//引脚复用
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10b0);//电器属性

    UART1 -> UCR1 = 0;//先给ucr1第零位清零,关闭uart
    UART1 ->UCR2 = 0;
    //第0位清零,准备让 UART 开始工作时,让它经历一次复位
    //第八位清零,无校验
    //第六位清零,1位停止位
    UART1 ->UCR2 |= (1 << 14) |(1 << 5)|(1 << 2)|(1 << 1);
    //第14位置1,一直接收,不管缓冲区是不是满的
    //第五位置1,传输8位数据位
    //第二位第一位置1,打开发送和接收
    UART1->UCR3 |= (1 << 2);//交叉使能
    UART1->UFCR = (5 << 7);//预分频1
    UART1->UBIR = 999;
    UART1->UBMR = 43401;
    //i.MX6ULL 的 UART 波特率计算公式(UBMR + 1) / (UBIR + 1) = RefFreq / 16 * BaudRate
    //带入RefFreq=80M,BaudRate = 115200
    UART1->UCR1 |= (1 << 0);//使能uart
}

配置好后,再来编写发送字符串函数:

实现每秒发送一次字符串:

再来编写接收函数:

2.I2C

IICBus简称,所以中文应该叫集成电路总线。是飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展而来的一种同步串行半双工通信总线方式。该总线允许同时连接多个设备(芯片)。每块芯片在总线上拥有特定的地址。I²C 是用 SCL(时钟线) + SDA (数据线)两根线,这两个信号线都是双向的,通过起始/停止条件和地址寻址,完成半双工串行通信的芯片间总线,适合连接 EEPROM、传感器、RTC 等低速外设。

**注意!一定要在scl和sda上面分别接一个上拉电阻,**I²C 使用开漏输出,设备只能通过"拉低"或"释放";上拉电阻把"释放"变成高电平,因此总线空闲必须靠上拉拉到高。

IIC通信时序图:


按照I2C标准,主设备发起通信时先发送一个起始信号,之后发送的第一个字节就是子设备的设备地址。需要注意的是。设备地址本身只占7个比特,最后一个比特所代表的是之后的数据流向。0代表主发从收,通常描述为写,1表示从发主收,通常描述为读。
例如,某个设备的从机地址为0x48(二进制0100 1000b),主机在发送完起始信号之后要发送要发送的从机地址其实是1001 000x,这里x就是数据流向位。如果x为0,表示接下来主机发送数据,从机接收数据。如果x为1,表示接下要求从机发送数据,主机接收数据。

2.1EEPROM

eeprom设备地址:

是一种 可电擦写、掉电不丢数据 ​ 的小容量非易失存储器,常在开发板上通过 I²C 总线​ 连接。

向eeprom存数据时序图:

页写同理:

从eeprom读数据时序图:

对某设备的某字节后的n个字节进行读取,原理相同。

2.2IIC寄存器

2.2.1I2Cx_IFDR

I²C 控制器用一个 **Peripheral Clock(ipg_perclk)**​ 分频得到 SCL

2.2.2I2Cx _I2CR

打开 I²C、设主/从、产生 START/STOP

2.2.3I2Cx _I2SR

轮询,用来判断"事情做完没"ack/nack

2.2.4I2Cx _I2DR

发送地址 / 数据,或读取接收数据

2.3iic初始化

首先设置引脚复用以及初始化:

2.4写设备以及读设备

按照流程图完成写和读:

cs 复制代码
void i2c_write(I2C_Type *base, unsigned char device_address, unsigned char reg_address, const unsigned char *data, int len)
{
    base->I2SR &= ~((1 << IAL) | (1 << IIF)); // 清除仲裁丢失标志和中断标志
    while((base->I2SR & (1 << ICF)) == 0); // 等待传输完成标志为空闲
    base->I2CR |= (1 << MSTA) | (1 << MTX); // 设置为主机模式并设为发送模式
    base->I2CR &= ~(1 << TXAK); // 设置发送应答使能
 
    base->I2SR &= ~(1 << IIF); // 清除中断标志
    base->I2DR = device_address << 1; // 发送设备地址(写方向)
    while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断
 
    base->I2SR &= ~(1 << IIF); // 清除中断标志
    base->I2DR = reg_address; // 发送寄存器地址
    while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断  
    
    while(len--) // 循环发送数据
    {
        base->I2SR &= ~(1 << IIF); // 清除中断标志
        base->I2DR = *data++; // 发送一个字节数据并移动指针
        while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断         
    }
    base->I2CR &= ~(1 << MSTA); // 清除主机模式标志,释放总线
    while((base->I2SR & (1 << IBB)) != 0) // 等待总线忙标志清除
    {
        delayus(100); // 延时等待总线释放
    }
}
 
void i2c_read(I2C_Type *base, unsigned char device_address, unsigned char reg_address, unsigned char *data, int len)
{
    base->I2SR &= ~((1 << IAL) | (1 << IIF)); // 清除仲裁丢失标志和中断标志
    while((base->I2SR & (1 << ICF)) == 0); // 等待传输完成标志为空闲
    base->I2CR |= (1 << MSTA) | (1 << MTX); // 设置为主机模式并设为发送模式
    base->I2CR &= ~(1 << TXAK); // 设置发送应答使能
 
    base->I2SR &= ~(1 << IIF); // 清除中断标志
    base->I2DR = device_address << 1; // 发送设备地址(写方向)
    while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断
 
    base->I2SR &= ~(1 << IIF); // 清除中断标志
    base->I2DR = reg_address; // 发送寄存器地址
    while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断  
    
    base->I2CR |= (1 << RSTA); // 产生重复起始条件
    base->I2SR &= ~(1 << IIF); // 清除中断标志   
    base->I2DR = device_address << 1 | 1; // 发送设备地址(读方向)
    while((base->I2SR & (1 << IIF)) == 0); // 等待发送完成中断 
    
    base->I2CR &= ~(1 << MTX); // 切换为接收模式
    base->I2SR &= ~(1 << IIF); // 清除中断标志  
    
    if(1 == len) // 如果只读一个字节
    {
        base->I2CR |= (1 << TXAK); // 设置发送非应答,表示最后一个字节
    }
 
    *data = base->I2DR; // 伪读取一次以启动接收
 
    while(len-- != 0) // 循环接收数据
    {
        while((base->I2SR & (1 << IIF)) == 0); // 等待接收完成中断
        base->I2SR &= ~(1 << IIF); // 清除中断标志  
        if(len == 0) // 如果是最后一个字节        
        {
            base->I2CR &= ~((1 << MSTA) | (1 << TXAK)); // 清除主机标志和发送应答标志,停止传输
            while((base->I2SR & (1 << IBB)) != 0) // 等待总线忙标志清除
            {
                delayus(100); // 延时等待总线释放
            }
        }
        else if(len == 1) // 如果还剩一个字节
        {
            base->I2CR |= (1 << TXAK); // 设置发送非应答
        }
        *data++ = base->I2DR; // 读取一个字节数据并移动指针
    }
}

2.5LM75

读取lm75温度传感器的温度(两个字节)

再用读取的两个字节计算出真实温度

lm75.c:

复制代码
#include"lm75.h"
#include"i2c.h"
#include"MCIMX6Y2.h"
float lm75_get_temperature(void)
{
    unsigned char buffer[2] = {0};
    short s;
    struct I2C_MSG msg =
    {
        .deiection = 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;
}
相关推荐
FreakStudio9 小时前
大话电容传感器和电容SOC芯片,看这一篇就够了
python·单片机·嵌入式·面向对象·并行计算·电子diy·电子计算机
信看10 小时前
常见通信接口
单片机·嵌入式硬件
Rsingstarzengjx11 小时前
STM32-F103ZET6开发板
stm32·单片机·嵌入式硬件
我先去打把游戏先11 小时前
VMware NAT 模式 Ubuntu 虚拟机「宿主机能上网、虚拟机 ping 不通外网 + apt 更新卡死」全故障复盘
linux·运维·vscode·单片机·嵌入式硬件·ubuntu·keil5
aini_lovee12 小时前
STM32 串口转CAN + WiFi模块实现WiFi转CAN网关
stm32·单片机·嵌入式硬件
zlinear数据采集卡12 小时前
输出短路保护电路深度解析:从电源的“最后一道防线”到ZLinear采集卡的硬核守护实战
开发语言·嵌入式硬件·持续集成
都在酒里12 小时前
FreeRTOS 手动移植教程(七):软件定时器 —— 不占硬件 Timer 的定时回调
stm32·单片机·嵌入式·rtos·嵌入式软件
原创小甜甜13 小时前
Windows 蓝屏自救手册:从紧急记录到硬件排查的完整指南
windows·stm32·单片机
有想法的py工程师13 小时前
手工处理 Oracle Cloud ARM 实例在线 DD Rocky Linux 10报错
linux·arm开发·oracle