OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 87|回复: 0

《ESP32-P4开发指南— V1.0》第三十三章 AP3216C实验

[复制链接]

1246

主题

1260

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5354
金钱
5354
注册时间
2019-5-8
在线时间
1377 小时
发表于 前天 09:35 | 显示全部楼层 |阅读模式
第三十三章 AP3216C实验

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

33.1 AP3216C介绍
AP3216C是敦南科技推出的一款三合一环境传感器, 包含了:数字环境光传感器(ALS)、接近传感器(PS)和一个红外LED(IR)。该芯片通过IIC接口和MCU连接,并支持中断(INT)输出。AP3216C实物图如下图所示:

第三十三章 AP3216C实验283.png
图33.1.1 AP3216C实物图

AP3216C的特点如下:
·IIC接口,支持高达400KHz通信速率
·支持多种工作模式(ALS、PS+IR、ALS+PS+IR等)
·内置温度补偿电路
·工作温度支持-30~80℃
·环境光传感器具有16位分辨率
·接近传感器具有10位分辨率
·红外传感器具有10位分辨率
·超小封装(4.1*2.4*1.35mm)
因为以上一些特性,AP3216C被广泛应用于智能手机上面,用来检测光强度(自动背光控制),和接近开关控制(听筒靠近耳朵,手机自动灭屏功能)。
AP3216C的框图如下图所示。


第三十三章 AP3216C实验553.png
图33.1.2 AP3216C框图

AP3216C的引脚说明如下表所示。

1.png
表33.1.1 AP3216C引脚说明

AP3216C和主控芯片只需要连接SCL、SDA和INT,就可以实现驱动。其SCL和SDA同24C02、XL9555共用,连接在IO32和IO33上,INT脚连接在XL9555的IO1_3上。

33.1.1 AP3216C寻址
要进行IIC通信,首先得知道器件地址,AP3216C器件地址是7位的,具体格式如下表。

2.png
表33.1.1.1 AP3216C地址格式

AP3216C器件地址为“0011110”即0x1E。读操作地址就为0x3D(0x1E << 1 | 0x1),即0011 1101;写操作地址就为0x3C(0x1E << 1 | 0x0),即0011 1100。

33.1.2 AP3216C寄存器介绍
AP3216C有一系列寄存器,由这些寄存器来控制AP3216C的工作模式,以及中断配置和数据输出等。这里我们仅介绍在本章需要用到的一些寄存器,其他寄存器的描述和说明,请大家参考AP3216C的数据手册。本章需要用到AP3216C的寄存器如下表所示。

3.png
表33.1.2.1 AP3216C相关寄存器及其说明

上表中,0X00是一个系统模式控制寄存器,主要在初始化的时候配置,初始化的时候,我们先设置其值为100,实行一次软复位,随后设置其值为011,开启ALS+PS+IR检测功能。
剩下的6个寄存器为数据寄存器,输出AP3216C内部三个传感器所检测到的数据(ADC值),并且还存在数据有效位以便判断寄存器的数据是否是有效的,描述如上表所示。
这里需要注意的是:读取间隔至少要大于112.5ms,因为,AP3216C内部完成一次ALS+PS+IR的数据转换,需要112.5ms的时间。

33.1.3 AP3216C时序介绍
ESP32-P4是通过IIC总线跟AP3216C进行通信的,对AP3216C相关寄存器进行写入配置,后面就是对相关数据寄存器进行读取。这里的时序主要就是写寄存器时序和读寄存器时序,我们一一介绍。
写寄存器时序
AP3216C的写寄存器时序如下图所示。

第三十三章 AP3216C实验2072.png
图33.1.3.1 AP3216C写寄存器时序

图中,先发送AP3216C的写操作地址0x3C(器件地址0X1E << 1 | 读写位0x0),随后发送8位寄存器地址,最后发送8位寄存器值。其中:S,表示IIC起始信号;W,表示读/写标志位(W=0表示写,W=1表示读);A,表示应答信号;P,表示IIC停止信号。
读寄存器时序图
AP3216C的读寄存器时序如下图所示。


第三十三章 AP3216C实验2261.png
图33.1.3.2 AP3216C读寄存器时序

图中,同样是先发送AP3216C的写操作地址0x3C,然后再发送寄存器地址,随后,重新发送起始信号(Sr),发送AP3216C的读操作地址0x3D(器件地址0X1E << 1 | 读写位0x1),然后读取寄存器值。其中:Sr,表示重新发送IIC起始信号;N,表示不对AP3216C进行应答;其他简写同上。
AP3216C的简介,我们就介绍到这里,关于该芯片的详细说明,请大家参考其数据手册。

33.2 硬件设计

