【CW32饭盒派开发板试用体验】2. 使用扩展板串口UART3以及scanf重定向到串口
【CW32饭盒派开发板试用体验】3. 使用BTIM实现任务调度器
本文主要讲解如何使用ADC,板载了一个电位计连接到了PB00上,官方提供了示例工程,本文就不做过多说明了。
本文使用ADC采集摇杆模块的模拟量,摇杆的X轴与Y轴分别连接到了PA0和PA1。
见下图:
知道了硬件连接,本来想参考官方示例工程直接上手的,但是看了下源代码,发现只能对一个通道进行单次转换,what???我想着这与我所知道的其他ADC不一样的呀,不应该是ADC下面的很多通道都可以单独转换吗?
然后看了下用户手册,发现转换模式有很多,如下,示例工程使用的就是单通道转换模式,只不过官方库文件封装的不是很好,导致使用起来产生了歧义。
建议官方可以再优化一下库,目前这个ADC的库用起来确实不是很好用。
看到有连续工作模式,但是只能支持4个通道连续采样,我只使用两个通道,所以最终还是确定使用单通道转换,只不过每转换完一个通道再切换到另一个通道就可以了,稍微麻烦一点。
下面是ADC支持的通道以及对应的引脚,CW32F030只有一路ADC,但是支持12个通道,如下:
单通道转换的步骤如下,用户手册写的还是比较清晰,这点好评。
知道了硬件工作原理,接下来就是软件开发了,我使用的中断模式来采集ADC,因为使用polling模式连续采样两个通道的时候需要软件参与,会导致代码存在一些等待延时,效率底下,使用中断模式可以避免这点。
下面是adc相关代码:
/*
@hehung
2023-5-28
email: 1398660197@qq.com
wechat: hehung95
reproduced and please indicate the source @hehung
*/
#include "app_common.h"
#include "app_adc.h"
static ADC_SingleChTypeDef ADC_SingleInitStruct;
static uint16_t adc_result[2] = {0, 0};
static uint8_t adc_int_cnt = 0;
void Adc_Running(void)
{
ADC_SoftwareStartConvCmd(ENABLE);
printf ("%d, %d\r\n", adc_result[0], adc_result[1]);
}
void Adc_Init(void)
{
__RCC_ADC_CLK_ENABLE(); // ADC时钟使能
__RCC_GPIOA_CLK_ENABLE();
//配置ADC测试IO口
PA00_ANALOG_ENABLE();
PA01_ANALOG_ENABLE();
//配置ADC测试IO口
ADC_SingleInitStruct.ADC_DiscardEn = ADC_DiscardNull;
ADC_SingleInitStruct.ADC_InitStruct.ADC_AccEn = ADC_AccDisable; //转换结果累加不使能
ADC_SingleInitStruct.ADC_InitStruct.ADC_Align = ADC_AlignRight; //ADC转换结果右对齐
ADC_SingleInitStruct.ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div16; //PCLK
ADC_SingleInitStruct.ADC_InitStruct.ADC_DMAEn = ADC_DmaDisable; //关闭DMA传输
ADC_SingleInitStruct.ADC_InitStruct.ADC_InBufEn = ADC_BufEnable; //开启跟随器
ADC_SingleInitStruct.ADC_InitStruct.ADC_OpMode = ADC_SingleChOneMode;
ADC_SingleInitStruct.ADC_InitStruct.ADC_SampleTime = ADC_SampTime5Clk; //5个ADC时钟周期
ADC_SingleInitStruct.ADC_InitStruct.ADC_TsEn = ADC_TsDisable; //内置温度传感器禁用
ADC_SingleInitStruct.ADC_InitStruct.ADC_VrefSel = ADC_Vref_VDDA;//VDDA参考电压
ADC_SingleInitStruct.ADC_WdtStruct.ADC_WdtAll = ADC_WdtDisable;
ADC_SingleInitStruct.ADC_Chmux = ADC_ExInputCH0;
ADC_SingleChOneModeCfg(&ADC_SingleInitStruct);
ADC_ITConfig(ADC_IT_EOC, ENABLE);
//ADC_ITConfig(ADC_IT_EOC | ADC_IT_EOS | ADC_IT_EOA, ENABLE);
ADC_EnableIrq(ADC_INT_PRIORITY);
ADC_ClearITPendingAll();
ADC_Enable(); // 使能ADC
// ADC_SoftwareStartConvCmd(ENABLE);
}
void Adc_InterruptHandler(void)
{
if (ADC_GetITStatus(ADC_IT_EOC))
{
ADC_ClearITPendingBit(ADC_IT_EOC);
adc_result[adc_int_cnt] = ADC_GetConversionValue();
if (adc_int_cnt == 0)
{
ADC_SingleInitStruct.ADC_Chmux = ADC_ExInputCH1;
ADC_SingleChOneModeCfg(&ADC_SingleInitStruct);
ADC_SoftwareStartConvCmd(ENABLE);
adc_int_cnt++;
}
else
{
adc_int_cnt = 0;
ADC_SingleInitStruct.ADC_Chmux = ADC_ExInputCH0;
ADC_SingleChOneModeCfg(&ADC_SingleInitStruct);
}
}
}
注:Adc_InterruptHandler函数需要放置到
interrupts_cw32f030.c
的ADC_IRQHandler里面,如下:
void ADC_IRQHandler(void)
{
extern void Adc_InterruptHandler(void);
/* USER CODE BEGIN */
Adc_InterruptHandler();
/* USER CODE END */
}
如下,试验成功。
更多回帖