msp430芯片初探

N年前作的一个超级烂的msp430 并口仿真器,当时是msp430刚刚进入中国的时候做的,竟然让我在箱子里面翻了出来,我都佩服我自己了。

尽管仿真器看着烂,但是居然能用!

此外,在箱子里面找出了M年前参加msp430研讨会送的msp430f437手表,依稀还能看到“手表”的风采。

其中手表的原理图如下:

手表的有关介绍如下:

Watch Operation:

First Startup:

When initially powered, the device will display the default time:  12:00:00.  It will immediately begin counting the seconds.

Normal Operation:

Setting the Time (Minutes):  Press and hold SW1, pressing SW2 now increments the minute value.  

Setting the Time (Hours):  Press and hold SW2, pressing SW1 now increments the hour value. 

Note: When pressing SW2, the device will first appear to change the unit mode.  This is ignored by the watch after SW1 is pressed.

Displaying the Temperature:  Press SW1, watch will return to clock mode after 6 seconds

Changing the unit Mode:  Press and hold SW2

Switching off LCD: Press SW1 (to enter Temperature mode) Press SW1 again.  The LCD will turn on after 5 seconds.

Note: while LCD is off, device is in “low-power clock” mode and not in temperature mode.

Erasing Calibration Values:  Press and hold SW2 until the temperature is displayed.  While temperature is displayed, SW2 increases the displayed value and SW1 decreases the displayed value.  Holding SW1 and SW2 simultaneously for 1 second saves the calibrated value.

Note For Instructors:  The code running on the watch boards when shipped does not save temperature calibrations between power offs.  The C file available on the web does include this function as well as displaying 1degree F to indicate being un-calibrated.

 

标准msp430的JTAG接口如下:

编译程序安装的是IAR 4.201版本,选择里面的connection为softbaugh LPT(其他有关LPT的选项也是可以的)。

手上还有一个JLINK,赶明再尝试一下是否可以仿真。

付程序如下:

//******************************************************************************
//  430Day 2004 watch.c - Multi-function demo with Clock & Temperature
//
//
//  Murugavel Raju
//  Lane Westlund
//  Texas Instruments, Inc
//  January, 2004
//  Built with IAR Embedded Workbench Version: 2.21B
//  Modified by Albus 3/25/2004
//
//
//******************************************************************************

#include 

#define PB_TEMP (1 << 1)                // Push Button 1, Temperature: P2.1
#define PB_ALT  (1 << 2)                // Push Button 2, Alternate: P2.2
#define TEMP_COMPENSATION 16802 / 4096

typedef unsigned int word;              // Type definition for 'word'

enum
{
  ENGLISH,
  METRIC
};

static char *LCD = LCDMEM;
static int MODE_TIME = 5;
static int LCD_OFF_TIME = 5;

static int Refcal_ram = 1500;           // ADC12 1.5V reference calibration variable
static int Temp_slope_ram = 761;        // Temperature slope calibration variable
static int Temp_offset_ram = 469;       // Temperature offset calibration variable

int unitMode = ENGLISH;                 // The current state for measurements (metric/english)
static unsigned char seconds = 0, minutes = 0, hours = 0x12; // The default time values
int tempModeTime;                       // The number of seconds left to display the temperature
int lcdOffModeTime;                     // The number of seconds left to have the LCD off
int twoButtonsPressed;                  // The amount of time both buttons were pressed
signed int tempF;                       // Temperature variable
int held_down = 0;

void displayTime( void );               // Displays time
void displayValue( int value, int stop );// Displays an int value on the LCD.  Value can be moved in memory using the stop variable (in order to append metric characters to an int value)
void clearLCD(void);                    // Clears the LCD memory
void init(void);                        // Increments the hours variable (and rolls over to 12 if needed)
void decMinutes(void);
void incMinutes(void);
void incHours(void);
void displayTemp(void);                 // Gets the current temperature and displays it on the LCD
void changeUnitMode(void);              // Changes the units of measurement from English to Metric
void calibrate(void);                   // Calibrates the temperature
void getTemp(void);                     // Gets the current temperature
void flashLCD(void);