33.2.1 例程功能
开机的时候先检测AP3216C是否存在,如检测不到AP3216C,则在LCD屏上面显示报错信息。如果检测到AP3216C,则显示正常,并在主循环里面,循环读取ALS+PS+IR的传感器数据,并显示在LCD屏幕上面。

33.2.2 硬件资源
1)LED灯
        LED        0        - IO51
2)RGBLCD / MIPILCD(引脚太多,不罗列出来)
3)AP3216C
        IIC_INT        - EXIO_11(XL9555)
        IIC_SDA        - IO33
        IIC_SCL        - IO32

33.2.3 原理图
AP3216C相关原理图,如下图所示。

第三十三章 AP3216C实验2775.png
图33.2.3.1 AP3216C原理图

这里说明一下,AP3216C的AP_INT脚是连接在XL9555器件的IO1_3脚上,如果大家要使用AP3216C的中断输出功能,必须先初始化XL9555器件并配置IO1_3为输入功能,监测XL9555中断引脚是否有中断产生。若发现有中断产生,则判断是否是IO1_3导致的,从而检测到AP3216C的中断。在本章中,并没有用到AP3216C中断功能,所以没有对XL9555器件的IO1_3做设置。

33.3 程序设计
IIC外设驱动已经在第十九章19.3.1小节做了说明,这里就不再赘述了。

33.3.1 程序流程图

第三十三章 AP3216C实验3083.png
图33.3.1.1 AP3216C实验程序流程图

33.3.2 程序解析
在24_ap3216c例程中,作者在24_ap3216c\components\BSP路径下新建了1个文件夹AP3216C,并且需要更改CMakeLists.txt内容,以便在其他文件上调用。
1. AP3216C驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。AP3216C驱动源码包括两个文件:ap3216c.c和ap3216c.h。
下面我们先解析ap3216c.h的程序。对AP3216C的中断引脚读取和器件地址做了相关定义。
  1. <font size="3">#define AP3216C_INT     xl9555_pin_read(AP_INT_IO)                /* 读取AP3216C中断状态 */</font>
  2. <font size="3">#define AP3216C_ADDR    0X1E                                 /* AP3216C器件地址 */</font>
复制代码
AP3216C的器件地址为0x1E,AP3216C_INT宏可读取AP3216C传感器的中断状态。
下面我们再解析ap3216c.cpp的程序,首先先来看一下初始化函数ap3216c_init,代码如下:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief            初始化AP3216C</font>
  3. <font size="3"> * [url=home.php?mod=space&uid=271674]@param[/url]            无</font>
  4. <font size="3"> * @retval            ESP_OK:初始化成功; ESP_FAIL:初始化失败</font>
  5. <font size="3"> */</font>
  6. <font size="3">esp_err_t ap3216c_init(void)</font>
  7. <font size="3">{</font>
  8. <font size="3">    uint8_t temp = 0x00;</font>

  9. <font size="3">    /* 未调用myiic_init初始化IIC */</font>
  10. <font size="3">    if (bus_handle == NULL)</font>
  11. <font size="3">    {</font>
  12. <font size="3">        ESP_ERROR_CHECK(myiic_init());</font>
  13. <font size="3">    }</font>

  14. <font size="3">    i2c_device_config_t ap3216c_i2c_dev_conf = {</font>
  15. <font size="3">        .dev_addr_length = I2C_ADDR_BIT_LEN_7,        /* 从机地址长度 */</font>
  16. <font size="3">        .scl_speed_hz    = IIC_SPEED_CLK,            /* 传输速率 */</font>
  17. <font size="3">        .device_address  = AP3216C_ADDR,            /* 从机7位的地址 */</font>
  18. <font size="3">    };</font>
  19. <font size="3">    /* I2C总线上添加ap3216c设备 */</font>
  20. <font size="3">ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &ap3216c_i2c_dev_conf, </font>
  21. <font size="3">&ap3216c_handle));</font>

  22. <font size="3">    ap3216c_write_one_byte(0x00, 0X04);             /* 复位AP3216C */</font>
  23. <font size="3">    vTaskDelay(pdMS_TO_TICKS(50));                 /* AP3216C复位至少10ms */</font>
  24. <font size="3">    ap3216c_write_one_byte(0x00, 0X03);             /* 开启ALS、PS+IR */</font>
  25. <font size="3">    temp = ap3216c_read_one_byte(0X00);             /* 读取刚刚写进去的0X03 */</font>

  26. <font size="3">    if (temp == 0X03)</font>
  27. <font size="3">    {</font>
  28. <font size="3">        ESP_LOGI(ap3216c_tag, "AP3216C success!!!");</font>
  29. <font size="3">        return ESP_OK;                              /* AP3216C正常 */</font>
  30. <font size="3">    }</font>
  31. <font size="3">    else</font>
  32. <font size="3">    {</font>
  33. <font size="3">        ESP_LOGE(ap3216c_tag, "AP3216C init fail!!!");</font>
  34. <font size="3">        return ESP_FAIL;                            /* AP3216C失败 */</font>
  35. <font size="3">    }</font>
  36. <font size="3">}</font>
