您的位置:首页 > 教育 > 培训 > 四川建设网地址电话_蚌埠网页设计培训_美国婚恋网站排名_互联网营销是什么意思

四川建设网地址电话_蚌埠网页设计培训_美国婚恋网站排名_互联网营销是什么意思

2025/2/24 11:33:49 来源:https://blog.csdn.net/weixin_44254079/article/details/142361368  浏览:    关键词:四川建设网地址电话_蚌埠网页设计培训_美国婚恋网站排名_互联网营销是什么意思
四川建设网地址电话_蚌埠网页设计培训_美国婚恋网站排名_互联网营销是什么意思

文章目录

  • 一、分析电路图
  • 二、AP3216c数据手册
    • (一)系统模式寄存器
    • (二)中断状态寄存器
    • (三)清除中断方式寄存器
    • (四)IR数据寄存器
    • (五)ALS环境光数据寄存器
    • (六)PS数据寄存器
  • 三、设备树
  • 四、驱动代码实现

一、分析电路图

在这里插入图片描述

SCL–PF14
SDA–PF15
INT1–PF13

INT1引脚外接上拉电阻,即默认状态为高电平,当产生中断时会产生一个下降沿。

二、AP3216c数据手册

在这里插入图片描述

(一)系统模式寄存器

在这里插入图片描述
000 掉电模式
001 环境光ALS模式,数据转换时间是100ms;PS数据不工作。
010 仅接近和红外传感器工作,典型的数据转换时间是12.5ms
011 ALS、PS、IR均开启,该模式下转换时间为112.5ms
在这里插入图片描述
100 复位 10ms后设备寄存器会恢复默认值,在此期间不要对寄存器操作

(二)中断状态寄存器

在这里插入图片描述
ALS INT位寄存器用于指示ALS中断是否被触发(设置为1)或未触发(设置为0)。在读取0x0D寄存器或写入0x01以清除(取决于INT Clear Manner标志)后,该位将被清除。

PS INT位寄存器用于指示PS中断是否被触发(设置为1)或未触发(设置为0)。在读取0x0F寄存器或写入0x02以清除(取决于INT Clear Manner标志)后,该位将被清除

(三)清除中断方式寄存器

在这里插入图片描述
CLR_MNR 0 自动清除; 1 手动清除。

(四)IR数据寄存器

在这里插入图片描述
红外数据分为10位数据,数据寄存器是只读寄存器。
先读取低字节寄存器,再读取高字节数据(低字节被读取时,高字节数据会存储在一个临时寄存器中)

IR_OF 红外溢出标志位,当其被置1时,表示在强红光环境下,数据无效

(五)ALS环境光数据寄存器

在这里插入图片描述
ALS数据寄存器只读,数据为16位。
需要先读取低字节数据,再读取高字节数据。

(六)PS数据寄存器

在这里插入图片描述
PS数据寄存器是10位数据,只读寄存器,先读低字节寄存器,在读高字节寄存器

目标状态位(OBJ):OBJ位用于指示目标是否靠近传感器。
当目标远离传感器并超过一定阈值时,OBJ位被重置为0;
当目标靠近传感器时,OBJ位被设置为1。

红外溢出标志(IR_OF):该标志用于指示在强红外光下,光电传感器的数据是否有效。如果IR_OF被设置为1,则表示数据无效。

三、设备树

根据传感器数据手册可知,该从设备的从机地址为0x1E

此外由上述电路图可知,通过I2C1总线进行通讯,中断引脚为PF13

&i2c1{status = "okay";//1.工作模式设置为复用, 模式有两种:工作模式(默认default), 休眠模式(sleep),//第三种挂起模式(idle)不用pinctrl-names = "default", "sleep";pinctrl-0 = <&i2c1_pins_b>;pinctrl-1 = <&i2c1_sleep_pins_b>;//2.主机通信速率, 只用设置主机的通信速率, 不需要设置从机的通信速率,//从机是被动接收的, 主机速率控制其速率,//但是主机设置速率时需要考虑从机能接收的最大速率clock-frequency = <400000>;//3.时钟scl上升沿时间, 下降沿时间, 帮助文档中提供了, 就写上i2c-scl-rising-time-ns = <185>;i2c-scl-falling-time-ns = <20>;ap3216c@1e{compatible = "zyx,ap3216c";reg = <0x1e>;interrupt-parent = <&gpiof>;interrupts = <13 0>;};
};

