最近买了一个现成的STM32F429 Discovery 的开发板,想尝试一下较大点的嵌入式操作系统如RTEMS的移植与应用。因为有了STM32F103/107的基础,熟悉了硬件与固件库,STM32F429其实很容易入手。下面就先定时器中断点个LED试下吧,主要是要组织好工程目录。
我是根据之前一直使用STM32F103的工程目录改了一下,使用STM32F4XX的最新固件库V1.6.1,至于为何不去直接操作寄存器,我想,虽然自己是硬件出身,搞寄存器更深入的了解处理器,但是,毕竟寄存器过多,有了库,可以封装一下,这样更可以快速的上手。如果需要查看寄存器,也是可以查的。用固件库可以少一些错误,毕竟我们是做应用的,首先要学会使用CPU来实现我们要的功能。
工程目录如下:这里使用最新的Keil MDK V5.17版本的,STM32F4XX的器件库等还需要进一步下载。这里使用的是自带的ST-Link下载程序,当然使用Jlink也是可以的。
STM32F429的系统定时器,原来是系统时钟180MHz的8分频,这个可以看一下STM32F4XX的参考手册,里面时钟RCC部分的框架介绍。我这里为了定时为1S,因此计算了一下。
以下为Tim2.c的主程序。Tim2.h 只是函数声明。
/******************** (C) COPYRIGHT 2016 **************************
* 文件名 :Tim2.c
* 描述 :定时器timer2 测试例程
* 实验平台:STM32F429ZIT6
* 库版本 :V1.6.1
*
* 编写日期:2016-05-02
* 修改日期:
* 作者 :
****************************************************************************/
#include "Tim2.h"
/*
* 函数名:TIM2_NVIC_Configuration
* 描述 :TIM2中断优先级配置
* 输入 :无
* 输出 :无
*/
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*TIM_Period--1000 TIM_Prescaler--(22500-1) -->中断周期为
((1/180000000)*8)*22500*1000=1S 1秒定时器 */
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period=1000; /* 自动重装载寄存器周期的值(计数值) */
/* 累计 TIM_Period个频率后产生一个更新或者中断 */
TIM_TimeBaseStructure.TIM_Prescaler= (22500 - 1); /* 时钟预分频数 (180M/8)/22500 */
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; /* 采样分频 */
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上计数模式 */
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); /* 清除溢出中断标志 */
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE); /* 开启时钟 */
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE); /* 先关闭等待使用 */
}
/*
* 函数名:TIM2_Config
* 描述 :TIM2配置
* 输入 :无
* 输出 :无
*/
void TIM2_Config(void)
{
TIM2_Configuration();
TIM2_NVIC_Configuration();
}
/******************* (C) COPYRIGHT 2016 *END OF FILE************/
/******************** (C) COPYRIGHT 2014 ***************************
* 文件名 :led.c
* 描述 :led 应用函数库
* 实验平台:
* 硬件连接:-----------------------
* | PG14 - LED1(RUN) |
* -----------------------
* 库版本 :ST3.5.0
* 编写日期:2014-11-04
* 修改日期:
* 作者 :
****************************************************************************/
#include "led.h"
/*
* 函数名:LED_GPIO_Config
* 描述 :配置LED用到的I/O口
* 输入 :无
* 输出 :无
*/
void LED_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启 LED1 的GPIOx的外设时钟*/
RCC_AHB1PeriphClockCmd( RCC_LED1, ENABLE);
/*选择要控制的LED1 GPIOx引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_LED1;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
/* 设置为推挽输出模式 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/* 设置为上拉 */
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;
/*调用库函数,初始化LED1 的GPIOx*/
GPIO_Init(GPIO_LED1_PORT, &GPIO_InitStructure);
/*开启 LED2 的GPIOx的外设时钟*/
RCC_AHB1PeriphClockCmd( RCC_LED2, ENABLE);
/*选择要控制的LED2 GPIOx引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_LED2;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
/* 设置为推挽输出模式 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/* 设置为上拉 */
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;
/*调用库函数,初始化LED1 的GPIOx*/
GPIO_Init(GPIO_LED2_PORT, &GPIO_InitStructure);
/* 关闭LED1 */
//GPIO_ResetBits(GPIO_LED1_PORT, GPIO_Pin_LED1);
//GPIO_ResetBits(GPIO_LED2_PORT, GPIO_Pin_LED2);
}
/******************* (C) COPYRIGHT 2014 *****END OF FILE************/
以下为LED的引脚定义:led.h
/******************** (C) COPYRIGHT 2014 ***************************
* 文件名 :led.h
* 描述 :led 应用函数库
* 实验平台:
* 硬件连接:-----------------------
* | PG14 - LED1(RUN) |
* -----------------------
* 库版本 :V1.6.1
* 编写日期:2016-04-30
* 修改日期:
* 作者 :
****************************************************************************/
#ifndef __LED_H
#define __LED_H
#include "stm32f4xx.h"
/* the macro definition to trigger the led on or off
* 1 - off
- 0 - on
*/
#define ON 1
#define OFF 0
#define RCC_LED1 RCC_AHB1Periph_GPIOG
#define GPIO_LED1_PORT GPIOG
#define GPIO_Pin_LED1 GPIO_Pin_13
#define RCC_LED2 RCC_AHB1Periph_GPIOG
#define GPIO_LED2_PORT GPIOG
#define GPIO_Pin_LED2 GPIO_Pin_14
//带参宏,可以像内联函数一样使用
#define LED1(a) if (a) \
GPIO_SetBits(GPIO_LED1_PORT,GPIO_Pin_LED1);\
else \
GPIO_ResetBits(GPIO_LED1_PORT,GPIO_Pin_LED1)
#define LED2(a) if (a) \
GPIO_SetBits(GPIO_LED2_PORT,GPIO_Pin_LED2);\
else \
GPIO_ResetBits(GPIO_LED2_PORT,GPIO_Pin_LED2)
void LED_GPIO_Config(void);
#endif /* __LED_H */
主程序:硬件的初始化。
/******************** (C) COPYRIGHT 2016 **************************
* 文件名 :main.c
* 描述 :STM32F429 LED测试
* 实验平台: STM32F429ZIT6
* 库版本 :V1.6.1
* 编写日期:2016-05-02
* 修改日期:
* 作者 :
**********************************************************************************/
#include "stm32f4xx.h"
//#include "usart1.h"
#include "led.h"
#include "Tim2.h"
void Delay(__IO uint32_t nTime)
{
while(--nTime != 0);
}
/*
* 函数名:main
* 描述 : "主机"的主函数
* 输入 :无
* 输出 : 无
*/
int main(void)
{
LED_GPIO_Config();
TIM2_Config();
LED1(ON);
LED2(ON);
while(1)
{
#if 0
Delay(0x2FFFFF);
LED1(OFF);
LED2(OFF);
Delay(0x2FFFFF);
LED1(ON);
LED2(ON);
#endif
}
}
/******************* (C) COPYRIGHT 2014 *****END OF FILE************/
以下为真正的实现函数:定时器2中断函数 stm32f4xx_it.c
/**
* @brief This function handles TIM2 Handler.
* @param None
* @retval None
*/
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
GPIO_WriteBit(GPIO_LED1_PORT,GPIO_Pin_LED1,
(BitAction)(1-GPIO_ReadOutputDataBit(GPIO_LED1_PORT,GPIO_Pin_LED1)));
}
}
编译并烧写,基本上可以看到LED 1S的亮,1S的灭,然后不断的循环下去,一般用于程序的运行指示灯。
重要的总结:
(1)GPIO的时钟,STM32F103的是APB时钟,STM32F429为:RCC_AHB1PeriphClockCmd,我开始弄错了,程序不运行!!
(2)STM32F429虽然180MHz的主频,但是系统定时器的时钟为其的8分频,STM32F103是直接使用的72MHz的主频,因此在计算分频与周期数时,要使用180MHz/8 的定时器基本时钟去计算。
Keil MDK 5.17的工程下载:点击打开链接