Outils pour utilisateurs

Outils du site

Traductions de cette page:

votre temps local: :: ()

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

Heure UTC client: :: Offset client: s - delai: ms - - timeZone: Heure UTC: ::

Panneau latéral

  • Corrélateurs
  • Bruits inhérent au numérique : bruit de phase, gigue, stabilité temporelle des circuits numériques
  • Compteur à intervalle de temps
  • Détection synchrone
  • Choix ADC/DAC pour applications TF
  • Mesure Sphi(f) et sigma_y(tau)
  • Servo controls (Liens fibrés, …)
  • Manipulation d'objets et fréquences (atomes froids, spectral hole burning, ions ….)
  • Datations « officielles »
  • Compteurs, avec et sans temps morts.
  • Logiciel / Pilotes
  • IP cores (FPGA)
  • Chipscope
fr:asservissement_numerique_de_temperature_pour_cavite_laser_ultra-stable

Asservissement en température numérique d'une cavité ultra-stable au LPL pour le Strontium

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: 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é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

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.txt · Dernière modification: 2018/04/06 11:01 par fwiotte