Linux-Ubuntu之I2C通信

Linux-Ubuntu之I2C通信

  • 一,I2C通信原理
    • 1.写时序
    • 2.读时序
  • 二,代码实现
  • 三,显示

一,I2C通信原理

使用I2C接口驱动AP3216C传感器,该传感器能实现两个效果,一个是感应光强,另一个是探测物体与传感器的接近程度,这个实验就是从这个传感器对应的寄存器中,读取数据。I2C通信使用两根两条线(SDA和SCL)在主机和设备之间实现通信,这个实验做完感觉和51的还是有点区别的,51的注重具体的时序来控制数据传输,要自己去控制SCL的高低电平和上升下降沿,从内部电平信号来实现,这个linux实验主要是控制寄存器的状态标准位来控制数据的传输,不用控制时序,可能是51比较简单,控制电平信号也相对容易实现,这个芯片就更智能一些,控制寄存器,好像是自动就控制了电平信号。

1.写时序

在这里插入图片描述 开始信号→发送设备的地址,说明进行写操作→设备发送ACK应答信号→再发送开始信号→发送要写入数据寄存器的地址→设备发送ACK应答信号→发送要写入寄存器的数据→设备发送应答信号→主机发送停止信号
在程序上,主要分成了三个部分:1-4:开始信号,写设备地址并说明传输方向,5-7:写寄存器地址,8-10:对设备的寄存器进行写入,做STOP信号。

2.读时序

在这里插入图片描述读操作和写操作,前面两个环节是一样的,不一样在于后面两个部分,读操作要再次写入设备的地址,最后对设备的寄存器数据进行读取。
开始信号→发送设备的地址,说明进行读写操作,虽然整体是读操作,但是这两步要进行还是写,因此在七位设备地址后面跟的是写标志位→设备发送ACK应答信号→再发送开始信号→发送要读取数据寄存器的地址→设备发送ACK应答信号→重新发送start信号→发送设备地址+读标志位→设备发送ACK应答信号→主机从设备的寄存器中读取数据→主机发送NO ACK信号,表示读取完成→主机发送STOP停止信号。
在程序上,分为四个部分:1-4:开始信号,写设备地址并说明传输方向为写,5-7:写寄存器地址,8-11:再次start,写设备地址并且说明是读,12-14:进行读操作,并且做NOACK和STOP信号。

二,代码实现

I2C部分代码,实现的是整个读和写时序进行的操作,利用i2c_master_transfer(I2C_Type *base,struct i2c_transfer_all *xfer);/*最终的处理函数*/ 这个函数,将start函数,stop函数,错误检查函数,读写函数放到一起,真正实现操作的是在传感器函数中,要对读写进行说明,怎么样去用这个处理函数。

/i2c.h/
#ifndef _DSP_RTC_H
#define _DSP_RTC_H
#include "imx6ul.h"

/*时间宏定义*/
#define SECONDS_IN_A_DAY  86400
#define SECONDS_IN_A_HOUR 3600
#define SECONDS_IN_A_MINUTE 60
#define DAYS_IN_A_YEAR  365
#define YEAR_RANGE_START 1970
#define YEAR_RANGE_END 2099

/*时间结构体*/
struct rtc_datetime{
    unsigned short year;
    unsigned char month;
    unsigned char day;
    unsigned char hour;
    unsigned char minute;
    unsigned char second;
};
/*rtc初始化*/
void rtc_init(void);
/*使能*/
void rtc_enable(void);
/*关闭使能*/
void rtc_disable(void);
/*判断润年*/
unsigned char rtc_isleapyear(unsigned short year);
/*将年月日时间转换为秒函数*/
unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime);
/*将相应秒数,写入到相应寄存器中*/
void rtc_in_register(struct rtc_datetime *rtctime);
/*将读出第秒数,转化为真的时间*/
void rtc_convertseconds_to_datetime(u64 seconds, struct rtc_datetime *datetime);
/*读寄存器值,从而得到时间*/
void rtc_out_register(struct rtc_datetime *rtctime);

#endif 
/i2c.c/
#include "dsp_rtc.h"

/*rtc初始化*/
void rtc_init(void)
{

    SNVS->HPCOMR |=(1<<31)|(1<<8);
    struct rtc_datetime rtcDate;
    rtcDate.year=2025;
    rtcDate.month=1;
    rtcDate.day=4;
    rtcDate.hour=8;
    rtcDate.minute=0;
    rtcDate.second=0;
    rtc_in_register(&rtcDate);

    rtc_enable();//使能
}

