之前发帖:
【瑞萨RA4系列开发板体验】1. 新建工程+按键控制LED
【瑞萨RA4系列开发板体验】2. KEIL环境搭建+STLINK调试+FreeRTOS使用
【瑞萨RA4系列开发板体验】3. KEIL下UART实现printf与scanf重定向
【瑞萨RA4系列开发板体验】4. PWM驱动LED
【瑞萨RA4系列开发板体验】5. 硬件IIC驱动OLED显示汉字
前言
本文的目的在与测试一下RA4M2的ADC功能,我会用一个摇杆模块来测试两路ADC的采集情况,本文实现如下功能:
- 本文基于KEIL开发环境;
- OLED会显示ADC的采集信息(OLED显示不是本文重点,请参考我上一篇文章);
- 摇杆模块有两路ADC信号,一路用于显示X轴,一路用于显示Y轴,用于表示当前摇杆所处的位置。
本文中实用到了所有驱动都能在我之前的文章中找到使用方法,有需要请参考。
硬件连接
查看原理图,了解芯片的ADC引脚的映射关系,我们才能接下来的工作。
RA4M2只有一路ADC,但是有很多通道。
本文中用到了ADC通道AN000以及AN001,分别连接到了P000引脚与P001引脚,如下图。
RASC配置
知道了ADC的引脚映射关系,接下来就开始我们的驱动配置了,打开RASC,打开方式不细说,请参考我之前的文章。
使能ADC
如下图,选中Pins->Analog:ADC,使能ADC0,并且使能AN000以及AN001,如果需要使能其他的ADC,直接选中相应的引脚使能即可。
ADC详细配置
使能了ADC引脚之后,开始配置ADC具体的采样功能,本文只进行了最基础的配置,其他的使用功能需要自行开发,如下图,新建ADC Stack。
因为单片机只提供了一路ADC,这里需要将Unit写为0,使用12bit采样方式,右对齐,按照默认即可。
输入选择使能Channel0以及Channel1.
输入回调函数的名字,这个函数需要我们自己实现。最后配置映射端口,其实无需我们自己编写会自动匹配。
代码实现
我新建了一个app_adc.c以及app_adc.h,代码实现逻辑不细说,瑞萨已经封装的很好了,理解起来很简单。
app_adc.c
该文件中实现了adc的回调函数的实现,初始化,ADC开始转换函数,ADC转换状态获取,ADC转换结果获取。
这些函数都是我再封装了一层,主要是为了使用起来方便。下面说一下调用关系:
- 初始化,不细说,系统上电的时候需要做的工作;
- 在循环中作如下操作:
- 调用Adc_StartSample启动ADC转换;
- 调用Adc_ReadChannel获取ADC转换结果;
- 如果转换结果反馈状态为ADC_COMPLETED,则调用Adc_ReadChannel获取ADC转换结果。
#include "hal_data.h"
#include "app_adc.h"
#include <stdio.h>
volatile bool adc_scan_complete_flag = false;
volatile bool last_adc_scan_flag = true;
void adc_notification(adc_callback_args_t * p_args)
{
(void)p_args;
adc_scan_complete_flag = true;
}
void Adc_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_ADC_Open(&g_adc0_ctrl, &g_adc0_cfg);
assert(FSP_SUCCESS == err);
err = R_ADC_ScanCfg(&g_adc0_ctrl, &g_adc0_channel_cfg);
assert(FSP_SUCCESS == err);
}
void Adc_StartSample(void)
{
if (false == adc_scan_complete_flag)
{
(void)R_ADC_ScanStart(&g_adc0_ctrl);
}
}
e_Adc_StatusType Adc_GetStatus(void)
{
if (true == adc_scan_complete_flag)
{
return ADC_COMPLETED;
}
else
{
return ADC_ONGOING;
}
}
uint16_t Adc_ReadChannel(adc_channel_t channel)
{
fsp_err_t err = FSP_SUCCESS;
uint16_t adc_value;
err = R_ADC_Read(&g_adc0_ctrl, channel, &adc_value);
assert(FSP_SUCCESS == err);
adc_scan_complete_flag = false;
return adc_value;
}
app_adc.h
#ifndef APP_ADC_H_
#define APP_ADC_H_
#include "stdint.h"
#include "hal_data.h"
typedef enum
{
ADC_COMPLETED = 0,
ADC_ONGOING
} e_Adc_StatusType;
extern void Adc_Init(void);
extern void Adc_StartSample(void);
extern e_Adc_StatusType Adc_GetStatus(void);
extern uint16_t Adc_ReadChannel(adc_channel_t channel);
#endif
主函数实现
没100毫秒采集一次ADC信息,并通过OLED显示出来X,Y坐标的偏移量,显示的是原ADC采样值,没有做计算处理。
void hal_entry(void)
{
char adc_str[16];
Uart_Init();
I2c_Init();
OLED_Init();
Adc_Init();
Dac_Init();
OLED_ShowString(12, 0, (const uint8_t*)"R7FA4M2AD3CFP", 16, 1);
OLED_ShowString(0, 16, (const uint8_t*)"elecfans", 16, 1);
OLED_ShowString(64, 16, (const uint8_t*)"|hehung", 16, 1);
OLED_Refresh_Gram();
while (1)
{
Adc_StartSample();
while (ADC_COMPLETED != Adc_GetStatus())
{}
sprintf(adc_str, "ADC X: %04d", Adc_ReadChannel(ADC_CHANNEL_0));
OLED_ShowString(0, 32, (const uint8_t*)adc_str, 16, 1);
sprintf(adc_str, "ADC Y: %04d", Adc_ReadChannel(ADC_CHANNEL_1));
OLED_ShowString(0, 48, (const uint8_t*)adc_str, 16, 1);
OLED_Refresh_Gram();
R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
}
#if BSP_TZ_SECURE_BUILD
R_BSP_NonSecureEnter();
#endif
}
显示效果
视频演示效果见文章末尾视频