四、驱动代码实现

ap3216c.h

#ifndef __AP3216C_H__
#define __AP3216C_H__
/**** SCL--PF14* SDA--PF15* INT1--PF13
***/
#define CNAME "ap3216c"#define REG_SYS_CONFIG  0x00
#define REG_INT_S   0x01
#define REG_INT_CM  0x02
#define REG_ALS_CONFIG  0x10
#define REG_IR_DATA_L   0x0A
#define REG_IR_DATA_H   0x0B
#define REG_ALS_DATA_L  0x0C
#define REG_ALS_DATA_H  0x0D
#define REG_PS_DATA_L   0x0E
#define REG_PS_DATA_H   0x0F#define CMD_RESET   0x04
//配置模式:0x01--ALS   0x02--PS+IR   0x03--PS+IR+ALS
#define CMD_MODE    0x03    
#define CMD_CLEAR_MANNER 0x00#define WAIT_CONVER_TIME 150typedef struct{int als;int ps;int ir;
}data_t;#endif

ap3216c.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include "ap3216c.h"struct cdev *cdev;
dev_t devno;
struct class *cls;
struct device *dev;struct i2c_client *ap3216c_client;  //保存int ap_irqno;           //软中断号
wait_queue_head_t wq;   //等待队列头
int condition=0;        //阻塞等待条件
struct work_struct mywork; //工作队列data_t kbuf;//配置传感器
/*i2c写协议*/
/**** 功能:向ap3216c的reg寄存器中写一字节的cmd***/
int i2c_write_ap3216c(u8 reg,u8 cmd){int ret;u8 data[2] = {reg,cmd};struct i2c_msg w_msg[]={[0]={.addr = ap3216c_client->addr,.flags = 0,.len = 2,.buf = data,}};ret = i2c_transfer(ap3216c_client->adapter,w_msg,ARRAY_SIZE(w_msg));if(1 != ret){pr_err("i2c_transfer error\n");return -EIO;}return 0;
}/*读协议*/
//一次读取一字节数据
u8 i2c_read_ap3216c(u8 reg){int ret;u8 data;//组装数据struct i2c_msg r_msg[2]={[0]={.addr = ap3216c_client->addr,.flags=0,.len = 1,.buf = &reg,},[1]={.addr = ap3216c_client->addr,.flags = 1,.len = 1,.buf = &data,},};//发送数据ret = i2c_transfer(ap3216c_client->adapter,r_msg,ARRAY_SIZE(r_msg));if(ret != 2){pr_err("i2c_transfer error\n");return -EIO;}return data;
}/***中断底半部函数***/
void mywork_bottom_func(struct work_struct *work){u8 flags = i2c_read_ap3216c(REG_INT_S);u8 temp1=0,temp2=0;u8 flag = 0; //只有在产生有效数据时,flag才会置1mdelay(WAIT_CONVER_TIME); //等待转换//测试该中断并不会触发,因此此处暂时注释掉中断判断// if(flags & 0x1){//说明ALS中断触发temp1 = i2c_read_ap3216c(REG_ALS_DATA_L);temp2 = i2c_read_ap3216c(REG_ALS_DATA_H);kbuf.als = temp1|(temp2<<8);flag = 1;// }if(flags & 0x2){//说明PS中断触发//PStemp1 = i2c_read_ap3216c(REG_PS_DATA_L);temp2 = i2c_read_ap3216c(REG_PS_DATA_H);if((temp1 & 0x80) && (temp2 & 0x80) && !(temp1 & 0x40) && !(temp2 & 0x40)){  //物体接近且红外不溢出temp1 &= 0x0f;temp2 &= 0x0f;kbuf.ps = temp1 | (temp2 << 4);flag = 1;}//IRtemp1 = i2c_read_ap3216c(REG_IR_DATA_L);temp2 = i2c_read_ap3216c(REG_PS_DATA_H);if(!(temp1 & 0x80)){temp1 &= 0x3;kbuf.ir = temp1 | (temp2 << 2);flag = 1;}}if(flag) condition = 1;wake_up_interruptible(&wq);
}//中断处理函数
irqreturn_t ap3216c_irq_handler(int irqno, void *dev){schedule_work(&mywork);//开启工作队列return IRQ_HANDLED;
}int ap3216c_open(struct inode *inode, struct file *file){printk("%s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__);return 0;
}ssize_t ap3216c_read(struct file *file, char __user *ubuf, size_t size, loff_t *offset){int ret;if(file->f_flags & O_NONBLOCK){ //非阻塞ioreturn -EINVAL;}else{//阻塞ret = wait_event_interruptible(wq,condition);if(ret){pr_err("interrupt by signal\n");return ret;}if(size>sizeof(kbuf))  size = sizeof(kbuf);ret = copy_to_user(ubuf,&kbuf,size);if(ret){pr_err("copy_to_user error\n");return ret;}}condition=0;return size;
}int ap3216c_close(struct inode *inode, struct file *file){printk("%s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__);return 0;
}struct file_operations fops = {.open = ap3216c_open,.read = ap3216c_read,.release = ap3216c_close,
};int ap3216_init(void){//复位传感器i2c_write_ap3216c(REG_SYS_CONFIG,CMD_RESET);mdelay(10); //延时10ms//配置寄存器模式为 ALS+PS+IRi2c_write_ap3216c(REG_SYS_CONFIG,CMD_MODE);//配置中断清除方式为自动清除i2c_write_ap3216c(REG_INT_CM,CMD_CLEAR_MANNER);i2c_write_ap3216c(REG_ALS_CONFIG,0x01);//采样四次产生一个硬件中断return 0;
}int ap3216_probe(struct i2c_client *client, const struct i2c_device_id *id){int ret;printk("%s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__);ap3216c_client = client;/***注册字符设备驱动***/cdev = cdev_alloc();if(NULL == cdev){pr_err("cdev_alloc error\n");ret = -ENOMEM;goto err0;}cdev_init(cdev,&fops);ret = alloc_chrdev_region(&devno,0,1,CNAME);if(ret){pr_err("alloc_chrdev_region error\n");goto err0;}//注册设备ret = cdev_add(cdev,devno,1);if(ret){pr_err("cdev_add error\n");goto err1;}/***自动创建设备节点***/cls = class_create(THIS_MODULE,CNAME);if(IS_ERR(cls)){pr_err("class_create error\n");goto err2;}dev = device_create(cls,NULL,devno,NULL,CNAME);if(IS_ERR(dev)){pr_err("device_create error\n");goto err3;}/******中断初始化***///获取软中断号ap_irqno = client->irq;//申请中断号ret = request_irq(ap_irqno,ap3216c_irq_handler,IRQF_TRIGGER_FALLING,"ap3216c_irq",NULL);if(ret){pr_err("request_irq error\n");goto err4;}/******初始化等待队列头***/init_waitqueue_head(&wq);/******中断底半部初始化******/INIT_WORK(&mywork,mywork_bottom_func);/******初始化传感器******/ap3216_init();return 0;
err4:device_destroy(cls,devno);
err3:class_destroy(cls);
err2:cdev_del(cdev);
err1:unregister_chrdev_region(devno,1);
err0:return ret;
}
int ap3216_remove(struct i2c_client *client){printk("%s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__);free_irq(ap_irqno,NULL);device_destroy(cls,devno);class_destroy(cls);cdev_del(cdev);unregister_chrdev_region(devno,1);return 0;
}struct of_device_id oftable[] = {{.compatible = "zyx,ap3216c"},{},
};struct i2c_driver ap3216c_driver = {.probe = ap3216_probe,.remove = ap3216_remove,.driver = {.of_match_table = oftable,.name = "ap3216",}
};module_i2c_driver(ap3216c_driver);
MODULE_LICENSE("GPL");

测试程序:
驱动提供了阻塞IO模型,因此只需要循环读取即可,无需担心会刷屏

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>#include "head.h"int main(int argc, char const *argv[])
{int fd = open("/dev/ap3216c",O_RDWR);if(fd < 0){perror("open error");return -1;}data_t mydata;while(1){read(fd,&mydata,sizeof(data_t));printf("ALS=[%d], PS=[%d], IR=[%d]\n",mydata.als,mydata.ps,mydata.ir);}return 0;
}

实验现象:
当接近该传感器时会触发中断,读取数据
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com