/*使能*/
void rtc_enable(void)
{
    SNVS->LPCR |=1<<0;
    while((SNVS->LPCR & 0x01)==0);//当为0时候,一直在while里面循环
}

/*关闭使能*/
void rtc_disable(void)
{
    SNVS->LPCR &=~(1<<0);
    while((SNVS->LPCR & 0x01)==1);//为1的时候,一直循环
}

/*判断润年*/
unsigned char rtc_isleapyear(unsigned short year)
{	
	unsigned char value=0;
	
	if(year % 400 == 0)
		value = 1;
	else 
	{
		if((year % 4 == 0) && (year % 100 != 0))
			value = 1;
		else 
			value = 0;
	}
	return value;
}
/*将年月日时间转换为秒函数*/
unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime)
{	
	unsigned short i = 0;
	unsigned int seconds = 0;
	unsigned int days = 0;
	unsigned short monthdays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
	
	for(i = 1970; i < datetime->year; i++)
	{
		days += DAYS_IN_A_YEAR; 		/* 平年,每年365天 */
		if(rtc_isleapyear(i)) days += 1;/* 闰年多加一天 		*/
	}

	days += monthdays[datetime->month];
	if(rtc_isleapyear(i) && (datetime->month >= 3)) days += 1;/* 闰年,并且当前月份大于等于3月的话加一天 */

	days += datetime->day - 1;

	seconds = days * SECONDS_IN_A_DAY + 
				datetime->hour * SECONDS_IN_A_HOUR +
				datetime->minute * SECONDS_IN_A_MINUTE +
				datetime->second;

	return seconds;	
}

/*将相应秒数,写入到相应寄存器中*/
void rtc_in_register(struct rtc_datetime *rtctime)
{
    unsigned int seconds = 0;
    rtc_disable();//关闭使能
    seconds=rtc_coverdate_to_seconds(rtctime);

    /*放入寄存器中*/
    SNVS->LPSRTCMR = (unsigned int)(seconds>>17);
    SNVS->LPSRTCLR = (unsigned int)(seconds<<15);
}
/*将读出第秒数,转化为真的时间*/
void rtc_convertseconds_to_datetime(u64 seconds, struct rtc_datetime *datetime)
{
    u64 x;
    u64  secondsRemaining, days;
    unsigned short daysInYear;

    /* 每个月的天数       */
    unsigned char daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};

    secondsRemaining = seconds; /* 剩余秒数初始化 */
    days = secondsRemaining / SECONDS_IN_A_DAY + 1; 		/* 根据秒数计算天数,加1是当前天数 */
    secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY; /*计算天数以后剩余的秒数 */

	/* 计算时、分、秒 */
    datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;
    secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
    datetime->minute = secondsRemaining / 60;
    datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;

    /* 计算年 */
    daysInYear = DAYS_IN_A_YEAR;
    datetime->year = YEAR_RANGE_START;
    while(days > daysInYear)
    {
        /* 根据天数计算年 */
        days -= daysInYear;
        datetime->year++;

        /* 处理闰年 */
        if (!rtc_isleapyear(datetime->year))
            daysInYear = DAYS_IN_A_YEAR;
        else	/*闰年,天数加一 */
            daysInYear = DAYS_IN_A_YEAR + 1;
    }
	/*根据剩余的天数计算月份 */
    if(rtc_isleapyear(datetime->year)) /* 如果是闰年的话2月加一天 */
        daysPerMonth[2] = 29;

    for(x = 1; x <= 12; x++)
    {
        if (days <= daysPerMonth[x])
        {
            datetime->month = x;
            break;
        }
        else
        {
            days -= daysPerMonth[x];
        }
    }

    datetime->day = days;

}

/*读寄存器值,从而得到时间*/
void rtc_out_register(struct rtc_datetime *rtctime)
{
    uint64_t seconds = 0;
    seconds = (uint64_t)((uint64_t)SNVS->LPSRTCMR<<17|SNVS->LPSRTCLR>>15);
    rtc_convertseconds_to_datetime(seconds,rtctime);

}

AP3216C函数,在定义的结构体中,进行配置,说明设备地址,设备寄存器地址,读或者写操作,并将读或者写的数据放到定义的变量中。

/ap3216c.h/
#ifndef _DSP_AP3216C_H
#define _DSP_AP3216C_H
#include "imx6ul.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

void ap3216c_init(void);
unsigned char ap3216c_write_one_byte(unsigned char addr,unsigned char reg,unsigned char data);
unsigned char ap3216c_read_one_byte(unsigned char addr,unsigned char reg);
void ap3216c_redata(unsigned short *ir,unsigned short *ps,unsigned short *als);
#endif 