void flash_write(word* address, int data);// Write the (integer) data to the addressed flash
void flash_erase(word* address);        // Erase the addressed flash segment

//added the following SIX lines to declare variables in Flash INFO memory for IAR 2.x
#pragma dataseg=INFOA
__no_init static word Refcal_flash;     // ADC12 reference calibration in Flash INFO memory
__no_init static word Temp_slope;       // Temperature sensor slope calibration in Flash INFO memory
__no_init static word Temp_offset;      // Temperature sensor offset calibration in Flash INFO memory
#pragma dataseg=default

// LCD segment definitions.
#define d 0x80
#define c 0x40
#define b 0x20
#define a 0x10
#define h 0x08
#define e 0x04
#define g 0x02
#define f 0x01

const char char_gen[] = {
  a+b+c+d+e+f,                          // Displays "0"
  b+c,                                  // Displays "1"
  a+b+d+e+g,                            // Displays "2"
  a+b+c+d+g,                            // Displays "3"
  b+c+f+g,                              // Displays "4"
  a+c+d+f+g,                            // Displays "5"
  a+c+d+e+f+g,                          // Displays "6"
  a+b+c,                                // Displays "7"
  a+b+c+d+e+f+g,                        // Displays "8"
  a+b+c+d+f+g,                          // Displays "9"
  a+b+c+e+f+g,                          // Displays "A"
  0x00,                                 // Displays  Blank
  a+d+e+f,                              // Displays "C"
  a+b+f+g,                              // Displays "degrees" o
  a+d+e+f+g,                            // Displays "E"
  a+e+f+g,                              // Displays "F"  
  h,                                    // Displays ":" or "."
  g,                                    // Displays "-"
  f+g+e+d                               // Displays "t"                                                       
};


#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef g
#undef h

void main(void)
{
 
  init();
  clearLCD();                                         
   
  while( 1 )
  {
    LPM3;                               // Wait in LPM3 for the 1 second timer interrupt
    if( tempModeTime > 0 )              // Called if tempMode is the highest non-zero mode (temp was the most recent pushed)
    {
        LCDCTL |= LCDON;
        getTemp();
       
        if (tempF > 79)
          P1OUT |= 0x01;
        else
          P1OUT &= ~0x01;
         
        displayTemp();
        tempModeTime--;                 // Decrement the temp time counter (once a second)
    }
    else if( (~P2IN & (PB_ALT)) )       // if alt button held
    {
      P1OUT &= ~0x01;
      held_down++;
      if( held_down == 4 )
      {
        held_down = 0;

        unitMode ^= 1;                  // Toggle between 1 and 0
        calibrate();
       
      }
    }
    else                                // Default, display the time
    {                              
      P1OUT &= ~0x01;
      if(lcdOffModeTime == 0)
      {
        LCDCTL |= LCDON;
        displayTime();                             
        twoButtonsPressed = 0;
      }
      else{
        lcdOffModeTime--;
      }
    }
  }
}

int __low_level_init(void)
{

  FLL_CTL0 |= XCAP18PF;                 // Set load capacitance for xtal
  WDTCTL = WDTPW + WDTHOLD;             // Disable the Watchdog
  while(FLL_CTL0 & LFOF);               // Wait until LF OSC stabilizes
    
  return (1);                           // Flag to initialize the data segment
}