复制代码
在AT24C02初始化函数中,首先对ap3216c_i2c_dev_conf变量的成员进行赋值,设置AP3216C的地址长度、设备地址以及传输速率,然后调用i2c_master_bus_add_device函数对AP3216C设备进行初始化。初始化AP3216C后,通过调用ap3216c_write_one_byte对AP3216C进行软件复位,然后开启光强度ALS、接近距离PS和红外线强度IR功能检测。后面再通过调用该ap3216c_read_one_byte函数读一下刚刚写入的配置参数看是否正常写入,以此作为判断AP3216C是否正常的依据。
接下来,看一下前面提及到的向AP3216C寄存器写入数据的函数ap3216c_write_one_byte,代码如下。
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief           AP3216C写入一个字节</font>
  3. <font size="3"> * @param                  reg   :寄存器地址</font>
  4. <font size="3"> * @param             data  :要写入的数据</font>
  5. <font size="3"> * @retval            ESP_OK:写入成功; 其他异常</font>
  6. <font size="3"> */</font>
  7. <font size="3">static esp_err_t ap3216c_write_one_byte(uint8_t reg, uint8_t data)</font>
  8. <font size="3">{</font>
  9. <font size="3">    uint8_t *buf = malloc(2);</font>
  10. <font size="3">    if (buf == NULL)</font>
  11. <font size="3">    {</font>
  12. <font size="3">        ESP_LOGE(ap3216c_tag, "%s memory failed", __func__);</font>
  13. <font size="3">        return ESP_ERR_NO_MEM; </font>
  14. <font size="3">    }</font>

  15. <font size="3">    buf[0] = reg;                  </font>
  16. <font size="3">    buf[1] = data;</font>

  17. <font size="3">    esp_err_t ret = i2c_master_transmit(ap3216c_handle, buf, 2, -1);</font>

  18. <font size="3">    free(buf);</font>

  19. <font size="3">    return ret;</font>
  20. <font size="3">}</font>
复制代码
该函数的实现,主要调用i2c_master_transmit函数。在这里需要进行数据整合,把写入数据的目的地址和要写入的数据重新存放到一个buf。在这里需要注意存放顺序,写入数据的目的地址要在要写入数据的前面,这样子通过i2c_master_transmit函数发送出去的数据才符合AP3216C的写数据操作。
继续看一下读取AP3216C寄存器数据的函数ap3216c_read_one_byte,代码如下。
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief             AP3216C读取一个字节</font>
  3. <font size="3"> * @param             reg: 寄存器地址</font>
  4. <font size="3"> * @retval            读到的数据</font>
  5. <font size="3"> */</font>
  6. <font size="3">static uint8_t ap3216c_read_one_byte(uint8_t reg)</font>
  7. <font size="3">{</font>
  8. <font size="3">    uint8_t rec_data = 0;</font>
  9. <font size="3">    i2c_master_transmit_receive(ap3216c_handle, &#174;, 1, &rec_data, 1, -1);</font>
  10. <font size="3">    return rec_data;</font>
  11. <font size="3">}</font>
复制代码
该函数的实现主要调用i2c_master_transmit_receive函数。从AP3216C的reg内存地址处读出rec_data数据,作为函数返回值返回。
初始化好AP3216C传感器之后,就可以对其采集到的数据进行获取,实现这个读取过程的函数为ap3216c_read_data,代码如下。
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief             读取AP3216C的数据</font>
  3. <font size="3"> * [url=home.php?mod=space&uid=60778]@note[/url]              读取原始数据,包括ALS,PS和IR</font>
  4. <font size="3"> *                   如果同时打开ALS,IR+PS的话两次数据读取的时间间隔要大于112.5ms</font>
  5. <font size="3"> * @param             ir  :IR传感器值指针</font>
  6. <font size="3"> * @param             ps  <img src="static/image/smiley/default/tongue.gif" border="0" smilieid="7" alt=":P">S传感器值指针</font>
  7. <font size="3"> * @param             als :ALS传感器值指针</font>
  8. <font size="3"> * @retval            无</font>
  9. <font size="3"> */</font>
  10. <font size="3">void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als)</font>
  11. <font size="3">{</font>
  12. <font size="3">    uint8_t buf[6] = {0};</font>
  13. <font size="3">    uint8_t i;</font>

  14. <font size="3">    for (i = 0; i < 6; i++)</font>
  15. <font size="3">    {</font>
  16. <font size="3">        buf</font><span style="font-size: medium;"> =  ap3216c_read_one_byte(0X0A + i);  /* 循环读取所有传感器数据 */
  17.     }

  18.     if (buf[0] & 0X80)      /* IR_OF位为1,则数据无效 */
  19.     {
  20.         *ir = 0;   
  21.     }
  22.     else
  23.     {
  24.         *ir = ((uint16_t)buf[1] << 2) | (buf[0] & 0X03);        /* 读取IR传感器数据 */
  25.     }

  26.     *als = ((uint16_t)buf[3] << 8) | buf[2];                   /* 读取ALS传感器数据 */

  27.     if (buf[4] & 0x40)      /* IR_OF位为1,则数据无效 */
  28.     {
  29.         *ps = 0;   
  30.     }
  31.     else
  32. {        /* 读取PS传感器的数据 */
  33.         *ps = ((uint16_t)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F);   
  34.     }
  35. }</span>
