【CW32饭盒派开发板试用体验】1. 开箱啦
【CW32饭盒派开发板试用体验】2. 使用扩展板串口UART3以及scanf重定向到串口
【CW32饭盒派开发板试用体验】3. 使用BTIM实现任务调度器
前言
本文主要讲解如何使用ADC,板载了一个电位计连接到了PB00上,官方提供了示例工程,本文就不做过多说明了。
本文使用ADC采集摇杆模块的模拟量,摇杆的X轴与Y轴分别连接到了PA0和PA1。
1 硬件连接
见下图:
- PA0 - ADC_IN0(摇杆X轴)
- PA1 - ADC_IN1(摇杆Y轴)
知道了硬件连接,本来想参考官方示例工程直接上手的,但是看了下源代码,发现只能对一个通道进行单次转换,what???我想着这与我所知道的其他ADC不一样的呀,不应该是ADC下面的很多通道都可以单独转换吗?
然后看了下用户手册,发现转换模式有很多,如下,示例工程使用的就是单通道转换模式,只不过官方库文件封装的不是很好,导致使用起来产生了歧义。
建议官方可以再优化一下库,目前这个ADC的库用起来确实不是很好用。
看到有连续工作模式,但是只能支持4个通道连续采样,我只使用两个通道,所以最终还是确定使用单通道转换,只不过每转换完一个通道再切换到另一个通道就可以了,稍微麻烦一点。
下面是ADC支持的通道以及对应的引脚,CW32F030只有一路ADC,但是支持12个通道,如下:
单通道转换的步骤如下,用户手册写的还是比较清晰,这点好评。
2 软件实现
知道了硬件工作原理,接下来就是软件开发了,我使用的中断模式来采集ADC,因为使用polling模式连续采样两个通道的时候需要软件参与,会导致代码存在一些等待延时,效率底下,使用中断模式可以避免这点。
下面是adc相关代码:
- Adc_Running: ADC采样启动函数,调用该函数会出发一次ADC转换,并将转换结果用printf打印,将该函数放置到100ms任务中运行
- Adc_Init:初始化为单通道采集,并使中断,设置首先采样AN0,但是不会触发中断,触发中断用Adc_Running
- Adc_InterruptHandler:中断处理函数,当中断第一次进入的时候,表示AN0采样结果完成,将结果写入adc_result[0]中,然后选择AN1,触发转换,当AN1转换完成,进入中断,将结果写入adc_result[1]中,然后选择AN0,但是不触发,再次等待Adc_Running来触发转换。
#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();
__RCC_GPIOA_CLK_ENABLE();
PA00_ANALOG_ENABLE();
PA01_ANALOG_ENABLE();
ADC_SingleInitStruct.ADC_DiscardEn = ADC_DiscardNull;
ADC_SingleInitStruct.ADC_InitStruct.ADC_AccEn = ADC_AccDisable;
ADC_SingleInitStruct.ADC_InitStruct.ADC_Align = ADC_AlignRight;
ADC_SingleInitStruct.ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div16;
ADC_SingleInitStruct.ADC_InitStruct.ADC_DMAEn = ADC_DmaDisable;
ADC_SingleInitStruct.ADC_InitStruct.ADC_InBufEn = ADC_BufEnable;
ADC_SingleInitStruct.ADC_InitStruct.ADC_OpMode = ADC_SingleChOneMode;
ADC_SingleInitStruct.ADC_InitStruct.ADC_SampleTime = ADC_SampTime5Clk;
ADC_SingleInitStruct.ADC_InitStruct.ADC_TsEn = ADC_TsDisable;
ADC_SingleInitStruct.ADC_InitStruct.ADC_VrefSel = ADC_Vref_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_EnableIrq(ADC_INT_PRIORITY);
ADC_ClearITPendingAll();
ADC_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);
Adc_InterruptHandler();
}
3 实验结果
如下,试验成功。