工具与软件:
大家好!
在中断中激活定时器时出现问题、此问题在微控制器处于 LPM4时发生。
在我的主函数中、我启用低功耗模式以节省能源、直到用户按下按钮。 之后、我进入了按钮的 ISR、想激活一个计时器以提供待机功能。 遗憾的是、我无法激活计时器、因为微控制器仍处于低功耗模式。
我在 ISR 中尝试了函数_BIC_SR_register 来立即停用低功耗模式、但这样无效、因为在完成 ISR 后、程序会在 LPM4中再次跳转。
我还尝试了_BIC_SR_register_on_exit 函数。 这样可以正确地停用 LPM、但只是当 ISR 完成并且我想激活 ISR 中的计时器时、所以计时器不会以这种方式激活。
我已将代码放在下方、且要激活和停用 LPM4的部分中注释为"DEEPSLEEP"
你们中有人能帮我解决问题吗?
非常感谢。
此致、
Timo Kurz
#include <msp430.h>
#include <stdint.h>
#include "asciizeichen.h"
#include <stdio.h>
#include <string.h>
// Definitions for Nokia 5110 display
#define LCD_RST BIT2
#define LCD_DC BIT4
#define LCD_DIN BIT5
#define LCD_CLK BIT6
#define LCD_CE BIT1
#define LCD_LED BIT7
#define SW BIT3 // ToDo: change to correct activation bit - VORSICHT!!!! AKTUELL NOCH PORT1 STATT PORT2
#define OUT BIT0 // ToDo: change to correct output bit
#define SENSOR_PIN (BIT1 | BIT2)
#define STANDBY_TIMEOUT 32768 // Timer for standby modus
#define DEBOUNCE_DELAY 5000 // debounce Timer
#define CHARGING 1000000 // Value for recognizing if device is plugged in
#define MAX_TEMP 120 // Value for safety overheat shutdown
#define MIN_VOLTAGE 0 // Value for safety shutdown if battery is empty
volatile uint16_t adc_result[3] = {0}; // Variable to store ADC results
volatile uint16_t current = 0; // Variable for actual charging current
volatile uint16_t voltage = 0; // Variable for actual battery voltage
volatile uint16_t temperature = 0; // Variable for actual temperature
static int started = 0;
void delay(unsigned int t);
void LCD_write_byte(unsigned char data, unsigned char mode);
void LCD_init();
void LCD_clear();
void LCD_string(char *characters);
void LCD_char(char character);
void ausgabe_string(char *str1, double kommazahl);
void main(void) {
double zahl = 0.0;
int zaehler = 0, i = 0;
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P1DIR |= OUT; // Set Output pin -> Output
P1DIR &= ~SW; // Set SW pin -> Input
P1REN |= SW; // Enable Resistor for SW pin
P1OUT |= SW; // Select Pull Up for SW pin
P1OUT &= ~OUT; // Disable Output at start
P1IES |= SW; // Select Interrupt on Falling Edge
P1IE |= SW; // Enable Interrupt on SW pin
// configure ADC
ADC10CTL1 = INCH_2 + CONSEQ_3; // Channel select A2 + sequence of channels
ADC10CTL0 = SREF_0 + ADC10SHT_2 + ADC10ON + ADC10IE; // REF = VCC & VSS + ADC SampleAndHoldTime 16 x ADC10CLKs + + //
ADC10AE0 |= SENSOR_PIN; // These bits enable the PIN 1.1 & P1.2 for analog input
P1SEL |= SENSOR_PIN; // ADC input select mode P1.1 & P1.2
// Timer0 to interrupt after 10 seconds
TA0CCR0 = STANDBY_TIMEOUT / 8; // 32.768 kHz crystal oscillator, divided by 8
TA0CTL = TASSEL_1 + MC_0 + ID_3; // ACLK (32.768 kHz), Stop mode, Divider 8
TA0CCTL0 |= CCIE;
// Timer1 for debouncing
TA1CCTL0 |= CCIE; // Enable Timer1 interrupt
TA1CCR0 = DEBOUNCE_DELAY; // Set debounce delay
TA1CTL = TASSEL_2 + MC_0 + TACLR; // SMCLK, Stop mode, clear timer
__bis_SR_register(GIE); // Enable global interrupts
while(1)
{
if(started)
{
LCD_init();
P1OUT |= OUT; // Toggle Output Pin 1.0
P1OUT |= LCD_LED; // Backlight on
LCD_clear();
while (started) {
char str1[20] = "Zahl: ";
ausgabe_string(str1, zahl);
LCD_string(" ");
LCD_string("Funktioniert ");
for (i = 0; i <= zaehler; i++) {
LCD_char(128);
}
zaehler += 1;
if (zaehler >= 5) {
zaehler = 0;
}
zahl += 0.1;
if (zahl >= 10.0) {
zahl = 0.0;
}
start_ADC_conversion(); // Start the ADC conversion
__delay_cycles(1000000); // one sec delay
}
}
// ToDo: value if device is currently charging
else if(current > CHARGING) // State if device Timeout and device is currently charging
{
P1OUT &= ~LCD_LED; // Backlight off
LCD_clear();
}
else
{
P1OUT &= ~LCD_LED; // Backlight off
LCD_clear();
P1OUT &= ~OUT; // Turn off Output
// __bis_SR_register(LPM4_bits + GIE); // ToDo: deepsleep
}
}
}
void start_ADC_conversion() {
ADC10CTL1 = INCH_10 + ADC10DIV_3; // Select channel A10 for temperature, divide by 4
ADC10CTL0 = SREF_1 + ADC10SHT_2 + ADC10ON + ADC10IE + REFON + REF2_5V; // Internal reference, 2.5V, ADC on, enable interrupt
__delay_cycles(1000); // Wait for reference to settle
ADC10CTL0 |= ADC10SC + ENC; // Start conversion
while (ADC10CTL1 & ADC10BUSY); // Wait for conversion to finish
adc_result[0] = ADC10MEM;
temperature = ((adc_result[0] - 673) * 423) / 1024; // Convert ADC value to temperature in Celsius
if(temperature > MAX_TEMP) // overheat protection
{
P1OUT &= ~OUT; // Turn off Output
// ToDo: Response, for overheating
}
ADC10CTL0 &= ~ENC; // Disable conversion
ADC10CTL0 &= ~REFON; // Turn off reference to save power
ADC10CTL1 = INCH_2; // select channel A2 as input
ADC10CTL0 |= ADC10SC + ENC;
while (ADC10CTL1 & ADC10BUSY);
adc_result[1] = ADC10MEM;
voltage = adc_result[1]; // ToDo: conversion to actual value
// ToDo: safety shutdown if battery is empty
// if(voltage < MIN_VOLTAGE)
// {
// P1OUT &= ~OUT; // Turn off Output
// // ToDo: Response, for empty battery
// }
ADC10CTL0 &= ~ENC;
ADC10CTL1 = INCH_1; // select channel A1 for ADC + Conversion sequence mode select == Sequence-of-channels + ACLK - clock (no input div)
ADC10CTL0 |= ADC10SC + ENC; // ADC10SC == 0 >> no sample start conversation + ENC == EnableConversation
while (ADC10CTL1 & ADC10BUSY);
adc_result[2] = ADC10MEM;
current = adc_result[2]; // ToDo: conversion to actual current
ADC10CTL0 &= ~ENC; // disable conversation
}
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void) {
ADC10CTL0 &= ~ADC10IFG; // Clear interrupt flag
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void) {
P1IE &= ~SW; // Disable button interrupt
P1IFG &= ~SW; // Clear SW interrupt flag
started = 1;
// __bic_SR_register(LPM4_bits); // ToDo: Wakeup from deepsleep
TA0CTL |= MC_1; // Start Timer0 in up mode
TA1CTL |= TASSEL_2 + MC_1; // Start Timer1 for debouncing
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void) {
TA0CTL &= ~MC_1; // Stop Timer0
started = 0;
TA0CCTL0 &= ~CCIFG;
}
#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer_A1_ISR(void) {
TA1CTL &= ~MC_1; // Stop Timer1
P1IE |= SW; // Re-enable button interrupt
TA1CTL |= TACLR; // Clear Timer1
TA1CCTL0 &= ~CCIFG; // Clear Timer1 interrupt flag
}