Monday, January 30, 2006

74HCT32 Quad 2 input OR Gate

Here's the tech stuff:
http://jameco.com/wcsstore/Jameco/Products/ProdDS/246457TI.pdf

Product link:
http://jameco.com/webapp/wcs/stores/servlet/ProductDisplay?langId=-1&storeId=10001&catalogId=10001&productId=246457

Monday, January 23, 2006

Two timers and a fade

The following code demonstrates the difference between the two timers on HCS08 and their respective channels. LED1 is on Timer1 Channel1 and LED3 is on Timer2 Channel0. Their interrupt functions are identical, but their behavior is different due to their respective timers and duties. Pressing SWITCH1 will increase pulseMod and thus decrease the blink rate, whereas pressing SWITCH2 will decrease pulseMod and increase the blink rate. Lastly, LED5 is a good example of exercising the duty cycle. It's duty is being decremented/incremented through the main loop and will thus decrease/increase the duty (time of period) that the led is on.
---------------------
#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908gb60.h"
#define PRESCALAR 7
//#define MODULUS 32768
//#define MODULUS 16384
//#define MODULUS 8192
//#define MODULUS 4096
#define MODULUS 2048
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
#define DUTY50 (MODULUS/2)
long cntr=0;
long cntr2=0;
int goUp = 0;
int goUp2 = 0;
long cntr3 = 0;
long timer2chnl0 = 0;
long pulseMod = 25;
int fadeTime = 4;

void MCU_init(void); /* Device initialization function declaration */

void speedUpOrSlowDown(){
    if(SWITCH3==DOWN){      
       TPM1C0V = TPM1C0V/2;
    } else if(SWITCH4 == DOWN){
      if(TPM1C0V <= (MODULUS/2))
        TPM1C0V = TPM1C0V*2;
    }
}


void  interrupt VTimer1Chnl1 intTimer1Chnl1(){//for every period of zone out on LED5, this intterupt is set 500 times
 
 if(cntr3 %pulseMod ==0 )
   LED1 = ~LED1 ;
 cntr3++;
 TPM1C1SC_CH1F = 0; //reset interrupt
}

void initTimer1Chnl1(){
   /*configure PWM mode and pulse*/
  TPM1C1SC = 1;
  TPM1C1SC_MS1B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C1SC_ELS1A = 1; /*Select low as true*/
  TPM1SC_PS1 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1C1V = DUTY50;

  TPM1C1SC_CH1IE = 1;//turn on interrupt
}



void initTimer1Chnl0(){//LED5
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM1SC_CLKSA = 1;/*Select BUS clock*/
  TPM1SC_CLKSB = 0;

  TPM1SC_PS0 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1MOD = MODULUS;/*counter value, counts up to*/
  TPM1SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM1C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C0SC_ELS0A = 1; /*Select low as true*/
  //TPM1C0V = DUTY75;/*select final divider (duty cycle)*/
  TPM1C0V = 16;/*select final divider (duty cycle)*/
 
}


void interrupt VTimer2Chnl0 intTimer2Chnl0(){
 if(timer2chnl0 % pulseMod ==0)
  LED3 = ~LED3;
 
 timer2chnl0++;
 TPM2C0SC_CH0F = 0;
}

void initTimer2Chnl0(){
  TPM2C0SC_CH0IE = 1;  //enable channel
   
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;

  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = 8192;/*counter value, counts up to*/
  TPM2SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
  TPM2C0V = TPM2MOD/2;/*select final divider (duty cycle)*/
 
}

void initICG(){
  /*configure Internal Clock Generator [ICG]*/
  /*MFD[]={4,6,8,10,12,14,16,18}*/
  ICGC2_MFD = 7; /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC2_MFD = 3
  */
  ICGC2_RFD = 0; /* RFD[]={1,2,4,8,16,32,64,128}*/
  //ICGC1 = 0b00110000;
  ICGC1 = 0b00111000;
  /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC1 = 0b01111000;
  */
  while((ICGS1_LOCK==0)||(ICGS1_ERCS==0)){
  /*Ensure COP doesn't reset device whilst waiting for clock lock*/
  __RESET_WATCHDOG(); /* kicks the dog */
  }
  ICGC2_LOCRE = 1; /*enable reset if clock fails*/
 
}

