11295|25

1944

帖子

32

TA的资源

纯净的硅(高级)

楼主
 

【晒心得】+ TI EZ430-CHRONOS-433 无线手表代码解析 [复制链接]

开个帖子,共同学习EZ430。使用了一下EZ430-CHRONOS ,感觉挺酷的!不过也遇到这样那样的问题,看到坛子上不少大神都遇到了,所以我不是最幸运的,哈哈。
不能拷贝系统时间到手表上,在deyisupport上问了很多天,也不见有人回复(见http://www.deyisupport.com/quest ... 0/f/55/t/45052.aspx)
所以先研究研究代码,想随后重新定制一下功能。因为很多配件要么压根没有,要么很贵,就像心律测试的,没有433MHz的,而且好几十美刀,消费不起啊。直接把这些个
功能去了,以后改成别的用途!看得到,用不到,闹心!!

以前没有接触过MSP430,所以估计有很多不妥当的地方,欢迎各位拍拍砖(别砸死我就行了)。另外也希望大家多多支持,增加点学习的信心,多点动力

代码分析,我想按照代码的执行路径,一步一步解析,有其他的引用,通过注释或者在后面的跟贴中解析。

EZ430-CHEONOS的相关文档也上传上来了,方便大家下载。
cc430f6137.pdf (1.19 MB, 下载次数: 87)
ez430.pdf (9.06 MB, 下载次数: 108)
zhcu020d.pdf (7.21 MB, 下载次数: 94)

最新回复

楼主能不能再分享一次完整的手表代码啊?德仪那个网页已经不能打开了,刚收的这个表 谢谢了!  详情 回复 发表于 2016-1-23 15:54
 
点赞 关注(1)

回复
举报

1944

帖子

32

TA的资源

纯净的硅(高级)

沙发
 
代码下载地址:http://www.ti.com/lit/sw/slac341c/slac341c.zip
比较大,里面还包含PC端驱动和软件,所以就不上传了。下面分析的代码就是这里安装包里面的代码。采用默认路径安装,则
代码的存放位置为:
C:\Program Files\Texas Instruments\eZ430-Chronos\Software Projects\Chronos Watch\eZ430-Chronos v1.1 - white PCB\CCS\Sports Watch
我收到的是白色PCB的版本,所以选择代码时选择V1.1 - white PCB。不知道有没有朋友收到黑色PCB的版本,相信那个版本还是使用
没有缩水的VTI的传感器。

啰嗦了这么多,下面开始代码分析。(一天写一点
  1. // *************************************************************************************************
  2. // @fn          main
  3. // @brief       Main routine
  4. // @param       none
  5. // @return      none
  6. // *************************************************************************************************
  7. int main(void)
  8. {
  9.     // Init MCU
  10. //初始化MCU,里面做的工作主要有配置MCU电源时钟,使能IO中断,复位关闭无线发射,初始化加速度传感器、LCD、按键、定时器、压力传感器
  11.     init_application();

  12.     // Assign initial value to global variables
  13. //初始化全局变量: 初始化菜单,复位各标志位,读取校正因子,复位时钟、日期、闹钟、蜂鸣器、跑表、高度计、加速度、协议栈、温度、电池电压等
  14. //如果你不想每次复位后手表都显示4:30,可以将初始化的初值改称你希望的值,包括日期。
  15.     init_global_variables();

  16.     // Branch to welcome screen
  17. //测试模式,持续按住*和up键进入测试模式,按其他键退出。测试模式显示LCD上所有的字段,关闭看门狗。
  18.     test_mode();

  19.     // Main control loop: wait in low power mode until some event needs to be processed
  20. //主循环:无事件触发的时候,进入LPM3模式
  21.     while (1)
  22.     {
  23.         // When idle go to LPM3
  24. //系统空闲进入LPM3模式
  25.         idle_loop();

  26.         // Process wake-up events
  27. //处理唤醒事件
  28. //button结构体中标志位包括手表上的五个按键——长按或短按标志位,这个结构体定义在ports.h中
  29. // Set of button flags
  30. typedef union
  31. {
  32.     struct
  33.     {
  34.         // Manual button events
  35.         u16 star : 1;           // Short STAR button press
  36.         u16 num : 1;            // Short NUM button press
  37.         u16 up : 1;             // Short UP button press
  38.         u16 down : 1;           // Short DOWN button press
  39.         u16 backlight : 1;      // Short BACKLIGHT button press
  40.         u16 star_long : 1;      // Long STAR button press
  41.         u16 num_long : 1;       // Long NUM button press
  42.         u16 star_not_long : 1;  // Between short and long STAR button press
  43.         u16 num_not_long : 1;   // Between short and long NUM button press
  44.     } flag;
  45.     u16 all_flags;              // Shortcut to all display flags (for reset)
  46. } s_button_flags;
复制代码
//sys结构体中标志位表包括系统中的标志位,结构体定义在project.h中
  1. // Set of system flags
  2. typedef union
  3. {
  4.     struct
  5.     {
  6.         u16 idle_timeout : 1;             // Timeout after inactivity
  7.         u16 idle_timeout_enabled : 1;     // When in set mode, timeout after a given period
  8.         u16 lock_buttons : 1;             // Lock buttons
  9.         u16 mask_buzzer : 1;              // Do not output buzz for next button event
  10.         u16 up_down_repeat_enabled : 1;   // While in set_value(), create virtual UP/DOWN button
  11.                                           // events
  12.         u16 low_battery : 1;              // 1 = Battery is low
  13.         u16 use_metric_units : 1;         // 1 = Use metric units, 0 = use English units
  14.         u16 delay_over : 1;               // 1 = Timer delay over
  15.     } flag;
  16.     u16 all_flags;                        // Shortcut to all system flags (for reset)
  17. } s_system_flags;
复制代码
if (button.all_flags || sys.all_flags)
            wakeup_event();

        // Process actions requested by logic modules
//处理逻辑模块触发事件
        if (request.all_flags)
            process_requests();

        // Before going to LPM3, update display
//有任何事件触发,更新显示
        if (display.all_flags)
            display_update();
    }
}
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

板凳
 
上一贴子中Button和sys描述有误,都是联合体,由于帖子审核后不能编辑,只能在这里重新说明一下了。

说道这里,顺便提一下位域的概念。
我们看到联合体中定义了flag的结构体,每个成员后都有一个“:”加上一个数字1。如紫色标注部分。
  1. typedef union
  2. {
  3.     struct
  4.     {
  5.         // Manual button events
  6.         u16 star : 1;           // Short STAR button press
  7.         u16 num : 1;            // Short NUM button press
  8.         u16 up : 1;             // Short UP button press
  9.         u16 down : 1;           // Short DOWN button press
  10.         u16 backlight : 1;      // Short BACKLIGHT button press
  11.         u16 star_long : 1;      // Long STAR button press
  12.         u16 num_long : 1;       // Long NUM button press
  13.         u16 star_not_long : 1;  // Between short and long STAR button press
  14.         u16 num_not_long : 1;   // Between short and long NUM button press
  15.     } flag;
  16.     u16 all_flags;              // Shortcut to all display flags (for reset)
  17. } s_button_flags;
复制代码
至于原因和作用(以前也没有注意过,
从来么有用过MSP430,一看才发现头文件中很多都是这样定义的),参考了一下度娘,下面摘录了部分内容
/*以下内容摘自"度娘"*/
    有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0
和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按
域名进行操作。   这样就可以把几个不同的对象用一个字节的二进制位域来表示。
    位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:           
    struct   位域结构名           
    {   位域列表   };         
    其中位域列表的形式为:   类型说明符   位域名:位域长度

带有'位域'的结构体并不是按照每个域对齐的,而是将一些位域成员'捆绑'在一起做对齐的。
1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
/*摘录部分结束*/

    flag中定义了9个U16类型的成员,9个成员所占位域空间之和9bit>8bit(1byte),所以占2个字节的空间
    这样一来,这个联合体只占2个字节的空间,节省了很多存储空间。
    联合体中成员的英文注释已经比较明了啦,这里就不再翻译啦。
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

4
 
下面开始解析函数init_application();
  1. // *************************************************************************************************
  2. // @fn init_application
  3. // @brief Initialize the microcontroller.
  4. // @param none
  5. // @return none
  6. // *************************************************************************************************
  7. void init_application(void)
  8. {
  9. volatile unsigned char *ptr;
  10. // ---------------------------------------------------------------------
  11. // Enable watchdog
  12. //使能看门狗
  13. // Watchdog triggers after 16 seconds when not cleared
  14. //16s位清除看门狗触发复位操作
  15. #ifdef USE_WATCHDOG
  16. //通过WDTCTL寄存器,看门狗模块可以配置为看门狗功能或者内部定时器功能。WDTCTL是一个16位的带密码保护的可读写寄存器,
  17. //读写操作必须使用字指令,写操作必须在高位字节包含写密码,0x5A。这里宏WDRPW定义为写密码0x5A00。
  18. //WDTIS为时钟间隔选择,一共有8种时钟间隔可供选择。
  19. //WDTSSEL为时钟源选择:SMCLK、ACLK、VLOCLK、X_CLK
  20. //WDRHOLD为1时停止看门狗定时器
  21. WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK;
  22. #else
  23. WDTCTL = WDTPW + WDTHOLD;
  24. #endif
  25. // ---------------------------------------------------------------------
  26. // Configure PMM
  27. //提升核心供电电压
  28. SetVCore(3);
  29. // Set global high power request enable
  30. //0xA5为电源管理模块寄存器写操作密码
  31. //开启PMM的高能量消耗允许
  32. PMMCTL0_H = 0xA5;
  33. PMMCTL0_L |= PMMHPMRE;
  34. //写入除0x5A外设和数字,锁定PMM寄存器写操作
  35. PMMCTL0_H = 0x00;
  36. //UCS包括5个时钟源
  37. //XT1CLK:低频/高频晶振,可以用低频32768Hz手表晶振、标准晶振、陶瓷振荡器、或范围4MHz-32MHz的外部时钟源。
复制代码
[ 本帖最后由 azhiking 于 2013-9-30 14:34 编辑 ]

1.JPG (62.21 KB, 下载次数: 3)

晶振

晶振

2.JPG (27.98 KB, 下载次数: 0)

原理图

原理图
 
 
 

回复

122

帖子

0

TA的资源

纯净的硅(初级)

5
 
不错,顶一下~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

6
 
写了好多,发表后全没了,

重新补上吧:

统一时钟系统模块包含5个时钟源:

XT1CLK:低频/高频晶振,可以用低频32768Hz手表晶振、标准晶振、陶瓷振荡器、或范围4MHz-32MHz的外部时钟源。

VLOCLK:内部非常低功率、低频率的12KHz典型频率的晶振

REFOCLK:内部的、修正过的、低频32768Hz典型频率振荡器,可以作为FLL的基准时钟。

DCOCLK:内部数控振荡器,可以用FLL稳定。

XT2CLK:可选择的高频振荡器,可以用标准晶振、陶瓷振荡器、或范围4MHz-40MHz的外部时钟源。

从统一时钟系统模块有3个有效的时钟信号:

ACLK:辅助时钟。ACLK可软件选择来自XT1CLK、REFOCLK、VLOCLK、DCOCLK、DCOCLKDIV和XT2CLK(如果有)的信号。DCOCLKDIV是在FLL模块作用下分频为1、2、4、6、8、16或32的DCOCLK频率。ACLK可软件选择为个人外设模块的信号。ACLK/n是ACLK被分为1,2,4,6,8,16,32,并且可以用一个引脚外部输出。

MCLK:系统主时钟。MCLK可软件选择来自XT1CLK、REFOCLK、VLOCLK、DCOCLK、DCOCLKDIV和XT2CLK(如果有)的信号。MCLK可分频为1,2,4,6,8,16或32。MCLK主要用于CPU与系统.

SMCLK:子系统时钟。SMCLK可软件选择来自XT1CLK、REFOCLK、VLOCLK、DCOCLK、DCOCLKDIV和XT2CLK(如果有)的信号。SMCLK可分频为1,2,4,6,8,16或32。SMCLK可软件选择为个人外设模块。


参考MSP430F6137的datasheet和EZ430的原理图,可以看到其使用的是P5.0和P5.1作为外部晶振的输入输出,所以有
P5SEL |= 0x03;              // Select XIN, XOUT on P5.0 and P5.1
接下来配置CPU时钟为12MHz
  1. // ---------------------------------------------------------------------
  2.     // Enable 32kHz ACLK
  3.     P5SEL |= 0x03;              // Select XIN, XOUT on P5.0 and P5.1
  4.     UCSCTL6 &= ~XT1OFF;         // XT1 On, Highest drive strength
  5.     UCSCTL6 |= XCAP_3;          // Internal load cap

  6.     UCSCTL3 = SELA__XT1CLK;     // Select XT1 as FLL reference
  7.     UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV;

  8.     // ---------------------------------------------------------------------
  9.     // Configure CPU clock for 12MHz
  10.     _BIS_SR(SCG0);              // Disable the FLL control loop
  11.     UCSCTL0 = 0x0000;           // Set lowest possible DCOx, MODx
  12.     UCSCTL1 = DCORSEL_5;        // Select suitable range
  13.     UCSCTL2 = FLLD_1 + 0x16E;   // Set DCO Multiplier
  14.     _BIC_SR(SCG0);              // Enable the FLL control loop

  15.     // Worst-case settling time for the DCO when the DCO range bits have been
  16.     // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
  17.     // UG for optimization.
  18.     // 32 x 32 x 12 MHz / 32,768 Hz = 375000 = MCLK cycles for DCO to settle
  19.     __delay_cycles(375000);

  20.     // Loop until XT1 & DCO stabilizes, use do-while to insure that
  21.     // body is executed at least once
  22.     do
  23.     {
  24.         UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG);
  25.         SFRIFG1 &= ~OFIFG;      // Clear fault flags
  26.     }
  27.     while ((SFRIFG1 & OFIFG));

  28.     // ---------------------------------------------------------------------
  29.     // Configure port mapping

  30.     // Disable all interrupts
  31.     __disable_interrupt();
  32.     // Get write-access to port mapping registers:
  33.     PMAPPWD = 0x02D52;
  34.     // Allow reconfiguration during runtime:
  35.     PMAPCTL = PMAPRECFG;

  36.     // P2.7 = TA0CCR1A or TA1CCR0A output (buzzer output)
  37.     ptr = &P2MAP0;
  38.     *(ptr + 7) = PM_TA1CCR0A;
  39.     P2OUT &= ~BIT7;
  40.     P2DIR |= BIT7;

  41. //参考原理图

  42. //配置SPI接口
  43.     // P1.5 = SPI MISO input
  44.     ptr = &P1MAP0;
  45.     *(ptr + 5) = PM_UCA0SOMI;
  46.     // P1.6 = SPI MOSI output
  47.     *(ptr + 6) = PM_UCA0SIMO;
  48.     // P1.7 = SPI CLK output
  49.     *(ptr + 7) = PM_UCA0CLK;

  50.     // Disable write-access to port mapping registers:
  51.     PMAPPWD = 0;
  52.     // Re-enable all interrupts
  53.     __enable_interrupt();

  54.     // ---------------------------------------------------------------------
  55.     // Configure ports

  56.     // ---------------------------------------------------------------------
  57.     // Reset radio core
  58.     radio_reset();
  59.     radio_powerdown();

  60.     // ---------------------------------------------------------------------
  61.     // Init acceleration sensor
  62. //初始化加速度传感器
  63.     as_init();

  64.     // ---------------------------------------------------------------------
  65.     // Init LCD
  66. //初始化LCD
  67.     lcd_init();

  68.     // ---------------------------------------------------------------------
  69.     // Init buttons
  70. //初始化按键
  71.     init_buttons();

  72.     // ---------------------------------------------------------------------
  73.     // Configure Timer0 for use by the clock and delay functions
  74. //配置Timer0
  75.     Timer0_Init();
  76.     // ---------------------------------------------------------------------

  77.     // ---------------------------------------------------------------------
  78.     // Init pressure sensor
  79. //初始化Bosch压力传感器
  80.     bmp_ps_init();
  81.     // Bosch sensor not found?
  82. //如果配置失败,清除标志位,然后初始化VTI SCP1000压力传感器,这个是为了兼容黑色pcb版本的Chorons。
  83.     if (!ps_ok)
  84.     {
  85.         bmp_used = 0;
  86.         cma_ps_init();
  87.     }
  88.     else
  89.     {
  90.             bmp_used = 1;
  91.     }
  92. }
复制代码

3.JPG (13.86 KB, 下载次数: 2)

3.JPG
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

7
 
  1. // *************************************************************************************************
  2. // @fn          test_mode
  3. // @brief       Manual test mode. Activated by holding buttons STAR and UP simultaneously.
  4. //                              Cancelled by any other button press.
  5. // @param       none
  6. // @return      none
  7. // *************************************************************************************************
  8. void test_mode(void)
  9. {
  10.     u8 test_step, start_next_test;
  11.     u8 *str;
  12.     u8 i;

  13.     // Disable timer - no need for a clock tick
  14. //关闭定时器
  15.     Timer0_Stop();

  16.     // Disable LCD charge pump while in standby mode
  17.     // This reduces current consumption by ca. 5礎 to ca. 10礎
  18.     LCDBVCTL = 0;

  19.     // Show welcome screen
  20. //显示LCD的所有字段
  21.     display_chars(LCD_SEG_L1_3_0, (u8 *) "0430", SEG_ON);
  22.     display_chars(LCD_SEG_L2_4_0, (u8 *) "CC430", SEG_ON);
  23.     display_symbol(LCD_SEG_L1_COL, SEG_ON);
  24.     display_symbol(LCD_ICON_HEART, SEG_ON);
  25.     display_symbol(LCD_ICON_STOPWATCH, SEG_ON);
  26.     display_symbol(LCD_ICON_RECORD, SEG_ON);
  27.     display_symbol(LCD_ICON_ALARM, SEG_ON);
  28.     display_symbol(LCD_ICON_BEEPER1, SEG_ON);
  29.     display_symbol(LCD_ICON_BEEPER2, SEG_ON);
  30.     display_symbol(LCD_ICON_BEEPER3, SEG_ON);
  31.     display_symbol(LCD_SYMB_ARROW_UP, SEG_ON);
  32.     display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON);
  33.     display_symbol(LCD_SYMB_AM, SEG_ON);

  34.     // Hold watchdog
  35. //关闭看门狗
  36.     WDTCTL = WDTPW + WDTHOLD;

  37.     // Wait for button press
  38. //等待按键
  39.     _BIS_SR(LPM3_bits + GIE);
  40.     __no_operation();

  41.     // Clear display
  42. //清除LCD显示
  43.     display_all_off();

  44. #ifdef USE_LCD_CHARGE_PUMP
  45.     // Charge pump voltage generated internally, internal bias (V2-V4) generation
  46.     // This ensures that the contrast and LCD control is constant for the whole battery lifetime
  47.     LCDBVCTL = LCDCPEN | VLCD_2_72;
  48. #endif

  49.     // Renenable timer
  50. //使能Timer0
  51.     Timer0_Start();

  52.     // Debounce button press
  53. //按键去抖,延时100ms
  54.     Timer0_A4_Delay(CONV_MS_TO_TICKS(100));


  55. //
  56. //按键定义见上原理图,P2口,0,1,2,3,4
  57. #define BUTTON_STAR_PIN             (BIT2)
  58. #define BUTTON_NUM_PIN               (BIT1)
  59. #define BUTTON_UP_PIN                  (BIT4)
  60. #define BUTTON_DOWN_PIN            (BIT0)
  61. #define BUTTON_BACKLIGHT_PIN      (BIT3)
  62. #define ALL_BUTTONS                     (BUTTON_STAR_PIN + BUTTON_NUM_PIN + BUTTON_UP_PIN + \
  63.                                                        BUTTON_DOWN_PIN + BUTTON_BACKLIGHT_PIN)
复制代码
while (1)
    {
        // Check button event
//针对不同的按键做出不同的响应
//如果"*"和向上键同时按下

        if (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED)
        {
            // Start with test #0
            test_step = 0;
            start_next_test = 1;
            while (1)
            {
                if (start_next_test)
                {
                    // Clean up previous test display
                    display_all_off();

                    start_next_test = 0;

                    switch (test_step)
                    {
                        case 0: // All LCD segments on
                            display_all_on();
                            // Wait until buttons are off
                            while (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED) ;
                            break;
                        case 1: // Altitude measurement
                            display_altitude(LINE1, DISPLAY_LINE_UPDATE_FULL);
                            for (i = 0; i < 2; i++)
                            {
                                while ((PS_INT_IN & PS_INT_PIN) == 0) ;
                                do_altitude_measurement(FILTER_OFF);
                                display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL);
                            }
                            stop_altitude_measurement();
                            break;
//温度测量
                        case 2: // Temperature measurement
                            display_temperature(LINE1, DISPLAY_LINE_UPDATE_FULL);
                            for (i = 0; i < 4; i++)
                            {
                                Timer0_A4_Delay(CONV_MS_TO_TICKS(250));
                                temperature_measurement(FILTER_OFF);
                                display_temperature(LINE1, DISPLAY_LINE_UPDATE_PARTIAL);
                            }
                            break;
//加速度测量,在初始化的时候已经根据硬件不同,置不同的标志位,这里根据标志位选择BOSCH或者VTI的加速度传感器。
//以兼容不同的硬件版本

                        case 3: // Acceleration measurement
                                if (bmp_used)
                                {
                                bmp_as_start();
                                }
                                else
                                {
                                cma_as_start();
                                }
                            for (i = 0; i < 4; i++)
                            {
                                Timer0_A4_Delay(CONV_MS_TO_TICKS(250));
                                    if (bmp_used)
                                    {
                                    bmp_as_get_data(sAccel.xyz);
                                    }
                                    else
                                    {
                                    cma_as_get_data(sAccel.xyz);
                                    }
                                str = int_to_array(sAccel.xyz[0], 3, 0);
                                display_chars(LCD_SEG_L1_2_0, str, SEG_ON);
                                str = int_to_array(sAccel.xyz[2], 3, 0);
                                display_chars(LCD_SEG_L2_2_0, str, SEG_ON);
                            }
                                if (bmp_used)
                                {
                                bmp_as_stop();
                                }
                                else
                                {
                                cma_as_stop();
                                }
                            break;
                        case 4: // BlueRobin test
                            button.flag.up = 1;
                            sx_bluerobin(LINE1);
//按键去抖,延时100ms
                            Timer0_A4_Delay(CONV_MS_TO_TICKS(100));
                            get_bluerobin_data();
                            display_heartrate(LINE1, DISPLAY_LINE_UPDATE_FULL);
                            stop_bluerobin();
                            break;
                    }

                    // Debounce button
//按键去抖,延时200ms
                    Timer0_A4_Delay(CONV_MS_TO_TICKS(200));
                }

                // Check button event
                if (BUTTON_STAR_IS_PRESSED)
                {
                    test_step = 1;
                    start_next_test = 1;
                }
                else if (BUTTON_NUM_IS_PRESSED)
                {
                    test_step = 2;
                    start_next_test = 1;
                }
                else if (BUTTON_UP_IS_PRESSED)
                {
                    test_step = 3;
                    start_next_test = 1;
                }
                else if (BUTTON_DOWN_IS_PRESSED)
                {
                    test_step = 4;
                    start_next_test = 1;
                }
                else if (BUTTON_BACKLIGHT_IS_PRESSED)
                {
                    // Wait until button has been released (avoid restart)
                    while (BUTTON_BACKLIGHT_IS_PRESSED) ;

                    // Disable LCD and LCD charge pump
                    LCDBCTL0 &= ~BIT0;
                    LCDBVCTL = 0;

                    // Debounce button press
//按键去抖,延时500ms
                    Timer0_A4_Delay(CONV_MS_TO_TICKS(500));

                    // Disable timer - no need for a clock tick
                    Timer0_Stop();

                    // Hold watchdog
                    WDTCTL = WDTPW + WDTHOLD;

                    // Sleep until button is pressed (ca. 4礎 current consumption)
                    _BIS_SR(LPM4_bits + GIE);
                    __no_operation();

                    // Force watchdog reset for a clean restart
//看门狗标志位置位,是系统复位
                    WDTCTL = 1;
                }

#ifdef USE_WATCHDOG
                // Service watchdog
                WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL;
#endif
                // To LPM3
//进入LPM3功耗模式
                _BIS_SR(LPM3_bits + GIE);
                __no_operation();
            }
        }
        else
        {
            // Debounce button
//按键去抖
            Timer0_A4_Delay(CONV_MS_TO_TICKS(100));
            button.all_flags = 0;

            // Turn off backlight
//关闭背光
            P2OUT &= ~BUTTON_BACKLIGHT_PIN;
            P2DIR &= ~BUTTON_BACKLIGHT_PIN;
            break;
        }
    }
}

4.JPG (17.98 KB, 下载次数: 0)

4.JPG
 
 
 

回复

1632

帖子

4

TA的资源

纯净的硅(高级)

8
 
我的手表很容易进水,里面全是水汽,就平时洗个手就这样

点评

记不太清楚了,好像我以前也出现过,不过很少见好像 不过我感觉哥空气的热缩冷胀还是很厉害的,我以前做过一个钓鱼温度计https://bbs.eeworld.com.cn/thread-366570-1-1.html,体积很大,而且里面空的体积很大,  详情 回复 发表于 2013-10-7 20:21
 
个人签名科技改变生活
 
 

回复

5276

帖子

5

TA的资源

裸片初长成(中级)

9
 
原帖由 眼大5子 于 2013-10-6 08:32 发表
我的手表很容易进水,里面全是水汽,就平时洗个手就这样

记不太清楚了,好像我以前也出现过,不过很少见好像

不过我感觉哥空气的热缩冷胀还是很厉害的,我以前做过一个钓鱼温度计https://bbs.eeworld.com.cn/thread-366570-1-1.html,体积很大,而且里面空的体积很大,结果导致到了夏天有点鼓了起来,中间按键上的隔离密封塑料片经常按脆裂,更新重新用胶密封,但是到更热的天气的时候再加上在非室温下鼓得更厉害,似乎已经漏气,因为所用的胶不想随意打开使用,所以一直放着没处理,等到什么时候其它地方也要用胶的时候一并处理。
 
 
 

回复

198

帖子

3

TA的资源

一粒金砂(中级)

10
 
分析的不错,支持一下
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

11
 
长假归来,继续
  1. idle_loop();
复制代码
这个函数的功能是当cpu IDLE的时候,切换进入LPM3低功耗模式。
CPU内的状态寄存器SR种的SCG1、SCG2、OscOff和CPUOff是重要的低功耗控制位。
MSP430的几种低功耗模式下的时钟运行情况如下图所示:

由于不同的休眠模式下,系统使用的时钟可能是不同的,所以在“喂狗”的时候需要选择合适的时钟源
  1. // *************************************************************************************************
  2. // @fn          idle_loop
  3. // @brief       Go to LPM. Service watchdog timer when waking up.
  4. // @param       none
  5. // @return      none
  6. // *************************************************************************************************
  7. void idle_loop(void)
  8. {
  9.     // To low power mode
  10. //
    #define LPM0_bits              (CPUOFF)
  11. #define LPM1_bits              (SCG0+CPUOFF)
  12. #define LPM2_bits              (SCG1+CPUOFF)
  13. #define LPM3_bits              (SCG1+SCG0+CPUOFF)
  14. #define LPM4_bits              (SCG1+SCG0+OSCOFF+CPUOFF)
复制代码
//_BIS_SR(LPM3_bits + GIE);
//void __bis_SR_register(unsigned short);
//功能:将CPU 中SR 寄存器中的某些位置1。其参数为屏蔽码,需要置1 的位为1。
    to_lpm();

#ifdef USE_WATCHDOG
    // Service watchdog
//清除看门狗定时器
    WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL;
#endif
}

点评

发现论坛回复编辑的一个BUG,如果使用“添加代码文字”功能后,在代码文字中再次使用“添加代码文字”功能,会导致 第一次添加的代码文字后边段不能正常显示为代码文字。:faint:  详情 回复 发表于 2013-10-10 15:30
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

12
 
这个函数用来处理内部和外部的各种唤醒事件,如按键操作,IDLE超时
// *************************************************************************************************
// @fn          wakeup_event
// @brief       Process external / internal wakeup events.
// @param       none
// @return      none
// *************************************************************************************************
void wakeup_event(void)
{
    // Enable idle timeout
    //使能IDEL超时,当“长时间”不做进一步操作的时候,做超时处理
    sys.flag.idle_timeout_enabled = 1;

    // If buttons are locked, only display "buttons are locked" message
    //如果按键被锁定,显示"buttons are locked"信息
    //同时按下#和向下方向键可以将按键锁定,有点类似于手机的按键锁一样
    if (button.all_flags && sys.flag.lock_buttons)
    {
        // Show "buttons are locked" message synchronously with next second tick
        if (!(BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED))
        {
            message.flag.prepare = 1;
            message.flag.type_locked = 1;
        }
        // Clear buttons
        button.all_flags = 0;
    }
    // Process long button press event (while button is held)
    //处理按键“长按”事件

    //长按*键
    else if (button.flag.star_long)
    {
        // Clear button event
        //清除长按*键标志位
        button.flag.star_long = 0;

        // Call sub menu function
        //进入当前菜单的子菜单,第一行菜单
        ptrMenu_L1->mx_function(LINE1);

        // Set display update flag
        //置刷新屏幕标志位
        display.flag.full_update = 1;
    }

    //长按#键
    else if (button.flag.num_long)
    {
        // Clear button event
        //清除长按#键标志位
        button.flag.num_long = 0;

        // Call sub menu function
        //进入当前菜单的子菜单,第二行菜单
        ptrMenu_L2->mx_function(LINE2);

        // Set display update flag
        //置刷新屏幕标志位
        display.flag.full_update = 1;
    }
    // Process single button press event (after button was released)
    //普通按键事件,短按按键
    else if (button.all_flags)
    {
        // M1 button event ---------------------------------------------------------------------
        // (Short) Advance to next menu item
        //“短按”进入下一个菜单,和长按不一样,长按是进入子菜单
        //短按*键
        if (button.flag.star)
        {
            // Clean up display before activating next menu item
            //清除第一行显示的内容
            fptr_lcd_function_line1(LINE1, DISPLAY_LINE_CLEAR);

            // Go to next menu entry
            //进入下一菜单
            ptrMenu_L1 = ptrMenu_L1->next;

            // Assign new display function
            //为第一行显示函数指针赋值
            fptr_lcd_function_line1 = ptrMenu_L1->display_function;

            // Set Line1 display update flag
            //置刷新第一行屏幕标志位
            display.flag.line1_full_update = 1;

            // Clear button flag
            //清除*键按下标志位
            button.flag.star = 0;
        }
        // NUM button event ---------------------------------------------------------------------
        // (Short) Advance to next menu item
        //短按#事件,与*类似,不再赘述
        else if (button.flag.num)
        {
            // Clear rfBSL confirmation flag
            rfBSL_button_confirmation = 0;

            // Clean up display before activating next menu item
            fptr_lcd_function_line2(LINE2, DISPLAY_LINE_CLEAR);

            // Go to next menu entry
            ptrMenu_L2 = ptrMenu_L2->next;

            // Assign new display function
            fptr_lcd_function_line2 = ptrMenu_L2->display_function;

            // Set Line2 display update flag
            display.flag.line2_full_update = 1;

            // Clear button flag
            button.flag.num = 0;
        }
        // UP button event ---------------------------------------------------------------------
        // Activate user function for Line1 menu item
        //向上按键事件
        //调用当前菜单的功能函数,置LINE1刷新标志位,清除按键事件标志位
        else if (button.flag.up)
        {
            // Call direct function
            ptrMenu_L1->sx_function(LINE1);

            // Set Line1 display update flag
            display.flag.line1_full_update = 1;

            // Clear button flag
            button.flag.up = 0;
        }
        // DOWN button event ---------------------------------------------------------------------
        // Activate user function for Line2 menu item
        //向下按键事件
        //如果当前菜单是RFBSL,do nothing
        //调用当前菜单功能函数,置LINE2刷新标志位,清除按键事件标志位
        else if (button.flag.down)
        {
            if (ptrMenu_L2 == &menu_L2_RFBSL)
            {

            }

            // Call direct function
            ptrMenu_L2->sx_function(LINE2);

            // Set Line1 display update flag
            display.flag.line2_full_update = 1;

            // Clear button flag
            button.flag.down = 0;
        }
    }
    // Process internal events
    //处理内部事件,IDLE超时
 //如果IDLE超时后,清除超时标志位,清除当前显示,刷新屏幕,并禁用超时功能
   //因为超时退出后,不需要超时了,所以禁用此功能
    if (sys.all_flags)
    {
        // Idle timeout ---------------------------------------------------------------------
        if (sys.flag.idle_timeout)
        {
            // Clear timeout flag
            sys.flag.idle_timeout = 0;

            // Clear display
            clear_display();

            // Set display update flags
            display.flag.full_update = 1;
        }
    }
    // Disable idle timeout
    sys.flag.idle_timeout_enabled = 0;
}
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

13
 
发现论坛回复编辑的一个BUG,如果使用“添加代码文字”功能后,在代码文字中再次使用“添加代码文字”功能,会导致
第一次添加的代码文字后边段不能正常显示为代码文字。
原帖由 azhiking 于 2013-10-10 14:23 发表
长假归来,继续idle_loop();这个函数的功能是当cpu IDLE的时候,切换进入LPM3低功耗模式。
CPU内的状态寄存器SR种的SCG1、SCG2、OscOff和CPUOff是重要的低功耗控制位。
MSP430的几种低功耗模式下的时钟运行情况如 ...
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

14
 
上面代码中提到menu,这里先插播一下ez430的menu吧。
menu结构体定义在menu.h中,具体如下
  1. struct menu
  2. {
  3.     // Pointer to direct function (start, stop etc)
  4. //当前功能函数指针
  5.     void (*sx_function)(u8 line);
  6.     // Pointer to sub menu function (change settings, reset counter etc)
  7. //子函数功能指针
  8.     void (*mx_function)(u8 line);
  9.     // Pointer to display function
  10. //显示函数指针
  11.     void (*display_function)(u8 line, u8 mode);
  12.     // Display update trigger
  13. //显示更新触发函数指针
  14.     u8 (*display_update)(void);
  15.     // Pointer to next menu item
  16. //指向下一菜单结构体的指针
  17.     const struct menu *next;
  18. };
复制代码
EZ430的屏幕上有两行,代码中把两行作为两个独立的菜单来对待,分别为LINE1和LINE2。
通过手表上的*和#键进行操作。
短按按键为进入下一菜单,长按按键进入子菜单。

菜单的初始化在menu.c中,两组菜单均初始化为循环单链表的数据结构,也就是说,你只能通过
按键,循环一圈才能回到当前菜单。因为对每组菜单的操作按键只有一个,上下键为修改功能键,
所以这么设计是合情合理的。

我们以LINE1菜单为例简单说明一下:
第一个菜单时间显示菜单初始化如下:
  1. const struct menu menu_L1_Time = {
  2.     FUNCTION(sx_time),                // direct function
  3.     FUNCTION(mx_time),                // sub menu function
  4.     FUNCTION(display_time),           // display function
  5.     FUNCTION(update_time),            // new display data
  6.     &menu_L1_Alarm,
  7. };
复制代码
最后一个菜单加速度初始化如下:
  1. // Line1 - Acceleration
  2. const struct menu menu_L1_Acceleration = {
  3.     FUNCTION(sx_acceleration),        // direct function
  4.     FUNCTION(dummy),                  // sub menu function
  5.     FUNCTION(display_acceleration),   // display function
  6.     FUNCTION(update_acceleration),    // new display data
  7.     &menu_L1_Time,
  8. };
复制代码
注意蓝色部分代码,最后一个菜单的下一菜单指向第一个菜单。

所以我们可以修改下一个菜单的指针,来"屏蔽"那些我们没法使用的功能
  1. // *************************************************************************************************
  2. // User navigation ( [____] = default menu item after reset )
  3. //
  4. //      LINE1:  [Time] -> Alarm -> Temperature -> Altitude -> Heart rate -> Speed -> Acceleration
  5. //
  6. //      LINE2:  [Date] -> Stopwatch -> Battery  -> ACC -> PPT -> SYNC -> Calories/Distance --> RFBSL
  7. // *************************************************************************************************
复制代码
  1. // Line1 - Altitude
  2. const struct menu menu_L1_Altitude = {
  3.     FUNCTION(sx_altitude),            // direct function
  4.     FUNCTION(mx_altitude),            // sub menu function
  5.     FUNCTION(display_altitude),       // display function
  6.     FUNCTION(update_time),            // new display data
  7.     &menu_L1_Speed,           //&menu_L1_Heartrate,如此修改就可以"屏蔽"Heart rate菜单
复制代码
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

15
 
在wakeup_event()中根据不同的事件置了不同的标志位,挂接对应的函数,
在process_requesets()中根据不同的标志位做不同的处理。
此函数调用底层的驱动接口,所以看起来比较简单明了。
  1. // *************************************************************************************************
  2. // @fn          process_requests
  3. // @brief       Process requested actions outside ISR context.
  4. // @param       none
  5. // @return      none
  6. // *************************************************************************************************
  7. void process_requests(void)
  8. {
  9.     // Do temperature measurement
  10. //温度测量
  11.     if (request.flag.temperature_measurement)
  12.         temperature_measurement(FILTER_ON);

  13.     // Do pressure measurement
  14. //压力测量
  15.     if (request.flag.altitude_measurement)
  16.         do_altitude_measurement(FILTER_ON);

  17.     // Do acceleration measurement
  18. //加速度测量
  19.     if (request.flag.acceleration_measurement)
  20.         do_acceleration_measurement();

  21.     // Do voltage measurement
  22. /电池电压测量
  23.     if (request.flag.voltage_measurement)
  24.         battery_measurement();

  25.     // Generate alarm (two signals every second)
  26. //蜂鸣器鸣叫
  27.     if (request.flag.buzzer)
  28.         start_buzzer(2, BUZZER_ON_TICKS, BUZZER_OFF_TICKS);

  29.     // Reset request flag
  30. //处理完对应的事件后,清除标志位
  31.     request.all_flags = 0;
  32. }
复制代码
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

16
 
下面这个函数的功能很简单,就是根据对应的显示标志位,刷新LCD
  1. // *************************************************************************************************
  2. // @fn          display_update
  3. // @brief       Process display flags and call LCD update routines.
  4. // @param       none
  5. // @return      none
  6. // *************************************************************************************************
  7. void display_update(void)
  8. {
  9.     u8 line;
  10.     u8 string[8];

  11.     // ---------------------------------------------------------------------
  12.     // Call Line1 display function
  13. //调用LINE1显示函数
  14.     if (display.flag.full_update || display.flag.line1_full_update)
  15.     {
  16. //清除LINE1显示内容
  17.         clear_line(LINE1);
  18. //更新显示LINE1内容
  19.         fptr_lcd_function_line1(LINE1, DISPLAY_LINE_UPDATE_FULL);
  20.     } else if (ptrMenu_L1->display_update())
  21.     {
  22.         // Update line1 only when new data is available
  23. //仅当有新数据的时候更新LINE1显示
  24.         fptr_lcd_function_line1(LINE1, DISPLAY_LINE_UPDATE_PARTIAL);
  25.     }

  26.     // ---------------------------------------------------------------------
  27.     // If message text should be displayed on Line2, skip normal update
  28. //如果有文本信息需要在LINE2显示
  29.     if (message.flag.show)
  30.     {
  31.         line = LINE2;

  32.         // Select message to display
  33.         if (message.flag.type_locked)
  34.             memcpy(string, "  LO?T", 6);
  35.         else if (message.flag.type_unlocked)
  36.             memcpy(string, "  OPEN", 6);
  37.         else if (message.flag.type_lobatt)
  38.             memcpy(string, "LOBATT", 6);
  39.         else if (message.flag.type_alarm_on)
  40.         {
  41.             memcpy(string, "  ON", 4);
  42.             line = LINE1;
  43.         } else if (message.flag.type_alarm_off)
  44.         {
  45.             memcpy(string, " OFF", 4);
  46.             line = LINE1;
  47.         }
  48.         // Clear previous content
  49.         clear_line(line);
  50.         fptr_lcd_function_line2(line, DISPLAY_LINE_CLEAR);

  51.         if (line == LINE2)
  52.             display_chars(LCD_SEG_L2_5_0, string, SEG_ON);
  53.         else
  54.             display_chars(LCD_SEG_L1_3_0, string, SEG_ON);

  55.         // Next second tick erases message and repaints original screen content
  56. //下一个tick清除文本信息,重新显示原始信息
  57.         message.all_flags = 0;
  58.         message.flag.erase = 1;
  59.     }
  60.     // ---------------------------------------------------------------------
  61.     // Call Line2 display function
  62. //LINE2显示更新
  63.     else if (display.flag.full_update || display.flag.line2_full_update)
  64.     {
  65.         clear_line(LINE2);
  66.         fptr_lcd_function_line2(LINE2, DISPLAY_LINE_UPDATE_FULL);
  67.     } else if (ptrMenu_L2->display_update() && !message.all_flags)
  68.     {
  69.         // Update line2 only when new data is available
  70.         fptr_lcd_function_line2(LINE2, DISPLAY_LINE_UPDATE_PARTIAL);
  71.     }
  72.     // ---------------------------------------------------------------------
  73.     // Restore blinking icons (blinking memory is cleared when calling set_value)
  74.     if (display.flag.full_update)
  75.     {
  76.         if (is_bluerobin() == BLUEROBIN_CONNECTED)
  77.         {
  78.             // Turn on beeper icon to show activity
  79.             display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_OFF);
  80.             display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_OFF);
  81.             display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_OFF);
  82.         }
  83.     }
  84.     // Clear display flag
  85.     display.all_flags = 0;
  86. }
复制代码
 
 
 

回复

26

帖子

0

TA的资源

一粒金砂(中级)

17
 
楼主能不能再分享一次完整的手表代码啊?德仪那个网页已经不能打开了,刚收的这个表
谢谢了!
 
 
 

回复

211

帖子

13

TA的资源

一粒金砂(高级)

18
 
LZ辛苦了~~
 
个人签名You have to do everything you can.You have to work your hardest.And if you do,if you stay positive,the you have a shot at a sliver lining.
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

19
 
john0517 发表于 2014-1-18 22:11
楼主能不能再分享一次完整的手表代码啊?德仪那个网页已经不能打开了,刚收的这个表
谢谢了!

Software Projects.rar (8.6 MB, 下载次数: 69)
 
 
 

回复

1944

帖子

32

TA的资源

纯净的硅(高级)

20
 
john0517 发表于 2014-1-18 22:11
楼主能不能再分享一次完整的手表代码啊?德仪那个网页已经不能打开了,刚收的这个表
谢谢了!

Documentation.rar (11.79 MB, 下载次数: 55, 售价: 1 分芯积分)
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表