/ap3216c.c/
#include "dsp_ap3216c.h"
#include "dsp_i2c.h"
#include "dsp_gpio.h"
#include "dsp_delay.h"
#include "stdio.h"
void ap3216c_init(void)
{
    unsigned char result=0;
    /*1.引脚设置*/
    IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL,1);		
	IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL,0X70b0);
    IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA,1);		
	IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA,0X70b0);

    /*2.I2C接口初始化*/
    i2c_init(I2C1);

    /*3.传感器初始化*/
    ap3216c_write_one_byte(AP3216C_ADDR,AP3216C_SYSTEMCONG,0x04);//初始化
    delay(50);
    ap3216c_write_one_byte(AP3216C_ADDR,AP3216C_SYSTEMCONG,0x03);
    result=ap3216c_read_one_byte(AP3216C_ADDR,AP3216C_SYSTEMCONG);
    printf("AP3216C_SYSTEMCONG的result= %d \r\n",result);

}
/*写一个字节设置*/
unsigned char ap3216c_write_one_byte(unsigned char addr,unsigned char reg,unsigned char data)
{
    unsigned char writedata = data;
    unsigned char  status =0;
    struct i2c_transfer_all masterXfer;
    masterXfer.slave_address=addr;//从机地址
    masterXfer.transfer_direction=KI2c_Write;//设置为写模式
    masterXfer.register_address =reg;//寄存器地址
    masterXfer.register_address_size = 1;
    masterXfer.data = &writedata;
    masterXfer.data_size = 1;
    if(i2c_master_transfer(I2C1,&masterXfer))//0正常 其他不正常
    {
        status = 1;
    }
    return status;
}
/*读一个字节*/
unsigned char ap3216c_read_one_byte(unsigned char addr,unsigned char reg)
{
    unsigned char readdata = 0;
    
    struct i2c_transfer_all masterXfer;
    masterXfer.slave_address=addr;//从机地址
    masterXfer.transfer_direction=KI2c_read;//设置为写模式
    masterXfer.register_address =reg;//寄存器地址
    masterXfer.register_address_size = 1;
    masterXfer.data = &readdata;
    masterXfer.data_size = 1;
    i2c_master_transfer(I2C1,&masterXfer);//读操作   
    return readdata;
}
/*读传感器数据*/
void ap3216c_redata(unsigned short *ir,unsigned short *ps,unsigned short *als)
{
    unsigned char buf[6]={};
    unsigned char i = 0;
    for(i=0;i<6;i++)//将寄存器数据放到buf中
    {
        buf[i]=ap3216c_read_one_byte(AP3216C_ADDR,AP3216C_IRDATALOW+i);
    }
    if(buf[0]&0x80)//这个标志判断ir als是否有效
    {
        *ir=0;
        *ps=0;
    }else 
    {
        *ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); 
        *als = ((unsigned short)buf[3] << 8) | buf[2];
    }
    if(buf[4]&0x40)//判断ps是否有效
    {
        *ps = 0;
    }else
    {
        *ps = ((unsigned short)(buf[5] & 0x3f)<<4 | (buf[4] & 0x0f)); 
    }

}

主函数:

#include "main.h"

#include "dsp_clk.h"

#include "dsp_led.h"

#include "dsp_delay.h"

#include "beep.h"

#include "dsp_key.h"

#include "dsp_int.h"

#include "dsp_exti.h"

#include "dsp_epit.h"

#include "dsp_uart.h"

#include "stdio.h"

#include "dsp_lcd.h"

#include "dsp_lcdapi.h"

#include "dsp_rtc.h"

#include "dsp_i2c.h"

#include "dsp_ap3216c.h"

int main(void)