void init( void )
{
  P1OUT = 0x00;                         // P1.0 = LED
  P1DIR = 0xFF;
  P2OUT = 0x00;
  P2DIR = 0xF9;
  P3OUT = 0x00;
  P3DIR = 0xFF;
 
  P6OUT = 0x00;
  P6DIR = 0xFF;
   
  LCDCTL = LCDON + LCDSG0_3 + LCD4MUX;  // 4mux LCD, segs0-15 = outputs
   
  BTCTL = BT_fLCD_DIV128 + BTDIV + BTIP2 + BTIP1;// Set LCD frame freq = ACLK/128, set interrupt interval
  IE2 |= BTIE;                          // Enable Basic Timer interrupt
  P5SEL  = 0xFC;                        // Set Rxx and COM pins for LCD   
  clearLCD();
   
  P2DIR = ~(PB_TEMP + PB_ALT);          // Set ports to input for temperature and alternate switches
 
  P2IFG = 0;                            // Clear pending P2 interrupts
  P2IES = PB_TEMP + PB_ALT;             // Set interrupt to occur on high-to-low transition on switches
  P2IE = PB_TEMP + PB_ALT;              // Enable interrupts for switches
   
  FCTL2 ^= FXKEY + FN2 + FN1 + FN0;     // Set FLASH timing generator 447.5Khz                            
        
  ADC12CTL1 = SHP;                      // Pulse mode select for ADC12
  ADC12IE = BIT0;                       // Enable interrupts for ADC12
 
  Refcal_ram = Refcal_flash;            // Make RAM copy of Vref cal value
  Temp_slope_ram = Temp_slope;          // Make RAM copy of Temp slope value
  Temp_offset_ram = Temp_offset;        // Make RAM copy of Temp offset value
 
  _EINT();                                                        
}

void flashLCD(void)
{
  int i;
  TACTL = TASSEL0 + TACLR + MC1;        // TACLK = ACLK, 16-bit up-mode
  for( i = 0; i < 20; i++)
  {
    LCD[i] = 0xff;
  }
  for( i = 0 ; i < 7; i++)
  {
    LCDCTL |= LCDSON;
    CCR1 = 60000;                       // Delay
    CCTL1 = CCIE;                       // Compare-mode interrupt
    LPM3;                               // Wait for delay
  }
}

void calibrate()
{     
  _DINT();
   
  Refcal_ram = 1500;                    // Make RAM copy of Vref cal value
  Temp_slope_ram = 761;                 // Make RAM copy of Temp slope value
  Temp_offset_ram = 469;                // Make RAM copy of Temp offset value
       
  _EINT();
  getTemp();
  Temp_offset_ram += tempF - 75;        // Make default temp 75 (user will be near there)
   
  while( !((~P2IN & PB_TEMP) && (~P2IN & PB_ALT)))// Loop until user holds down both buttons
  {
   
    TACTL = TASSEL0 + TACLR + MC1;      // TACLK = ACLK, 16-bit up-mode.
    P2IE &= ~(PB_TEMP + PB_ALT);        // disable interrupts for switches
 
    if(~P2IN & PB_TEMP)
    {
      Temp_offset_ram++;
    }
    if(~P2IN & PB_ALT)
    {
      Temp_offset_ram--;
    }
    
    CCR1 = 10000;                       // Delay
    CCTL1 = CCIE;                       // Compare-mode interrupt
       
    LPM3;                               // Wait for delay
       
    getTemp();
    displayTemp();
  }
  while( (~P2IN & PB_TEMP) && (~P2IN & PB_ALT) ); // pause until user stops holding down buttons
  tempModeTime = 0;
  P2IFG = 0;
  P2IE |= PB_TEMP + PB_ALT;           // Enable interrupts for switches
 
  flash_erase((void *)&Refcal_flash);   // Erase Flash INFO segment A
  flash_write((void *)&Refcal_flash, Refcal_ram);// Write cal data to Refcal
  flash_write((void *)&Temp_offset, Temp_offset_ram);// Write offset data
  flash_write((void *)&Temp_slope, Temp_slope_ram);// Write slope data
 
  _EINT();                              // Re-enable general interrupts
 
  Refcal_ram = Refcal_flash;            // Make RAM copy of Vref cal value
  Temp_slope_ram = Temp_slope;          // Make RAM copy of Temp slope value
  Temp_offset_ram = Temp_offset;        // Make RAM copy of Temp offset value

}