void initKeyboardInterrupt(){
  KBI1SC_KBIE = 1;  //KBIE =>Keyboard Interrupt Enable
  KBI1PE_KBIPE4 = 1; //Keyboard Interrupt Port Enable 4 (switch1)
  KBI1PE_KBIPE5 = 1; //Keyboard Interrupt Port Enable 5 (switch2)
  KBI1PE_KBIPE6 = 1; //Keyboard Interrupt Port Enable 6 (switch3)
  KBI1PE_KBIPE7 = 1; //Keyboard Interrupt Port Enable 7 (switch4)
}

void interrupt Vkeyboard intSWITCH1(){
 if(SWITCH1 == DOWN){
  pulseMod +=2;
 }
 if(SWITCH2 == DOWN){
  pulseMod -=2;
 }
 KBI1SC_KBACK = 1;//ack
}

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  LED1 = OFF;
  LED2 = OFF;
  LED3 = OFF;
  LED4 = OFF;
  LED5 = OFF;
 
  initICG();
 
  initKeyboardInterrupt();
 
  initTimer1Chnl0();//LED5
 
  initTimer1Chnl1();//LED1
 
  initTimer2Chnl0();//LED3

  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
    
      if(goUp==1){
        TPM1C0V = TPM1C0V+fadeTime;
        cntr=0;
        cntr2++;
        if(TPM1C0V >= MODULUS){
          goUp = 0;
        }
      } else{
        //TPM1C0V = TPM1C0V/2;
        TPM1C0V = TPM1C0V-fadeTime;
        cntr2=0;
        cntr++;
        if (TPM1C0V <=0){
          goUp =1;
          TPM1C0V = fadeTime;
        }
      }
     
  } /* loop forever */
  /* please make sure that you never leave this function */
}

Saturday, January 21, 2006

timer fun

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908gb60.h"
#define PRESCALAR 7
//#define MODULUS 32768 //16*2048
//#define MODULUS 16384
//#define MODULUS 8192
//#define MODULUS 4096
#define MODULUS 2048
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
#define DUTY50 (MODULUS/2)
long cntr=0;
long cntr2=0;
int goUp = 0;
int goUp2 = 0;
long cntr3 = 0;

void MCU_init(void); /* Device initialization function declaration */

void speedUpOrSlowDown(){
    if(SWITCH3==DOWN){      
       TPM1C0V = TPM1C0V/2;
    } else if(SWITCH4 == DOWN){
      if(TPM1C0V <= (MODULUS/2))
        TPM1C0V = TPM1C0V*2;
    }
}


void  interrupt VTimer1Chnl1 intTimer1Chnl1(){//for every period of zone out on LED5, this intterupt is set 500 times
 
 if(cntr3 %50 ==0 )
   LED1 = ~LED1 ;
 cntr3++;
 TPM1C1SC_CH1F = 0; //reset interrupt
}

void initTimer1Chnl1(){
   /*configure PWM mode and pulse*/
  TPM1C1SC = 1;
  TPM1C1SC_MS1B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C1SC_ELS1A = 1; /*Select low as true*/
  TPM1SC_PS1 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1C1V = DUTY50;

  TPM1C1SC_CH1IE = 1;//turn on interrupt
}



void initTimer1Chnl0(){//LED5
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM1SC_CLKSA = 1;/*Select BUS clock*/
  TPM1SC_CLKSB = 0;

  TPM1SC_PS0 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1MOD = MODULUS;/*counter value, counts up to*/
  TPM1SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM1C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C0SC_ELS0A = 1; /*Select low as true*/
  //TPM1C0V = DUTY75;/*select final divider (duty cycle)*/
  TPM1C0V = 16;/*select final divider (duty cycle)*/
 
}


void interrupt VTimer2Chnl0 intTimer2Chnl0(){
 LED3 = ~LED3;
 TPM2C2SC_CH2F = 0;
}

void initTimer2Chnl0(){
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;

  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = 32768;/*counter value, counts up to*/
  TPM2SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
  TPM2C0V = TPM2MOD/2;/*select final divider (duty cycle)*/
}

void initICG(){
  /*configure Internal Clock Generator [ICG]*/
  /*MFD[]={4,6,8,10,12,14,16,18}*/
  ICGC2_MFD = 7; /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC2_MFD = 3
  */
  ICGC2_RFD = 0; /* RFD[]={1,2,4,8,16,32,64,128}*/
  //ICGC1 = 0b00110000;
  ICGC1 = 0b00111000;
  /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC1 = 0b01111000;
  */
  while((ICGS1_LOCK==0)||(ICGS1_ERCS==0)){
  /*Ensure COP doesn't reset device whilst waiting for clock lock*/
  __RESET_WATCHDOG(); /* kicks the dog */
  }
  ICGC2_LOCRE = 1; /*enable reset if clock fails*/
 
}

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  LED1 = OFF;
  LED2 = OFF;
  LED3 = OFF;
  LED4 = OFF;
  LED5 = OFF;
 
  initICG();
  initTimer1Chnl0();//LED5
 
  initTimer1Chnl1();//LED1
 
  initTimer2Chnl0();//LED3

  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
    
      if(goUp==1){
        TPM1C0V = TPM1C0V+8;
        cntr=0;
        cntr2++;
        if(TPM1C0V >= MODULUS){
          goUp = 0;
        }
      } else{
        //TPM1C0V = TPM1C0V/2;
        TPM1C0V = TPM1C0V-8;
        cntr2=0;
        cntr++;
        if (TPM1C0V <=0){
          goUp =1;
          TPM1C0V = 8;
        }
      }
      
 if(goUp2==1){
        TPM2C0V = TPM2C0V+32;
        if(TPM2C0V >= MODULUS){
          goUp2 = 0;
        }
      } else{
        TPM2C0V = TPM2C0V-32;
        if (TPM2C0V <=0){
          goUp2 =1;
          TPM2C0V = 32;
        }
      }
     
    
    
    
  } /* loop forever */
  /* please make sure that you never leave this function */
}

cvs creation string

cvs import -m "creation" drproj/project proj start

where "drproj/project" is now the name to check out, and proj is the directory of the files to place into the new CVS project.

Monday, January 16, 2006

Interrupts, timer, LED code

Fun time figuring out flags and interrupts to get this work on my M68DEMO908GB60.
-------------------------------
/* File: M68DEMO908GB60.h*/
/* include peripheral declarations */
#include <MC9S08GB60.h>
/*define value for led's when on and off*/
#define ON 0
#define OFF 1
/*define value for switches when up (not pressed) and down (pressed)*/
#define UP 1
#define DOWN 0
/*define led's*/
#define LED1 PTFD_PTFD0
#define LED2 PTFD_PTFD1
#define LED3 PTFD_PTFD2
#define LED4 PTFD_PTFD3
#define LED5 PTDD_PTDD0

/*define switches*/
#define SWITCH1 PTAD_PTAD4
#define SWITCH2 PTAD_PTAD5
#define SWITCH3 PTAD_PTAD6
#define SWITCH4 PTAD_PTAD7

#define Vspi 15
#define Vkeyboard 22
//define Timer1 interrupts
#define VTimer1Overflow 8
#define VTimer1Chnl2 7
#define VTimer1Chnl1 6
#define VTimer1Chnl0 5

//define Timer2 interrupts
#define VTimer2Overflow 14
#define VTimer2Chnl4 13
#define VTimer2Chnl3 12
#define VTimer2Chnl2 11
#define VTimer2Chnl1 10
#define VTimer2Chnl0 9

#define Vatd 23
#define Viic 24
-------------------------------


#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908GB60.h"

#define PRESCALAR 7
#define MODULUS 32768
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
int sequenceNumber = 0;

void resetLEDs(){
 LED1 = OFF;
 LED2 = OFF;
 LED3 = OFF;
 LED4 = OFF;
 LED5 = OFF;
}

void interrupt Vkeyboard intSWITCH1(){
  resetLEDs();
  if(SWITCH1 == DOWN){
    sequenceNumber = 1;
  }else if(SWITCH2 == DOWN){
    sequenceNumber = 2;
  }else if(SWITCH3 == DOWN){
    sequenceNumber = 3;
  }else if(SWITCH4 == DOWN){
    sequenceNumber = 0;
  }
   
  KBI1SC_KBACK = 1;//ack
}

/*
* Reset all LEDs
*/
int ledsAreReset(){
 return ((LED1 == OFF) && (LED2 == OFF)&&(LED3 == OFF)&&(LED4 == OFF)&&(LED5 == OFF));
}

/*
* Light up the LEDs in sequence
*/
void ledLightInSeq(){
  if(((LED1 == OFF) && (LED5 == ON)) || (ledsAreReset())){
     resetLEDs();
     LED1 = ON;
   }else if((LED2 == OFF) && (LED1 == ON)){
     resetLEDs();
     LED2 = ON;
   }else if((LED3 == OFF) && (LED2 == ON)){
     resetLEDs();
     LED3 = ON;
   }else if((LED4 == OFF) && (LED3 == ON)){
     resetLEDs();
     LED4 = ON;
   }else if((LED5 == OFF) && (LED4 == ON)){
     resetLEDs();
     LED5 = ON;
   }
}
/*
* Light up the LEDs in reverse sequence
*/
void ledLightRevSeq(){
  if(((LED5 == OFF) && (LED1 == ON)) || (ledsAreReset())){
     resetLEDs();
     LED5 = ON;
   }else if((LED4 == OFF) && (LED5 == ON)){
     resetLEDs();
     LED4 = ON;
   }else if((LED3 == OFF) && (LED4 == ON)){
     resetLEDs();
     LED3 = ON;
   }else if((LED2 == OFF) && (LED3 == ON)){
     resetLEDs();
     LED2 = ON;
   }else if((LED1 == OFF) && (LED2 == ON)){
     resetLEDs();
     LED1 = ON;
   }
}

/*
* Light LEDs from middle going out
*/
void ledLightMidOut(){
  if(((LED5 == ON) && (LED1 == ON)) || (ledsAreReset())){
    resetLEDs();
    LED3 = ON;
  }else if((LED3 == ON)){
    resetLEDs();
    LED2 = ON;
    LED4 = ON;
  }else if((LED2 == ON) && (LED4 == ON)){
    resetLEDs();
    LED1 = ON;
    LED5 = ON;
  }
}

/*
* Interrupt handler for controlling light sequence based on Timer2 clock overflow
*/
void interrupt VTimer2Overflow intTimer2Ovf(){
 if(sequenceNumber ==1 ){
   ledLightInSeq();  
  
 } else if(sequenceNumber == 2){
   ledLightRevSeq();
 } else if(sequenceNumber == 3){
   ledLightMidOut();
 } else {
   LED1 = ~LED1;
   LED5 = ~LED5;
 }

 TPM2SC_TOF = 0;//ack, change overflow bit
}

/*
* Initialize TPM2
*/
void initTimer2(){
  TPM2SC_TOIE = 1;
  /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;
  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = MODULUS;/*set Counter modulus*/
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
 

  TPM2C0V = DUTY75;//sets number that if matched by counter, will set channel flag

}

void initLedStuff(){
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port D&F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  PTDDD = 0x0f;
  resetLEDs();
}

void initKeyboardInterrupt(){
  KBI1SC_KBIE = 1;  //KBIE =>Keyboard Interrupt Enable
  KBI1PE_KBIPE4 = 1; //Keyboard Interrupt Port Enable 4 (switch1)
  KBI1PE_KBIPE5 = 1; //Keyboard Interrupt Port Enable 5 (switch2)
  KBI1PE_KBIPE6 = 1; //Keyboard Interrupt Port Enable 6 (switch3)
  KBI1PE_KBIPE7 = 1; //Keyboard Interrupt Port Enable 7 (switch4)
}

/*
* Sample code from docs
*/
void manageDuty(){
   if(SWITCH3==DOWN){
      /*Switch pressed*/
      if(SWITCH4==DOWN){/**/
        TPM1C0V = DUTY75;/**/
        LED3 = ON;/**/
        LED4 = OFF;/**/
      }else{
        TPM1C0V = DUTY25;/**/
        LED3 = OFF;/**/
        LED4 = ON;/**/
      }
    }
}



void MCU_init(void); /* Device initialization function declaration */

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  initLedStuff();
  initTimer2();
  initKeyboardInterrupt();
 
 
  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
   
    
  } /* loop forever */
 
}

Thursday, January 12, 2006

Freescale HCS908

