打开keil目录找到C:\Keil\ARM\Boards\ST\STM32F0-Discovery\
下面有两个Keil自带的探索板子的示例演示程序,很好玩的。
打开后可以看到包含启动代码和源程序代码以及说明文档
启动代码就当是启动系统必须的部分吧,我们先懒得看他们。
看到SourceFiles感到很亲切,玩51单片机都是这个部分属于我们的。
看第一个示例Blinky,看名字就知道是让LED闪烁的程序。跑马灯等都是这一类程序。
看文件LED.c的代码
/*----------------------------------------------------------------------------
* Name: LED.c
* Purpose: Low level LED functions
* Note(s):
*----------------------------------------------------------------------------
* This file is part of the uVision/ARM development tools.
* This software may only be used under the terms of a valid, current,
* end user licence from KEIL for a compatible version of KEIL software
* development tools. Nothing else gives you the right to use this software.
*
* This software is supplied "AS IS" without warranties of any kind.
*
* Copyright (c) 2012 Keil - An ARM Company. All rights reserved.
*----------------------------------------------------------------------------*/
#include <stm32f0xx.h> /* STM32F0xx Definitions */
#include "LED.h"
const unsigned long led_mask[] = {1UL << 8, 1UL << 9};
/*-----------------------------------------------------------------------------
* LED_Init: Initialize LEDs
*
* Parameters: (none)
* Return: (none)
*----------------------------------------------------------------------------*/
void LED_Init (void) {
/* Enable clock for GPIOC */
RCC->AHBENR |= (1UL << 19);
/* Configure LED (PC.8..9) pins as push-pull outputs */
GPIOC->MODER &= ~((3UL << 2 * 8) | (3UL << 2 * 9));
GPIOC->MODER |= ((1UL << 2 * 8) | (1UL << 2 * 9));
GPIOC->OTYPER &= ~((1UL << 8) | (1UL << 9));
}
/*-----------------------------------------------------------------------------
* LED_On: Turns on requested LED
*
* Parameters: num - LED number
* Return: (none)
*----------------------------------------------------------------------------*/
void LED_On (uint32_t num) {
if (num < LED_NUM) {
GPIOC->BSRR |= (led_mask[num]);
}
}
/*-----------------------------------------------------------------------------
* LED_Off: Turns off requested LED
*
* Parameters: num - LED number
* Return: (none)
*----------------------------------------------------------------------------*/
void LED_Off (uint32_t num) {
if (num < LED_NUM) {
GPIOC->BSRR |= (led_mask[num] << 16);
}
}
/*-----------------------------------------------------------------------------
* LED_Val: Write value to LEDs
*
* Parameters: val - value to be displayed on LEDs
* Return: (none)
*----------------------------------------------------------------------------*/
void LED_Out (uint32_t val) {
int i;
for (i = 0; i < LED_NUM; i++) {
if (val & (1<<i)) {
LED_On (i);
} else {
LED_Off(i);
}
}
}
以上全部是子函数,因为没有主函数main()
而我们的C语言是以main函数为顺序执行的。
看到blinky.c里面含有main,我们以main函数来观察整个工程。
/*----------------------------------------------------------------------------
* Name: Blinky.c
* Purpose: LED Flasher
* Note(s):
*----------------------------------------------------------------------------
* This file is part of the uVision/ARM development tools.
* This software may only be used under the terms of a valid, current,
* end user licence from KEIL for a compatible version of KEIL software
* development tools. Nothing else gives you the right to use this software.
*
* This software is supplied "AS IS" without warranties of any kind.
*
* Copyright (c) 2012 Keil - An ARM Company. All rights reserved.
*----------------------------------------------------------------------------*/
//#include <stdio.h>
#include "STM32F0xx.h"
#include "LED.h"
volatile uint32_t msTicks; /* counts 1ms timeTicks */
/*----------------------------------------------------------------------------
SysTick_Handler
*----------------------------------------------------------------------------*/
void SysTick_Handler(void) {
msTicks++;
}
/*----------------------------------------------------------------------------
delays number of tick Systicks (happens every 1 ms)
*----------------------------------------------------------------------------*/
void Delay (uint32_t dlyTicks) {
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
/*----------------------------------------------------------------------------
Function that initializes Button pins
*----------------------------------------------------------------------------*/
void BTN_Init(void) {
RCC->AHBENR |= ((1UL << 17) ); /* Enable GPIOA clock */
GPIOA->MODER &= ~((3UL << 2*0) ); /* PA.0 is input */
GPIOA->OSPEEDR &= ~((3UL << 2*0) ); /* PA.0 is Low Speed */
GPIOA->PUPDR &= ~((3UL << 2*0) ); /* PA.0 is no Pull up */
}
/*----------------------------------------------------------------------------
Function that read Button pins
*----------------------------------------------------------------------------*/
uint32_t BTN_Get(void) {
return (GPIOA->IDR & (1UL << 0));
}
/*----------------------------------------------------------------------------
set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)
*----------------------------------------------------------------------------*/
void SystemCoreClockSetHSI(void) {
RCC->CR |= ((uint32_t)RCC_CR_HSION); /* Enable HSI */
while ((RCC->CR & RCC_CR_HSIRDY) == 0); /* Wait for HSI Ready */
RCC->CFGR = RCC_CFGR_SW_HSI; /* HSI is system clock */
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); /* Wait for HSI used as system clock */
FLASH->ACR = FLASH_ACR_PRFTBE; /* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_LATENCY; /* Flash 1 wait state */
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* HCLK = SYSCLK */
RCC->CFGR |= RCC_CFGR_PPRE_DIV1; /* PCLK = HCLK */
RCC->CR &= ~RCC_CR_PLLON; /* Disable PLL */
/* PLL configuration: = HSI * 12 = 48 MHz */
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
RCC->CFGR |= (RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL12);
RCC->CR |= RCC_CR_PLLON; /* Enable PLL */
while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); /* Wait till PLL is ready */
RCC->CFGR &= ~RCC_CFGR_SW; /* Select PLL as system clock source */
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); /* Wait till PLL is system clock src */
}
/*----------------------------------------------------------------------------
MAIN function
*----------------------------------------------------------------------------*/
int main (void) {
int32_t num = -1;
int32_t dir = 1;
uint32_t btns = 0;
SystemCoreClockSetHSI();
SystemCoreClockUpdate(); /* Get Core Clock Frequency */
if (SysTick_Config(SystemCoreClock / 1000)) { /* SysTick 1 msec interrupts */
while (1); /* Capture error */
}
LED_Init();
BTN_Init();
while(1) { /* Loop forever */
btns = BTN_Get(); /* Read button states */
if (btns != (1UL << 0)) {
/* Calculate 'num': 0,1,...,LED_NUM-1,LED_NUM-1,...,1,0,0,... */
num += dir;
if (num == LED_NUM) { dir = -1; num = LED_NUM-1; }
else if (num < 0) { dir = 1; num = 0; }
LED_On (num);
Delay( 50); /* Delay 50ms */
LED_Off(num);
Delay(450); /* Delay 450ms */
}
else {
LED_Out (0x0F);
Delay(10); /* Delay 10ms */
}
}
}
效果和板子出厂时候自带的一样,因为这就是演示板自带的那个程序。
刚开始调用时钟初始化的子函数,然后检测是否配置正确,不正确了就进入while死循环,什么事情都不干。如果时钟配置好了,就初始化LED,初始化按钮。
接下来进入传说中的工作while死循环,先检测按键状态一下。并对按键进行统计,判断是否有再次按键行为,根据是否有再次按键行为作出两种不同的闪烁方法。 |