Outils pour utilisateurs

Outils du site


votre temps local: :: ()

heure officielle (en France) : ::(TZ:)

Heure UTC client: :: Offset client: s - delai: ms - - timeZone: Heure UTC: ::
fr:asservissement_numerique_de_temperature_pour_cavite_laser_ultra-stable

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
fr:asservissement_numerique_de_temperature_pour_cavite_laser_ultra-stable [2018/03/23 13:34]
fwiotte
fr:asservissement_numerique_de_temperature_pour_cavite_laser_ultra-stable [2018/04/06 11:01] (Version actuelle)
fwiotte
Ligne 1: Ligne 1:
-**Asservissement en température d'une cavité ultra-sable au LPL pour le Strontium** +**Asservissement en température ​numérique ​d'une cavité ultra-stable ​au LPL pour le Strontium** 
-//condition de stabilité//​+ 
 +**//condition de stabilité// ​+/- 10mK** 
 + 
 +**Résultas obtenus : 1mk sur la journée** 
 + 
 +Compte tenu des constantes de temps d'​intégration nous avons opté pour un lock 
 +numérique avec un uC 16 bits. ADC et DAC 12 bits  
 +  
 +**MSP430F169 16bits Texas instruments,​ and IAR Workbench for MSP430 or Code composer studio** 
 Cahier des charges: Cahier des charges:
 La précision du lock en température devrait être de l'​ordre de 10 mK, pour assurer une stabilité en fréquence du laser de l'​ordre de quelques kHz.  La précision du lock en température devrait être de l'​ordre de 10 mK, pour assurer une stabilité en fréquence du laser de l'​ordre de quelques kHz. 
 L'​élément chauffant a une résistance de 6 Ohm. Un courant de l'​ordre de 0.6 A devrait fournir la puissance pour nous amener au point de fonctionnement vers 27°C. L'​élément chauffant a une résistance de 6 Ohm. Un courant de l'​ordre de 0.6 A devrait fournir la puissance pour nous amener au point de fonctionnement vers 27°C.
 Élément de mesure : thermistor MC65F103B Élément de mesure : thermistor MC65F103B
 +
 +Ci-joint le code C du projet: ​
 +gestion affiche LCD + calcul température + fonction standby + contrôle de la consigne de température + lock 
 ++ timer + déclaration des variables + déclaration prototypes + fichier init système (ADC-DAC TIMER-PORT IN OUT)
 +
 +Manuel descriptif de la cavité:
 {{ vh6010-4_inst_manual.pdf}} {{ vh6010-4_inst_manual.pdf}}
 +
 +
 +{{:​fr:​pcb_asservissement.png?​600 |}}
 +{{:​fr:​asservissement_de_temperature.png?​800|}}
 +
 +
 +
 +** Function prototypes**
 +   void init_sys(void); ​               // MSP430 Initialisation routine ​
 +   void tempo_loop(long loop_number); ​         // wait
 +   void write_DAC12_0(int out_data); // write DAC12_0 routine
 +   void write_DAC12_1(unsigned short out_data); // write DAC12_1 routine
 +   int read_ADC12(int chanel); ​      // read routine on ADC12
 +   char lock();
 +   void standby(); ​                // init state of state machine
 +   ​unsigned short racine(unsigned long valIn);
 +   int Lcd_Cmd(int portP4);
 +   int lcd_display(char *disp);
 +   int lcd_display2(char *disp2);
 +   int lcd_print(char *s);
 +   int Lcd_Clear();​
 +   void Lcd_Init(void);​
 +   int load_LCD_consigne(void);​
 +   int calcul_Resistor_thermistance(void);​
 +   void visu_etat_lock(void);​
 +
 +** déclaration des variables**
 +   
 +   int consigne=2048;​
 +   ​static unsigned int DAC0_out;
 +   ​static unsigned int DAC1_out;
 +   ​static int ADC_in;
 +   ​static int ADC_in_2;
 +   ​static float ADC_in_2_convert_in_volt;​
 +   ​static long error_signal;​
 +   ​static long accu_out;
 +   ​static long prop;
 +   ​static unsigned long valIn;
 +   ​static unsigned short valOut;
 +   ​static long control;
 +   ​static char next_state = 0;
 +   ​static char state = 0;
 +   ​static char s[20];
 +   ​static char t[20];
 +   ​static double RTH;
 +   ​static double Temperature_in_degre;​
 +   ​static double calcul_ln;
 +   char i = 0;
 +   char j = 0;
 +
 +** main**
 +
 +   void main(void)
 +   {
 +    init_sys(); ​ // Initialise the MSP430
 +    Lcd_Init(); ​
 +    tempo_loop(10);​
 +    Lcd_Clear();​
 +    tempo_loop(10);​
 +    Lcd_Cmd(0x80);​
 +    lcd_display("​Welcome to");
 +    Lcd_Cmd(0xc0);​
 +    lcd_display("​CNRS-LPL-IG-UP13"​);​
 +    tempo_loop(10);​
 +    Lcd_Clear();​
 +    tempo_loop(10);​
 +    Lcd_Cmd(0x84);​
 +    lcd_display("​Atelier"​);​
 +    Lcd_Cmd(0xc2);​
 +    lcd_display("​Electronique"​);​
 +    tempo_loop(10);​
 +    Lcd_Clear();​
 +    tempo_loop(10);​
 +    sprintf(t,"​T in Deg= %.3f",​Temperature_in_degre);​
 +    Lcd_Cmd(0x80);​
 +    lcd_display(t);​
 +    copy_RAM_to_consigne();​
 +    Lcd_Cmd(0xc0);​
 +    sprintf(s,"​consigne= %d",​consigne);​
 +    lcd_display(s);​
 +    ​
 +    standby();
 +    ​
 +    _BIS_SR(LPM0_bits + GIE);             // Enter LPM0 w/ interrupt
 +   ​} ​  
 + 
 +   
 +**gestion affichage LCD**
 +   //​Table 1: Character LCD pins with 1 Controller
 +   //​**********************************************//​
 +   //​1 VSS Power supply (GND)
 +   //​2 VCC Power supply (+5V)
 +   //​3 VEE Contrast adjust
 +   //​4 RS 0 = Instruction input
 +   //1 = Data input
 +   //​5 R/​W 0 = Write to LCD module
 +   //1 = Read from LCD module
 +   //​6 EN Enable signal
 +   //​7 D0 Data bus line 0 (LSB)
 +   //​8 D1 Data bus line 1
 +   //​9 D2 Data bus line 2
 +  //​10 D3 Data bus line 3
 +  //​11 D4 Data bus line 4
 +  //​12 D5 Data bus line 5
 +  //​13 D6 Data bus line 6
 +  //​14 D7 Data bus line 7 (MSB)
 +  ​
 +    int Lcd_Port(int portP4)
 +     {
 +     P4OUT = portP4;
 +     ​return 0;
 +     ​} ​
 +     
 +     // ​ Function for sending command to LCD
 +     int Lcd_Cmd(int portP4)
 +     {
 +     //RS = 0x00;             // => RS = 0
 +     P1OUT &= ~BIT7; ​   /* Pin P1.6 = 0 */
 +     ​Lcd_Port(portP4);​
 +     //​E ​ = 0x40;             // Enable = 1
 +     P1OUT |= BIT6;     /* Pin P1.7 = 1 */
 +     ​tempo_loop(1000);​
 +     //​E ​ = 0x00;             // Enable = 0
 +     P1OUT &= ~BIT6; ​   /* Pin P1.7 = 0 */
 +     ​return 0;
 +     }
 +     
 +     // ​ Function for sending data to LCD
 +     int Lcd_data(int portP4)
 +     {
 +     ​Lcd_Port(portP4);​
 +     //​RS ​  = 0x80;  // RS = 1
 +     P1OUT |= BIT7;     /* Pin P1.6 = 1 */
 +     //​E ​  = 0x40;    //Enable = 1
 +     P1OUT |= BIT6;     /* Pin P1.7 = 1 */
 +     ​tempo_loop(1000);​
 +     //​E ​  = 0x00;    // Enable = 0
 +     P1OUT &= ~BIT6; ​   /* Pin P1.7 = 0 */
 +     ​return 0;
 +     }
 +     
 +     int Lcd_Clear()
 +     {
 +     ​Lcd_Cmd(0);​
 +     ​Lcd_Cmd(1);​
 +     ​return 0;
 +     }
 +     
 +     void Lcd_display_off()
 +     {
 +     ​Lcd_Cmd(0);​
 +     ​Lcd_Cmd(0x0C);​
 +     }
 +     
 +     void Lcd_Shift_Right()
 +     {
 +     ​Lcd_Cmd(0x01);​
 +     ​Lcd_Cmd(0x18);​
 +     }
 +     void Lcd_Shift_Left()
 +     {
 +     ​Lcd_Cmd(0x01);​
 +     ​Lcd_Cmd(0x1C);​
 +     }
 +     // ​ Function for initializing LCD
 +    void Lcd_Init()
 +    { 
 +     ​Lcd_Cmd(0x38); ​    //​Function set: 2 Line, 8-bit, 5x7 dots
 +     ​Lcd_Cmd(0x0c);​
 +     ​Lcd_Cmd(0x01); ​    //​Clear LCD
 +     ​Lcd_Cmd(0x06); ​    //​Entry mode, auto increment with no shift
 +     ​Lcd_Cmd(0x83); ​ // DDRAM addresses 0x80..0x8F + 0xC0..0xCF are used.
 +    }
 +    //  Function for sending string to LCD
 +     int lcd_display(char *disp)
 +     {
 +    int x=0;
 +    while(disp[x]!=0)
 +    {
 +        Lcd_data(disp[x]);​
 +        x++;
 +    }
 +    return 0;
 +    }
 +  ​
 +**Calcul température + affichage** ​
 +
 +    int calcul_Resistor_thermistance(void)
 +    {
 +    WDTCTL = WDTPW + WDTHOLD; ​  // stop Watch Dog Timer
 +    ADC_in_2_convert_in_volt = (ADC_in_2*2.498)/​4096;​
 +    RTH = (ADC_in_2_convert_in_volt*9100)/​(2.498 - ADC_in_2_convert_in_volt);​
 +    float K = 298.15; ​    // T(25°C)
 +    calcul_ln = log((RTH/​10000)); ​            //log népérien ​
 +    Temperature_in_degre = 1/​(calcul_ln/​3988 + 1/K) - 273.15; ​  //​température en degrès C
 +    sprintf(t,"​T in Deg= %.3f",​Temperature_in_degre);​
 +    Lcd_Cmd(0x80);​
 +    lcd_display(t);​
 +    return 0;
 +    }
 +
 +**fonction standby** ​
 +
 +    void standby()
 +    {
 +    WDTCTL = WDTPW + WDTHOLD; ​           // stop WatchDog ​   ​
 +    DAC0_out= consigne; ​                 // init DAC0
 +    DAC1_out= 0;                        // init DAC1
 +    accu_out= 0;
 +    P2OUT &= ~BIT1; ​   /* Pin P2.1 = 0 */
 +    P2OUT &= ~BIT2; ​   /* Pin P2.2 = 0 */
 +    P2OUT &= ~BIT3; ​   /* Pin P2.3 = 0 */
 +    P2OUT &= ~BIT4; ​   /* Pin P2.4 = 0 */
 +    P2OUT &= ~BIT5; ​   /* Pin P2.5 = 0 */
 +    }
 +
 +**fonction lock**
 +    ​
 +    char lock()
 +    {
 +    error_signal = (ADC_in - consigne); // error_signal => int (16 bits) (-32768 to 32767)
 +    prop = error_signal << 21;
 +    control = prop + accu_out ; // + (accu_out >> 8); 
 +  ​
 +    visu_etat_lock();​
 +  ​
 +    if(P1IN & 0x20)
 +    {
 +      if (accu_out >= 2147000000 | accu_out <= -2147000000) ​     ​
 +      {
 +        accu_out = accu_out;
 +      }
 +      else {accu_out = (error_signal << 7) + accu_out;}
 +      ​
 +    }     
 +  ​
 +    if(control < 0)
 +    { valIn = 0;}
 +    else
 +    {valIn = (control << 1);}
 +    valOut = racine(valIn);​
 +    DAC1_out = valOut >> 4;
 +    return 0;
 +    }
 +    unsigned short racine(unsigned long valIn) //on linéarise la réponse de la thermistance
 +    {
 +    unsigned short valOut=0;
 +    unsigned long diff=0L;
 +    for(int i=0; i<16; i++)
 +   {
 + diff <<= 2;
 + valOut <<=1;
 + diff |= valIn >> 30;
 + valIn <<=2;
 + if(diff > 2*valOut)
 + {
 + diff -= (2*valOut)+1;​
 + valOut++;​
 + }
 + }
 + return valOut;
 +     }
 +**fonction TIMER pour échantillonnage** ​
 +
 +    ​
 +     #​pragma vector = TIMERB0_VECTOR ​   // timer pour échantillonner à 0.1s
 +     ​__interrupt void Timer_B (void)
 +    {
 +    WDTCTL = WDTPW + WDTCNTCL; ​                   // clear and start WatchDog ​
 +    write_DAC12_1(DAC1_out); ​                     // write DAC1_out to DAC12_1
 +    write_DAC12_0(DAC0_out); ​                     // write DAC0_out to DAC12_0
 +    ADC_in = read_ADC12(INCH_3); ​                 // read signal erreur
 +    ADC_in_2 = read_ADC12(INCH_4); ​               // read tension thermistor
 +    calcul_Resistor_thermistance();​
 +    ​
 +    if((P2IN & 0x01)==0x01) ​      //​P2.0 ​ modification de la valeur de consigne +
 +    {
 +      if(P3IN & 0x01)
 +      {consigne = consigne + 10;}  //handle P1.7 switch
 +      if (P3IN & 0x02)
 +      {consigne = consigne + 100;} 
 +      if(( P3IN & BIT0 ) == 0 && ( P3IN & BIT1 ) == 0 )
 +      {consigne = consigne + 1;}
 +      ​
 +    }P1IFG &= ~BIT1; ​
 +    ​
 +     ​if((P1IN & 0x01)==0x01) ​      //​P1.0 modification de la valeur de consigne -
 +     {
 +      if(P3IN & 0x01)
 +      {consigne = consigne - 10;} //handle P1.7 switch
 +      if (P3IN & 0x02)
 +      {consigne = consigne - 100;} 
 +      if(( P3IN & BIT0 ) == 0 && ( P3IN & BIT1 ) == 0 )
 +      {consigne = consigne - 1;}
 +          ​
 +     ​}P1IFG &= ~BIT0;
 +   
 +     ​chargement_consigne();​
 +     ​DAC0_out = consigne;
 +     ​Lcd_Cmd(0xc0);​
 +     ​sprintf(s,"​consigne= %d",​consigne);​
 +     ​lcd_display(s); ​   ​
 +     state = next_state; ​
 +      ​
 +     ​if(P1IN & 0x10)   // P1.4  mode standby ou lock
 +     {
 +     ​state=0;​
 +     }
 +     else {state=1;}
 +      ​
 +     ​switch (state)
 +     {
 +     case 0:​{standby();​}break;​
 +     case 1:​{lock();​}break; ​     ​
 +     ​} ​  
 +     }
 +     
 +** fonction init system**
 +     
 +    void init_sys(void)
 +    {
 +    P1SEL = 0x00;                             // P1 I/O select
 +    P2SEL = 0x00;                             // P2 I/O select
 +    P3SEL = 0x00;                             // P3 I/O select
 +    P4SEL = 0x00;                             // P4 I/O select ​
 +    P5SEL = 0x1B;                             // P5.1,3 SPI option select CS P5.0
 +    P6SEL = 0x18;                             // P6.5 ADC_3 options select ​ Enable A/D channel A3 channel A4
 +    P1DIR = 0xC0;                             // P1 inputs direction P1.6 P1.7 outputs
 +    P2DIR = 0xFE;                             // P2 input direction P2.0 input
 +    P3DIR = 0xFC;                             // P3 output direction P3.0 P3.1 inputs
 +    P4DIR = 0xFF;                             // P4 output direction ​
 +    P5DIR = 0xFF;                             // P5 output direction
 +    P6DIR = 0xF7;                             // P6.3 input/other output
 +    //ADC12CTL0 = REF2_5V + REFON; ​             // Internal 2.5V ref on
 +    ADC12CTL0 |= SHT0_4 + ADC12ON; ​           // Set sampling time, turn on ADC12
 +    ADC12CTL1 |= SHP + ADC12SSEL_3; ​          // Use sampling timer & SMCLK clock
 +    //​ADC12MCTL0 |= SREF_1; ​                    // Use Internal 2.5V for ADC
 +    ADC12MCTL0 = SREF_2; ​                     // Vr+ = VeREF+ (external)
 +    //​DAC12_0CTL = DAC12IR + DAC12AMP_2 + DAC12RES; ​ // 8bits, internal ref gain 1 (DAC_0 select with DAC12AMP_2)
 +    //​DAC12_1CTL = DAC12IR + DAC12AMP_2 + DAC12RES; ​ // 8bits, internal ref gain 1 (DAC_1 select with DAC12AMP_2) ​
 +    DAC12_0CTL = DAC12IR + DAC12SREF_3 + DAC12AMP_7 + DAC12ENC; ​ //Ref = Veref+, Full-Speed, Enable Conv.  ​
 +    DAC12_1CTL = DAC12IR + DAC12SREF_3 + DAC12AMP_7 + DAC12ENC; ​ //Ref = Veref+, Full-Speed, Enable Conv.     
 +    // DCO frequency ~200 kHz
 +    DCOCTL &= ~(DCO1 + DCO0); ​
 +    BCSCTL1 &= ~RSEL2;
 +    BCSCTL1 |= RSEL1; // + ~RSEL0;
 +    // timer B
 +    TBCCTL0 = CCIE;                           // CCR0 interrupt enabled
 +    TBCTL = TASSEL_2 + MC_1 + ID_3;           // clk = SMCLK/8 (=DCO/8), Up mode
 +    //TBCCR0 = 2500;                           // timer count at 1/2500 clk : 0,1s
 +    TBCCR0 = 250;  ​
 +    }
 +
  
fr/asservissement_numerique_de_temperature_pour_cavite_laser_ultra-stable.1521808453.txt.gz · Dernière modification: 2018/03/23 13:34 par fwiotte