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
}