概述 本文将通过官方提供的芯片驱动库程序,使用KEIL MDK集成开发环境,一步一步来创建一个新的工程模版,实现功能如下:使用外部16MHz晶振时钟源,通过PLL倍频到64MHz频率,然后将系统时钟切换到PLL通道,让MCU工作在64MHz的系统主频时钟上;配置板载LED灯的GPIO端口引脚,使用SysTick定时器结合MultiTimer开源程序库来实现LED灯的电平翻转控制,达到闪烁的效果。
创建模版工程
- 点击菜单栏Project->New uVision Project...
- 在弹出的Create New Project窗口中选择工程文件需要保存的路径、输入工程文件名,然后点击保存
- 在弹出的Select Device fro Target窗口中选择开发板上对应的芯片型号:CW32F030C8,然后点击OK
- 在弹出的Manage Run-Time Environment窗口中暂时不需要配置,直接点击OK进入到下一步
- 此时一个空的MDK工程就创建完成了,接下来进行工程文件添加和配置工程
- 点击工具栏上的Manage Project Items按钮,添加工程文件
- 在弹出的Manage Project Items窗口中的Project Items中,我们可以修改Project Targets名称,在Groups中添加文件分组,在Files中添加对应分组中的源代码,操作完成后点击OK
- 接下来我们继续点击工具栏上的Options for Target按钮,进行工程配置
- 在Target中将Code Generation区域的ARM Compiler选择Use default compiler version5、勾选Use MicroLIB
- 在Output中勾选Create HEX File,这样在我们编译完工程后就可以自动生成HEX烧录文件了
- 在C/C++中,勾选C99 Mode,然后在Include Paths栏添加头文件的包含路径
- 在Debug中选择调试下载器:CMSIS-DAP Debugger
- 在Utilities中保持默认选项设置,然后点击Settings按键,在弹出窗口的Flash Download中勾选Reset and Run,这样我们在通过KEIL下载完程序后,会自动复位芯片然后运行程序,在确认了Programming Algorithm中程序下载算法是对应的之后,点击OK
此时我们完整的KEIL工程就创建、配置完成了,接下来我们需要编写代码,然后编译、下载程序、运行调试了。
创建工程模版有感 - 参考官方的Example创建工程时,在APP Group中我添加了main.c和cw32f030_it.c这两个文件,原官方例程中cw32f030_it.c叫另外一个名字interrupts_cw32f030.c,所以在我重命名之后对文件中的函数进行了整理,这个文件中实现了所有中断的入口函数,具体的实现需要等我们用到的时候再进行编写,但在整理的时候好像缺少了SysTick中断处理函数,看到后面时我明白了。
- 一个工程肯定有基于对应芯片的启动文件startup_cw32f030.s,官方例程中这个文件是存放在IdeSupport这个文件夹下的,有KEIL MDK和IAR EWARM两个版本,所以在创建工程时我将这个文件夹重命名为了Startup,而在KEIL工程中的Startup Group中,除了添加这个启动文件,我还添加了一个system_cw32f030.c文件;system_cw32f030.c文件中有一个SystemInit函数是在启动文件中被调用的,所以我放在了一起;而system_cw32f030.c这个文件官方是存放在Libraries中的src文件夹下。
- 在system_cw32f030.c的SystemInit函数中,并没有对系统时钟做太多的设置,而是保持了芯片上电复位后的时钟配置:芯片默认工作在HSIOSC,6分频的系统时钟下,即8MHz;所以在应用程序设计时,如果需要更快的系统工作频率,需要自行进行配置。在system_cw32f030.c文件中还实现了基于SysTick定时器的delay1ms、delay100us和delay10us这三个精确定时函数,所以在使用到这几个延时函数时,可别再用到SysTick中断功能了哈。
- 在库函数中我们发再多出了一个cw32f030_systick.c文件,其中实现了对SysTick定时器的配置以及中断函数的实现,这个文件的出现刚刚好,可以结合MultiTimer实现简单的时间片任务调度,同时cw32f030_systick.c文件中也提供了一个基于SysTick单位时间的精确延时函数,所以在使用延时函数时需要特别注意,这边的延时函数千万不要和前面的那个延时函数混用。
MultiTimer MultiTimer是一个软件定时器扩展模块,可无限扩展应用所需要的定时器任务,从而取代传统的标志位判断的实现方式,更优雅更便捷的管理程序的时间触发时序。它是一开源的软件代码库:https://github.com/0x1abin/MultiTimer
MultiTimer的使用也特别简单,配合cw32f030_systick.c文件中的GetTick函数,可以给MultiTimer提供系统时间基准;实例化一个定时器对象,设置定时时间和超时回调处理函数,然后启动定时器,然后在主循环里调用定时器后台处理函数就可以啦……具体的实现参考附件中的工程源代码哈。
编写代码 系统时钟配置 void SetSysClock(void)
{
RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE);
RCC_HSE_Enable(RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
RCC_PLL_Enable(RCC_PLLSOURCE_HSEOSC, 16000000, RCC_PLL_MUL_4);
FLASH_SetLatency(FLASH_Latency_3);
RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
SystemCoreClock = 64000000;
}
LED端口控制及闪烁控制 MultiTimer LED_MultiTimer;
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pins = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
MultiTimerStart(&LED_MultiTimer, 250, LED_MultiTimerCallback, "LED Toggle");
}
void LED_MultiTimerCallback(MultiTimer *timer, void *userData)
{
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
MultiTimerStart(&LED_MultiTimer, 250, LED_MultiTimerCallback, "LED Toggle");
}
主程序 int main(void)
{
SetSysClock();
InitTick(SystemCoreClock);
MultiTimerInstall(PlatformTicksFunction);
KEY_Init();
LED_Init();
while(1)
{
MultiTimerYield();
}
}
运行效果
问题反馈 在配置系统工作时钟时,刚开始选用的是HSIOSC,参考例程将其进行2分频率时(RCC_HSIOSC_DIV2),芯片是可以正常启动工作的;当我想提升系统工作频率,将其进行1分频时(RCC_HSIOSC_DIV1),此时芯片反而无法正常启动运行了;刚开始以为是因为FLASH取指周期没有配置正确的原因,参考官方示例程序配置后,芯片还是无法正常启动运行,所以想问一下是HSIOSC是不可以1分频作为SysClk吗?还是我如下的配置不正确? RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE);
RCC_HSI_Enable(RCC_HSIOSC_DIV1);
FLASH_SetLatency(FLASH_Latency_2);
SystemCoreClock = 48000000;
工程源码
|