以我的MSPf5529LP为例,它有A0-A15共计16个输入通道,其中有12个是外部通道。与之相应地,ADC12部分有相当多的各种寄存器,接下来一一介绍,最后依然附上一些代码。
目录
ADC12CTLn ADC12MEMx ADC12MCTLx
寄存器介绍
由于其为数众多的通道数,ADC12有相当可观数量的寄存器,但是去除重合的一些后只有6个,它们分别负责处理一些功能。
ADC12CTLn
它分为CTL0、CTL1、CTL2。三者的功能区别也不小,分别介绍一下。然后ADC12CTL0的设置很多,ADC12CT1和ADC12CTL2的操作我用到不多,查到的资料也不多,所以对它的讲解会和机翻很像。
ADC12CTL0
ADC12SHTnx | 这一位寄存器控制采样时间的长度 ADC12SHT1x负责通道8-15,ADC12SHT0x负责通道0-7 二者都是4位的,所以可以写出0-15的所有数字 ADC12SHTnx = xxxx b(四位二进制数),如果将二进制数化为十进制数y 那么采样时间的长度即为2^(2+y)个ADC12CLK时钟周期长度 |
ADC12MSC | 如果机翻的话翻成混合采样,实际上就是连续采样,只在多通道或连续采样时才可用 0 采集到SHI的上升沿信号时触发采样和转换 1 在第一次采集到SHI上升信号后,每次采样转换完成立刻执行下一次 |
ADC12REF2_5V | 控制参考电压(只在下面那个REFON置1时可用) 0 参考电压为1.5V 1 参考电压为2.5V |
ADC12REFON | 是否选择参考 0 不选择 1 选择使用参考 |
ADC12ON | 打开ADC12_A 0 关闭 1 打开 |
ADC12OVIE | ADC12MEMx(储存x通道采集到的数据的寄存器,后面会说)的溢出中断使能,如果设置这位的话GIE中断也要配一下 0 失能 1 使能 |
ADC12TOVIE | ADC12转换超时(时间的“溢出”)使能,如果设置这位的话GIE中断也要配一下 0 失能 1 使能 这一位和上一位用的都很少 |
ADC12ENC | 使能转换,这一位的地位有些特殊 0 失能 1 使能 所有其他寄存器的更改配置操作都要在这一位为0时配置 |
ADC12SC | 启动转换,它会在开始后自动复0,所以要在循环里手动置1 0 不要开始采样 1 开始采样 |
ADC12CTL1
ADC12CSTARTADDx | 数据起始地址,从0到F,对应MEM0-MEM15 |
ADC12SHSx | 采样-保持源的选择 00 ADC12SC 01 10 11 这三个取决于具体型号 |
ADC12SHP | 采样-保持 脉冲-模式选择 0 SAPCON信号源自采样输入信号 1 SAMPCON信号源自采样定时器 |
ADC12ISSH | 反转采样信号(0和1反转) 0 不反转 1 反转 |
ADC12DIVx | 分频系数。有三位,所以可以1-8分频 |
ADC12SSELx | 选择时钟,同样是ACLK和SMCLK更常用 00 ADC12OSC(MODCLK) 01 ACLK 10 MCLK 11 SMCLK |
ADC12CONSEQx | 转换模式,这个根据实际需要来使用 00 单通道单采集 01 多通道单采集 10 单通道多采集 11 多通道多采集 |
ADC12BUSY | 标志当前是否有操作 0 无操作 1 有操作 |
ADC12CTL2
ADC12PDIV | 控制时钟预分频系数 0 1分频(不分频) 1 4分频 |
ADC12TCOFF | 控制ADC12外接的温度传感器,不用的话最好关闭省电,置1才是关闭 注意:这一位只有在REFMSTR置0时才可用 0 开启 1 关闭 |
ADC12RES | 这个位定义了转换结果分辨率 00 8位(9个时钟周期转换时间) 01 9位(11个时钟周期转换时间) 10 10位(13个时钟周期转换时间) 11 保留(就是暂时先不用) |
ADC12DF | 数据回读格式 0 无符号 1 有符号 |
ADC12SR | 配置采样率 0 最高约200kps 1 最高约50kps |
ADC12REFOUT | 参考输出,只在REFMSTR置0时有效 0 关闭 1 开启 |
ADC12REFBURST | 设置缓冲器的 0 持续打开缓冲器 1 只在采样转换时打开缓冲器 |
ADC12MEMx
就是通过前面ADC12CSTARTADDx那一位寄存器控制送到这些寄存器里以供使用。
ADC12MCTLx
ADC12EOS | 表明是采样序列的最后一个,这样说可能有些抽象,看一下代码就清楚了 0 不是结尾 1 是结尾 |
ADC12SREFx | 选择参考,一共有8个,全部贴出来太多了 |
ADC12INCHx | 选择输入通道,四位对应到A0-A7,内部参考,A13-A15共计十五个通道 |
ADC12IE
看着很哈人,但是实际上只要使能你需要的通道就可以了,并不麻烦。
ADC12IFG
当对应的通道号引起中断后,对应IFG置1。
ADC12IV
类似于TAxIV,它也可以记录到底是哪一位引起了中断。
例程
有关寄存器的介绍终于算是结束了,这么多的内容可能对阅读不那么友好,接下来跟着例程看寄存器怎么配置,AD采集的例子不多,全部都是抽象的也不太好,结合具体的外设来看。我介绍两个,一个温度传感器,一个灰度传感器,正好契合一个单通道采集和一个多通道采集。
温度传感器
这个传温度的传感器跳动可能比较大,我自己测的时候一直在27℃-29℃跳变。具体想要查看温度数值的话可以debug,在观察窗口里面看,或者添加一个OLED也可以,我自己是加了OLED的,但是因为本篇的篇幅太长了,于是将之删去。
#include <msp430.h>
#define CALADC12_15V_30C *((unsigned int *)0x1A1A)
#define CALADC12_15V_85C *((unsigned int *)0x1A1C)
//这两个宏定义用于温度校准使用,不必在意,校准30和85
#define REF_30C CALADC12_15V_30C
#define REF_85C CALADC12_15V_85C
unsigned int temp;
volatile float temperatureDegC;
volatile float temperatureDegF;
//volatile类型的变量主要是因为单片机访问机制的问题,如果不加上这一位可能导致读取的数据不变
int main(void)
{
WDTCTL = WDTPW + WDTHOLD;
REFCTL0 &= ~REFMSTR; // 将REFMSTR置0以设置参考
ADC12CTL0 = ADC12ON + ADC12SHT0_8 + ADC12REFON ;
//打开ADC12;设置采样时间;开启参考(未设置ADC12REF2_5V位,故参考电压1.5V)
ADC12CTL1 = ADC12SHP; // 以采样定时器为SAMPCON信号源
ADC12IE = 0x001; // 使能MEM0的IFG中断
__delay_cycles(100); // 等待ref设置完成
ADC12CTL0 |= ADC12ENC;
while(1)
{
ADC12CTL0 &= ~ADC12SC; // 手动停止上一次采集
ADC12CTL0 |= ADC12SC; // 重新开始新的一次
__bis_SR_register(LPM4_bits + GIE); // 进入低功耗模式4并使能中断(等待采样完成)
//在中断结束后会自动退出低功耗模式,就进入了下面的计算
temperatureDegC=(float)(((long)temp-REF_30C)*(85 - 30))/(REF_85C - REF_30C)+30.0f;
temperatureDegF = temperatureDegC * 9.0f / 5.0f + 32.0f;
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV,34))
{
case 0: break; // Vector 0: 无
case 2: break; // Vector 2: ADC 溢出
case 4: break; // Vector 4: ADC 超时
case 6: // Vector 6: ADC12IFG0
temp = ADC12MEM0;
__bic_SR_register_on_exit(LPM4_bits);
break;
case 8: break; // Vector 8: ADC12IFG1
case 10: break; // Vector 10: ADC12IFG2
case 12: break; // Vector 12: ADC12IFG3
case 14: break; // Vector 14: ADC12IFG4
case 16: break; // Vector 16: ADC12IFG5
case 18: break; // Vector 18: ADC12IFG6
case 20: break; // Vector 20: ADC12IFG7
case 22: break; // Vector 22: ADC12IFG8
case 24: break; // Vector 24: ADC12IFG9
case 26: break; // Vector 26: ADC12IFG10
case 28: break; // Vector 28: ADC12IFG11
case 30: break; // Vector 30: ADC12IFG12
case 32: break; // Vector 32: ADC12IFG13
case 34: break; // Vector 34: ADC12IFG14
default: break;
}
}
灰度传感器
是P6.0到P6.4五个引脚,对应五路灰度传感器。
#include <msp430.h>
volatile unsigned int A0results;
volatile unsigned int A1results;
volatile unsigned int A2results;
volatile unsigned int A3results;
volatile unsigned int A4results;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD;
P6SEL = BIT0 + BIT1 + BIT2 + BIT3 + BIT4; // 使能
ADC12CTL0 = ADC12ON + ADC12MSC + ADC12SHT0_8;
//打开ADC12 在第一个SHI信号后自动采样 设置采样时间
ADC12CTL1 = ADC12SHP + ADC12CONSEQ_3; // 使用定时器作为采样信号源, 多通道采集
ADC12MCTL0 = ADC12INCH_0; // A0
ADC12MCTL1 = ADC12INCH_1; // A1
ADC12MCTL2 = ADC12INCH_2; // A2
ADC12MCTL3 = ADC12INCH_3; // A3
ADC12IE = 0x08; // 使能IFG3
ADC12CTL0 |= ADC12ENC; // 使能转换
while(1)
{
ADC12CTL0 |= ADC12SC; // SC这一位会自动复0,要手动置1
__bis_SR_register(LPM0_bits + GIE); // 低功耗0, 使能中断
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV,34))
{
case 0: break; // Vector 0: 无
case 2: break; // Vector 2: ADC溢出
case 4: break; // Vector 4: ADC超时
case 6: break; // Vector 6: ADC12IFG0
case 8: break; // Vector 8: ADC12IFG1
case 10: break; // Vector 10: ADC12IFG2
case 12: // Vector 12: ADC12IFG3
A0results = ADC12MEM0;
A1results = ADC12MEM1;
A2results = ADC12MEM2;
A3results = ADC12MEM3;
A4results = ADC12MEM4;
__bic_SR_register_on_exit(LPM0_bits);
case 14: break; // Vector 14: ADC12IFG4
case 16: break; // Vector 16: ADC12IFG5
case 18: break; // Vector 18: ADC12IFG6
case 20: break; // Vector 20: ADC12IFG7
case 22: break; // Vector 22: ADC12IFG8
case 24: break; // Vector 24: ADC12IFG9
case 26: break; // Vector 26: ADC12IFG10
case 28: break; // Vector 28: ADC12IFG11
case 30: break; // Vector 30: ADC12IFG12
case 32: break; // Vector 32: ADC12IFG13
case 34: break; // Vector 34: ADC12IFG14
default: break;
}
}
总结
ADC12的寄存器特别多,配置起来也很复杂,尤其是工程比较大时配置得很让人头疼,这也是大多数人选择不用寄存器的主要原因。但是就一般情况来说,配置还是有迹可循的。在大多数情况下只需要如下配置。
ADC12CTL0 = ADC12ON + ADC12MSC + ADC12SHT0_8;
打开ADC ,自动采样,选择采样时间
ADC12CTL1 = ADC12SHP + ADC12CONSEQ_x;
选择采样源,根据需要选择采集方式
ADC12MCTLx = ADC12INCH_x;
选择输入通道
ADC12IE = BITx;
使能对应输入通道对应的IFG
ADC12CTL0 |= ADC12ENC;
最后再使能转换,注意这条一定在最后