zl程序教程

您现在的位置是:首页 >  硬件

当前栏目

ZYNQ-实现外设驱动开发-iic接口的光强度传感器GY-30

驱动接口开发 实现 30 传感器 ZYNQ 外设
2023-09-14 09:13:04 时间

学习内容

使用SDK和提供的API进行初始化IIC,并驱动iic接口的光强度传感器GY-30。

开发环境

vivado 18.3 && SDK
开发板 pynq-z2
(由于这里的pynq的开发板没有相应的MIO可以供直接使用ARM端进行开发,所以本次内容仅仅用于模拟流程开发)
已经更新,使用EMIO驱动完成光强传感器的读取

IIC知识部分

嵌入式-iic通信的一些概念
网上自行查找,不再赘述。

硬件平台搭建

首先我们需要打开我们的vivado进行block design的建立,方法同前文helloworld
在这里插入图片描述
添加zynq ip
在这里插入图片描述
对ip进行相应的配置,这里没有用到ps-pl部分,仅仅实现的是zynq的arm端的配置,所以这里的config勾选全部去掉。
在这里插入图片描述
设置选中sd,uart,iic,并根据自己的开发板进行合适的配置,由于zynq没有MIO对应空闲的引脚,(看了半天原理图只有一个,所以就随便配置下吧,MIO的位置)
在这里插入图片描述
配置完成后,点击auto,生成下图
在这里插入图片描述
如果没啥问题,就进行生成HDL Wrapper,生成顶层文件。
在这里插入图片描述
然后综合生成bit流文件
在这里插入图片描述
生成bit流文件后选中导出hardware,
在这里插入图片描述
并包含bit流文件
在这里插入图片描述
运行sdk
在这里插入图片描述

SDK软件部分

新建project
在这里插入图片描述
生成默认的helloworld后可以对相应的helloworld.c进行改名,(通常使用main.c,和keil的习惯相同),然后我们就要找到,官方给出的API,进行iic的开发。在bsp的目录下,我们可以很容易的找到各种头文件方便我们调用,和stm32的库相类似

在这里插入图片描述
如果我们想查看我们已经定义的功能区的所要用的函数,可以在system.mss中查看
在这里插入图片描述
打开后,可以看到我们之前在bd中配置的东西这里都会有相应的使用api的文件
在这里插入图片描述
点击打开iicps的文件,我们就可以查看相应的api的使用方法。
在这里插入图片描述
在这里插入图片描述

初始化外设需要的函数

XIicPs_LookupConfig();//查找外设的配置结构体
XIicPs_CfgInitialize();//初始化外设
XIicPs_SetSClk();//设置IIC速度

XIicPs_LookupConfig()

在这里插入图片描述

根据唯一的设备ID查找设备配置。
表格包含系统中每个设备的配置信息。
参数DeviceId包含要为其查找配置的设备的ID。 返回指向找到的配置的指针;如果未找到指定的设备ID,则返回NULL。 有关XIicPs_Config的定义,请参见xiicps.h。

XIicPs_CfgInitialize()

在这里插入图片描述

初始化特定的XIicPs实例,以便驱动程序可以使用。
初始化后设备的状态为:禁用设备从模式参数InstancePtr是指向XIicPs实例的指针。 ConfigPtr是对包含有关特定IIC设备信息的结构的引用。 此函数为Config的内容指定的特定设备初始化InstancePtr对象。
EffectiveAddr是虚拟内存地址空间中的设备基地址。
一旦调用此函数,调用方负责保持从EffectiveAddr到设备物理基址的地址映射不变。
如果在调用此函数后地址映射发生更改,可能会发生意外错误。 如果不使用地址转换,请对该参数使用ConfigPtr->
BaseAddress,而是传递物理地址。 返回值如果成功,则返回值为XST_SUCCESS。

XIicPs_SetSClk();//设置IIC速度

在这里插入图片描述