void getTemp(void)
{
  ADC12CTL0 &= ~ENC;                    // Clear ENC first
  ADC12CTL0 = SHT0_15 + REFON + ADC12ON;
  ADC12MCTL0 = INCH_10 + SREF_1;        // Sample channel 10 using internal reference
  TACTL = TASSEL0 + TACLR + MC1;        // TACLK = ACLK, 16-bit up-mode
  CCR1 = 1500;                          // Delay to allow Ref to settle
  CCTL1 = CCIE;                         // Compare-mode interrupt
  LPM3;                                 // Wait for delay
  ADC12CTL0 |= ENC + ADC12SC;           // Start conversion
  LPM3;                                 // Wait for conversion completion
  ADC12CTL0 &= ~ENC;                    // Clear ENC first
  ADC12CTL0 = 0;                        // Turn-off ADC12
   
  tempF = (((long) ADC12MEM0 * Temp_slope_ram) / 4096 - Temp_offset_ram);
}

void displayTemp(void)
{
  clearLCD();
 
  if( unitMode == ENGLISH )
  {
    displayValue(tempF, 2);
    LCDM7 = char_gen[15];               // Display "F'
    LCDM6 = char_gen[13];               // Display degree
  }
  else
  {
    tempF -= 32;
    tempF *= .5555;                     // 5/9
       
    displayValue(tempF, 2);
    LCDM7 = char_gen[12];               // Display "C"
    LCDM6 = char_gen[13];               // Display degree
  }
}

void displayTime(void)
{
  LCDM7 = 0;
   
  LCDM6 = char_gen[seconds&0x0f];
  LCDM5 = char_gen[(seconds>>4)&0x0f]+char_gen[16];
   
  LCDM4 = char_gen[minutes&0x0f];
  LCDM3 = char_gen[(minutes>>4)&0x0f]+char_gen[16];
   
  LCDM2 = char_gen[hours&0x0f];
  if( hours & 0x10 )
  {
    LCDM1 = char_gen[1];
  }
  else
  {
    LCDM1 = 0;
  }
}

void displayValue( int value, int stop )
{
  int i;
  int sign = 0;
  if( value < 0 )
  {
    value = ~value +1;
    sign = 1;
  }
  i = 6-stop;
  while( value > 9 )
  {
    LCD[i] = char_gen[value%10];
    value = value/10;
    i--;
  }
  LCD[i] = char_gen[value];
  if( sign )
  {
    LCD[i-1] = char_gen[17];
  }
}

void incHours (void)
{   
  hours = __bcd_add_short(hours, 0x01);
 
  if (hours == 0x13)
    hours = 0x01;                       // If hrs transition is 12 to 13, hrs = 1

}

void incMinutes(void)
{   
  minutes = __bcd_add_short(minutes, 0x01);
  if (minutes == 0x60)
  {
    minutes = 0;
    incHours();
  } 
}

void decMinutes(void)
{
  if( (--minutes & 0x0f) == 0x0f )
  {
    minutes = (minutes & 0xf0)+0x09;
    if( minutes == 0xf9 )
    {
      minutes = 0x59;
      if( --hours == 0x00)
      {
        hours = 0x12;
      }
      else if( hours == 0x0f )
      {
        hours = 0x09;
      }
    }
  }

}


void clearLCD(void)
{
  int i;
  for( i = 0; i < 20; i++ ){
    LCD[i] = 0;
  }
}

void changeUnitMode(void)
{

  unitMode ^= 1;                        // Toggle between 1 and 0
  clearLCD();
  if(unitMode == METRIC)
  {
    LCDM7 = char_gen[12];               // Display degrees C for indication
    LCDM6 = char_gen[13];
  }
  else
  {
    LCDM7 = char_gen[15];               // Display degrees F for indication
    LCDM6 = char_gen[13];
  }
}


