就到9月16日, 三款TI eStore最热销产品2折起, 库存有限, 立刻行动!
|
希望可以有更多的产品加入到促销
ti的网站打不开啊
最近网站好像又打不开了!
【晒心得】+ TI EZ430-CHRONOS-433 无线手表代码解析
作者EEWORLD网友 azhiking
开个帖子,共同学习EZ430。使用了一下EZ430-CHRONOS ,感觉挺酷的
!不过也遇到这样那样的问题,看到坛子上不少大神都遇到了,所以我不是最幸运的,哈哈。所以先研究研究代码,想随后重新定制一下功能。因为很多配件要么压根没有,要么很贵,就像心律测试的,没有433MHz的,而且好几十美刀,消费不起啊。直接把这些个
功能去了,以后改成别的用途!看得到,用不到,闹心!
以前没有接触过MSP430,所以估计有很多不妥当的地方,欢迎各位拍拍砖(别砸死我就行了
)。另外也希望大家多多支持,增加点学习的信心,多点动力
代码分析,我想按照代码的执行路径,一步一步解析,有其他的引用,通过注释或者在后面的跟贴中解析。
EZ430-CHEONOS的相关文档也上传上来了,方便大家下载。
代码下载地址: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的传感器。
啰嗦了这么多,下面开始代码分析。(一天写一点
)
- // *************************************************************************************************
- // @fn main
- // @brief Main routine
- // @param none
- // @return none
- // *************************************************************************************************
- int main(void)
- {
- // Init MCU
- //初始化MCU,里面做的工作主要有配置MCU电源时钟,使能IO中断,复位关闭无线发射,初始化加速度传感器、LCD、按键、定时器、压力传感器
- init_application();
- // Assign initial value to global variables
- //初始化全局变量: 初始化菜单,复位各标志位,读取校正因子,复位时钟、日期、闹钟、蜂鸣器、跑表、高度计、加速度、协议栈、温度、电池电压等
- //如果你不想每次复位后手表都显示4:30,可以将初始化的初值改称你希望的值
,包括日期。
- init_global_variables();
- // Branch to welcome screen
- //测试模式,持续按住*和up键进入测试模式,按其他键退出。测试模式显示LCD上所有的字段,关闭看门狗。
- test_mode();
- // Main control loop: wait in low power mode until some event needs to be processed
- //主循环:无事件触发的时候,进入LPM3模式
- while (1)
- {
- // When idle go to LPM3
- //系统空闲进入LPM3模式
- idle_loop();
- // Process wake-up events
- //处理唤醒事件
- //button结构体中标志位包括手表上的五个按键——长按或短按标志位,这个结构体定义在ports.h中
-
// Set of button flags
- typedef union
- {
- struct
- {
- // Manual button events
- u16 star : 1; // Short STAR button press
- u16 num : 1; // Short NUM button press
- u16 up : 1; // Short UP button press
- u16 down : 1; // Short DOWN button press
- u16 backlight : 1; // Short BACKLIGHT button press
- u16 star_long : 1; // Long STAR button press
- u16 num_long : 1; // Long NUM button press
- u16 star_not_long : 1; // Between short and long STAR button press
- u16 num_not_long : 1; // Between short and long NUM button press
- } flag;
- u16 all_flags; // Shortcut to all display flags (for reset)
- } s_button_flags;
//sys结构体中标志位表包括系统中的标志位,结构体定义在project.h中
- // Set of system flags
- typedef union
- {
- struct
- {
- u16 idle_timeout : 1; // Timeout after inactivity
- u16 idle_timeout_enabled : 1; // When in set mode, timeout after a given period
- u16 lock_buttons : 1; // Lock buttons
- u16 mask_buzzer : 1; // Do not output buzz for next button event
- u16 up_down_repeat_enabled : 1; // While in set_value(), create virtual UP/DOWN button
- // events
- u16 low_battery : 1; // 1 = Battery is low
- u16 use_metric_units : 1; // 1 = Use metric units, 0 = use English units
- u16 delay_over : 1; // 1 = Timer delay over
- } flag;
- u16 all_flags; // Shortcut to all system flags (for reset)
- } 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();
}
}
上一贴子中Button和sys描述有误,都是联合体,由于帖子审核后不能编辑,只能在这里重新说明一下了。
说道这里,顺便提一下位域的概念。
我们看到联合体中定义了flag的结构体,每个成员后都有一个“:”加上一个数字1。如紫色标注部分。
- typedef union
- {
- struct
- {
- // Manual button events
- u16 star : 1; // Short STAR button press
- u16 num : 1; // Short NUM button press
- u16 up : 1; // Short UP button press
- u16 down : 1; // Short DOWN button press
- u16 backlight : 1; // Short BACKLIGHT button press
- u16 star_long : 1; // Long STAR button press
- u16 num_long : 1; // Long NUM button press
- u16 star_not_long : 1; // Between short and long STAR button press
- u16 num_not_long : 1; // Between short and long NUM button press
- } flag;
- u16 all_flags; // Shortcut to all display flags (for reset)
- } s_button_flags;
至于原因和作用(以前也没有注意过,
从来么有用过MSP430,一看才发现头文件中很多都是这样定义的),参考了一下度娘,下面摘录了部分内容
/*以下内容摘自"度娘"*/
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0
和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按
域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
struct 位域结构名
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度
带有'位域'的结构体并不是按照每个域对齐的,而是将一些位域成员'捆绑'在一起做对齐的。
1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
/*摘录部分结束*/
flag中定义了9个U16类型的成员,9个成员所占位域空间之和9bit>8bit(1byte),所以占2个字节的空间
这样一来,这个联合体只占2个字节的空间,节省了很多存储空间。
联合体中成员的英文注释已经比较明了啦,这里就不再翻译啦。
下面开始解析函数init_application();
- // *************************************************************************************************
- // @fn init_application
- // @brief Initialize the microcontroller.
- // @param none
- // @return none
- // *************************************************************************************************
- void init_application(void)
- {
- volatile unsigned char *ptr;
- // ---------------------------------------------------------------------
- // Enable watchdog
- //使能看门狗
- // Watchdog triggers after 16 seconds when not cleared
- //16s位清除看门狗触发复位操作
- #ifdef USE_WATCHDOG
- //通过WDTCTL寄存器,看门狗模块可以配置为看门狗功能或者内部定时器功能。WDTCTL是一个16位的带密码保护的可读写寄存器,
- //读写操作必须使用字指令,写操作必须在高位字节包含写密码,0x5A。这里宏WDRPW定义为写密码0x5A00。
- //WDTIS为时钟间隔选择,一共有8种时钟间隔可供选择。
- //WDTSSEL为时钟源选择:SMCLK、ACLK、VLOCLK、X_CLK
- //WDRHOLD为1时停止看门狗定时器
- WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK;
- #else
- WDTCTL = WDTPW + WDTHOLD;
- #endif
- // ---------------------------------------------------------------------
- // Configure PMM
- //提升核心供电电压
- SetVCore(3);
- // Set global high power request enable
- //0xA5为电源管理模块寄存器写操作密码
- //开启PMM的高能量消耗允许
- PMMCTL0_H = 0xA5;
- PMMCTL0_L |= PMMHPMRE;
- //写入除0x5A外设和数字,锁定PMM寄存器写操作
- PMMCTL0_H = 0x00;
- //UCS包括5个时钟源
-
//XT1CLK:低频/高频晶振,可以用低频32768Hz手表晶振、标准晶振、陶瓷振荡器、或范围4MHz-32MHz的外部时钟源。
接上篇
参考电路
统一时钟系统模块包含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
// ---------------------------------------------------------------------
// Enable 32kHz ACLK
P5SEL |= 0x03; // Select XIN, XOUT on P5.0 and P5.1
UCSCTL6 &= ~XT1OFF; // XT1 On, Highest drive strength
UCSCTL6 |= XCAP_3; // Internal load cap
UCSCTL3 = SELA__XT1CLK; // Select XT1 as FLL reference
UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKdiv | SELM__DCOCLKdiv;
// ---------------------------------------------------------------------
// Configure CPU clock for 12MHz
_BIS_SR(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_5; // Select suitable range
UCSCTL2 = FLLD_1 + 0x16E; // Set DCO Multiplier
_BIC_SR(SCG0); // Enable the FLL control loop
// Worst-case settling time for the DCO when the DCO range bits have been
// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
// UG for optimization.
// 32 x 32 x 12 MHz / 32,768 Hz = 375000 = MCLK cycles for DCO to settle
__delay_cycles(375000);
// Loop until XT1 & DCO stabilizes, use do-while to insure that
// body is executed at least once
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG);
SFRIFG1 &= ~OFIFG; // Clear fault flags
}
while ((SFRIFG1 & OFIFG));
// -----------------------------------------