{

    // int b=0;

    unsigned short ir,ps,als;

    unsigned char kkkk=0;

    struct rtc_datetime rtc_now_time;

    char buf[160]={};

    int_init();//中断初始化

    imx6u_clkinit();//时钟初始化

    key_init();//按键初始化

    clk_enable();//时钟初始化

    uart_init();//串口初始化

    beep_init();//凤鸣器初始化

    led_init();//led初始化

    lcd_init();//LCD读ID号

    rtc_init();//RTC初始化

    ap3216c_init();//传感器初始化

    tftlcd_dev.forecolor = LCD_RED;

    tftlcd_dev.backcolor = LCD_WHITE;

    // unsigned char *b,*c,*f;

    // unsigned short *a;

   // lcd_show_string(10,40,260,32,32,(char *)"Fucking high");

    

    lcd_show_string(100, 160, 200, 32, 32, (char*)" IR:");	 

	lcd_show_string(100, 200, 200, 32, 32, (char*)" PS:");	

	lcd_show_string(100, 240, 200, 32, 32, (char*)"ALS:");

    while(1)

    {

        ap3216c_redata(&ir,&ps,&als);

		lcd_shownum(200, 160, ir, 5, 32);	

        lcd_shownum(200, 200, ps, 5, 32);	

        lcd_shownum(200, 240, als, 5, 32);	 

        printf("ir = %d    ps = %d  als = %d  \r\n",ir,ps,als);

        tftlcd_dev.forecolor = LCD_RED;

        rtc_out_register(&rtc_now_time);

        sprintf(buf,"%d.%d.%d-%d:%d:%d\r\n",rtc_now_time.year,rtc_now_time.month,

                rtc_now_time.day,rtc_now_time.hour,rtc_now_time.minute,rtc_now_time.second);

        lcd_show_string(70,70,240,32,32,(char *)buf);

        led_mode(kkkk);

        delay(1000);

        kkkk = !kkkk;     

    }

    return 0;    

}

三,显示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/948269.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

音视频入门基础:MPEG2-PS专题(4)——FFmpeg源码中,判断某文件是否为PS文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.ps 可以判断出某个文件是否为PS文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为PS文件呢&#xff1f;它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…

框架模块说明 #09 日志模块_01

背景 日志模块是系统的重要组成部分&#xff0c;主要负责记录系统运行状态和定位错误问题的功能。通常&#xff0c;日志分为系统日志、操作日志和安全日志三类。虽然分布式数据平台是当前微服务架构中的重要部分&#xff0c;但本文的重点并不在此&#xff0c;而是聚焦于自定义…

【数据仓库】hadoop3.3.6 安装配置

文章目录 概述下载解压安装伪分布式模式配置hdfs配置hadoop-env.shssh免密登录模式设置初始化HDFS启动hdfs配置yarn启动yarn 概述 该文档是基于hadoop3.2.2版本升级到hadoop3.3.6版本&#xff0c;所以有些配置&#xff0c;是可以不用做的&#xff0c;下面仅记录新增操作&#…

算法题(25):只出现一次的数字(三)

审题&#xff1a; 该题中有两个元素只出现一次并且其他元素都出现两次&#xff0c;需要返回这两个只出现一次的数&#xff0c;并且不要求返回顺序 思路: 由于对空间复杂度有要求&#xff0c;我们这里不考虑哈希表。我们采用位运算的方法解题 方法&#xff1a;位运算 首先&#…

将机器学习预测模型融入AI agent的尝试(一)

将机器学习临床预测模型融入AI agent的尝试&#xff08;一&#xff09; 我主要是使用机器学习制作临床预测模型和相关的应用&#xff0c;最近考虑的事情是自己之前的的工作能不能和AI agent进行融合&#xff0c;将AI 对自然语言理解能力和预测模型的预测能力结合在一起&#x…

51单片机——按键实验

由于机械点的弹性作用&#xff0c;按键开关在闭合时不会马上稳定的接通&#xff0c;在断开时也不会一下子断开&#xff0c;因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的&#xff0c;一般为 5ms 到 10ms&#xff0c;为了确保 CPU 对按键的…

电子邮件对网络安全的需求

&#xff08; 1&#xff09;机密性&#xff1a;传输过程中不被第三方阅读到邮件内容&#xff0c;只有真正的接收方才可以阅读邮件。&#xff08; 1.5 分&#xff09; &#xff08; 2&#xff09;完整性&#xff1a;支持在邮件传输过程中不被篡改&#xff0c;若发生篡改&#…

vue路由模式面试题

vue路由模式 1.路由的模式有哪些?有什么区别? history和hash模式 区别: 1.表现的形态不同: 在地址栏url中:hash模式中带有**#**号,history没有 2.请求错误时表现不同: 在hash模式中,对于404地址请求时,不会进行请求 但是在history模式中,对于404请求时,仍然会进行请求…

电子应用设计方案86:智能 AI背景墙系统设计

智能 AI 背景墙系统设计 一、引言 智能 AI 背景墙系统旨在为用户创造一个动态、个性化且具有交互性的空间装饰体验&#xff0c;通过融合先进的技术和创意设计&#xff0c;提升室内环境的美观度和功能性。 二、系统概述 1. 系统目标 - 提供多种主题和风格的背景墙显示效果&…

Python爬虫 - 豆瓣图书数据爬取、处理与存储