复制代码
该函数用于读取AP3216C传感器的ALS+PS+IR数据。通过调用ap3216c_read_data函数读取相关寄存器的值,然后判断数据有效位,再整合得到IR值、ALS值、PS值。
2. CMakeLists.txt文件
本例程的功能实现主要依靠AP3216C驱动。要在main函数中,成功调用AP3216C文件中的内容,就得需要修改BSP文件夹下的CMakeLists.txt文件,修改如下:
  1. set(src_dirs
  2.                    LED
  3.                         LCD
  4.                         MYIIC
  5.                   AP3216C)

  6. set(include_dirs
  7.                   LED
  8.                         LCD
  9.                         MYIIC
  10.                   AP3216C)

  11. set(requires
  12.                    driver
  13.                    esp_lcd
  14.                    esp_common)

  15. idf_component_register(        SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

  16. component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
复制代码
3. main.c驱动代码
在main.c里面编写如下代码。
  1. void app_main(void)
  2. {
  3.     esp_err_t ret;
  4.     uint16_t ir, als, ps;

  5.     ret = nvs_flash_init();           /* 初始化NVS */
  6.     if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
  7.     {
  8.         ESP_ERROR_CHECK(nvs_flash_erase());
  9.         ESP_ERROR_CHECK(nvs_flash_init());
  10.     }

  11.     led_init();                             /* LED初始化 */
  12.     lcd_init();                             /* LCD屏初始化 */

  13.     lcd_show_string(30, 50, 200, 16, 16, "ESP32-P4", RED);
  14.     lcd_show_string(30, 70, 200, 16, 16, "AP3216C TEST", RED);
  15.     lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);

  16.     while (ap3216c_init())          /* 初始化AP3216C */
  17.     {
  18.         lcd_show_string(30, 110, 200, 16, 16, "AP3216C Check Failed!", RED);
  19.         vTaskDelay(pdMS_TO_TICKS(200));
  20.         lcd_fill(30, 110, 239, 126, WHITE);
  21.         vTaskDelay(pdMS_TO_TICKS(200));
  22.     }

  23.     lcd_show_string(30, 110, 200, 16, 16, "AP3216C Ready!", RED);
  24.     lcd_show_string(30, 130, 200, 16, 16, " IR:", RED);
  25.     lcd_show_string(30, 150, 200, 16, 16, " PS:", RED);
  26.     lcd_show_string(30, 170, 200, 16, 16, "ALS:", RED);

  27.     while(1)
  28.     {
  29.         ap3216c_read_data(&ir, &ps, &als);          /* 读取数据  */
  30.         lcd_show_num(62, 130, ir,  5, 16, BLUE);    /* 显示IR数据 */
  31.         lcd_show_num(62, 150, ps,  5, 16, BLUE);    /* 显示PS数据 */
  32.         lcd_show_num(62, 170, als, 5, 16, BLUE);    /* 显示ALS数据  */

  33.         LED0_TOGGLE();
  34.         vTaskDelay(pdMS_TO_TICKS(500));
  35.     }
  36. }
复制代码
在app_main函数中,设置一个while循环去初始化AP3216C,若AP3216C成功被初始化,程序便可往下执行。在while循环中每隔500毫秒调用ap3216c_read_data函数读取ALS+PS+IR的数据,并显示在LCD上面。LED灯每隔500毫秒状态翻转,实现闪烁效果。这里的延时时间设为500ms,以满足AP3216C的ALS+PS+IR的转换时间,确保了数据正常。

33.4 下载验证
将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。LCD显示的内容如下图所示:

第三十三章 AP3216C实验9384.png
图33.4.1 AP3216C实验程序运行效果图

我们可以用手遮挡/靠近AP3216C传感器,可以看到三个传感器的数据变化,说明我们的代码是正常工作的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-1-26 05:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表