【RA-Eco-RA6M4开发板评测】光照强度监测仪
# 【RA-Eco-RA6M4开发板评测】光照强度监测仪本文介绍了 RA-Eco-RA6M4-100PIN-V2.0 开发板通过 IIC 协议驱动 ADS1115 模块,并连接 TEMT6000 传感器模块,实现环境光照强度监测仪的项目设计,包括项目介绍、工程创建、参数配置、工程调试以及效果演示等。
## 项目介绍
- 模块设计:TEMT6000 传感器、ADS1115 模块、模块 PCB 设计、原理图;
- 准备工作:硬件连接、环境搭建;
- 工程测试:工程创建、工程配置、流程图、代码、编译上传、效果演示。
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215726iujx7lmpqyf6xzju.jpg)
## ADS1115 模块
ADS1115是一款由德州仪器推出的16位模拟数字转换器(ADC),支持I2C接口。工作电流仅为20μA,转换速率可在 8SPS 到 860SPS 之间自定义;支持 2.0V 到 5.5V 的宽电压输入。
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215440hb2cib520br243i2.jpg)
更多参数详见:(https://www.ti.com.cn/product/cn/ADS1115) .
原理图
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215415o60eeg0jgcw5lgeh.jpg)
PCB 项目详见:(https://oshwhub.com/jinleili/project_pemhgfob) .
### TEMT6000
TEMT6000是一个三极管类型的光敏传感器,其光照强度和基极的电流成正比。
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215353mzjdozi57r9srsg0.jpg)
详见:(https://www.vishay.com/en/product/81579/) .
## 硬件连接
使用杜邦线连接 ADS1115 模块与 RA6M4-Eco 开发板,接线方式如下
| ADS1115 | RA6M4 | Note |
| ------- | ----- | ------------ |
| SDA | P400| Serial Data|
| SCL | P401| Serial Clock |
| GND | GND | Ground |
| VCC | 3V3 | Power |
使用杜邦线连接 ADS1115 模块和 TEMT6000 传感器模块,接线方式如下
| TEMT6000 | ADS1115 | Note |
| -------- | ------- | ------ |
| S | A0 | Signal |
| G | A- | Ground |
| V | A+ | Power|
使用杜邦线连接 JLINK-OB 和 RA6M4,实现工程调试、固件上传、串口通信,接线方式如下
| Jlink-OB | RA6M4 | Note |
| :------- | :--------- | :-------- |
| DIO | SWDIO | Data I/O|
| CLK | SWCLK | Clock |
| RXD | TXD (P109) | Transmite |
| TXD | RXD (P110) | Receive |
| GND | GND | Ground |
| 3V3 | VCC | Power |
实物图
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215458p0upb4muvhz6iybv.jpg)
自制 JLINK-OB 工程详见:(https://oshwhub.com/jinleili/j-link-ob-gai-jin-ban) .
## 环境搭建
搭建和使用 e^2^ studio IDE 开发环境。
- 下载并安装 [瑞萨FSP (flexible software package) 灵活配置软件包](https://www.renesas.cn/zh/software-tool/flexible-software-package-fsp) ;
- 安装时注意选择 GNU ARM 工具链;
## 工程创建
- 文件 - 新建 - 瑞萨 C/C++ 项目 - `Renesas RA ` ;
- 自定义设备选择 `R7FA6M4AF3CFP` ,调试器选择 J-Link ;
- 项目创建完成后,选择进入透视图模式;
## 工程配置
工程配置包括引脚时钟配置、串口配置、IIC 配置。
### 时钟配置
根据原理图可知,板载 XTAL 晶振频率为 12MHz,需要重新配置 IDE 时钟树。
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215514c0kx107dl8llz0pn.jpg)
### 串口配置
- 进入 FSP 配置界面,打开 Pins 标签页,根据原理图,板载 CH340 对应串口引脚为 P109 和 P110,因此将 SCI9 配置为异步串口模式;
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215533ke401ejl1yq6gllj.jpg)
- 打开 `Stacks` 标签页,新建串口通信堆栈 `New Stack` - `Connectivity` - `UART (r_sci_uart)` ;
- 串口属性配置,General 标签下的 Channel 改为 9,名称改为 `g_uart9`,中断回调函数命名为 `user_uart9_callback`;
- 进入 BSP 标签页,配置 RA Common 属性,RA Common 标签下的 Heap size 改为 `0x2000`;
详见:[瑞萨RA-Eco-RA6M4评测 - 介绍、环境搭建、工程测试](//m.qjumbo.com/forum/thread-235881-1-1.html) .
### IIC 配置
- 打开 `Stacks` 标签页,新建硬件 IIC 总线堆栈 `New Stack` - `Connectivity` - `IIC Master (r_iic_master)` ;
- IIC 属性配置,Module 标签下的 Channel 设置为 0,名称为 `g_i2c_master0`,地址 `0x48`,中断回调函数命名为 `IIC_master_callback`;
- 检查引脚定义 SCL0 对应 P400,SDA0 对应 P401 ;
- 由原理图可知,P400 和 P401 引脚位于 PMOD1 接口,且 P400 需要将 SB13 短接,或使用 0603 封装的 0Ω 电阻焊接;
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215552iy36ydmlm6tgdgy3.jpg)
- 点击 `Generate Project Content` ;
- 右键项目文件夹,构建工程,确认无报错;
## 流程图
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215611ojf0c55000ee9am5.jpg)
## 工程代码
包括主程序和 ADS1115 传感器驱动程序。
### 主程序
打开 `./src/hal_entry.c` 文件,添加如下代码
```c++
#include "hal_data.h"
#include "ads1115.h"
#include <stdio.h>
/********************************
* UART Configurations
* see
* //m.qjumbo.com/forum/thread-235881-1-1.html
* for details
********************************/
/* 全局ADS1115句柄 */
static ads1115_handle_t g_ads1115;
// I2C Callback
i2c_master_event_t i2c_event = I2C_MASTER_EVENT_ABORTED;
void IIC_master_callback(i2c_master_callback_args_t *p_args)
{
i2c_event = I2C_MASTER_EVENT_ABORTED;
if (NULL != p_args)
{
i2c_event = p_args->event;
}
}
void hal_entry(void)
{
/* TODO: add your own code here */
err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
assert(FSP_SUCCESS == err);
float voltage;
/* 初始化ADS1115,使用I2C0实例 */
err = ads1115_init(&g_ads1115, &g_i2c_master0, ADS1115_ADDR);
if (err != FSP_SUCCESS)
{
printf("ADS1115 init failed: %d\r\n", err);
while(1);
}
printf("RA6M4 + ADS1115 Module Driver Test\r\n");
printf("==================================\r\n");
#if 1/* 单次转换模式示例 */
printf("\r\n");
while (1)
{
/* 读取A0通道电压,PGA=±4.096V,128SPS */
err = ads1115_read_voltage(&g_ads1115, ADS1115_MUX_AIN0_GND, &voltage);
if (err == FSP_SUCCESS)
{
printf("A0 = %.4f V\r\n", voltage);
}
else
{
printf("Read error: %d\r\n", err);
}
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
}
}
```
保存文件。
### 驱动程序
在 `./src` 文件夹新建 `ads1115.h` 驱动头文件,添加如下代码
```c++
#ifndef ADS1115_H
#define ADS1115_H
#include "hal_data.h"
#include <stdint.h>
#include <stdbool.h>
/* ADS1115 I2C地址(ADDR引脚接GND) */
#define ADS1115_ADDR 0x48
/* ADS1115寄存器地址 */
#define ADS1115_REG_CONVERSION0x00
#define ADS1115_REG_CONFIG 0x01
#define ADS1115_REG_LO_THRESH 0x02
#define ADS1115_REG_HI_THRESH 0x03
/* 输入通道选择(MUX位) */
typedef enum
{
ADS1115_MUX_AIN0_AIN1 = 0x00,// 差分:A0 - A1
ADS1115_MUX_AIN0_AIN3 = 0x01,// 差分:A0 - A3
ADS1115_MUX_AIN1_AIN3 = 0x02,// 差分:A1 - A3
ADS1115_MUX_AIN2_AIN3 = 0x03,// 差分:A2 - A3
ADS1115_MUX_AIN0_GND= 0x04,// 单端:A0
ADS1115_MUX_AIN1_GND= 0x05,// 单端:A1
ADS1115_MUX_AIN2_GND= 0x06,// 单端:A2
ADS1115_MUX_AIN3_GND= 0x07,// 单端:A3
} ads1115_mux_t;
/* PGA量程配置 */
typedef enum
{
ADS1115_PGA_6_144V = 0x00,// ±6.144V, LSB = 187.5uV
ADS1115_PGA_4_096V = 0x01,// ±4.096V, LSB = 125uV
ADS1115_PGA_2_048V = 0x02,// ±2.048V, LSB = 62.5uV (默认)
ADS1115_PGA_1_024V = 0x03,// ±1.024V, LSB = 31.25uV
ADS1115_PGA_0_512V = 0x04,// ±0.512V, LSB = 15.625uV
ADS1115_PGA_0_256V = 0x05,// ±0.256V, LSB = 7.8125uV
} ads1115_pga_t;
/* 数据速率 */
typedef enum
{
ADS1115_DR_8SPS = 0x00,
ADS1115_DR_16SPS= 0x01,
ADS1115_DR_32SPS= 0x02,
ADS1115_DR_64SPS= 0x03,
ADS1115_DR_128SPS = 0x04,// 默认
ADS1115_DR_250SPS = 0x05,
ADS1115_DR_475SPS = 0x06,
ADS1115_DR_860SPS = 0x07,
} ads1115_dr_t;
/* 工作模式 */
typedef enum
{
ADS1115_MODE_CONTINUOUS = 0x00,
ADS1115_MODE_SINGLE = 0x01,
} ads1115_mode_t;
/* 设备句柄 */
typedef struct
{
i2c_master_instance_t const * p_i2c; // I2C实例指针
uint8_t addr; // I2C地址
ads1115_pga_t pga; // 当前PGA配置
ads1115_dr_t dr; // 当前数据速率
} ads1115_handle_t;
/* 初始化与反初始化 */
fsp_err_t ads1115_init(ads1115_handle_t * p_handle, i2c_master_instance_t const * p_i2c, uint8_t addr);
fsp_err_t ads1115_deinit(ads1115_handle_t * p_handle);
/* 配置 */
fsp_err_t ads1115_set_config(ads1115_handle_t * p_handle, ads1115_mux_t mux, ads1115_pga_t pga,
ads1115_dr_t dr, ads1115_mode_t mode);
/* 单次转换读取 */
fsp_err_t ads1115_read_single(ads1115_handle_t * p_handle, ads1115_mux_t channel, int16_t * p_raw);
fsp_err_t ads1115_read_voltage(ads1115_handle_t * p_handle, ads1115_mux_t channel, float * p_voltage);
/* 连续转换模式 */
fsp_err_t ads1115_start_continuous(ads1115_handle_t * p_handle, ads1115_mux_t channel);
fsp_err_t ads1115_read_continuous(ads1115_handle_t * p_handle, int16_t * p_raw);
fsp_err_t ads1115_read_continuous_voltage(ads1115_handle_t * p_handle, float * p_voltage);
/* 原始值转电压 */
float ads1115_raw_to_voltage(int16_t raw, ads1115_pga_t pga);
/* 获取转换时间(ms) */
uint16_t ads1115_get_conversion_time_ms(ads1115_dr_t dr);
#endif /* ADS1115_H */
```
保存文件。
#### 源文件
在 `./src` 文件夹新建 `ads1115.c` 驱动源文件,并添加如下代码
```c++
#include "ads1115.h"
#include <string.h>
/* 内部缓冲区 */
static uint8_tg_tx_buffer;
static uint8_tg_rx_buffer;
static volatile bool g_i2c_complete = false;
static i2c_master_event_t g_i2c_event;
/* 内部I2C回调 */
static void ads1115_i2c_callback(i2c_master_callback_args_t *p_args)
{
g_i2c_event = p_args->event;
g_i2c_complete = true;
}
/* 等待I2C传输完成 */
static fsp_err_t ads1115_wait_complete(uint32_t timeout_us)
{
uint32_t timeout = timeout_us;
while (!g_i2c_complete)
{
if (--timeout == 0)
{
return FSP_ERR_TIMEOUT;
}
}
g_i2c_complete = false;
return FSP_SUCCESS;
}
/* 写寄存器 */
static fsp_err_t ads1115_write_reg(ads1115_handle_t * p_handle, uint8_t reg, uint16_t value)
{
fsp_err_t err;
g_tx_buffer = reg;
g_tx_buffer = (uint8_t)(value >> 8); // MSB first
g_tx_buffer = (uint8_t)(value & 0xFF);// LSB
err = p_handle->p_i2c->p_api->write(p_handle->p_i2c->p_ctrl, g_tx_buffer, 3, false);
if (err != FSP_SUCCESS) return err;
err = ads1115_wait_complete(100000);
if (err != FSP_SUCCESS) return err;
return (g_i2c_event == I2C_MASTER_EVENT_TX_COMPLETE) ? FSP_SUCCESS : FSP_ERR_ABORTED;
}
/* 读寄存器 */
static fsp_err_t ads1115_read_reg(ads1115_handle_t * p_handle, uint8_t reg, uint16_t * p_value)
{
fsp_err_t err;
/* 写寄存器地址(带restart) */
g_tx_buffer = reg;
err = p_handle->p_i2c->p_api->write(p_handle->p_i2c->p_ctrl, g_tx_buffer, 1, true);
if (err != FSP_SUCCESS) return err;
err = ads1115_wait_complete(100000);
if (err != FSP_SUCCESS) return err;
/* 读2字节数据 */
err = p_handle->p_i2c->p_api->read(p_handle->p_i2c->p_ctrl, g_rx_buffer, 2, false);
if (err != FSP_SUCCESS) return err;
err = ads1115_wait_complete(100000);
if (err != FSP_SUCCESS) return err;
if (g_i2c_event != I2C_MASTER_EVENT_RX_COMPLETE)
{
return FSP_ERR_ABORTED;
}
*p_value = ((uint16_t)g_rx_buffer << 8) | g_rx_buffer;
return FSP_SUCCESS;
}
/* 构建配置寄存器值 */
static uint16_t ads1115_build_config(ads1115_mux_t mux, ads1115_pga_t pga, ads1115_dr_t dr,
ads1115_mode_t mode, bool start_conversion)
{
uint16_t config = 0;
if (start_conversion)
{
config |= (1U << 15);// OS = 1, 启动单次转换
}
config |= ((uint16_t)mux & 0x07) << 12; // MUX
config |= ((uint16_t)pga & 0x07) << 9; // PGA
config |= ((uint16_t)mode & 0x01) << 8; // MODE
config |= ((uint16_t)dr & 0x07) << 5; // DR
config |= (0x03U << 0); // CQUE = 11, 禁用比较器
return config;
}
/* 初始化 */
fsp_err_t ads1115_init(ads1115_handle_t * p_handle, i2c_master_instance_t const * p_i2c, uint8_t addr)
{
fsp_err_t err;
if (p_handle == NULL || p_i2c == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
memset(p_handle, 0, sizeof(ads1115_handle_t));
p_handle->p_i2c = p_i2c;
p_handle->addr= addr;
p_handle->pga = ADS1115_PGA_2_048V;// 默认
p_handle->dr = ADS1115_DR_128SPS; // 默认
/* 打开I2C */
err = p_i2c->p_api->open(p_i2c->p_ctrl, p_i2c->p_cfg);
if (err != FSP_SUCCESS) return err;
/* 设置回调 */
err = p_i2c->p_api->callbackSet(p_i2c->p_ctrl, ads1115_i2c_callback, NULL, NULL);
if (err != FSP_SUCCESS) return err;
return FSP_SUCCESS;
}
/* 反初始化 */
fsp_err_t ads1115_deinit(ads1115_handle_t * p_handle)
{
if (p_handle == NULL || p_handle->p_i2c == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
return p_handle->p_i2c->p_api->close(p_handle->p_i2c->p_ctrl);
}
/* 设置配置 */
fsp_err_t ads1115_set_config(ads1115_handle_t * p_handle, ads1115_mux_t mux, ads1115_pga_t pga,
ads1115_dr_t dr, ads1115_mode_t mode)
{
fsp_err_t err;
uint16_t config;
if (p_handle == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
p_handle->pga = pga;
p_handle->dr= dr;
config = ads1115_build_config(mux, pga, dr, mode, false);
err = ads1115_write_reg(p_handle, ADS1115_REG_CONFIG, config);
return err;
}
/* 单次转换读取原始值 */
fsp_err_t ads1115_read_single(ads1115_handle_t * p_handle, ads1115_mux_t channel, int16_t * p_raw)
{
fsp_err_t err;
uint16_t config;
uint16_t raw_u16;
if (p_handle == NULL || p_raw == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
/* 构建配置并启动转换 */
config = ads1115_build_config(channel, p_handle->pga, p_handle->dr, ADS1115_MODE_SINGLE, true);
err = ads1115_write_reg(p_handle, ADS1115_REG_CONFIG, config);
if (err != FSP_SUCCESS) return err;
/* 等待转换完成 */
R_BSP_SoftwareDelay(ads1115_get_conversion_time_ms(p_handle->dr), BSP_DELAY_UNITS_MILLISECONDS);
/* 读取结果 */
err = ads1115_read_reg(p_handle, ADS1115_REG_CONVERSION, &raw_u16);
if (err != FSP_SUCCESS) return err;
*p_raw = (int16_t)raw_u16;
return FSP_SUCCESS;
}
/* 单次转换读取电压 */
fsp_err_t ads1115_read_voltage(ads1115_handle_t * p_handle, ads1115_mux_t channel, float * p_voltage)
{
fsp_err_t err;
int16_t raw;
err = ads1115_read_single(p_handle, channel, &raw);
if (err != FSP_SUCCESS) return err;
*p_voltage = ads1115_raw_to_voltage(raw, p_handle->pga);
return FSP_SUCCESS;
}
/* 启动连续转换模式 */
fsp_err_t ads1115_start_continuous(ads1115_handle_t * p_handle, ads1115_mux_t channel)
{
uint16_t config;
if (p_handle == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
config = ads1115_build_config(channel, p_handle->pga, p_handle->dr, ADS1115_MODE_CONTINUOUS, false);
return ads1115_write_reg(p_handle, ADS1115_REG_CONFIG, config);
}
/* 连续模式读取原始值 */
fsp_err_t ads1115_read_continuous(ads1115_handle_t * p_handle, int16_t * p_raw)
{
fsp_err_t err;
uint16_t raw_u16;
if (p_handle == NULL || p_raw == NULL)
{
return FSP_ERR_INVALID_ARGUMENT;
}
err = ads1115_read_reg(p_handle, ADS1115_REG_CONVERSION, &raw_u16);
if (err != FSP_SUCCESS) return err;
*p_raw = (int16_t)raw_u16;
return FSP_SUCCESS;
}
/* 连续模式读取电压 */
fsp_err_t ads1115_read_continuous_voltage(ads1115_handle_t * p_handle, float * p_voltage)
{
fsp_err_t err;
int16_t raw;
err = ads1115_read_continuous(p_handle, &raw);
if (err != FSP_SUCCESS) return err;
*p_voltage = ads1115_raw_to_voltage(raw, p_handle->pga);
return FSP_SUCCESS;
}
/* 原始值转电压 */
float ads1115_raw_to_voltage(int16_t raw, ads1115_pga_t pga)
{
float lsb;
switch (pga)
{
case ADS1115_PGA_6_144V: lsb = 0.0001875f; break;
case ADS1115_PGA_4_096V: lsb = 0.000125f; break;
case ADS1115_PGA_2_048V: lsb = 0.0000625f;break;
case ADS1115_PGA_1_024V: lsb = 0.00003125f; break;
case ADS1115_PGA_0_512V: lsb = 0.000015625f; break;
case ADS1115_PGA_0_256V: lsb = 0.0000078125f; break;
default: lsb = 0.0000625f;break;
}
return (float)raw * lsb;
}
/* 获取转换时间(ms),留有余量 */
uint16_t ads1115_get_conversion_time_ms(ads1115_dr_t dr)
{
switch (dr)
{
case ADS1115_DR_8SPS: return 130;
case ADS1115_DR_16SPS:return 70;
case ADS1115_DR_32SPS:return 35;
case ADS1115_DR_64SPS:return 20;
case ADS1115_DR_128SPS: return 12;
case ADS1115_DR_250SPS: return 6;
case ADS1115_DR_475SPS: return 4;
case ADS1115_DR_860SPS: return 3;
default: return 12;
}
}
```
保存文件。
## 工程编译
- 右键项目文件夹,选择 `属性` ,进入 `C/C++ 构建` - `设置` 选项;
- 进入 `GNU Arm Cross Create Flash Image - General` 选项;
- 在输出格式中选择 `Intel HEX` ,应用并关闭;
- 右键项目文件夹,构建工程,确认无报错;
- 查看工程目录下的 `Debug` 文件夹,生成相应的 HEX 格式的固件;
## 固件上传
开发板支持串口烧录、J-Link、EZ-Cube 调试器烧录等,这里使用 JLINK-OB 调试工程。
- 点击工具栏的小虫子 Debug 按钮,进入调试界面;
- 或右键项目文件夹,选择调试配置,选中当前项目对应的 elf 文件,调试工具为 JLINK,开始调试;
- 进入调试界面,点击菜单栏的运行按钮,程序开始执行;
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215639nl60wz1z1o0szguz.jpg)
使用 USB 烧录固件的方案详见:[瑞萨RA-Eco-RA6M4评测 - 介绍、环境搭建、工程测试](//m.qjumbo.com/forum/thread-235881-1-1.html) .
## 效果演示
- 运行串口调试助手软件,连接 Jlink CDC 虚拟串口,配置波特率等参数;
- 打开串口,接收 A0 电压数据;
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215653upmyhxhsvmzmp1yb.gif)
- 串口打印 A0 电压和 TEMT6000 光照强度数据;
!(//m.qjumbo.com/forum/data/attachment/forum/202607/20/215708f1uxzl323lx5llx8.jpg)
## 总结
本文介绍了 RA-Eco-RA6M4-100PIN-V2.0 开发板通过 IIC 协议驱动 ADS1115 模块,并连接 TEMT6000 传感器模块,实现环境光照强度监测仪的项目设计,包括项目介绍、工程创建、参数配置、工程调试以及效果演示等,为相关产品的快速开发和应用设计提供了参考。
页:
[1]