Simple stopwatch based on MSP430f149 MCU[Copy link]
Function: Press a button to start timing, press the button again to pause timing, that is, one button can realize the pause and start function, set another button, press the button for more than three seconds, the stopwatch is reset. The timing accuracy is required to be 10 milliseconds. This experiment uses the timing function of timerA of MSP430 microcontroller, and LCD1602 is used as the display device. The code is as follows: [csharp] view plain copy #include
#include "Config.h" int second = 0, minute = 0, count = 0, flag = 0, a = 0, b = 0, c = 0; unsigned char FlagLcd; //**************************************************************************** // Initialize IO port subroutine//**************************************************************************** void Port_init() { P4SEL = 0x00; P4DIR = 0xFF; //Data port output mode P5SEL = 0x00; P5DIR|= BIT5 + BIT6 + BIT7; //Control port is set to output mode P1SEL = 0x00; //P1 normal IO function P1DIR = 0xF0; //P10~P13 input mode, external circuit has been connected to pull-up resistor P1IE = 0x0f; //Enable bit interrupt P1IES = 0x00; //Rising edge triggers interrupt P1IFG = 0x00; //Software clears interrupt flag register} //************************************************************************ // Display command write function//*********************************************************************** void LCD_write_com(unsigned char com) { RS_CLR; RW_CLR; EN_SET; DataPort = com; //Command write port delay_ms(5); EN_CLR; } //*********************************************************************** // Display data write function//*********************************************************************** void LCD_write_data(unsigned char data) { RS_SET; RW_CLR; EN_SET; DataPort = data; //Data write port delay_ms(5); EN_CLR; } //*************************************************************************** // } //************************************************************************ void LCD_clear(void) { LCD_write_com(0x01); //Clear screen display delay_ms(5); } //*********************************************************************** // Display screen string write function//*********************************************************************** void LCD_write_str(unsigned char x,unsigned char y,int w) { if (y == 0) { LCD_write_com(0x80 + x); //First line display} else { LCD_write_com(0xC0 + x); //Second line display} LCD_write_data(48+w); } //*************************************************************************** // Display screen single character write function//*********************************************************************** void LCD_write_char(unsigned char x,unsigned char y,unsigned char data) { if (y == 0) { LCD_write_com(0x80 + x); //Display the first line } else { LCD_write_com(0xC0 + x); //Display the second line } LCD_write_data( data); } //*********************************************************************** // Display screen initialization function//*************************************************************************** void LCD_init(void) { LCD_write_com(0x38); //Display mode setting delay_ms(5); LCD_write_com(0x08); //Display off delay_ms(5); LCD_write_com(0x01); //Display clear delay_ms(5); LCD_write_com(0x06); //Display cursor movement setting delay_ms(5); LCD_write_com(0x0C); //Display on and cursor setting delay_ms(5); } //*************************************************************************** // TIMERA initialization, set to UP mode counting//******************************************************************* void TIMERA_Init(void) //UP mode counting, counting period is CCR0+1 { TACTL |= TASSEL1 + TACLR + ID0 + ID1 + MC0 + TAIE; //SMCLK as clock source, 8-division, increase counting mode, open interrupt TACCR0 = 9999; //CCR0=9999, interrupt once every 10ms} //*************************************************************************** // Turn off timing, pause counting//*************************************************************************** void TimerA_end(void) { TACTL &= 0xfffd; } //****************************************************************************** // Scan key P1^2 to see if it is long pressed//**************************************************************************** void GetKey()//Long press, return 2; short press, return 1. { unsigned char keyRetu=0; //Returned key value static unsigned char s_keyState=0,keyTime=0; //Key state, key pressing time switch (s_keyState) { case 0: { if((P1IN&0x02)==0x00) //Detect that a key is pressed, switch to state 1, which is equivalent to the debounce process. { s_keyState=1; } } break; case 1: { if((P1IN&0x02)==0x00) //A key is detected again, go to state 2 { s_keyState=2; keyTime=0; //Clear key time counter } else { s_keyState=0; //No key is detected, indicating that state 0 detects a jitter, and goes back to state 0 } } break; case 2: { if((P1IN&0x02)==0x02) //Key release is detected { s_keyState=0; //State goes to state 0 keyRetu=1; //Output 1 } else { if(++keyTime>=150) //Press time>1s { s_keyState=3; //Go to state 3 keyTime=0; //Clear key time counter keyRetu=2; //Output 2 } } } break; case 3:{ if((P1IN&0x02)==0x02) //Detect that the key is released{ s_keyState=0; //The state goes to state 0 } else { s_keyState=3; //Go to state 3 } } break; } if(keyRetu==2) { a = 0; b = 0; c = 0; count = 0; second = 0; minute = 0; } } //*********************************************************************** // TIMERA interrupt service routine, need to judge the interrupt type//*************************************************************************** #pragma vector = TIMERA1_VECTOR __interrupt void Timer_A(void) { switch(TAIV) //Need to judge the type of interrupt{ case 2:break; case 4:break; case 10:count++;break; //Set the flag Flag } if(count==100) //100 times is 1 second{ second++; count=0; } if(second == 60) { minute++; second = 0; } GetKey(); } //********************************************************************** // P1 port interrupt service routine, need to judge//********************************************************************** #pragma vector = PORT1_VECTOR __interrupt void P1_IRQ(void) { switch(P1IFG&0x0F) { case 0x01: { flag++; P1IFG=0x00; } break; default:P1IFG = 0x00;break; } } //*********************************************************************** // Main program//*********************************************************************** void main(void) { WDT_Init(); //Watchdog settings Clock_Init(); //System clock settingsPort_init(); //System initialization, set IO port propertiesdelay_ms(100); //Delay 100ms LCD_init(); //LCD parameter initialization settingsLCD_clear(); //Clear screenTIMERA_Init(); _EINT(); while (1) { if(flag%2==0) { LCD_write_str(0,1,c/10); LCD_write_str(1,1,c%10); LCD_write_char(2,1,0x3a); LCD_write_str(3,1,b/10); LCD_write_str(4,1,b%10); LCD_write_char(5,1,0x3a); LCD_write_str(6,1,a/10); LCD_write_str(7,1,a%10); } else { count = a; second = b; minute = c; LCD_write_str(0,1,minute/10); LCD_write_str(1,1,minute%10); LCD_write_char(2,1,0x3a); LCD_write_str(3,1,second/10); LCD_write_str(4,1,second%10); LCD_write_char(5,1,0x3a); LCD_write_str(6,1,count/10); LCD_write_str(7,1,count%10); a = count; b = second; c = minute; } } } Configuration file Config.h [csharp] view plain copy ****************************************************************/ //Delay function, IAR comes with, often used #define CPU_F ((double)8000000) //External high frequency crystal oscillator 8MHZ //#define CPU_F ((double)32768) //External low frequency crystal oscillator 32.768KHZ #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) //Custom data structure, easy to use #define uchar unsigned char #define uint unsigned int #define ulong unsigned long //8 LED lights, connected to P6 port, can be stopped by disconnecting the power supply. Disconnect the power supply when ADC is in use#define LED8DIR P6DIR #define LED8 P6OUT //P6 port connected to LED lights, 8 //4 independent keys are connected to P10~P13 #define KeyPort P1IN //Independent keyboard is connected to P10~P13 //Serial port baud rate calculation, when BRCLK=CPU_F, the following formula can be used to calculate, otherwise the division coefficient must be added according to the setting#define baud 9600 //Set the baud rate#define baud_setting (uint)((ulong)CPU_F/((ulong)baud)) //Baud rate calculation formula#define baud_h (uchar)(baud_setting>>8) //Extract high bit#define baud_l (uchar)(baud_setting) //Low bit//RS485 control pin, CTR is used to control RS485 in receiving or sending state#define RS485_CTR1 P5OUT |= BIT2; //Control line high, RS485 sending status#define RS485_CTR0 P5OUT &= ~BIT2; //Control line low, RS485 receiving status//2.8-inch TFT color screen display control related hardware configuration#define RS_CLR P5OUT &= ~BIT5 //RS low#define RS_SET P5OUT |= BIT5 //RS high#define RW_CLR P5OUT &= ~BIT6 //RW low#define RW_SET P5OUT |= BIT6 //RW high#define RD_CLR P5OUT &= ~BIT7 //E low#define RD_SET P5OUT |= BIT7 //E high#define CS_CLR P5OUT &= ~BIT0 //CS low#define CS_SET P5OUT |= BIT0 //CS high#define RST_CLR P5OUT &= ~BIT3 //RST set low#define RST_SET P5OUT |= BIT3 //RST set high#define LE_CLR P5OUT &= ~BIT1 //LE set low#define LE_SET P5OUT |= BIT1 //LE set high//2.8 inch TFT color touch screen control related hardware configuration#define PEN_CLR P2OUT &= ~BIT0 //PEN set low, when touching the touch screen, the Penirq pin changes from high level when not touched to low level#define PEN_SET P2OUT |= BIT0 //PEN set high#define PEN (P2IN & 0x01) //P2.0 input value#define TPDO_CLR P2OUT &= ~BIT1 //TPDO set low#define TPDO_SET P2OUT |= BIT1 //TPDO set high#define TPDOUT ((P2IN>>1)&0x01) //P2.1 Input value#define BUSY_CLR P2OUT &= ~BIT3 //BUSY set low#define BUSY_SET P2OUT |= BIT3 //BUSY set high#define TPDI_CLR P2OUT &= ~BIT4 //TPDI set low#define TPDI_SET P2OUT |= BIT4 //TPDI set high#define TPCS_CLR P2OUT &= ~BIT5 //TPCS set low#define TPCS_SET P2OUT |= BIT5 //TPCS set high#define TPCLK_CLR P2OUT &= ~BIT6 //TPCLK set low#define TPCLK_SET P2OUT |= BIT6 //TPCLK set high//Data port for color screen/12864 LCD/1602 LCD, shared by three LCDs#define DataDIR P4DIR //Data port direction#define DataPort P4OUT //P4 port is the data port //12864/1602 LCD control pin#define RS_CLR P5OUT &= ~BIT5 //RS set low#define RS_SET P5OUT |= BIT5 //RS set high#define RW_CLR P5OUT &= ~BIT6 //RW set low#define RW_SET P5OUT |= BIT6 //RW set high#define EN_CLR P5OUT &= ~BIT7 //E set low#define EN_SET P5OUT |= BIT7 //E set high#define PSB_CLR P5OUT &= ~BIT0 //PSB set low, serial port mode#define PSB_SET P5OUT |= BIT0 //PSB set high, parallel port mode#define RESET_CLR P5OUT &= ~BIT1 //RST set low#define RESET_SET P5OUT |= BIT1 //RST set high //12864 application instruction set #define CLEAR_SCREEN 0x01 //Clear screen instruction: clear the screen and AC value is 00H #define AC_INIT 0x02 //Set AC to 00H. And the cursor moves to the origin position #define CURSE_ADD 0x06 //Set the cursor movement direction and the overall image movement direction (default cursor moves right, the image does not move as a whole) #define FUN_MODE 0x30 //Working mode: 8-bit basic instruction set #define DISPLAY_ON 0x0c //Display on, display cursor, and the cursor position is reversed #define DISPLAY_OFF 0x08 //Display off #define CURSE_DIR 0x14 //Cursor moves to the right:AC=AC+1 #define SET_CG_AC 0x40 //Set AC, range: 00H~3FH #define SET_DD_AC 0x80 //Set DDRAM AC #define FUN_MODEK 0x36 //Working mode: 8-bit extended instruction set //Color code, for TFT display #define White 0xFFFF //Display color code #define Black 0x0000 #define Blue 0x001F #define Blue2 0x051F #define Red 0xF800 #define Magenta 0xF81F #define Green 0x07E0 #define Cyan 0x7FFF #define Yellow 0xFFE0 //NRF2401 module control line #define RF24L01_CE_0 P1OUT &=~BIT5 //CE is at P15 #define RF24L01_CE_1 P1OUT |= BIT5 #define RF24L01_CSN_0 P2OUT &=~BIT7 //CS is at P27 #define RF24L01_CSN_1 P2OUT |= BIT7 #define RF24L01_SCK_0 P3OUT &=~BIT3 //SCK is at P33 #define RF24L01_SCK_1 P3OUT |= BIT3 #define RF24L01_MISO_0 P3OUT &=~BIT2 //MISO is at P32 #define RF24L01_MISO_1 P3OUT |= BIT2 #define RF24L01_MOSI_0 P3OUT &=~BIT1 //MOSI is at P31 #define RF24L01_MOSI_1 P3OUT |= BIT1 #define RF24L01_IRQ_0 P1OUT &=~BIT4 //IRQ is in P14 #define RF24L01_IRQ_1 P1OUT |= BIT4 //DS18B20 control pin, single-pin control#define DQ_IN P1DIR &= ~BIT7 //Set input, DS18B20 connected to MCU P53 port#define DQ_OUT P1DIR |= BIT7 //Set output#define DQ_CLR P1OUT &= ~BIT7 //Set low level#define DQ_SET P1OUT |= BIT7 //Set high level#define DQ_R P1IN & BIT7 //Read level//Infrared receiver H1838 control pin, single-pin control#define RED_IN P1DIR &= ~BIT6 //Set input, infrared receiver connected to MCU PE3 port#define RED_OUT P1DIR |= BIT6 //Set output#define RED_L P1OUT &= ~BIT6 //Set low level#define RED_H P1OUT |= BIT6 //Set to high level#define RED_R (P1IN & BIT6) //Read level//************************************************************************ // System clock initialization, external 8M crystal oscillator//*********************************************************************** void Clock_Init() { uchar i; BCSCTL1&=~XT2OFF; //Turn on XT2 oscillator BCSCTL2|=SELM1+SELS; //MCLK is 8MHZ, SMCLK is 8MHZ do{ IFG1&=~OFIFG; //Clear oscillator error flagfor(i=0;i<100;i++) _NOP(); } while((IFG1&OFIFG)!=0); //If the flag is 1, continue to loop and waitIFG1&=~OFIFG; } //*************************************************************************** // System clock initialization, internal RC crystal oscillator //************************************************************************ void Clock_Init_Inc() { uchar i; // DCOCTL = DCO0 + DCO1 + DCO2; // Max DCO // BCSCTL1 = RSEL0 + RSEL1 + RSEL2; // XT2on,max RSEL DCOCTL = 0x60 + 0x00; //DCO is about 3MHZ, 3030KHZ BCSCTL1 = DIVA_0 + 0x07; BCSCTL2 = SELM_2 + DIVM_0 + SELS + DIVS_0; } //*********************************************************************** // System clock initialization, external 32.768K crystal oscillator//*************************************************************************** void Clock_Init_Ex32768() { uchar i; BCSCTL2|=SELM1 + SELM0 + SELS; //MCLK is 32.768KHZ, SMCLK is 8MHZ do{ IFG1&=~OFIFG; //Clear oscillator error flag for(i=0;i<100;i++) _NOP(); } while((IFG1&OFIFG)!=0); //If the flag is 1, continue the loop and wait for IFG1&=~OFIFG; } //*********************************************************************** // MSP430 internal watchdog initialization//*********************************************************************** void WDT_Init() { WDTCTL = WDTPW + WDTHOLD; //Turn off the watchdog }