实现温控的初步想法 :二

既然已经确定了只用一个时钟就可以实现很多功能,那么接下来就涉及到问题了,可不可以在每隔10ms的一个时钟中断内实现ADC12的转换并且将ADC12转换后的值取出并赋给变量呢?

这个问题很重要,因为以前做ADC的转换的时候,需要将转换结果赋值时,还需要使用ADC的一个内部的中断。那么这个问题难道还要涉及到中断的嵌套之类的问题吗?

先看了下msp430f5438A上的关于中断优先级的讲述:

所以说ADC12_A的优先级是高于TA1,所以使用中断优先级的方法先完成10ms的定时中断,然后再完成ADC12_A的取样赋值貌似并不是很靠谱。(其实我并不是很清楚中断优先级这些玩意)

那么有没有可能在Timer_A的中断内部再使能一个ADC12_A的中断呢?

话不多说,开始实验:

额。。。上午10点要开始实验的,结果一直到了晚上8点了都没搞出啥来,主要是感觉有点麻烦,毛毛躁躁的,导致效率太低了。现在再扎实一点重新验证想法:

一:代码如下

volatile unsigned int result; // Needs to be global in this example,Otherwise, the compiler removes it

// because it is not used for anything.
void InitADC12_A()
{
  ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_15; // Turn on ADC12, set sampling time

  ADC12CTL1 = ADC12SHP+ADC12CONSEQ_2; // Use sampling timer, repeat single channel (我觉得这一个设定可能会比较关键)

  ADC12MCTL0 = ADC12SREF_2 + ADC12INCH_3; // ref+=Veref=2.5V, channel = A3

  ADC12IE = ADC12IE0; // Enable ADC12IFG.0

  ADC12CTL0 |= ADC12ENC; // Enable conversions
}

#pragma vector=ADC12_VECTOR

__interrupt void ADC12ISR (void)

{
  switch(__even_in_range(ADC12IV,34))

  {

    case 0: break; // Vector 0: No interrupt

    case 2: break; // Vector 2: ADC overflow

    case 4: break; // Vector 4: ADC timing overflow

    case 6: // Vector 6: ADC12IFG0

    result = ADC12MEM0; // Move results, IFG is cleared

    P11OUT ^= BIT0; //light red LED

    __bic_SR_register_on_exit(LPM4_bits);

    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;

  }

}

void main(void)

{
  InitADC12_A();

  WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer

  ADC12CTL0 |= ADC12SC; // Start convn - software trigger

  P11DIR |= BIT0; //设置P11.0为输出

  P11OUT &= ~BIT0; //点亮LED灯 设置这两行的目的其实有观察ADC12MEM0寄存器的作用。

  __bis_SR_register(LPM4_bits + GIE); // Enter LPM4, Enable interrupts

  __no_operation(); // For debugger


}

然后debug.

然后可以发现,当程序运行到ADC12CTL0 |= ADC12SC; // Start convn - software trigger时:

ADC12MEM0寄存器的值是0x0897

当运行到P11DIR |= BIT0; //设置P11.0为输出时:

ADC12MEM0寄存器的值为 0x08C6

当运行到P11OUT &= ~BIT0时,ADC12MEM0寄存器的值为 0x08C7 ,ADC12IFG0 = 1;

当运行到__bis_SR_register(LPM4_bits + GIE);时,ADC12MEM0寄存器的值为 0x08BD。ADC12IFG0 = 1;

当运行到 result = ADC12MEM0时,ADC12MEM0寄存器的值为 0x08D9,result的值为2239 。ADC12IFG0 = 1;

当运行到__bic_SR_register_on_exit(LPM4_bits);ADC12MEM0寄存器的值为 0x08C3 , result的值为2239,ADC12IFG0 = 1。

当一直运行时我们发现,这个程序就一直没有从中断中出来过。

从这些运行结果我们可以看出,ADC12MEM0寄存器的值一直都在改变,而自从转换后ADC12IFG0=1就一直没变过。这也就导致了程序一直被困在中断中不能返回主函数。

既然这样,那么在Timer_A中进入ADC12后,由于ADC12IFG0=1,所以就再也回不到Timer_A产生的中断了。这是由ADC12CONSEQx决定的。

 

二:猜想将ADC12CONSEQx设为0时,那么会有:

ADC12CTL1 = ADC12SHP+ADC12CONSEQ_2; // Use sampling timer, repeat single channel (我觉得这一个设定可能会比较关键)

改为:ADC12CTL1 = ADC12SHP+ADC12CONSEQ_0; // Use sampling timer, single single channel (我觉得这一个设定可能会比较关键)

那么debug结果为:

当程序运行到ADC12CTL0 |= ADC12SC; // Start convn - software trigger时:

ADC12MEM0寄存器的值是0x08C1,ADC12IFG0 = 1;

当运行到P11DIR |= BIT0; //设置P11.0为输出时:

ADC12MEM0寄存器的值为 0x08C6,ADC12IFG0 = 1;

