//______________________________________________________________________ void main(void) { //____________ menu attribute TTTDDCCC, // TTT toggle option offset/2 // DD digit setup pos, static const uint8_t menu_attrs[] = { 0x00, (3<<2)|(1), // time (4<<2)|(1), // alarm (0<<2)|(1), // count down (4<<2)|(2), // auto sleep #ifdef TEMP_SENSE (5<<2)|(3), // dimmer, shorted #else (0<<2)|(3), // dimmer, shorted #endif }; WDTCTL = WDTPW + WDTHOLD + WDTNMI + WDTNMIES; // stop WDT, enable NMI hi/lo BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; //____________________ 1mhz clock base CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 62500; TACTL = TASSEL_2 + MC_2 + TAIE; // SMCLK, continous _BIS_SR(GIE); // 0x1000 0x10ff infomem #ifdef TEMP_SENSE //________ temperature sensing setup G2231 only ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; #endif #ifdef TONE uint8_t const *mode5 = (uint8_t *) 0; #endif uint16_t mode4 = 0; uint16_t *show = 0; uint8_t sec=45; P1SEL = 0; P2SEL = 0; uint8_t menu=1; uint8_t mode=1; uint8_t state=ST_HOLD; uint8_t setup=4; uint8_t sec2sleep=0; while (1) { if (!menu && stacked) { while (stacked) { stacked--; if (++sec >= 60) { sec = 0; time[1]++; //________ alarm ? if (__is_alarm_on && time[1] == time[2]) { state |= (ST_BUZZ|ST_REFRESH); state &= ~ST_BUTTON; mode = 1; }//if }//if }//while if (__is_autosleep && mode && mode <= 3) { if (sec2sleep) { sec2sleep--; if (!sec2sleep) mode = 0; }//if }//if if ((mode != 1) || !sec) state |= ST_REFRESH; }//if uint8_t adv = 0; uint8_t txt = 0; //_____________________________________ check input if (state & ST_BUTTON) { // needs attention if (__is_autosleep) sec2sleep = time[4]; if ((state & ST_BUZZ) || !mode) { // stop alarm state &= ~(ST_BUZZ|ST_BUTTON); mode = 1; state |= ST_REFRESH; continue; }//if if (setup) { if (state & ST_HOLD) { switch (setup) { case 3: menu_attr >>= 2; if (menu_attr) { //______ on to options toggle state |= ST_PRESSED; setup++; break; }//if case 4: switch (menu) { case 3: mode4 = *show; mode = 4; break; default: mode = 1; break; }//switch show = time + 1; menu = 0; setup = 0; break; default: setup++; break; }//switch }//if if (state & ST_PRESSED) { if (setup == 4) { if (!(state & ST_HOLD)) *time ^= 1<<menu; txt = (menu_attr<<1) + ((*time & 1<<menu) ? 1 : 0); }//if else { adv = setup; }//else }//if }//if else { if (state & ST_HOLD) { //_______ advance menu if (mode) { //_________ not option, not edit, advance menu menu++; //___________ detect option conditions //while ((menu_attrs[menu]&0x07) && opts&(1<<(menu_attrs[menu]&0x07))) menu++; //while (opts & (1<<4) && ((menu == 2) || (menu == 3))) menu++; while ((opts&BUZZ_PINP) && (menu&0x02)) menu++; if (menu > 5) menu = 0; else txt = menu; menu_attr = menu_attrs[menu]; mode = 1; }//if }//if else { if (menu) { //_______ menu selected //mode = 1; show = time + menu; setup = menu_attr & 0x03; }//if else { //_______ advance display mode mode++; mode &= 0x03; stays = 0; }//else }//else }//else }//if if (state&(ST_REFRESH|ST_BUTTON) && !stays) { state &= ~(ST_REFRESH|ST_BUTTON); if (txt) { seg2port(menu_desc[txt], 0x20); }//if else { switch (mode) { case 1: // hour + min if (adv == 1) { *show += 60; adv = 0; }//if while (*show>=(24*60)) *show -= 24*60; *show = seg2port(*show, adv); if (!__is_24hr && menu < 3) { // 12HR display uint16_t hhmm = *show; if (hhmm>=(12*60)) { //__________ 12Hr mode, pm indicator adv = 1; hhmm -= 12*60; }//if if (hhmm<60) hhmm += 12*60; seg2port(hhmm, 0); }//if break; case 2: // alarm on/off + seconds //seg2port(sec+(POS__*100) + (__is_alarm_on ? POSb1*1600 : 0), 0x10); seg2port(sec, 0); if (__is_alarm_on) adv = 1; break; #ifdef TEMP_SENSE case 3: { // temperature int16_t temp = ADC10MEM; if (temp) { // oF = ((A10/1024)*1500mV)-923mV)*1/1.97mV = A10*761/1024 - 468 // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278 //temp = ((temp - 630) * 761) / 1024; oF //temp = ((temp - 673) * 423) / 1024; C 0 offset //temp = ((temp - 552) * 423) / 1024; C -50 offset // 1.464mv/u 3.55 temp = ((temp - 673) * 423) / 1024; if (__is_fahrenheit) temp = (temp * 10 / 8) + 32; temp <<= 4; // if (temp < 0) { temp = -temp; temp += POSb2 * 1600; }//if seg2port(temp|(__is_fahrenheit?POS_f:POS_C), 0x10); }//if ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled } break; #endif case 0: // blank // //_BIS_SR(LPM3_bits + GIE); // sleep while (ticks%4);// asm("nop"); // sync to 1/4 sec ticks stacked += sec; sec = 0; // sync to minute for alarm checking //P1DIR = P1OUT = 0; //P2DIR = P2OUT = 0; P1REN = BUTTON_PIN; P1IES &= ~BUTTON_PIN; // low-high trigger P1IFG &= ~BUTTON_PIN; // clear P1IE = BUTTON_PIN; // pin interrupt enable BCSCTL3 = XCAP_3; P2SEL = BIT6|BIT7; // need xtal CCTL0 = 0; // stop timer a WDTCTL = WDT_ADLY_250 + WDTNMI + WDTNMIES; // WDT at 250ms, NMI hi/lo IE1 |= WDTIE; // Enable WDT interrupt _BIS_SR(LPM3_bits + GIE); // now i and deep sleep // we wake up here P1IFG &= ~BUTTON_PIN; // clear P1IE = 0; while (P1IN&BUTTON_PIN); // make sure key is not depressed state |= ST_PRESSED; IE1 &= ~WDTIE; // Diable WDT interrupt WDTCTL = WDTPW + WDTHOLD + WDTNMI + WDTNMIES; CCTL0 = CCIE; // CCR0 interrupt enabled, time keep w/ DCO from now on P2SEL = 0; // turn xtal pins back to gio for led multiplexing // #ifndef TEMP_SENSE case 3: // no temperature sensor state |= ST_PRESSED; break; #endif case 5: // blank state |= ST_REFRESH; break; case 4: // counter seg2port(mode4, 0); if (mode4) mode4--; else state |= ST_BUZZ; default: break; }//switch if (adv) *(output + (3*3+1)) |= SEG_d_P1; }//else }//if // if (state & ST_BUZZ) { if (ticks & 0x04) { P1DIR = 0x00; P2DIR = BUZZ_PINP|BUZZ_PINN; P2OUT ^= BUZZ_PINP; // toggle buzzer }//if }//if // // if (stays & 0x0f) { stays--; continue; } // dimmer stays >>= time[5]%10; // P2DIR = 0; P1DIR = 0; P2OUT = 0; P1OUT = 0; // if (stays) { stays--; continue; } // //if (mode == 5) continue; #ifdef TONE if (mode) { P2DIR = BUZZ_PINN; P2OUT = BUZZ_PINP; P2REN |= BUZZ_PINP; if ((opts&BUZZ_PINP) && !(P2IN&BUZZ_PINP)) { //______ user attach buzzer, show menu, may be he wants to setup alarm menu = 1; state |= ST_HOLD; }//if opts = P2IN; P2REN = 0; P2DIR = 0; P2OUT = 0; P1DIR = CNTR_PINN; P1OUT = CNTR_PINP; P1REN |= CNTR_PINP; opts |= P1IN; //opts = CNTR_PINP|BUZZ_PINP; //opts = CNTR_PINP; // if (!(opts & CNTR_PINP)) { // tune player buzzer present mode5 = tune; P1DIR = CNTR_PINN; P1OUT = CNTR_PINP; P1REN |= CNTR_PINP; while (!(P1IN&CNTR_PINP)) { if (!*mode5) mode5 = tune; // point to 1st note _ccr1 = 0; ticks &= 0x0f; uint8_t wait = ticks + ((*mode5&0x03)<<2); uint8_t i = *mode5>>2; uint8_t const *v = tune_map; while (i) { // set note frequency //CCR1 += *v>>4; _ccr1 += *v>>4; if (!(--i)) break; //CCR1 += *v&0x0f; _ccr1 += *v&0x0f; v++; i--; }//while //CCR1 <<= 3; CCR1 = _ccr1; if (_ccr1) { CCTL1 = OUTMOD_4|CCIE; P1DIR = CNTR_PINP|CNTR_PINN; P1SEL = CNTR_PINP; }//if P1OUT = 0; P1REN = 0; while (ticks<wait); // __asm("nop"); // wait note duration CCTL1 = 0x00; P1SEL = 0x00; mode5++; P1DIR = CNTR_PINN; P1OUT = CNTR_PINP; P1REN |= CNTR_PINP; }//while }//if P1REN = 0; P1DIR = 0; P1OUT = 0; }//if
//______________________________________________________________________ void main(void) { //____________ menu attribute TTTDD, // TTT toggle option offset/2 // DD digit setup pos, static const uint8_t menu_attrs[] = { 0x00, (3<<2)|(1), // time (4<<2)|(1), // alarm (0<<2)|(1), // count down #ifdef NO_TEMP_CHOICE (0<<2)|(2), // clock gain, no choice for temp units C/F #else (5<<2)|(2), // clock gain #endif (0<<2)|(3), // dimmer, shorted }; WDTCTL = WDTPW + WDTHOLD + WDTNMI + WDTNMIES; // stop WDT, enable NMI hi/lo uint8_t use_32khz = 1; // assume we have crystal 1st BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator CCR0 = 4096-1; CCTL0 = CCIE; // CCR0 interrupt enabled TACTL = TASSEL__ACLK + MC__UP + TACLR; // ACLK, upmode WDTCTL = WDT_MDLY_8 + WDTNMI + WDTNMIES; // WDT at 8ms, NMI hi/lo while (!tps) { IE1 |= WDTIE; // Enable WDT interrupt _BIS_SR(GIE); // enable interrupt // wait for VLO calibration be done // timer interrupt to reduce rounds from 122 to 0 while (rounds); if (tps) break; // works, must have 32khz crystal //______ couldn't get tps, now fallback to use VLO //BCSCTL3 |= LFXT1S_2; // use VLO as ACLK, ~12Khz В оригинале было раскоментировано //CCR0 = 64-1; // В оригинале было раскоментировано //_______ VLO calibration, // WDT counts 122x8ms (on 1 Mhz MCLK) times and see how many ACLK counts per sec // now we got tps as ACLK/64 counts in one sec // for 1/8 sec per interrupt we will need to set CCR0 to tps * 8 // next round up to calibrate VLO // use_32khz = 0; // В оригинале было раскоментировано }//while // save ticks per second value for later setting uint8_t use_tps = tps; uint16_t time[6]; char *flash = (char*) 0x1040; char *src = (char*) time; uint8_t i=0; // read configuration from flash for (i=0;i<12;i++) { if (*flash != 0xff) *src = *flash; src++; flash++; }//for //________ temperature sensing setup G2231 only ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; uint16_t mode4 = 10; // Было 0 uint16_t *show; uint8_t sec=45; P1SEL = 0; P2SEL = (1<<6)|(1<<7); // will use crystal uint8_t menu=1; uint8_t mode=4; // Было 1 uint8_t state=ST_PRESSED; // Было ST_HOLD uint8_t setup=0; // Было 4 // ******** Начало главного цикла **** while (1) { if (!menu && stacked) { while (stacked) { stacked--; // stacked - число непосчитанных секунд накопленных от прерывания кварца // здесь обнуляется, превращаясь в секунды и минуты. if (++sec >= 60) { sec = 0; time[1]++; //________ alarm ? if ((*time & (1<<2)) && time[1] == time[2]) { state |= (ST_BUZZ|ST_REFRESH); mode = 1; }//if }//if }//while if ((mode != 1) || !sec) state |= ST_REFRESH; #ifdef DEVICE_20P *(output + (1*3+1)) &= ~SEG_d_P1; if (use_32khz) if ((mode==1) && (sec&0x01)) *(output + (1*3+1)) |= SEG_d_P1; #endif }//if uint8_t adv = 0; uint8_t txt = 0; //_____________________________________ check input if (state & ST_BUTTON) { // needs attention if ((state & ST_BUZZ) || !mode) { // stop alarm state &= ~(ST_BUZZ|ST_BUTTON); mode = 1; state |= ST_REFRESH; continue; }//if // Режим настройки if (setup) { if (state & ST_HOLD) { // Меню настройки switch (setup) { case 3: menu_attr >>= 2; if (menu_attr) { //______ on to options toggle state |= ST_PRESSED; setup++; break; }//if case 4: { //___________ done, flash char *flash = (char*) 0x1040; char *src = (char*) time; FCTL1 = FWKEY + ERASE; FCTL3 = FWKEY; *flash = 0x0000; FCTL1 = FWKEY + WRT; for (i=0;i<12;i++) *flash++ = *src++; FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; //_________ load fresh parameters // you can save a lot by omitting boundary checks //time[4] %= 100; //time[5] %= 10; time[4] &= 0x003f; time[5] &= 0x0007; if (!use_32khz) CCR0 = (use_tps-time[4])*8; CCTL0 = CCIE; // CCR0 interrupt enabled TACTL = TASSEL__ACLK + MC__UP + TACLR; // ACLK, upmode switch (menu) { case 3: mode4 = *show; mode = 4; break; default: mode = 1; break; }//switch show = time + 1; menu = 0; setup = 0; break; } default: setup++; break; }//switch }//if if (state & ST_PRESSED) { if (setup == 4) { if (!(state & ST_HOLD)) *time ^= 1<<menu; txt = (menu_attr<<1) + ((*time & 1<<menu) ? 1 : 0); }//if else { adv = setup; }//else }//if }//if else { if (state & ST_PRESSED) { if (menu) { //_______ menu selected //mode = 1; show = time + menu; setup = menu_attr & 0x03; }//if else { //_______ advance display mode mode++; mode &= 0x03; seg2port(menu_desc[0], 0x20); stays = 0; }//else }//if else { //_______ advance menu if (mode) { //_________ not option, not edit, advance menu menu++; //___________ see if we need alarm function (buzzer attached?) //while (opts & (1<<2) && (menu & 0x02)) menu++; if (menu > 5) menu = 0; else txt = menu; menu_attr = menu_attrs[menu]; mode = 1; }//if }//else }//else }//if if (state&(ST_REFRESH|ST_BUTTON) && !stays) { state &= ~(ST_REFRESH|ST_BUTTON); if (txt) { seg2port(menu_desc[txt], 0x20); }//if else { if (adv == 1) { *show += 60; adv = 0; }//if if (*show>=(24*60)) *show -= 24*60; switch (mode) { case 1: // hour + min *show = seg2port(*show, adv); if (!(*time & (1<<1)) && menu < 3) { // 12HR display uint16_t hhmm = *show; if (hhmm>=(12*60)) { //__________ 12Hr mode, pm indicator adv = 1; hhmm -= 12*60; }//if if (hhmm<60) hhmm += 12*60; seg2port(hhmm, 0); }//if break; case 2: // alarm on/off + seconds //seg2port(sec+(POS__*100) + ((*time & (1<<2)) ? POSb1*1600 : 0), 0x10); seg2port(sec, 0); if (*time & (1<<2)) adv = 1; break; case 3: { // temperature int16_t temp = ADC10MEM; if (temp) { // oF = ((A10/1024)*1500mV)-923mV)*1/1.97mV = A10*761/1024 - 468 // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278 //temp = ((temp - 630) * 761) / 1024; oF //temp = ((temp - 673) * 423) / 1024; C 0 offset //temp = ((temp - 552) * 423) / 1024; C -50 offset // 1.464mv/u 3.55 #ifdef NO_TEMP_CHOICE temp = ((temp - 673) * 423) / 1024; #ifndef METRIC_TEMP temp = (temp * 10 / 8) + 32; #endif temp <<= 4; #ifdef METRIC_TEMP if (temp < 0) { temp = -temp; temp += POSb2 * 1600; }//if #endif #else temp = ((temp - 673) * 423) / 1024; if (*time & (1<<4)) // imperial temperature temp = (temp * 10 / 8) + 32; temp <<= 4; // if (temp < 0) { temp = -temp; temp += POSb2 * 1600; }//if #endif #ifdef NO_TEMP_CHOICE #ifdef METRIC_TEMP seg2port(temp|POS_C, 0x10); #else seg2port(temp|POS_f, 0x10); #endif #else seg2port(temp|((*time & (1<<4))?POS_f:POS_C), 0x10); #endif }//if ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled } break; case 0: // blank _BIS_SR(LPM3_bits + GIE); // sleep case 5: // blank state |= ST_REFRESH; break; case 4: // counter seg2port(mode4, 0); if (mode4) mode4--; else state |= ST_BUZZ; default: break; }//switch if (adv) *(output + (3*3+1)) |= SEG_d_P1; }//else }//if if (state & ST_BUZZ) { if (ticks & 0x02) { P2DIR = _P2DIR; P1DIR = BUZZ_PINP|BUZZ_PINN; P1OUT ^= BUZZ_PINP; // toggle buzzer }//if }//if // allow led segments stays on if (stays & 0x0f) { stays--; continue; } // time[5] contains dimmer value stays >>= time[5]; // turn off all io pins, led blanks P2DIR = _P2DIR; P1DIR = 0; P2OUT = 0; P1OUT = 0; // allow led segments stays blank out, dimming if (stays) { stays--; continue; } P1REN = BTNP_P1; if (mode) { //____________ only if we are not asleep P1DIR = BUZZ_PINN; P1OUT = BUZZ_PINP; P1REN |= BUZZ_PINP; //------------- ОПРЕДЕЛЕНИЕ, ПОДКЛЮЧЕН ЛИ ДИНАМИК и переключение на меню !!!! /* if ((opts & BUZZ_PINP) && !(P1IN & BUZZ_PINP)) { menu = 1; state |= ST_HOLD; }*/ //---------------------------------------------------------------------- // store port 1 pin status opts = P1IN; }//if //___________ check button // button must be position at P1.2 as it's tied to RESET pin // we need it be pressed after power's been applied (boot) uint16_t wait=0; do { if (wait == 0x0040) { state |= ST_PRESSED; }//if else { if (wait++ > 0x6000) { state &= ~ST_PRESSED; state |= ST_HOLD; //if (wait&0x0f) P1DIR ^= 0x30; #ifdef DEVICE_20P P2DIR ^= 0x06; #else P1DIR ^= 0x30; #endif }//if }//else wait++; } while (P1IN & BTNP_P1); P1REN = 0; //P1DIR = 0; P1OUT = 0; if ((state & ST_BUTTON) || !mode) continue; static uint8_t pos=0; static const uint8_t digit_map1[] = { DIGIT_0_P1, DIGIT_1_P1, DIGIT_2_P1, DIGIT_3_P1, }; static const uint8_t digit_map2[] = { DIGIT_0_P2, DIGIT_1_P2, DIGIT_2_P2, DIGIT_3_P2, }; // flasher during individual digit setup //___________ load segments and turn on 1 of 4 digits //uint8_t setup = state & ST_SETUP; uint8_t *ioptr = output + (pos*3); if (!setup || !(ticks & 0x02) || (pos != setup && (pos|setup) != 0x01)) { // use this (w/ negate) if led is common anode //P2OUT = ~(*ioptr & ~digit_map2[pos]); P2OUT = *ioptr & ~digit_map2[pos]; P2DIR = (*ioptr++ | digit_map2[pos]) | _P2DIR; // use this (w/ negate) if led is common anode //P1OUT = ~(*ioptr & ~digit_map1[pos]); P1OUT = *ioptr & ~digit_map1[pos]; P1DIR = *ioptr++ | digit_map1[pos]; stays = *ioptr; }//if pos++; pos &= 0x03; }//while Конц главного цикла