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 <msp430x43x.h>
#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 clearLCDvoid); // Clears the LCD memory
void initvoid); // Increments the hours variable and rolls over to 12 if needed)
void decMinutesvoid);
void incMinutesvoid);
void incHoursvoid);
void displayTempvoid); // Gets the current temperature and displays it on the LCD
void changeUnitModevoid); // Changes the units of measurement from English to Metric
void calibratevoid); // Calibrates the temperature
void getTempvoid); // Gets the current temperature
void flashLCDvoid);
void flash_writeword* address, int data);// Write the integer) data to the addressed flash
void flash_eraseword* 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 mainvoid)
{
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;
iflcdOffModeTime == 0)
{
LCDCTL |= LCDON;
displayTime);
twoButtonsPressed = 0;
}
else{
lcdOffModeTime–;
}
}
}
}
int __low_level_initvoid)
{
FLL_CTL0 |= XCAP18PF; // Set load capacitance for xtal
WDTCTL = WDTPW + WDTHOLD; // Disable the Watchdog
whileFLL_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 flashLCDvoid)
{
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_erasevoid *)&Refcal_flash); // Erase Flash INFO segment A
flash_writevoid *)&Refcal_flash, Refcal_ram);// Write cal data to Refcal
flash_writevoid *)&Temp_offset, Temp_offset_ram);// Write offset data
flash_writevoid *)&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 getTempvoid)
{
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 displayTempvoid)
{
clearLCD);
if unitMode == ENGLISH )
{
displayValuetempF, 2);
LCDM7 = char_gen[15]; // Display "F'
LCDM6 = char_gen[13]; // Display degree
}
else
{
tempF -= 32;
tempF *= .5555; // 5/9
displayValuetempF, 2);
LCDM7 = char_gen[12]; // Display "C"
LCDM6 = char_gen[13]; // Display degree
}
}
void displayTimevoid)
{
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_shorthours, 0x01);
if hours == 0x13)
hours = 0x01; // If hrs transition is 12 to 13, hrs = 1
}
void incMinutesvoid)
{
minutes = __bcd_add_shortminutes, 0x01);
if minutes == 0x60)
{
minutes = 0;
incHours);
}
}
void decMinutesvoid)
{
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 clearLCDvoid)
{
int i;
for i = 0; i < 20; i++ ){
LCD[i] = 0;
}
}
void changeUnitModevoid)
{
unitMode ^= 1; // Toggle between 1 and 0
clearLCD);
ifunitMode == 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_writeword* address, int data)// Write the integer) data to the addressed flash
{
word gie = _BIC_SRGIE) & 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_SRgie); // Restore interrupts to previous state)
}
void flash_eraseword* address) // Erase the addressed flash segment
{
word gie = _BIC_SRGIE) & 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_SRgie); // Restore interrupts to previous state)
}
// Basic Timer interrupt service routine
#pragma vector=BASICTIMER_VECTOR
__interrupt void bt_isrvoid)
{
seconds = __bcd_add_shortseconds, 0x01);
if seconds == 0x60 )
{
seconds = 0;
minutes = __bcd_add_shortminutes, 0x01);
if minutes == 0x60 )
{
minutes = 0;
hours = __bcd_add_shorthours, 0x01);
if hours == 0x13 )
{
hours = 0x01;
}
}
}
LPM3_EXIT; // Exit LPM3 mode on return
}
#pragma vector=PORT2_VECTOR
__interrupt void p2_isrvoid)
{ 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_isrvoid)
{
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_isrvoid)
{
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
}