当运行到P11OUT &= ~BIT0时,ADC12MEM0寄存器的值为 0x08C1 ,ADC12IFG0 = 1;

当运行到__bis_SR_register(LPM4_bits + GIE);时,ADC12MEM0寄存器的值为 0x08C1。ADC12IFG0 = 1;

当运行到 result = ADC12MEM0时,ADC12MEM0寄存器的值为 0x08D9,result的值为2241 。ADC12IFG0 = 0;

当运行到__bic_SR_register_on_exit(LPM4_bits);ADC12MEM0寄存器的值为 0x08C1 , result的值为2241,ADC12IFG0 = 0。

再debug,会发现程序回到了主函数,然后结束运行。

三:回到原来的那个问题,我应该怎么样才能实现温控呢?

尝试着写以下代码:

#include "io430.h"

//这个函数用来产生5MHz的时钟信号
void InitClock()
{
P1DIR |= BIT0;
P1SEL |= BIT0; //ACLK output,这时候可以使用示波器观察时钟信号

UCSCTL3 |= SELREF_2; // FLLref = REFO
UCSCTL4 = SELM__DCOCLKDIV + SELS__DCOCLKDIV + SELA__DCOCLKDIV;// 时钟来源:主系统时钟来源DCOCLKDIV;子系统时钟来源DCOCLKDIV;辅助系统时钟来源DCOCLKDIV
UCSCTL5 |= DIVM__1 + DIVS__4 + DIVA__1; // 分频:主系统时钟1分频;子系统时钟16分频;辅助系统时钟1分频

__bis_SR_register(SCG0); // Disable FLL
UCSCTL1 = DCORSEL_6; // 10.7MHz<Fdco<39MHz
UCSCTL2 |= FLLD__2 +151 ; // 约5MHz DCOCLKDIV Fdco/4
__bic_SR_register(SCG0); // Enable FLL

// 等待错误标志清除,振动器稳定
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
}


//初始化Timer_A

void Init_Timer_A()
{

P7DIR |= 0x08; // P7.3 output

P7SEL |= 0x08; // P7.3 options select

P11DIR |= 0x01; // P11.0 output red_LED

P11OUT &= ~BIT0; //输出低电平 LED灯亮

TA1CCTL0 = CCIE; // CCR0 interrupt enabled

TA1CCR0 = 39062; //设置周期为250ms

TA1CCTL2 = OUTMOD_3; // CCR2 set/reset

TA1CCR2 = 40000; // CCR2 original PWM duty cycle 1/5

TA1CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, upmode, clear TAR
}

// 初始化ADC12

void InitADC12()
{
P6SEL = 0x08; // Enable P6.3 as A/D channel input

ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_2; // Turn on ADC12, set sampling time, 16ADC12CLK cycles

ADC12CTL1 = ADC12SHP+ADC12CONSEQ_0+ADC12SSEL_2; // Use sampling timer, single time single channel,MCLK=5M

ADC12MCTL0 = ADC12SREF_2+ADC12INCH_3; // ref+ = VeREF+, ref- = AVSS, channel = A4

ADC12IE = 0x01; // Enable ADC12IFG.0

ADC12CTL0 |= ADC12ENC; // Enable conversions
}

volatile unsigned result ;

void main(void)

{

WDTCTL = WDTPW + WDTHOLD; // Stop WDT

InitClock();

Init_Timer_A();

P11OUT ^= 0x01; // Toggle触发 P11.0

while(1)
{
__bis_SR_register(LPM0_bits + GIE);

__no_operation();

}

}

#pragma vector=TIMER1_A0_VECTOR

__interrupt void TIMER1_A0_ISR(void)

{

P11OUT ^= 0x01; // Toggle触发 P11.0

InitADC12();

ADC12CTL0 |= ADC12SC;

__bis_SR_register(LPM0_bits + GIE);

__no_operation();

}

#pragma vector=ADC12_VECTOR

__interrupt void ADC12ISR (void)

{


switch(__even_in_range(ADC12IV,34))

{

case 0: break; // Vector 0: No interrupt

case 2: break; // Vector 2: ADC overflow

case 4: break; // Vector 4: ADC timing overflow

case 6: // Vector 6: ADC12IFG0

result = ADC12MEM0; // Move result, IFG置0

__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU, SET BREAKPOINT HERE

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;

}

}

这个代码很好理解,先是程序进入Timer_A1的中断,然后初始化ADC12,再实现模数转换,进入ADC12的中断,将ADC采集到的数据传到result,然后再进入Timer_A1的中断。

调试过程没有问题,得到了定时采集ADC值的效果。

同时观察到红色LED灯闪烁,说明确实是隔了一段定时的时间进入中断。

到此为止,温控的程序逻辑算是调试结束了。

结束语:在学习这种新东西时,一定不要着急,宁慢勿慌。就算一天就搞懂一个知识点,也比焦虑慌乱结果一事无成要好。

原文地址:https://www.cnblogs.com/qifengle/p/5087431.html