点个灯先~~~
首先,打开软件,新建工程。点击Flie,选择New,然后点击第一个选项如图。
接下来按照下图中进行选择就OK,这一步主要选择的是芯片或者测试板的型号和类别,以及使用的SDK和IDE工具链,然后点击NEXT。EFM8BB52是一个51内核的单片机,其实只要我们对51单片机熟悉的话,那么玩这个芯片还是比较容易上手的。
点击完NEXT进入到如下界面。可选项有三个,第一个是有基础配置文件的工程,第二个是空工程,类似于我们使用Keil新建的空白工程。第三个则是官方的点灯例程,使用的是Timer定时器中断实现的,我们在做开发的时候,如果自己不想从头开始搭建工程,可以接选定该例程,在这个基础_上进一步做改动即可。为了省事儿,我们选第三个。
再次点击NEXT,进入到给工程命名的界面。我们给工程命名为LED_test如下图,然后点击右下角FINISH就搞定。
展开工程文件列表,可以看到各个文件如下图。其中包括.c以及.h文件,既然要操作LED,我们就直接打开看一看。
首先打开EFM8BB52_Blinky.c文件看看。
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <SI_EFM8BB52_Register_Enums.h>
#include <InitDevice.h>
该文件是主函数所在的文件,加载好相关的头文件。在我们初学51单片机的时候,头文件用的是reg52.h,而这里用的是
SI_EFM8BB52_Register_Enums.h
比较难记,直接复制粘贴就妥了。
第二个头文件InitDevice.h所对应的InitDevice.c函数里,完成的是设备的初始化相关的工作。简单看一下:
//==============================================================================
// enter_DefaultMode_from_RESET
//==============================================================================
extern void enter_DefaultMode_from_RESET(void) {
// $[Config Calls]
// Save the SFRPAGE
uint8_t SFRPAGE_save = SFRPAGE;
WDT_0_enter_DefaultMode_from_RESET();
PORTS_1_enter_DefaultMode_from_RESET();
PBCFG_0_enter_DefaultMode_from_RESET();
TIMER16_2_enter_DefaultMode_from_RESET();
INTERRUPT_0_enter_DefaultMode_from_RESET();
// Restore the SFRPAGE
SFRPAGE = SFRPAGE_save;
// [Config Calls]$
}
主要干的事儿,就是在芯片复位后规定了一些外设的工作模式,或者叫初始化状态。从代码可以看出,其中包括WDT看门狗的,包括P1引脚的,包括WEAKUP和串口1的,包括对定时器的配置和中断的配置等。
看明白之后,我们就可以进一步修改并使用它们做自己的代码了。接下来我们看到main函数,可以看出,主函数中就开了个全局中断,然后停在while(1)死循环,那么灯在哪儿点的呢?不着急,我们看一看Interrupts.c,果不其然,在这里。
//-----------------------------------------------------------------------------
SI_INTERRUPT(TIMER2_ISR, TIMER2_IRQn)
{
TMR2CN0_TF2H = 0; // Clear Timer2 interrupt flag
LED0 = !LED0; // Change state of LED0
}
代码中将定时器2的高位中断溢出标志清零后,开始对LED0进行了电平反转的操作。这个LED0在哪儿被定义的呢?喏,这句代码:
// Global CONSTANTS
//-----------------------------------------------------------------------------
SI_SBIT(LED0, SFR_P1, 4); // P1.4 LED0
这里把P1.4这个IO口,取了个名儿叫做LED0。跟我们STC51单片机稍稍有点区别,其实也没什么,习惯就好。
较为关键的一点就是对timer2定时器的配置了,经过代码分析,我们可以看出,代码中将其设置成了使用默认内部时钟作为系统时钟(49MHz±2%进行12分频得到)的16位的计数模式,其中这两句话就是给定时计数器Timer2装初值
// $[TMR2RLH - Timer 2 Reload High Byte]
/*
// TMR2RLH (Timer 2 Reload High Byte) = 0x38
*/
TMR2RLH = (0x38 << TMR2RLH_TMR2RLH__SHIFT);
// [TMR2RLH - Timer 2 Reload High Byte]$
// $[TMR2RLL - Timer 2 Reload Low Byte]
/*
// TMR2RLL (Timer 2 Reload Low Byte) = 0x9E
*/
TMR2RLL = (0x9E << TMR2RLL_TMR2RLL__SHIFT);
// [TMR2RLL - Timer 2 Reload Low Byte]$
高字节为0x38,低字节为0x9e,经过推理计算(计算器代劳),得知每过将近200ms产生一次中断,也就是说,每秒钟LED灯的亮灭闪烁两次半简单在代码中改一改,让LED每过2s完成一次闪烁周期。
//-----------------------------------------------------------------------------
SI_INTERRUPT(TIMER2_ISR, TIMER2_IRQn)
{
TMR2CN0_TF2H = 0; // Clear Timer2 interrupt flag
LEDCOUNT++;
if(LEDCOUNT == 5)
{
LED0 = !LED0; // Change state of LED0
LEDCOUNT = 0;
}
}
改完之后,点击编译,然后烧写,正常闪烁。
由于时间原因,没有用示波器去进一步验证误差,但是大体上差不太多。
这样一来,我们就搞清楚了定时器的工作方式,接下来我们在这个基础上,进一步去完成智能小夜灯的设计。