📄 smoke detector.c
字号:
//******************************************************************************
// Smoke Detector Code for F2002
//
// THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
// REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
// INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
// COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
// TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
// POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
// INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
// YOUR USE OF THE PROGRAM.
//
// IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
// THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
// OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
// EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
// REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
// OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
// USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
// AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
// YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
// (U.S.$500).
//
// Unless otherwise stated, the Program written and copyrighted
// by Texas Instruments is distributed as "freeware". You may,
// only under TI's copyright in the Program, use and modify the
// Program without any charge or restriction. You may
// distribute to third parties, provided that you transfer a
// copy of this license to the third party and the third party
// agrees to these terms by its first use of the Program. You
// must reproduce the copyright notice and any other legend of
// ownership on each copy or partial copy, of the Program.
//
// You acknowledge and agree that the Program contains
// copyrighted material, trade secrets and other TI proprietary
// information and is protected by copyright laws,
// international copyright treaties, and trade secret laws, as
// well as other intellectual property laws. To protect TI's
// rights in the Program, you agree not to decompile, reverse
// engineer, disassemble or otherwise translate any object code
// versions of the Program to a human-readable form. You agree
// that in no event will you alter, remove or destroy any
// copyright notice included in the Program. TI reserves all
// rights not specifically granted under this license. Except
// as specifically provided herein, nothing in this agreement
// shall be construed as conferring by implication, estoppel,
// or otherwise, upon you, any license or other right under any
// TI patents, copyrights or trade secrets.
//
// You may not use the Program in non-TI devices.
//
//******************************************************************************
#include <msp430x20x2.h>
#define LED 0x01
#define IRLED 0x40
#define OA_power 0x20
unsigned int dark_buffer[4]; // buffer for 4 ADC samples
unsigned int light_buffer[4]; // buffer for 4 ADC samples
unsigned int dark_average; // Average 4 samples with no IRLED
unsigned int light_average; // Average 4 samples with IRLED on
unsigned char smoke_detect_count = 0; // Counter for smoke detections
unsigned char alarm_flag = 0; // Alarm status. 1 means smoke
void Setup(void); // Function protos
void Sample (void);
void Average (void);
unsigned int Cal_VLO(void);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
Setup(); // Call init routine
for (;;)
{
LPM3;
Sample();
Average();
if (light_average > (dark_average + 30))
{
if (alarm_flag == 0)
{
smoke_detect_count++; // Increment detection counter
smoke_detect_count &= 0x03; // Only count values of up to 3
if (smoke_detect_count == 1)
TACTL &= ~ID0; // Clear ID0 in TACTL. This sets the
// TA clock divider to /4 instead of /8.
// This cuts the sample period in half to 4s
else if (smoke_detect_count == 2)
TACTL &= ~ID_3; // This sets the TA clock divider to /1
// which makes the sample period 1s
else if (smoke_detect_count == 3)
{
alarm_flag = 1; // Set alarm flag
P1OUT |= LED; // Turn on visible LED
// Enable TA1 output for .5 second alarm cadence
P1SEL |= BIT2; // Enable P1.2 for TA1 output
TACCTL1 = OUTMOD_3; // Set/Reset mode for PWM
}
}
}
else // light_average not > dark_average+30
{
P1OUT &= ~LED; // Turn off visible LED, but leave pull-up
P1SEL &= ~BIT2; // Put P1.6 back to I/O function = no buzzer
alarm_flag = 0; // If no smoke present, clear alarm flag
smoke_detect_count = 0; // Clear smoke detect counter
TACCTL1 = 0; // Clear output mode of buzzer driver
TACTL |= ID_3; // Back to divide by 8 for TACLK for 8s interrupt
}
}
}
void Setup(void)
{
unsigned int a, counts;
signed long temp = 8000000;
// Ports
P1DIR = 0xed; // All P1 but P1.1 and P1.4 as outputs
P1OUT = BIT1; // All P1 outputs low, P1.1 is pulled up
P1SEL = BIT4; // P1.4 as analog, other I/O
P1IE = BIT1; // Enable switch interrupt
P1IES = BIT1; // H to L transition for interrupt
P1REN = BIT1; // Enable internal pull-up
P1IFG = 0; // Clear any pending IFGs
P2DIR = 0xff; // Output direction, except P2.3
P2OUT = 0; // All P2 low
ADC10AE = BIT4; // Disable A4 CMOS buffer
// Setup DCO and VLO
BCSCTL1 = CALBC1_1MHZ; // Use 1Mhz cal data for DCO
DCOCTL = CALDCO_1MHZ; // Use 1Mhz cal data for DCO
BCSCTL3 = LFXT1S_2; // Use VLO for ACLK
counts = Cal_VLO(); // counts is # of VLO clocks in 8MHz
// setup TA for 8 second interrupt
TACTL = TASSEL_1 + ID_3 + TACLR; // TA = ACLK/8
TACCTL0 = CCIE; // Enable CCR0 interrupt
// Divide 8Mhz by counts to get # of VLO counts in 1 second period
a = 0;
do {
temp -= counts;
a++;
} while (temp > 0);
TACCR0 = a; // TACCR0 period for 1 second
TACCR1 = TACCR0 >> 1; // Put half-period into TACCR1 for use
// when alarming.
// Start timer
TACTL |= MC_1; // Up mode
_EINT();
}
unsigned int Cal_VLO (void)
{
unsigned int First_Cap, counts;
BCSCTL1 |= DIVA_3; // Divide ACLK by 8
TACCTL0 = CM_1 + CCIS_1 + CAP; // Capture on ACLK
TACTL = TASSEL_2 + MC_2 + TACLR; // Start TA, MCLK(DCO), Continuous
while ((TACCTL0 & CCIFG) == 0); // Wait until capture
TACCR0 = 0; // Ignore first capture
TACCTL0 &= ~CCIFG; // Clear CCIFG
while ((TACCTL0 & CCIFG) == 0); // Wait for next capture
First_Cap = TACCR0; // Save first capture
TACCTL0 &= ~CCIFG; // Clear CCIFG
while ((TACCTL0 & CCIFG) ==0); // Wait for next capture
counts = (TACCR0 - First_Cap); // # of VLO clocks in 8Mhz
BCSCTL1 &= ~DIVA_3; // Clear ACLK/8 settings
return counts;
}
void Sample (void)
{
unsigned volatile int i, temp;
temp = P1OUT; // Preserve LED "on" if alarming
P1OUT |= OA_power + LED; // Turn on OA. Settling delay is below
ADC10CTL0 = ADC10ON + REFON + ADC10SHT_1 + MSC + ADC10IE + SREF_1;
// ADC on, ref = 1.5V, sampling = 8 clocks
// NOTE: REF takes 30us to settle, But
// because of other instructs
// no need for additional delay loop
ADC10CTL1 = INCH_4 + CONSEQ_2; // Channel A4, repeat single channel mode
ADC10DTC1 = 4; // Do 4 conversions
ADC10SA = (unsigned int)dark_buffer; // Start address for DTC
i = 6; // Delay for OA settling
do i--;
while (i != 0);
ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversions
LPM3; // Enter LPM3 while 4 conversions made
ADC10CTL0 &= ~ENC; // Clear ENC to stop conversion
P1OUT |= IRLED; // Turn on IRLED
ADC10SA = (unsigned int)light_buffer; // Start address for DTC
i = 4; // Short delay for settling
do i--;
while (i != 0);
ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversions
LPM3; // Enter LPM3 while 4 conversions made
P1OUT = temp; // Restore P1OUT, turns off IRLED and OA
ADC10CTL0 &= ~ENC; // Clear ENC to stop conversions
ADC10CTL0 = 0; // Turn off ADC and reference
}
void Average (void)
{
unsigned int i;
dark_average = 0;
light_average = 0;
for (i = 0; i < 4; i++)
{
dark_average += dark_buffer[i];
light_average += light_buffer[i];
}
dark_average = (dark_average >> 2);
light_average = (light_average >> 2);
}
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0 (void)
{
LPM3_EXIT;
}
// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10 (void)
{
LPM3_EXIT;
}
// P1.0 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void P1_ISR (void)
{
unsigned volatile int i;
i = 5000; // ~50ms Debounce delay
do i--; //
while (i != 0);
P1IFG = 0; // Clear IFG
P1OUT ^= BIT2; // Toggle of P1.2 to turn on/off siren
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -