• Linux驱动开发+QT应用编程实现IIC读取ap3216c


    Linux驱动开发:IIC驱动开发

    Linux I2C驱动框架的简介

    bsp_i2c.c 称之为 主机驱动,写完不需要修改。
    bsp_ap3216c.c称之为设备驱动,根据主机驱动适配到设备上。

    Linux内核将IIC驱动分为

    • IIC总线驱动:总线驱动等同于裸机中的IIC主机驱动,这里叫IIC适配器驱动
    • IIC设备驱动:设备驱动就是针对ap3216c专门编写的驱动。

    1、IIC读写代码示例(重要)

    使用 i2c_transfer 函数发送数据之前要先构建好 i2c_msg,使用 i2c_transfer 进行 I2C 数据收发的示例代码如下:

     /* 设备结构体 */
    struct xxx_dev {
    		......
    		void *private_data; /* 私有数据,一般会设置为 i2c_client */
    };
    
    /*
    * @description : 读取 I2C 设备多个寄存器数据
    * @param – dev : I2C 设备
    * @param – reg : 要读取的寄存器首地址
    * @param – val : 读取到的数据
    * @param – len : 要读取的数据长度
    * @return : 操作结果
    */
    static int xxx_read_regs(struct xxx_dev *dev, u8 reg, void *val,int len)
    {
    		int ret;
    		struct i2c_msg msg[2];
    		struct i2c_client *client = (struct i2c_client *)
    		dev->private_data;
    
    		/* msg[0],第一条写消息,发送要读取的寄存器首地址 */
    		msg[0].addr = client->addr; /* I2C 器件地址 */
    		msg[0].flags = 0; /* 标记为发送数据 */
    		msg[0].buf = ® /* 读取的首地址 */
    		msg[0].len = 1; /* reg 长度 */
    
    		/* msg[1],第二条读消息,读取寄存器数据 */
    		msg[1].addr = client->addr; /* I2C 器件地址 */
    		msg[1].flags = I2C_M_RD; /* 标记为读取数据 */
    		msg[1].buf = val; /* 读取数据缓冲区 */
    		msg[1].len = len; /* 要读取的数据长度 */
     
    
    		ret = i2c_transfer(client->adapter, msg, 2);
    		if(ret == 2) {
    				ret = 0;
    		} else {
    				ret = -EREMOTEIO;
    		}
    		return ret;
    }
    
    /*
    * @description : 向 I2C 设备多个寄存器写入数据
    * @param – dev : 要写入的设备结构体
    * @param – reg : 要写入的寄存器首地址
    * @param – buf : 要写入的数据缓冲区
    * @param – len : 要写入的数据长度
    * @return : 操作结果
    */
    static s32 xxx_write_regs(struct xxx_dev *dev, u8 reg, u8 *buf,u8 len)
    {
    		u8 b[256];
    		struct i2c_msg msg;
    		struct i2c_client *client = (struct i2c_client *)
    		dev->private_data;
    		
    		b[0] = reg; /* 寄存器首地址 */
    		memcpy(&b[1],buf,len); /* 将要发送的数据拷贝到数组 b 里面 */
    		
    		msg.addr = client->addr; /* I2C 器件地址 */
    		msg.flags = 0; /* 标记为写数据 */
    		
    		msg.buf = b; /* 要发送的数据缓冲区 */
    		msg.len = len + 1; /* 要发送的数据长度 */
    		
    		return i2c_transfer(client->adapter, &msg, 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    另外两个API函数分别用于I2C数据的收发操作,这两个函数最终都会调用i2c_transfer。
    函数原型如下:

    int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
    
    函数参数和返回值含义如下:
    client:I2C 设备对应的 i2c_client。
    
    buf:要发送的数据。
    
    count:要发送的数据字节数,要小于 64KB,以为 i2c_msg 的 len 成员变量是一个 u16(无符号 16)类型的数据。
    
    返回值:负值,失败,其他非负值,发送的字节数。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    I2C 数据接收函数为 i2c_master_recv,函数原型如下:

    int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
    
    函数参数和返回值含义如下:
    
    client:I2C 设备对应的 i2c_client。
    
    buf:要接收的数据。
    
    count:要接收的数据字节数,要小于 64KB,以为 i2c_msg 的 len 成员变量是一个 u16(无符号 16)类型的数据。
    
    返回值:负值,失败,其他非负值,发送的字节数。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、i2c_driver 的设备树注册示例代码如下:

    i2c 驱动的 probe 函数
    static int xxx_probe(struct i2c_client *client,const struct i2c_device_id *id)
    {
    	 /* 函数具体程序 */
    	return 0;
    }
    
    i2c 驱动的 remove 函数
    static int xxx_remove(struct i2c_client *client)
     {
    	函数具体程序 
    	 return 0;
    }
    
    设备树匹配列表
    static const struct of_device_id xxx_of_match[] = {
    { .compatible = "xxx" },
    { /* Sentinel */ }
    };
    
    i2c 驱动结构体
    static struct i2c_driver xxx_driver = {
    		.probe = xxx_probe,
    		.remove = xxx_remove,
    		.driver = {
    		.owner = THIS_MODULE,
    		.name = "xxx",
    		.of_match_table = xxx_of_match,
    		},
    		.id_table = xxx_id,
    };
    
    驱动入口函数
    static int __init xxx_init(void)
    {
    		int ret = 0;
    		ret = i2c_add_driver(&xxx_driver);
    		return ret;
    }
    
    驱动出口函数
    static void __exit xxx_exit(void)
    {
    	i2c_del_driver(&xxx_driver);
    }
    
    module_init(xxx_init);
    module_exit(xxx_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • of_device_id,设备树所使用的匹配表。
    • i2c_driver,当 I2C 设备和 I2C 驱动匹配成功以后 probe 函数就会执行,这些和 platform 驱动一样,probe函数里面基本就是标准的字符设备驱动那一套了。

    ap3216c驱动开发

    1、修改设备树,pinctrl子节点添加设备的电气属性,配置GPIO并且设置电气属性:
    在这里插入图片描述
    pinctrl_i2c1 就是 I2C1 的 IO 节点,这里将 UART4_TXD 和 UART4_RXD 这两个 IO 分别复用为 I2C1_SCL 和 I2C1_SDA,电气属性都设置为 0x4001b8b0。

    2、在 i2c1 节点追加 ap3216c 子节点

    &i2c1 {
    	clock-frequency = <100000>;
    	pinctrl-names = "default";
    	pinctrl-0 = <&pinctrl_i2c1>;
    	status = "okay";
    
    	ap3216c@1e {
    		compatible = "alientek,ap3216c";
    		reg = <0x1e>;
    	};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果:
    在这里插入图片描述
    寄存器地址:

    #ifndef AP3216C_H
    #define AP3216C_H
    
    #define AP3216C_ADDR    	0X1E	/* AP3216C器件地址  */
    
    /* AP3316C寄存器 */
    #define AP3216C_SYSTEMCONG	0x00	/* 配置寄存器       */
    #define AP3216C_INTSTATUS	0X01	/* 中断状态寄存器   */
    #define AP3216C_INTCLEAR	0X02	/* 中断清除寄存器   */
    #define AP3216C_IRDATALOW	0x0A	/* IR数据低字节     */
    #define AP3216C_IRDATAHIGH	0x0B	/* IR数据高字节     */
    #define AP3216C_ALSDATALOW	0x0C	/* ALS数据低字节    */
    #define AP3216C_ALSDATAHIGH	0X0D	/* ALS数据高字节    */
    #define AP3216C_PSDATALOW	0X0E	/* PS数据低字节     */
    #define AP3216C_PSDATAHIGH	0X0F	/* PS数据高字节     */
    
    #endif
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    驱动代码:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "ap3216creg.h"
    
    #define AP3216C_CNT	1
    #define AP3216C_NAME	"ap3216c"
    
    struct ap3216c_dev {
    	dev_t devid;			/* 设备号 	 */
    	struct cdev cdev;		/* cdev 	*/
    	struct class *class;	/* 类 		*/
    	struct device *device;	/* 设备 	 */
    	struct device_node	*nd; /* 设备节点 */
    	int major;			/* 主设备号 */
    	void *private_data;	/* 私有数据 */
    	unsigned short ir, als, ps;		/* 三个光传感器数据 */
    };
    
    static struct ap3216c_dev ap3216cdev;
    
    /*
     * @description	: 从ap3216c读取多个寄存器数据
     * @param - dev:  ap3216c设备
     * @param - reg:  要读取的寄存器首地址
     * @param - val:  读取到的数据
     * @param - len:  要读取的数据长度
     * @return 		: 操作结果
     */
    static int ap3216c_read_regs(struct ap3216c_dev *dev, u8 reg, void *val, int len)
    {
    	int ret;
    	struct i2c_msg msg[2];
    	struct i2c_client *client = (struct i2c_client *)dev->private_data;
    
    	/* msg[0]为发送要读取的首地址 */
    	msg[0].addr = client->addr;			/* ap3216c地址 */
    	msg[0].flags = 0;					/* 标记为发送数据 */
    	msg[0].buf = &reg;					/* 读取的首地址 */
    	msg[0].len = 1;						/* reg长度*/
    
    	/* msg[1]读取数据 */
    	msg[1].addr = client->addr;			/* ap3216c地址 */
    	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
    	msg[1].buf = val;					/* 读取数据缓冲区 */
    	msg[1].len = len;					/* 要读取的数据长度*/
    
    	ret = i2c_transfer(client->adapter, msg, 2);
    	if(ret == 2) {
    		ret = 0;
    	} else {
    		printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
    		ret = -EREMOTEIO;
    	}
    	return ret;
    }
    
    /*
     * @description	: 向ap3216c多个寄存器写入数据
     * @param - dev:  ap3216c设备
     * @param - reg:  要写入的寄存器首地址
     * @param - val:  要写入的数据缓冲区
     * @param - len:  要写入的数据长度
     * @return 	  :   操作结果
     */
    static s32 ap3216c_write_regs(struct ap3216c_dev *dev, u8 reg, u8 *buf, u8 len)
    {
    	u8 b[256];
    	struct i2c_msg msg;
    	struct i2c_client *client = (struct i2c_client *)dev->private_data;
    	
    	b[0] = reg;					/* 寄存器首地址 */
    	memcpy(&b[1],buf,len);		/* 将要写入的数据拷贝到数组b里面 */
    		
    	msg.addr = client->addr;	/* ap3216c地址 */
    	msg.flags = 0;				/* 标记为写数据 */
    
    	msg.buf = b;				/* 要写入的数据缓冲区 */
    	msg.len = len + 1;			/* 要写入的数据长度 */
    	//msg 的 len 为 len+1,因为要加上一个字节的寄存器地址。
    
    	return i2c_transfer(client->adapter, &msg, 1);
    }
    
    /*
     * @description	: 读取ap3216c指定寄存器值,读取一个寄存器
     * @param - dev:  ap3216c设备
     * @param - reg:  要读取的寄存器
     * @return 	  :   读取到的寄存器值
     */
    static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev, u8 reg)
    {
    	u8 data = 0;
    
    	ap3216c_read_regs(dev, reg, &data, 1);
    	return data;
    
    #if 0
    	struct i2c_client *client = (struct i2c_client *)dev->private_data;
    	return i2c_smbus_read_byte_data(client, reg);
    #endif
    }
    
    /*
     * @description	: 向ap3216c指定寄存器写入指定的值,写一个寄存器
     * @param - dev:  ap3216c设备
     * @param - reg:  要写的寄存器
     * @param - data: 要写入的值
     * @return   :    无
     */
    static void ap3216c_write_reg(struct ap3216c_dev *dev, u8 reg, u8 data)
    {
    	u8 buf = 0;
    	buf = data;
    	ap3216c_write_regs(dev, reg, &buf, 1);
    }
    
    /*
     * @description	: 读取AP3216C的数据,读取原始数据,包括ALS,PS和IR, 注意!
     *				: 如果同时打开ALS,IR+PS的话两次数据读取的时间间隔要大于112.5ms
     * @param - ir	: ir数据
     * @param - ps 	: ps数据
     * @param - ps 	: als数据 
     * @return 		: 无。
     */
    void ap3216c_readdata(struct ap3216c_dev *dev)
    {
    	unsigned char i =0;
        unsigned char buf[6];
    	
    	/* 循环读取所有传感器数据 */
        for(i = 0; i < 6; i++)	
        {
            buf[i] = ap3216c_read_reg(dev, AP3216C_IRDATALOW + i);	
        }
    
        if(buf[0] & 0X80) 	/* IR_OF位为1,则数据无效 */
    		dev->ir = 0;					
    	else 				/* 读取IR传感器的数据   		*/
    		dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); 			
    	
    	dev->als = ((unsigned short)buf[3] << 8) | buf[2];	/* 读取ALS传感器的数据 			 */  
    	
        if(buf[4] & 0x40)	/* IR_OF位为1,则数据无效 			*/
    		dev->ps = 0;    													
    	else 				/* 读取PS传感器的数据    */
    		dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F); 
    }
    
    /*
     * @description		: 打开设备
     * @param - inode 	: 传递给驱动的inode
     * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
     * 					  一般在open的时候将private_data指向设备结构体。
     * @return 			: 0 成功;其他 失败
     */
    static int ap3216c_open(struct inode *inode, struct file *filp)
    {
    	filp->private_data = &ap3216cdev;
    
    	/* 初始化AP3216C */
    	ap3216c_write_reg(&ap3216cdev, AP3216C_SYSTEMCONG, 0x04);		/* 复位AP3216C 			*/
    	mdelay(50);														/* AP3216C复位最少10ms 	*/
    	ap3216c_write_reg(&ap3216cdev, AP3216C_SYSTEMCONG, 0X03);		/* 开启ALS、PS+IR 		*/
    	return 0;
    }
    
    /*
     * @description		: 从设备读取数据 
     * @param - filp 	: 要打开的设备文件(文件描述符)
     * @param - buf 	: 返回给用户空间的数据缓冲区
     * @param - cnt 	: 要读取的数据长度
     * @param - offt 	: 相对于文件首地址的偏移
     * @return 			: 读取的字节数,如果为负值,表示读取失败
     */
    static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
    {
    	short data[3];
    	long err = 0;
    
    	struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;
    	
    	ap3216c_readdata(dev);
    
    	data[0] = dev->ir;
    	data[1] = dev->als;
    	data[2] = dev->ps;
    	err = copy_to_user(buf, data, sizeof(data));
    	return 0;
    }
    
    /*
     * @description		: 关闭/释放设备
     * @param - filp 	: 要关闭的设备文件(文件描述符)
     * @return 			: 0 成功;其他 失败
     */
    static int ap3216c_release(struct inode *inode, struct file *filp)
    {
    	return 0;
    }
    
    /* AP3216C操作函数 */
    static const struct file_operations ap3216c_ops = {
    	.owner = THIS_MODULE,
    	.open = ap3216c_open,
    	.read = ap3216c_read,
    	.release = ap3216c_release,
    };
    
     /*
      * @description     : i2c驱动的probe函数,当驱动与
      *                    设备匹配以后此函数就会执行
      * @param - client  : i2c设备
      * @param - id      : i2c设备ID
      * @return          : 0,成功;其他负值,失败
      */
    static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
    	/* 1、构建设备号 */
    	if (ap3216cdev.major) {
    		ap3216cdev.devid = MKDEV(ap3216cdev.major, 0);
    		register_chrdev_region(ap3216cdev.devid, AP3216C_CNT, AP3216C_NAME);
    	} else {
    		alloc_chrdev_region(&ap3216cdev.devid, 0, AP3216C_CNT, AP3216C_NAME);
    		ap3216cdev.major = MAJOR(ap3216cdev.devid);
    	}
    
    	/* 2、注册设备 */
    	cdev_init(&ap3216cdev.cdev, &ap3216c_ops);
    	cdev_add(&ap3216cdev.cdev, ap3216cdev.devid, AP3216C_CNT);
    
    	/* 3、创建类 */
    	ap3216cdev.class = class_create(THIS_MODULE, AP3216C_NAME);
    	if (IS_ERR(ap3216cdev.class)) {
    		return PTR_ERR(ap3216cdev.class);
    	}
    
    	/* 4、创建设备 */
    	ap3216cdev.device = device_create(ap3216cdev.class, NULL, ap3216cdev.devid, NULL, AP3216C_NAME);
    	if (IS_ERR(ap3216cdev.device)) {
    		return PTR_ERR(ap3216cdev.device);
    	}
    
    	ap3216cdev.private_data = client;
    
    	return 0;
    }
    
    /*
     * @description     : i2c驱动的remove函数,移除i2c驱动的时候此函数会执行
     * @param - client 	: i2c设备
     * @return          : 0,成功;其他负值,失败
     */
    static int ap3216c_remove(struct i2c_client *client)
    {
    	/* 删除设备 */
    	cdev_del(&ap3216cdev.cdev);
    	unregister_chrdev_region(ap3216cdev.devid, AP3216C_CNT);
    
    	/* 注销掉类和设备 */
    	device_destroy(ap3216cdev.class, ap3216cdev.devid);
    	class_destroy(ap3216cdev.class);
    	return 0;
    }
    
    /* 传统匹配方式ID列表 */
    static const struct i2c_device_id ap3216c_id[] = {
    	{"alientek,ap3216c", 0},  
    	{}
    };
    
    /* 设备树匹配列表 */
    static const struct of_device_id ap3216c_of_match[] = {
    	{ .compatible = "alientek,ap3216c" },
    	{ /* Sentinel */ }
    };
    
    /* i2c驱动结构体 */	
    static struct i2c_driver ap3216c_driver = {
    	.probe = ap3216c_probe,
    	.remove = ap3216c_remove,
    	.driver = {
    			.owner = THIS_MODULE,
    		   	.name = "ap3216c",
    		   	.of_match_table = ap3216c_of_match, 
    		   },
    	.id_table = ap3216c_id,
    };
    		   
    /*
     * @description	: 驱动入口函数
     * @param 		: 无
     * @return 		: 无
     */
    static int __init ap3216c_init(void)
    {
    	int ret = 0;
    
    	ret = i2c_add_driver(&ap3216c_driver);
    	return ret;
    }
    
    /*
     * @description	: 驱动出口函数
     * @param 		: 无
     * @return 		: 无
     */
    static void __exit ap3216c_exit(void)
    {
    	i2c_del_driver(&ap3216c_driver);
    }
    
    /* module_i2c_driver(ap3216c_driver) */
    
    module_init(ap3216c_init);
    module_exit(ap3216c_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("zdyz");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332

    QT应用编程

    “mainwindow.cpp”文件主要承担着布局及数据显示的功能。

    获取传感器信息的函数:

    void MainWindow::getAp3216cData()
    {
        static QString als = ap3216c->alsData();
        if (als != ap3216c->alsData()) {
            als = ap3216c->alsData();
            arcGraph[0]->setangleLength(als.toUInt() * 360 / 65535);
        }
    
        static QString ps = ap3216c->psData();
        if (ps != ap3216c->psData()) {
            ps = ap3216c->psData();
            arcGraph[1]->setangleLength(ps.toUInt() * 360 / 1023);
        }
    
        static QString ir = ap3216c->irData();
        if (ir != ap3216c->irData()) {
            ir = ap3216c->irData();
            arcGraph[2]->setangleLength(ir.toUInt() * 360 / 1023);
        }
    
        glowText[0]->setTextData(als);
        glowText[1]->setTextData(ps);
        glowText[2]->setTextData(ir);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    HeadView类

    主要是来配置界面的顶部样式和布局:
    在这里插入图片描述比较简单

    iconWidget = new QWidget(this);//图标配置
    
    textLabel = new QLabel(this);//内容显示配置
    
    lineWidget = new QWidget(this);//底部白色线条的显示
    
    vBoxLayout = new QVBoxLayout();//垂直布局
    
    hBoxLayout = new QHBoxLayout();//水平布局
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ArcGraph类

    在这里插入图片描述

       /******************************************************************
    Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
    * @projectName   08_ii2_ap3216c_sensor
    * @brief         arcgraph.cpp
    * @author        Deng Zhimao
    * @email         1252699831@qq.com
    * @net           www.openedv.com
    * @date          2021-05-22
    *******************************************************************/
    #include "arcgraph.h"
    
    ArcGraph::ArcGraph(QWidget *parent)
        : QWidget(parent),
          startAngle(90),
          angleLength(100)
    {
        this->setMinimumSize(100, 100);
        setAttribute(Qt::WA_TranslucentBackground, true);
    }
    
    ArcGraph::~ArcGraph()
    {
    }
    
    void ArcGraph::setstartAngle(int angle)
    {
        startAngle = angle;
        this->repaint();
    }
    
    void ArcGraph::setangleLength(int length)
    {
        angleLength = length;
        this->repaint();
    }
    
    void ArcGraph::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
    
        /* 保存状态 */
        painter.save();
    
        /* 设置抗锯齿 */
        painter.setRenderHints(QPainter::Antialiasing, true);
    
        /* 最外层的圆 */
        QRect drawRect = event->rect();
        QRadialGradient gradient1(drawRect.center(),
                                  drawRect.width() / 2,
                                  drawRect.center());
        gradient1.setColorAt(0, Qt::transparent);
        gradient1.setColorAt(0.5, Qt::transparent);
        gradient1.setColorAt(0.51, QColor("#00237f"));
        gradient1.setColorAt(0.58, QColor("#00237f"));
        gradient1.setColorAt(0.59, Qt::transparent);
        gradient1.setColorAt(1, Qt::transparent);
        painter.setBrush(gradient1);
        painter.setPen(Qt::NoPen);
        painter.drawEllipse(drawRect);
    
        /* 里层的圆 */
        QRadialGradient gradient2(drawRect.center(),
                                  drawRect.width() / 2,
                                  drawRect.center());
        gradient2.setColorAt(0, Qt::transparent);
        gradient2.setColorAt(0.420, Qt::transparent);
        gradient2.setColorAt(0.421, QColor("#885881e3"));
        gradient2.setColorAt(0.430, QColor("#5881e3"));
        gradient2.setColorAt(0.440, QColor("#885881e3"));
        gradient2.setColorAt(0.441, Qt::transparent);
        gradient2.setColorAt(1, Qt::transparent);
        painter.setBrush(gradient2);
        painter.setPen(Qt::NoPen);
        painter.drawEllipse(drawRect);
    
        /* 数字 */
        QFont font;
        font.setPixelSize(drawRect.width() / 10);
        painter.setPen(Qt::white);
        painter.setFont(font);
        painter.drawText(drawRect, Qt::AlignCenter,
                         QString::number(angleLength * 100 / 360) + "%");
    
        /* 发光背景圆 */
        painter.translate(drawRect.width() >> 1, drawRect.height() >> 1);
        int radius = drawRect.width() / 2;
        /* radius<< 1(左移1位)相当于radius*2 */
        QRectF rect(-radius, -radius, radius << 1, radius << 1);
    
        QRadialGradient gradient3(0, 0, radius);
        gradient3.setColorAt(0, Qt::transparent);
        gradient3.setColorAt(0.42, Qt::transparent);
        gradient3.setColorAt(0.51, QColor("#500194d3"));
        gradient3.setColorAt(0.55, QColor("#22c1f3f9"));
        gradient3.setColorAt(0.58, QColor("#500194d3"));
        gradient3.setColorAt(0.68, Qt::transparent);
        gradient3.setColorAt(1.0, Qt::transparent);
        painter.setBrush(gradient3);
        QPainterPath path1;
        path1.arcTo(rect, startAngle, -angleLength);
        painter.setPen(Qt::NoPen);
        painter.drawPath(path1);
    
        /* 发光圆/弧 */
        QRadialGradient gradient4(0, 0, radius);
        gradient4.setColorAt(0, Qt::transparent);
        gradient4.setColorAt(0.49, Qt::transparent);
        gradient4.setColorAt(0.50, QColor("#4bf3f9"));
        gradient4.setColorAt(0.59, QColor("#4bf3f9"));
        gradient4.setColorAt(0.60, Qt::transparent);
        gradient4.setColorAt(1.0, Qt::transparent);
        painter.setBrush(gradient4);
        QPainterPath path2;
        path2.arcTo(rect, startAngle, -angleLength);
        painter.setPen(Qt::NoPen);
        painter.drawPath(path2);
    
        /* 恢复状态 */
        painter.restore();
    
        /* 设置事件对象的accept标志 */
        event->accept();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    GlowText类:发光文字

    /******************************************************************
    Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
    * @projectName   GlowText
    * @brief         glowtext.cpp
    * @author        Deng Zhimao
    * @email         1252699831@qq.com
    * @net           www.openedv.com
    * @date          2021-05-21
    *******************************************************************/
    #include "glowtext.h"
    #include 
    #include 
    
    GlowText::GlowText(QWidget *parent)
        : QWidget(parent),
          textColor("#4bf3f9"),
          fontSize(18),
          textData("100")
    {
        QFont font;
        font.setPixelSize(fontSize);
        QPalette pal;
        pal.setColor(QPalette::WindowText, textColor);
        textLabelbg = new QLabel(this);
        textLabelbg->setAttribute(Qt::WA_TranslucentBackground, true);
        textLabelbg->setPalette(pal);
        textLabelbg->setFont(font);
        textLabelbg->setText(textData);
        textLabelbg->setAlignment(Qt::AlignCenter);
    
        /* 设置模糊特效 */
        QGraphicsBlurEffect *ef = new QGraphicsBlurEffect();
        ef->setBlurRadius(25);
        ef->setBlurHints(QGraphicsBlurEffect::QualityHint);
        textLabelbg->setGraphicsEffect(ef);
    
        textLabel = new QLabel(this);
        textLabel->setAttribute(Qt::WA_TranslucentBackground, true);
        textLabel->setPalette(pal);
        textLabel->setFont(font);
        textLabel->setText(textData);
        textLabel->setAlignment(Qt::AlignCenter);
        textLabelbg->adjustSize();
        textLabel->adjustSize();
    
        this->resize(textLabel->size().width() + 10,
                     textLabel->size().height() + 10);
        /* 背景透明化 */
        this->setAttribute(Qt::WA_TranslucentBackground, true);
    }
    
    GlowText::~GlowText()
    {
    }
    
    void GlowText::setTextColor(QColor color)
    {
        QPalette pal;
        pal.setColor(QPalette::WindowText, color);
        textLabelbg->setPalette(pal);
        textLabel->setPalette(pal);
    }
    
    void GlowText::setFontSize(int size)
    {
        QFont font;
        font.setPixelSize(size);
    
        textLabelbg->setFont(font);
        textLabel->setFont(font);
    
        textLabel->adjustSize();
        textLabelbg->adjustSize();
        this->resize(textLabel->size().width() + 10,
                     textLabel->size().height() + 10);
    }
    
    void GlowText::setTextData(QString text)
    {
        textLabelbg->setText(text);
        textLabel->setText(text);
    
        textLabel->adjustSize();
        textLabelbg->adjustSize();
        this->resize(textLabel->size().width() + 10,
                     textLabel->size().height() + 10);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    Ap3216c 类

    Ap3216c 类的作用就是从驱动层提供给 Linux 应用层的接口获取数据,回归linux应用编程,使用C语言访问设备节点文件,之后调用驱动层代码,实现应用层访问驱动层数据,并且读取到数据。

    #include "ap3216c.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    Ap3216c::Ap3216c(QObject *parent) : QObject (parent)
    {
        timer = new QTimer();
        connect(timer, SIGNAL(timeout()), this, SLOT(timer_timeout()));
    }
    
    Ap3216c::~Ap3216c()
    {
    
    }
    
    void Ap3216c::timer_timeout()
    {
        alsdata = readAlsData();
        psdata = readPsData();
        irdata = readIrData();
        emit ap3216cDataChanged();
    }
    
    QString Ap3216c::readIrData()
    {
        char const *filename = "/sys/class/misc/ap3216c/ir";
        int err = 0;
        int fd;
        char buf[10];
    
        fd = open(filename, O_RDONLY);
        if(fd < 0) {
            close(fd);
            return "open file error!";
        }
    
        err = read(fd, buf, sizeof(buf));
        if (err < 0) {
            close(fd);
            return "read data error!";
        }
        close(fd);
    
        QString irValue = buf;
        QStringList list = irValue.split("\n");
        return list[0];
    }
    
    QString Ap3216c::readPsData()
    {
        char const *filename = "/sys/class/misc/ap3216c/ps";
        int err = 0;
        int fd;
        char buf[10];
    
        fd = open(filename, O_RDONLY);
        if(fd < 0) {
            close(fd);
            return "open file error!";
        }
    
        err = read(fd, buf, sizeof(buf));
        if (err < 0) {
            close(fd);
            return "read data error!";
        }
        close(fd);
    
        QString psValue = buf;
        QStringList list = psValue.split("\n");
        return list[0];
    }
    
    QString Ap3216c::readAlsData()
    {
        char const *filename = "/sys/class/misc/ap3216c/als";
        int err = 0;
        int fd;
        char buf[10];
    
        fd = open(filename, O_RDONLY);
        if(fd < 0) {
            close(fd);
            return "open file error!";
        }
    
        err = read(fd, buf, sizeof(buf));
        if (err < 0) {
            close(fd);
            return "read data error!";
        }
        close(fd);
    
        QString alsValue = buf;
        QStringList list = alsValue.split("\n");
        return list[0];
    }
    
    QString Ap3216c::alsData()
    {
        return alsdata;
    }
    
    QString Ap3216c::irData()
    {
        return irdata;
    }
    
    QString Ap3216c::psData()
    {
        return psdata;
    }
    
    void Ap3216c::setCapture(bool str)
    {
        if(str)
            timer->start(500);
        else
            timer->stop();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
  • 相关阅读:
    Java 网络编程 —— 创建非阻塞的 HTTP 服务器
    null 和 undefined 的区别
    MFC 多文档程序的基本编程
    【程序人生】4年创作纪念日,不忘初心,继续前行
    ROC曲线简明讲解
    linux每天一个命令(ls)
    消息队列一|从秒杀活动开始聊起消息队列
    五大网络IO模型
    支持M1/M2/intel芯片 Cinema 4D Studio R2023中文版for Mac(C4D超强三维动画设计)已发布,让你分分钟得到惊人的效果
    [附源码]计算机毕业设计JAVAjsp基于servlet技术实现游戏娱乐平台
  • 原文地址:https://blog.csdn.net/m0_46152793/article/details/125889382