⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exercise-9.c

📁 TI MSP430针对cap sense 按键的源码, 可实现单击或滑动键, 如IPOD上的人机接口.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Exercise 9

    An illustration of how a high quality RTC can be made, using an MSP430 with a very low cost
    32768Hz crystal. This code corrects for two sources of error.

        - the basic manufacturing tolerance error of the crystal, which is calibrated at
          production time, and then allowed for in operation.

        - the temperature dependant change in the crystal frequency, based on the temperature
          measured by the ADC's internal temperature measurement diode.
*/
#include <msp430x42x0.h>
#include <stdint.h>

#define FALSE 0
#define TRUE (!FALSE)

#define SEG_a           0x01
#define SEG_b           0x02
#define SEG_c           0x10
#define SEG_d           0x04
#define SEG_e           0x80
#define SEG_f           0x20
#define SEG_g           0x08
#define SEG_h           0x40

#define CHAR_SPACE	0
#define CHAR_MINUS	SEG_g
#define CHAR_ALL	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g|SEG_h)
#define CHAR_0		(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f)
#define CHAR_1  	(SEG_b|SEG_c)
#define CHAR_2  	(SEG_a|SEG_b|SEG_d|SEG_e|SEG_g)
#define CHAR_3  	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_g)
#define CHAR_4  	(SEG_b|SEG_c|SEG_f|SEG_g)
#define CHAR_5  	(SEG_a|SEG_c|SEG_d|SEG_f|SEG_g)
#define CHAR_6  	(SEG_a|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_7  	(SEG_a|SEG_b|SEG_c)
#define CHAR_8  	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_9  	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_f|SEG_g)
#define CHAR_A  	(SEG_a|SEG_b|SEG_c|SEG_e|SEG_f|SEG_g)
#define CHAR_B  	(SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_C  	(SEG_a|SEG_d|SEG_e|SEG_f)
#define CHAR_D  	(SEG_b|SEG_c|SEG_d|SEG_e|SEG_g)
#define CHAR_E  	(SEG_a|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_F  	(SEG_a|SEG_e|SEG_f|SEG_g)

const uint8_t lcd_digit_table[18] =
{
    CHAR_0,
    CHAR_1,
    CHAR_2,
    CHAR_3,
    CHAR_4,
    CHAR_5,
    CHAR_6,
    CHAR_7,
    CHAR_8,
    CHAR_9,
    CHAR_A,
    CHAR_B,
    CHAR_C,
    CHAR_D,
    CHAR_E,
    CHAR_F,
    CHAR_MINUS,
    CHAR_SPACE
};

void LCDchar(int ch, int pos);
void LCDdec(uint16_t value, int pos);
void update_rtc_time_display(void);
void update_rtc_date_display(void);
void update_lcd(void);
void init_lcd(void);

void estimate_current_cycles_per_second(int16_t temperature);
void update_pulse_stuffer(void);
void init_pulse_stuffer(void);
int32_t assess_rtc_speed(void);

#define CRYSTAL_BASE_CYCLES_PER_SECOND          1048576

/* If defined, this makes the software use 4 basic timer interrupts per
   second. This raised the current consumption a little, but avoids
   obvious visible hops of the RTC display. */
#define AVOID_VISIBLE_RTC_HOPS

/* These values come from the crystal's data sheet. The are characteristic of the crystal
   design, and do not significantly vary from sample to sample. Crystals vary in a parabolic
   manner with temperature. */
/* This value is the temperature, in degrees C, of the parabolic error curve for the crystal. */
#define CRYSTAL_QUADRATIC_CENTRE_TEMPERATURE    25
/* This value must be 65536 times the parts per million per degree Celcius squared error specified
   for the crystal. The following is for a -0.035ppm per C^2 crystal. */
#define CRYSTAL_QUADRATIC_COEFF                 2294

enum
{
    RTC_CORRECTION_NONE,
    RTC_CORRECTION_CRYSTAL_ERROR,
    RTC_CORRECTION_TEMPERATURE,
    RTC_CORRECTION_CRYSTAL_ERROR_AND_TEMPERATURE,
};

/* This variable is TRUE if a timer A is being used to generate a compensated
   one pulse per second signal */
int one_pps_active = TRUE;

/* This variable only exists for demonstration purposes. It allows the type of
clock correction to be easily varied. */
//int correction_components = RTC_CORRECTION_NONE;
//int correction_components = RTC_CORRECTION_CRYSTAL_ERROR;
int correction_components = RTC_CORRECTION_CRYSTAL_ERROR_AND_TEMPERATURE;

/* These values would be calibrated, and stored in info memory in a real application */
/* This value is the reading for the ADC when measuring the temperature diode at zero
   degrees Celcius. It varies somewhat from sample to sample of the MSP430, but is
   easy to calibrate at the equipment factory. It is merely necessary to measure the
   diode at room temperature, and allow for the slope of the diode's characteric to
   estimate the value at zero degrees Celcius. */
const int temperature_diode_intercept = 20500;
/* This value represents the slope of the temperature diode characteristic. It varies
   little from sample to sample of the MSP430, so it does not need to be calibrated for
   each sample of the device. */
const int temperature_diode_slope = 1408;
/* This is the crystal's manufacturing error. Its is the frequency error, in parts per
   million, at the centre of the crystal's parabolic characteristic. */
const int32_t crystal_base_error = 76;

int16_t raw_temperature_from_adc;
int16_t temperature_in_celsius;
/* This is the current estimate for the exact number of clock cycles in one second */
int32_t current_estimated_cycles_per_second;
/* This is the current estimate for the parts per million of error in 32*32768Hz clock. */
int16_t current_rtc_correction;