void flash_write(word* address, int data)// Write the (integer) data to the addressed flash
{
  word gie = _BIC_SR(GIE) & GIE;        // Disable interrupts

  FCTL3 = FWKEY;                        // Unlock the flash
  FCTL1 = FWKEY + WRT;                  // Enable flash write
  *address = data;                      // Write the data to the flash
  FCTL1 = FWKEY;                        // Disable flash write
  FCTL3 = FWKEY + LOCK;                 // Lock the flash
  _BIS_SR(gie);                         // Restore interrupts (to previous state)
}

void flash_erase(word* address)         // Erase the addressed flash segment
{
  word gie = _BIC_SR(GIE) & GIE;        // Disable interrupts
 
  FCTL3 = FWKEY;                        // Unlock the flash
  FCTL1 = FWKEY + ERASE;                // Enable flash segment erase
  *address = 0;                         // Erase the flash segment
  FCTL1 = FWKEY;                        // Disable flash segment erase
  FCTL3 = FWKEY + LOCK;                 // Lock the flash
  _BIS_SR(gie);                         // Restore interrupts (to previous state)
}

// Basic Timer interrupt service routine
#pragma vector=BASICTIMER_VECTOR
__interrupt void bt_isr(void)
{
  seconds = __bcd_add_short(seconds, 0x01);
  if( seconds == 0x60 )
  {
    seconds = 0;
    minutes = __bcd_add_short(minutes, 0x01);
    if( minutes == 0x60 )
    {
      minutes = 0;
      hours = __bcd_add_short(hours, 0x01);
      if( hours == 0x13 )
      {
        hours = 0x01;
      }
    }
  }

  LPM3_EXIT;                            // Exit LPM3 mode on return
}


#pragma vector=PORT2_VECTOR
__interrupt void p2_isr(void)
{ unsigned volatile int i;

  for (i = 0x3000; i>0 ; i--);          //Debounce
 
  if( (~P2IN & PB_TEMP)&&(P2IFG&PB_ALT) )//If temp button held, and alt button pressed...
  {
    incMinutes();
    tempModeTime = 0;
    displayTime();
    P1OUT &= ~0x01;
  }
  else if( (~P2IN & PB_ALT)&&(P2IFG&PB_TEMP) )//If alt button held, and temp button pressed...
  {

    unitMode ^= 1;                      // Toggle between 1 and 0
    incHours();
    displayTime();
    tempModeTime = 0;
    P1OUT &= ~0x01;
    held_down = 0;
  }
  else if ( tempModeTime > 0 && P2IFG & PB_TEMP ){
    LCDCTL &= ~LCDON;
    lcdOffModeTime = LCD_OFF_TIME;
    tempModeTime = 0;
  }
  else if( P2IFG & PB_TEMP )            // If temp button pressed, start displaying temp
  {        
    tempModeTime = MODE_TIME;
  }
 
  else if ( P2IFG & PB_ALT )            // If alt button pressed, toggle degrees C & F
  {       
    changeUnitMode();
  }
 
  P2IFG = 0;
}

#pragma vector=ADC_VECTOR
__interrupt void adc_isr(void)
{
  ADC12IFG &= ~BIT0;                    // Clear MEM0 interrupt flag
  LPM3_EXIT;                            // The ADC value is available in ADC12MEM0
}

enum
{
  NO_INT = 0,
  CC1_INT = 2,
  CC2_INT = 4,
  TA_INT = 10
};

#pragma vector=TIMERA1_VECTOR
__interrupt void ta1_isr(void)
{
  switch (TAIV)
  {
    case NO_INT: break;
    case CC1_INT: TACTL = 0; break;     // Disable TimerA
    case CC2_INT: break;
    case TA_INT: break;
    default: break;
  }
  LPM3_EXIT;                            // Exit LPM3 on return
}

 

你可能感兴趣的:(msp430开发)