该功能设置IIC设备的串行时钟速率。
在设置这些设备选项之前,设备必须处于空闲状态而不是忙于传输数据。
数据速率由控制寄存器中的值设置。 确定正确寄存器值的公式为:Fscl = Fpclk /(22 x(divisor_a + 1)x(divisor_b + 1))有关设置串行时钟速率的完整说明,请参见硬件数据手册。
参数InstancePtr是指向XIicPs实例的指针。 FsclHz是以Hz为单位的时钟频率。 两种最常见的时钟频率是100KHz和400KHz。 如果成功设置了选项,则返回XST_SUCCESS。
XST_DEVICE_IS_STARTED(如果设备当前正在传输数据)。 设置选项之前,传输必须完成或中止。
如果无法设置Fscl频率,则为XST_FAILURE。

DEVICE_ID的查找办法:

在bsp文件夹中的lib中找到xparameters.h的文件然后进行ctrl+f查找输入iic,快速定位到相对应的文件。
在这里插入图片描述

初始化函数

首先初始化对应的结构体指针:

XIicPs *iicps;
XIicPs_Config * iicpscfgtr;

编写初始化函数

int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){
	int status;
	iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID);
	status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress);
	if(status !=XST_SUCCESS){
		return XST_FAILURE;
	}
	status = XIicPs_SetSClk(iips,I2C_0_CLK);
	if(status !=XST_SUCCESS){
		return XST_FAILURE;
	}
	return 0;
}

最后根据gy-30的手册进行编写读取光强的数据,完整main如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xiicps.h"
#include "xparameters.h"
#include "sleep.h"
#define I2C_0_DEVICE_ID XPAR_PS7_I2C_0_DEVICE_ID
#define I2C_0_CLK 100000
#define IIC_0_SALV_ADDR 0x23 //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改
                              //ALT  ADDRESS引脚接地时地址为0x46,接电源时地址为0xB8

// XIicPs* iicps;
XIicPs iicps;
XIicPs_Config * iicpscfgtr;


//初始化 iic
int InitIic(XIicPs *iips,XIicPs_Config *iiccfg);

int main()
{
    int status;
    double out=0;
    unsigned short tmp;
    unsigned char Cmdon = 0x01;
    unsigned char Cmdlight = 0x10;
    char temp[2];
    init_platform();
    status=InitIic(&iicps,iicpscfgtr);
    if(status !=XST_SUCCESS){
    	return XST_FAILURE;
    }
    //初始化
    status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
    	    if(status !=XST_SUCCESS){
    		   return XST_FAILURE;
    	    }
    usleep(10000);//延时10ms
    printf("init iic successful!\n");
    while(1){
		status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
	    if(status !=XST_SUCCESS){
		   return XST_FAILURE;
	    }
		status = XIicPs_MasterSendPolled(&iicps,&Cmdlight,1,IIC_0_SALV_ADDR);
		if(status !=XST_SUCCESS){
					return XST_FAILURE;
	    }
		usleep(180000);//延时180ms
		status = XIicPs_MasterRecvPolled(&iicps,&temp,2,IIC_0_SALV_ADDR);

		//串口检测结果
		tmp = (temp[0]<<8)| temp[1];
		out = tmp/1.2;
		printf("light intensity : %.1f lx\n",out);
		usleep(1000000);
    }
    cleanup_platform();
    return 0;
}
int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){
	int status;
	iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID);
	status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress);
	if(status !=XST_SUCCESS){
		return XST_FAILURE;
	}
	status = XIicPs_SelfTest(iips);
			if (status != XST_SUCCESS) {
				return XST_FAILURE;
			}
	status = XIicPs_SetSClk(iips,I2C_0_CLK);
	if(status !=XST_SUCCESS){
		return XST_FAILURE;
	}
	return 0;
}

summary

在使用sdk时候,有个小细节要注意,我用的是18.3版本的sdk,在每次编写代码完成后要点一下保存才会将之前的内容覆盖,也就是该版本的SDK,编译前不会自动保存刚刚写好的代码,这一点需要注意。

因为本次只是进行模拟实验,所以没有实验效果的反馈图,也不知道具体在启用读iic数据的正确性,往后再学习一些后,我将会使用ps和pl交互的管脚进行重跑本次实验。

更新配置EMIO后成功进行了传感器数据的读取。
在这里插入图片描述