The onboard demos work as described in the "Getting Started with the M68DEMO908GB60 rev 02)", but the file M68DEMO908GB60demo.mcp does not exist, there is not a "M68DEMS.zip" file included on the demo board CD. UPDATE: M68DEMS.zip is included on the CD underneath the Code Warrior package. But, even still, the code did not contain what was referenced.

Referencing the AN2616_Getting_Started_With_HCS08_and_CodeWarrior references (p4)AN2616SW.zip, which also does not exist with the bundled software. Sheesh.

So the HCS908 is debuggable, out of box, using the db9 serial connector with SCI1.

New project creation:
By selecting "P&E Full Chip Simulation", "P&amp;E Hardware Debugging" and "Motorola Serial Monitor", it will be possible to use either simulation, the serial monitor within the HCS08 FLASH, or BDM to debug code.There is no code overhead as a result of choosing multiple connection methods.

To enable serial monitor connection press switch 4 and switch the power on, set the target to be "Monitor". Once the debugger appears a couple modal dialogs should quickly appear and disappear showing that the FLASH is being erased. If this doesn't happen then there is likely a communications problem and the simulator will then run the program.

Here's the first go at LED manipulation:

#include <hidef.h> /* for EnableInterrupts macro */
#include <MC9S08GB60.h> /* include peripheral declarations */

#define ON 0
#define OFF 1

#define UP 1
#define DOWN 0

#define LED1 PTFD_PTFD0
#define LED2 PTFD_PTFD1
#define LED3 PTFD_PTFD2
#define LED4 PTFD_PTFD3
#define LED5 PTFD_PTFD4

#define SWITCH1 PTAD_PTAD4
#define SWITCH2 PTAD_PTAD5
#define SWITCH3 PTAD_PTAD6
#define SWITCH4 PTAD_PTAD7
long approxTwoSeconds = 100000;


void delay(long millis){
long cnt=0;
for(cnt=0; cnt<millis; cnt++){
//wait
}
}
static void pulse(long flashTime){
LED1 = ON;
LED2 = ON;
LED3 = ON;
LED4 = ON;
LED5 = ON;
delay(flashTime);
LED1 = OFF;
LED2 = OFF;
LED3 = OFF;
LED4 = OFF;
LED5 = OFF;
delay(flashTime);
LED1 = ON;
LED2 = ON;
LED3 = ON;
LED4 = ON;
LED5 = ON;
delay(flashTime);
LED1 = OFF;
LED2 = OFF;
LED3 = OFF;
LED4 = OFF;
LED5 = OFF;
delay(flashTime);


}

static void simpleSequence(long delayBetweenLights){

LED1 = ON;
delay(delayBetweenLights);
LED1 = OFF;

LED2 = ON;
delay(delayBetweenLights);
LED2 = OFF;

LED3 = ON;
delay(delayBetweenLights);
LED3 = OFF;

LED4 = ON;
delay(delayBetweenLights);
LED4 = OFF;

LED5 = ON;
delay(delayBetweenLights);
LED5 = OFF;



}
void main(void) {
int cnt = 0;

EnableInterrupts; /* enable interrupts */
/* include your code here */
PTADD = 0;//initialize input
PTAPE=0xF0;//Pullups on upper 4 bits
PTFDD=0x0F; //initializes ports 0,1,2,3 of Port F as outputs (which are connected to the LEDs)
LED1=OFF;
LED2=OFF;
LED3=OFF;
LED4=OFF;
LED5=OFF;

for(;;) {

__RESET_WATCHDOG(); /* feeds the dog */

simpleSequence(approxTwoSeconds);
pulse(10000);
}

}

Thursday, January 05, 2006

Nullable fields in a unique constraint, BAD

Can't have a unique constraint with a nullable field and treat that nullable as a "unique" value.

(Oracle) http://www.adp-gmbh.ch/ora/misc/integrity_constraints.html ,
http://www.techonthenet.com/oracle/unique.php

(Postgresql)http://www.postgresql.org/docs/8.1/interactive/indexes-unique.html

(MySQL5) http://dev.mysql.com/doc/refman/5.0/en/create-table.html

A UNIQUE index is one in which all values in the index must be distinct. An error occurs if you try to add a new row with a key that matches an existing row. The exception to this is that if a column in the index is allowed to contain NULL values, it can contain multiple NULL values. This exception does not apply to BDB tables, for which an indexed column allows only a single NULL.