目录
BF7006的ADC是12位的,只有一组,共28个通道,其中24个是外部通道。
#define HW_ADC_CH_0 0
#define HW_ADC_CH_1 1
#define HW_ADC_CH_2 2
#define HW_ADC_CH_3 3
#define HW_ADC_CH_4 4
#define HW_ADC_CH_5 5
#define HW_ADC_CH_6 6
#define HW_ADC_CH_7 7
#define HW_ADC_CH_8 8
#define HW_ADC_CH_9 9
#define HW_ADC_CH_10 10
#define HW_ADC_CH_11 11
#define HW_ADC_CH_12 12
#define HW_ADC_CH_13 13
#define HW_ADC_CH_14 14
#define HW_ADC_CH_15 15
#define HW_ADC_CH_16 16
#define HW_ADC_CH_17 17
#define HW_ADC_CH_18 18
#define HW_ADC_CH_19 19
#define HW_ADC_CH_20 20
#define HW_ADC_CH_21 21
#define HW_ADC_CH_22 22
#define HW_ADC_CH_23 23
#define HW_ADC_CH_24 24 //VREFA
#define HW_ADC_CH_25 25 //VREFS
#define HW_ADC_CH_26 26 //Temperature
#define HW_ADC_CH_27 27 //BG(1.267V Typical)
#define HW_ADC_CH_MAX 28
为了保持通道连续, 把VREFA和VREFS改到通道24、25,软件上做变换。
1. 初始化
1.1 关闭ADC
ADC_SC1寄存器的输入通道位选择全部设置为1即可关闭ADC。
ADC_SC1 = 0x1f;
默认使用单次转换(位5为0)。
1.2 设置触发方式
通过ADC_SC2 寄存器的位6设置触发方式,默认设置为软件触发。
ADC_SC2 = 0;
1.3 设置分频率
通过ADC_CFG寄存器的位2设置。
if(resolution == 8)
ADC_CFG = 0; //resolution = 8
else
ADC_CFG = (1 << 2); //resolution = 12
1.4 设置频率
ADC的时钟源只有系统时钟。通过ADC_CFG寄存器的位4:6设置频率分频系数。 当系统时钟等于32M时,ADC必须最少二分频,即ADC最大支持16M。
switch(clkDiv)
{
case ADC_CLK_DIV1:
default:
if(SystemCoreClock == (uint32_t)32*1000*1000)
ADC_CFG |= (1 << 4); //max support 16M
break;
case ADC_CLK_DIV2:
ADC_CFG |= (1 << 4);
break;
case ADC_CLK_DIV3:
ADC_CFG |= (7 << 4);
break;
case ADC_CLK_DIV4:
ADC_CFG |= (2 << 4);
break;
case ADC_CLK_DIV6:
ADC_CFG |= (3 << 4);
break;
case ADC_CLK_DIV8:
ADC_CFG |= (4 << 4);
break;
case ADC_CLK_DIV10:
ADC_CFG |= (5 << 4);
break;
case ADC_CLK_DIV12:
ADC_CFG |= (6 << 4);
break;
}
1.5 时序设置
一个完整的ADC转换过程由以下时序组成:T= Timer1+ Sample_Time+ Time2+ Time3
Timer1=(ADC_CKC_SAMDEL+2)* 单个ADC时钟时间;
Sample_Timer= (ADC_SPT+1)* 单个ADC时钟时间;
Time2=(ADC_CKC_WNUM +3)* 单个ADC时钟时间;
Time3=(12+2)* 单个ADC时钟时间(12位模式)
Time3=(8+2)* 单个ADC时钟时间(8位模式)
通过ADC_CKC 寄存器设置时序。
1.5.1 采样时序与比较时序间隔选择
通过ADC_CKC寄存器的位7设置。
ADC可以配置比较功能来检查上限或下限,这里是设置采样时序与比较时序间隔,一般是设置为1个ADC时钟。
ADC_CKC = (1 << 7);
1.5.2 采样延迟时间选择
通过ADC_CKC寄存器的位4:6设置。
即设置ADC转换过程中Timer1的时间。这个时间遵循的是频率越高,数字越大,似乎没规律,只能参考例程设置对应的值。
1.5.3 采样完毕后距离转换间隔时间选择
通过ADC_CKC寄存器的位2:3设置。
即设置ADC转换过程中Time2的时间。
1.5.4 模拟输入时钟信号分频
通过ADC_CKC寄存器的位1:0设置。
这个具体的信息没有写,只有一个要求:需保证ADC_CKC_WNUM *ADC时钟周期>5*(系统时钟的ADC_CKC_CKV配置周期)
以上3个配置没有规律,所以只能参考例程配置(可能是经验值):
ADC_CKC |= 0x00 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 1, WNUM = 3, SAMDEL = 2
switch(clkDiv)
{
case ADC_CLK_DIV1:
default:
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CFG |= (1 << 4); //max support 16M
ADC_CKC |= 0x01 | ((uint8_t)0x03 << 2) | ((uint8_t)0x03 << 4); //CKV = 2, WNUM = 6, SAMDEL = 8
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x00 | ((uint8_t)0x03 << 2) | ((uint8_t)0x03 << 4); //CKV = 1, WNUM = 6, SAMDEL = 8
}
else
{
ADC_CKC |= 0x00 | ((uint8_t)0x03 << 2) | ((uint8_t)0x02 << 4); //CKV = 1, WNUM = 6, SAMDEL = 4
}
break;
case ADC_CLK_DIV2:
ADC_CFG |= (1 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x03 << 2) | ((uint8_t)0x03 << 4); //CKV = 2, WNUM = 6, SAMDEL = 8
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x03 << 2) | ((uint8_t)0x02 << 4); //CKV = 2, WNUM = 6, SAMDEL = 4
}
break;
case ADC_CLK_DIV3:
ADC_CFG |= (7 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x01 << 2) | ((uint8_t)0x03 << 4); //CKV = 2, WNUM = 4, SAMDEL = 8
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x01 << 2) | ((uint8_t)0x02 << 4); //CKV = 2, WNUM = 4, SAMDEL = 4
}
break;
case ADC_CLK_DIV4:
ADC_CFG |= (2 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x02 | ((uint8_t)0x03 << 2) | ((uint8_t)0x02 << 4); //CKV = 4, WNUM = 6, SAMDEL = 4
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 2, WNUM = 3, SAMDEL = 2
}
break;
case ADC_CLK_DIV6:
ADC_CFG |= (3 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x02 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 4, WNUM = 3, SAMDEL = 2
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 2, WNUM = 3, SAMDEL = 2
}
break;
case ADC_CLK_DIV8:
ADC_CFG |= (4 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x02 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 4, WNUM = 3, SAMDEL = 2
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 2, WNUM = 3, SAMDEL = 2
}
break;
case ADC_CLK_DIV10:
ADC_CFG |= (5 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x02 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 4, WNUM = 3, SAMDEL = 2
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 2, WNUM = 3, SAMDEL = 2
}
break;
case ADC_CLK_DIV12:
ADC_CFG |= (6 << 4);
if(SystemCoreClock == (uint32_t)32*1000*1000)
{
ADC_CKC |= 0x02 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 4, WNUM = 3, SAMDEL = 2
}
else if(SystemCoreClock == (uint32_t)16*1000*1000)
{
ADC_CKC |= 0x01 | ((uint8_t)0x00 << 2) | ((uint8_t)0x01 << 4); //CKV = 2, WNUM = 3, SAMDEL = 2
}
break;
}
1.6 设置采样时间
通过ADC_SPT 寄存器设置采样时间,好像也没有什么标准限制,参考例程设为15.
ADC_SPT = 15;
1.7 默认寄存器配置
有3个寄存器是要采用默认的配置,不能修改,也没有任何说明。
ADC_ISEL = 0x19;
ADC_FRSEL = 0x00;
ADC_CTRLSEL = 0x00;
2. 使能ADC
2.1 使能通道
通过ADC_APCTL寄存器设置,每个位对应通道。由于把VREFA和VREFS改到通道24、25,这里做个转换。
if(port >= HW_ADC_MAX)
return;
if(ch >= HW_ADC_CH_MAX)
return;
if(ch == HW_ADC_CH_24)
ch = 29;
if(ch == HW_ADC_CH_25)
ch = 30;
ADC_APCTL = 0x00;
ADC_APCTL |= ch;
2.2 开启ADC
通过ADC_PD寄存器设置。
ADC_PD = 0x00;
2.3 开启转换
通过设置ADC_SC1的位0:4对应通道即开启转换。
ADC_SC1 |= 0x1f;
ADC_SC1 &= (0xe0 | ch);
3. 获取结果
通过ADC_SC1寄存器的位7判断转换结束。
然后通过ADC_DATA寄存器得到ADC值。
uint16_t adcGetValue(uint8_t port, uint8_t ch)
{
while((ADC_SC1 & (1 << 7)) == 0);
return (uint16_t)ADC_DATA;
}