之前发帖:
【瑞萨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的采集情况,本文实现如下功能:
本文中实用到了所有驱动都能在我之前的文章中找到使用方法,有需要请参考。
查看原理图,了解芯片的ADC引脚的映射关系,我们才能接下来的工作。
RA4M2只有一路ADC,但是有很多通道。
本文中用到了ADC通道AN000以及AN001,分别连接到了P000引脚与P001引脚,如下图。
知道了ADC的引脚映射关系,接下来就开始我们的驱动配置了,打开RASC,打开方式不细说,请参考我之前的文章。
如下图,选中Pins->Analog:ADC,使能ADC0,并且使能AN000以及AN001,如果需要使能其他的ADC,直接选中相应的引脚使能即可。
使能了ADC引脚之后,开始配置ADC具体的采样功能,本文只进行了最基础的配置,其他的使用功能需要自行开发,如下图,新建ADC Stack。
因为单片机只提供了一路ADC,这里需要将Unit写为0,使用12bit采样方式,右对齐,按照默认即可。
输入选择使能Channel0以及Channel1.
输入回调函数的名字,这个函数需要我们自己实现。最后配置映射端口,其实无需我们自己编写会自动匹配。
我新建了一个app_adc.c以及app_adc.h,代码实现逻辑不细说,瑞萨已经封装的很好了,理解起来很简单。
该文件中实现了adc的回调函数的实现,初始化,ADC开始转换函数,ADC转换状态获取,ADC转换结果获取。
这些函数都是我再封装了一层,主要是为了使用起来方便。下面说一下调用关系:
/*
@hehung
2022-12-01
*/
#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;
/* Callback function of ADC */
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;
/* Initializes the adc. */
err = R_ADC_Open(&g_adc0_ctrl, &g_adc0_cfg);
/* Handle any errors. This function should be defined by the user. */
assert(FSP_SUCCESS == err);
/* Enable channels. */
err = R_ADC_ScanCfg(&g_adc0_ctrl, &g_adc0_channel_cfg);
assert(FSP_SUCCESS == err);
}
/* ADC sampling */
void Adc_StartSample(void)
{
if (false == adc_scan_complete_flag)
{
/* Enable scan triggering from ELC events. */
(void)R_ADC_ScanStart(&g_adc0_ctrl);
}
}
/* Get ADC sampling status */
e_Adc_StatusType Adc_GetStatus(void)
{
if (true == adc_scan_complete_flag)
{
return ADC_COMPLETED;
}
else
{
return ADC_ONGOING;
}
}
/* Read conversion result */
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);
// printf ("ADC%d: %d\n", channel, adc_value);
adc_scan_complete_flag = false;
return adc_value;
}
/*
@hehung
2022-12-01
*/
#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];
/* Initialize the uart for implement the 'printf' and 'scanf' */
Uart_Init();
/* Initialize the os and some tasks */
// Task_Create();
/* Initialize the I2c */
I2c_Init();
/* Initialize the OLED */
OLED_Init();
/* Initialize the ADC */
Adc_Init();
/* Initialize the DAC */
Dac_Init();
OLED_ShowString(12, 0, (const uint8_t*)"R7FA4M2AD3CFP", 16, 1);
// OLED_ShowHzStringRow(32, 24, (const char*)"电子发烧友", 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_OutputVal(DAC_DAC0, 2000);
// Adc_OutputVal(DAC_DAC1, 4000);
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
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
视频演示效果见文章末尾视频
更多回帖