zoukankan      html  css  js  c++  java
  • 实现温控的初步想法 :二

    既然已经确定了只用一个时钟就可以实现很多功能,那么接下来就涉及到问题了,可不可以在每隔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灯闪烁,说明确实是隔了一段定时的时间进入中断。

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

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

  • 相关阅读:
    周末毒鸡汤时间
    MySQL 8.0发布,你熟悉又陌生的Hash Join?
    你可能需要的Kafka面试题与答案整理
    流程控制结构
    视图
    事务
    常用约束
    sql99语法的连接查询
    数据类型
    数据操作语句(DML)
  • 原文地址:https://www.cnblogs.com/qifengle/p/5087431.html
Copyright © 2011-2022 走看看