打印
[CW32F030系列]

【CW32F030CxTx StartKit测评】02.创建模板工程

[复制链接]
1014|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
概述
本文将通过官方提供的芯片驱动库程序,使用KEIL MDK集成开发环境,一步一步来创建一个新的工程模版,实现功能如下:使用外部16MHz晶振时钟源,通过PLL倍频到64MHz频率,然后将系统时钟切换到PLL通道,让MCU工作在64MHz的系统主频时钟上;配置板载LED灯的GPIO端口引脚,使用SysTick定时器结合MultiTimer开源程序库来实现LED灯的电平翻转控制,达到闪烁的效果。


创建模版工程
  • 打开KEIL MDK集成开发环境


  • 点击菜单栏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;


工程源码
Template.zip (4.43 MB)

使用特权

评论回复
沙发
七毛钱| | 2022-7-4 11:50 | 只看该作者
亮灯了亮灯了,恭喜恭喜

使用特权

评论回复
板凳
pssyx| | 2022-7-4 13:46 | 只看该作者
先设置好FLASH存储器读等待周期配置,再HSI分频。交换后的代码如下:
      RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE);
      FLASH_SetLatency(FLASH_Latency_2);
      RCC_HSI_Enable(RCC_HSIOSC_DIV1);
      SystemCoreClock = 48000000;

使用特权

评论回复
地板
molun| | 2022-7-4 15:19 | 只看该作者
学习了

使用特权

评论回复
5
xld0932|  楼主 | 2022-7-4 15:29 | 只看该作者
pssyx 发表于 2022-7-4 13:46
先设置好FLASH存储器读等待周期配置,再HSI分频。交换后的代码如下:
      RCC_AHBPeriphClk_Enable(RCC_A ...

好的,稍后我试一下

使用特权

评论回复
6
xld0932|  楼主 | 2022-7-4 19:26 | 只看该作者
pssyx 发表于 2022-7-4 13:46
先设置好FLASH存储器读等待周期配置,再HSI分频。交换后的代码如下:
      RCC_AHBPeriphClk_Enable(RCC_A ...

正如你说的解决方案,现在正常了……程序如下:
void SetSysClock(void)
{
#if 0
    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;
#else
    RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE);

    FLASH_SetLatency(FLASH_Latency_2);

    RCC_HSI_Enable(RCC_HSIOSC_DIV1);

    SystemCoreClock = 48000000;
#endif
}
然后也对比了一下上面配置64MHz的情况,对FLASH取指周期的设置,也是在将系统时钟切换到PLL之前设置的,所以在配置系统时钟为HSIOSC一分频的时候,也需要先设置FLASH的取指周期,再对时钟进行切换设置……

感谢!

使用特权

评论回复
7
xld0932|  楼主 | 2022-7-4 19:56 | 只看该作者
pssyx 发表于 2022-7-4 13:46
先设置好FLASH存储器读等待周期配置,再HSI分频。交换后的代码如下:
      RCC_AHBPeriphClk_Enable(RCC_A ...

感谢!

使用特权

评论回复
8
xiaoyaodz| | 2022-9-7 20:23 | 只看该作者
这个使用官网的例程吧

使用特权

评论回复
9
suzhanhua| | 2022-9-8 14:23 | 只看该作者
基于iar的有吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

69

主题

2998

帖子

31

粉丝