文章目录 前言一、使用版本二、需求分析1. 分析要爬取的内容1.1 分析要爬取的单个图书信息1.2 爬取步骤1.2.1 爬取豆瓣图书标签分类页面1.2.2 爬取分类页面1.2.3 爬取单个图书页面 1.3 内容所在的标签定位 2. 数据用途2.1 基础分析2.2 高级分析 3. 应对反爬机制的策略3.1 使用 …

西安电子科技大学初/复试笔试、面试、机试成绩占比

西安电子科技大学初/复试笔试、面试、机试成绩占比 01通信工程学院 02电子工程学院 03计算机科学与技术学院 04机电工程学院 06经济与管理学院 07数学与统计学院 08人文学院 09外国语学院 12生命科学与技术学院 13空间科学与技术学院 14先进材料与纳米科技学院 15网络与信息安…

多模态论文笔记——CogVLM和CogVLM2(副)

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍多模态模型的LoRA版本——CogVLM和CogVLM2。在SD 3中使用其作为captioner基准模型的原因和优势。 文章目录 CogVLM论文背景VLMs 的任务与挑战现有方法及…

智慧工地信息管理与智能预警平台

建设背景与政策导向 智慧工地信息管理与智能预警平台的出现&#xff0c;源于工地管理面临的诸多挑战&#xff0c;如施工地点分散、危险区域多、监控手段落后等。随着政府对建筑产业现代化的积极推动&#xff0c;各地纷纷出台政策支持智慧工地的发展&#xff0c;旨在通过信息技…

【从零开始入门unity游戏开发之——C#篇42】C#补充知识——随机数(Random)、多种方法实现string字符串拼接、语句的简写

文章目录 一、随机数1、Random.Next()生成随机整数示例&#xff1a;生成一个随机整数生成指定范围内的随机整数 2、Random.NextSingle生成随机浮点数示例&#xff1a;生成随机浮点数 3、 生成随机字母或字符示例&#xff1a;生成随机字母示例&#xff1a;生成随机小写字母 二、…

「Mac畅玩鸿蒙与硬件54」UI互动应用篇31 - 滑动解锁屏幕功能

本篇教程将实现滑动解锁屏幕功能&#xff0c;通过 Slider 组件实现滑动操作&#xff0c;学习事件监听、状态更新和交互逻辑的实现方法。 关键词 滑动解锁UI交互状态管理动态更新事件监听 一、功能说明 滑动解锁屏幕功能包含以下功能&#xff1a; 滑动解锁区域&#xff1a;用…

VScode SSH 错误:Got bad result from install script 解決

之前vscode好好的&#xff0c;某天突然连接报错如下 尝试1. 服务器没有断开,ssh可以正常连接 2. 用管理员权限运行vscode&#xff0c;无效 3. 删除服务器上的~/.vscode-server 文件夹&#xff0c;无效 试过很多后&#xff0c;原来很可能是前一天anaconda卸载导致注册表项 步…

[论文笔记]Representation Learning with Contrastive Predictive Coding

引言 今天带来论文 Representation Learning with Contrastive Predictive Coding的笔记。 提出了一种通用的无监督学习方法从高维数据中提取有用表示&#xff0c;称为对比预测编码(Contrastive Predictive Coding,CPC)。使用了一种概率对比损失&#xff0c; 通过使用负采样使…

【C#深度学习之路】如何使用C#实现Yolo5/8/11全尺寸模型的训练和推理

【C#深度学习之路】如何使用C#实现Yolo5/8/11全尺寸模型的训练和推理 项目背景项目实现调用方法项目展望写在最后项目下载链接 本文为原创文章&#xff0c;若需要转载&#xff0c;请注明出处。 原文地址&#xff1a;https://blog.csdn.net/qq_30270773/article/details/1449186…

如何很快将文件转换成另外一种编码格式?编码?按指定编码格式编译?如何检测文件编码格式?Java .class文件编码和JVM运行期内存编码?

如何很快将文件转换成另外一种编码格式? 利用VS Code右下角的"选择编码"功能&#xff0c;选择"通过编码保存"可以很方便将文件转换成另外一种编码格式。尤其&#xff0c;在测试w/ BOM或w/o BOM, 或者ANSI编码和UTF编码转换&#xff0c;特别方便。VS文件另…

[Python学习日记-74] 面向对象实战2——选课系统

[Python学习日记-74] 面向对象实战2——选课系统 简介 开发要求 实现&#xff1a;选课系统 简介 在前面的《年会答题系统》当中我们介绍了面向对象软件开发的一些流程&#xff0c;当然这一流程只是涵括了大部分的&#xff0c;目前在业界也没有一个统一的标准&#xff0c;每个…