int32_t cycles_left_this_second;

typedef struct rtc_s
{
    uint8_t year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
    uint8_t sumcheck;
} rtc_t;

/* Return values for bump_rtc. These indicate the most significant element
   of the rtc which was changed. The rtc is not updated if it's sumcheck is
   incorrect, so nothing is updated for an inconsistent rtc setting. */
#define RTC_INCONSISTENT	0
#define RTC_CHANGED_SECOND	1
#define RTC_CHANGED_MINUTE	2
#define RTC_CHANGED_HOUR	3
#define RTC_CHANGED_DAY		4
#define RTC_CHANGED_MONTH	5
#define RTC_CHANGED_YEAR	6

void set_rtc_sumcheck(void);
int bump_rtc(void);
int update_rtc(void);
int check_rtc_sumcheck(void);
int leap_year(void);
int weekday(void);

const int8_t month_lengths[13] =
{
    00,
    31, 28, 31,
    30, 31, 30,
    31, 31, 30,
    31, 30, 31
};

/* We want the rtc to be uninitialized, so it can persist past a processor
   reset. The rtc structure contains a sumcheck, so we can do a consistency
   check on the rtc as we come out of reset. */
rtc_t rtc;

int32_t integrated_rtc_correction;
uint8_t skip_a_second;

int32_t last_rtc_correction;

int key_1_down = FALSE;
int key_2_down = FALSE;

int8_t display_item;

void set_rtc_sumcheck(void)
{
    rtc.sumcheck = ~(rtc.second + rtc.minute + rtc.hour + rtc.day + rtc.month + rtc.year);
}

/* Bump the RTC by a second, and return an indication of the most significant
   element of the date to have changed. Maintain a sumcheck byte to help check
   for corrupted RTC settings after a reset. */
int bump_rtc(void)
{
    /* First check the consistency of the current rtc setting. If it is inconsistent,
       (i.e. has a bad sumcheck) do not bump it. */
    if (!check_rtc_sumcheck())
        return RTC_INCONSISTENT;
    if (++rtc.second < 60)
    {
        set_rtc_sumcheck();
        return RTC_CHANGED_SECOND;
    }
    rtc.second = 0;
    if (++rtc.minute < 60)
    {
        set_rtc_sumcheck();
        return RTC_CHANGED_MINUTE;
    }
    rtc.minute = 0;
    if (++rtc.hour < 24)
    {
        set_rtc_sumcheck();
        return RTC_CHANGED_HOUR;
    }
    rtc.hour = 0;
    if ((rtc.month == 2  &&  (rtc.year & 3) == 0  &&  rtc.day < 29)
        ||
        rtc.day < month_lengths[rtc.month])
    {
        ++rtc.day;
        set_rtc_sumcheck();
        return RTC_CHANGED_DAY;
    }
    rtc.day = 1;
    if (++rtc.month <= 12)
    {
        set_rtc_sumcheck();
        return RTC_CHANGED_MONTH;
    }
    rtc.month = 1;
    ++rtc.year;
    set_rtc_sumcheck();
    return RTC_CHANGED_YEAR;
}

/* This can be used to check the integrity of the RTC after a reset */
int check_rtc_sumcheck(void)
{
    return rtc.sumcheck == ((~(rtc.second + rtc.minute + rtc.hour + rtc.day + rtc.month + rtc.year)) & 0xFF);
}

int leap_year(void)
{
    /* This simple test is good enough for this century */
    return (rtc.year & 0x03) == 0;
}

/* Return the current day of the week, based on the RTC. */
int weekday(void)
{
    int i;
    int days;

    /* This works for years 2000-2099 */
    /* Result is 0=Sunday, 1=Monday, etc. */
    /* Allow for the day of the month */
    days = rtc.day + 6;
    /* Allow for the months to date this year... */
    for (i = 1;  i < rtc.month;  i++)
        days += month_lengths[i];
    /* ...with a little offset if we are early in a leap year */
    if ((rtc.year & 0x03) == 0  &&  rtc.month <= 2)
        days--;
    /* Allow for the years... */
    days += rtc.year;
    /* ...and a little extra for the leap years */
    days += (rtc.year >> 2);
    days %= 7;
    return days;
}

/* Perform a temperature compensated one second update of the RTC */
int update_rtc(void)
{
#if defined(AVOID_VISIBLE_RTC_HOPS)
    static int step = 0;

    integrated_rtc_correction += current_rtc_correction;
    if (integrated_rtc_correction >= CRYSTAL_BASE_CYCLES_PER_SECOND)
    {
        integrated_rtc_correction -= CRYSTAL_BASE_CYCLES_PER_SECOND;
        /* We need to add a quarter of a second to the RTC */
        step++;
    }
    else if (integrated_rtc_correction <= CRYSTAL_BASE_CYCLES_PER_SECOND)
    {
        integrated_rtc_correction += CRYSTAL_BASE_CYCLES_PER_SECOND;
        /* We need to subtract a quarter of a second from the RTC */
        step--;
    }
    if (++step >= 4)
    {
        step -= 4;
        bump_rtc();
        return 1;
    }
    return 0;
#else
    integrated_rtc_correction += current_rtc_correction;
    if (integrated_rtc_correction >= CRYSTAL_BASE_CYCLES_PER_SECOND)
    {
        integrated_rtc_correction -= CRYSTAL_BASE_CYCLES_PER_SECOND;
        /* We need to add an extra second to the RTC */
        bump_rtc();
        return 0;
    }
    else if (integrated_rtc_correction <= -CRYSTAL_BASE_CYCLES_PER_SECOND)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -