使用MCC一段时间了,总的感觉还是相当不错的,但这款软件也有着很显著的缺点,帮助系统非常不完善,几乎完全靠摸索,尤其对于MCC生成框架代码后如何使用,很少资料参考。
本文通过由MCC配置Timer0,采用中断方式实现Curiority Nano开发板板载LED闪烁功能的完整过程介绍,希望能对广大初学者有所帮助。
新建基于开发板芯片PIC18F47Q10的工程项目,起名Timer0ISR_Blink,具体的过程请参考“”【Curiosity Nano测评报告】 外部引脚重定位之初体验(一)。
单击MCC按钮,缺省保存后开始配置。首先在“System Module”选择内部时钟,4MHz,Clock Divider选择1,看门狗选择关闭,低电压编程允许。
从Device Resource面板,添加Timer0模块。
在Timer0配置面板中,首先选择时钟源为之前设定的HFINTOSC,这里顺便说一句,新的Timer0和我们过去熟悉的那个古老的Timer0不太一样了,可以工作在8位和16位两种模式,我们为了怀旧,还是用一下8位模式。
另一个不同是现在Timer0有了前置和后置两个倍频器,当选择不同的倍频时,系统会自动计算出能够实现的定时范围,显示在Timer Period区域,这里我们希望LED的闪烁频率为1Hz,所以需要每500ms切换一次量灭状态。经过尝试,我们将前置及后置倍频器都调至最高,范围(2.048~524.288)ms,我们在Request Period输入框中输入期望的500ms,回车后系统自动计算出能够实现的最接近的值,499.712ms,对我们的应用而言,足够了。
勾选Enable Timer, Enable Synchronisation以及Enable Timer Interupt,如上图所示。
接下来我们设置LED输出引脚,通过Curiorisity Nano开发板的电路原理图可以看到,LED与RE0引脚相连
在Pin Manager面板中,将RE0设定为输出:
之后打开Pin Module面板,将RE0设置为单一的输出功能。为了之后编程的方便,此处最好给引脚起一个别名,本项目我们设定别名为“LED”
至此,我们已完成MCC的配置流程,单击Generate,成功后关闭MCC。
打开MCC为我们生成的tmr0.h,请大家注意这里的注解内容,它会简要介绍每个函数的功能和用法示例,当然,由于MCC还在不断的更新,所以可能这部分内容不是特别完善。但个人觉得,参考意义还是很大的。
这里截取一段tmr0.h的内容
void TMR0_SetInterruptHandler(void (* InterruptHandler)(void));
/**
@Summary
Timer Interrupt Handler
@Description
This is a function pointer to the function that will be called during the ISR
@Preconditions
Initialize the TMR0 module with interrupt before calling this isr.
@Param
None
@Returns
None
*/
请大家注意描述部分,这个函数是专门用来设置在中断调用中执行的用户函数的。如果感觉很困惑,看一下tmr0.c中具体的中断执行代码,可能就清楚多了。红色部分的含义是,如果TMR0_InterruptHandler不为空,就执行这一函数。而之后的TMR0_SetInterruptHandler的功能,就是把输入的InterruptHandler函数指针,赋给TMR0_InterruptHandler,所以我们推断,设计一个符合要求的函数,用TMR0_SetInterruptHandler将其置为Handler,则在TMR0中断调用时,该函数就会执行。
void TMR0_ISR(void)
{
// clear the TMR0 interrupt flag
PIR0bits.TMR0IF = 0;
if(TMR0_InterruptHandler)
{
TMR0_InterruptHandler();
}
// add your TMR0 interrupt custom code
}
void TMR0_SetInterruptHandler(void (* InterruptHandler)(void)){
TMR0_InterruptHandler = InterruptHandler;
}
初学者可能觉得很绕,为什么不直接在TMR0_ISR中断函数内直接编写需要的功能呢,这一圈绕的。开始笔者也有同样的困惑,而且也想当然的采用了自以为更正确简单的方式处理,结果就带来很多问题。
下面填一下个人总结的经验、理解,可能不完全正确,仅供参考。经过一段时间的时间,对MCC的设计思想有了一定的理解,MCC是用来生成函数调用框架的,它生成的东西,只能用,不能改!
个人对这种限制的理解是这样的,我们在开发过程中,会经常反复修改MCC实现的功能,这样当MCC重新生成对应框架代码时,就不能和用户编写的程序很好的协调。所以,对MCC生成的框架,我们只能在主程序或者另外的子模块中调用,而绝不要在原始文件里修改。
观察tmr0.h中TMR0_InterruptHandler的定义,
extern void (*TMR0_InterruptHandler)(void);
根据功能要求,这个中断函数应该使LED的状态实现翻转,查阅MCC生成的pin_manager.h,我们找到了需要的函数LED_Toggle()
我们在主程序main.c中,#include之后,定义如下函数
void My_Timer0ISR(void){
LED_Toggle();
}
之后在main.c中,在SYSTEM_Initialize之后,调用 TMR0_SetInterruptHandler(My_Timer0ISR),然后将全局中断允许之前的注释取消,就完成了所有代码的创建。
完整的main.c程序代码如下:
#include "mcc_generated_files/mcc.h"
void My_Timer0ISR(void){
LED_Toggle();
}
/*
Main application
*/
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
TMR0_SetInterruptHandler(My_Timer0ISR);
// If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
// If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts
// Use the following macros to:
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Enable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptEnable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
while (1)
{
// Add your application code
}
}
编译运行后,Curiorisity Nano板载的LED正常闪烁。
|