1 建立工程
根据MDK-RAM建立工程的步骤建立STM32F10_LED新工程。
2 时钟
(1) 时钟信号
时钟信号 (Clock):时钟信号是提供给同步内存做讯号同步之用,同步记忆体的存取动作必需与时钟信号同步(只有时钟信号到来且存储命令同时到来时 才会发生存取动作)。同步是时钟控制系统中的主要制约条件,同步是指在有效信号沿发生时刻,希望写入单元的数据也有效。数据有效则是指数据量比较稳定(不发生改变),并且只有当输入发生变化时数值才会发生变化。由于组合电路无法实现反馈,所以只要输入量不发生变化,输出最后最终会是一个稳定有效的量。
将时钟信号总结为:同步记忆体只有在时钟信号和存取操作同时到来才会发生存取动作,而且一旦操作发生后会稳定保持存取操作过后的状态。直到新的时钟信号和新的操作来改变上一次得到的稳定状态。
(2) STM32系统时钟
系统时钟SYSCLK是供STM32中绝大部分部件工作的时钟源。SYSCLK可由PLL、HSI或者HSE提供输出,并且它通过AHB分频器分频后送给各模块使用。其中AHB分频器输出的时钟送给5大模块使用:
- 送给AHB总线、内核、内存和DMA使用的HCLK时钟。
- 分频后送给STM32芯片的系统定时器时钟。
- 直接送给Cortex的自由运行时钟FCLK。
- 送给APB1分频器。经APB1分频器后的一路输出供APB1外设使用(PCLK1),另一路送给”定时器(Timer)x”倍频器使用。该倍频器选择倍频后的时钟输出供”定时器x”使用。
- 送给APB2分频器。经APB2分频器后的输出一路供APB2外设使用(PCLK2),另一路送给“定时器y”倍频器使用。该倍频器选择倍频后的时钟输出供“定时器y”使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。[x和y的值具体看参考手册]。
Hclk为优秀的高性能总线(AHB bus peripherals)供给时钟信号(AHB为advanced high-performance bus)。Fclk(free running clock)为供给CPU内核的时钟信号,我们所说的cpu主频为XXXXMHz,就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期。Pclk为优秀的高性能外设总线(APBbus peripherals)供给时钟信号(其中APB为advanced peripherals bus)。
3 编写流水灯程序
编写一个流水灯程序的流程为:
- 根据原理图确定流水灯模块与STM32F10XXX芯片的连接关系。
- 根据STM32F10XXX参考手册查看需要配置得相关寄存器。
- 因为流水灯操作的是GPIO,所以需要使能GPIO模块的时钟。
(1) 时钟初始化
时钟初始化是指配置“系统时钟SYSCLK频率”、“HCLK,PCLK时钟的分频值”。
如果工程中只添加了“启动文件”,添加到工程中的“启动文件”会调用”SystemInit()”及”main()”两个函数。那么我们就需要自己编码实现一个“系统文件”中”SystemInit()”功能的函数,且函数名需要为”SystemInit()”(不修改启动文件的话)。”SystemInit()”函数完成一些系统初始化的操作,其中就包含“时钟的初始化”,它被编写在“系统文件” ” system_stm32f10x.c“中。如果用户要自定义实现,按照功能根据参考手册配置时钟相关寄存器即可实现这些功能。
如果工程中连“启动文件”都没有添加,那么我们就需要自己编码实现“启动文件”和“系统文件”的功能。
如果在工程中添加了“启动文件”和“系统文件”,那么我们只要使能各模块时钟后就可以使用对应的时钟了。
(2) 使能GPIO端口时钟
STM32中在使用任何一个外设都必须打开相应的时钟。经“时钟初始化”后,就可以直接使能GPIO时钟了,GPIO属APB2外设使用的是PCLK2( 查看《参考手册》 )。从原理图中看出流水灯模块连接到主控芯片的PORTE之上,见下图:(3) 配置GPIO寄存器设置引脚模式
明确PORTE[0…2]引脚的功能为”输出”。到”STM32F10XXX”参考手册中查看需要操作的寄存器为GPIOE_ CRL,GPIO_BSRR或GPIO_ODR。根据原理图可以看出,当PORTE[0..2]被置低时灯亮。以PORTE[0…2]引脚为对象,根据寄存器的配置需求将“GPIO时钟使能”和“引脚配置的功能”集成在一个函数内: //LED Init void LedInit(void) { //使能PORTE时钟 RCC->APB2ENR = 1 << 6;
//PORTE0~7清0 /设置PORTE[0…2]为输出、最大为10MHZ、通用推免模式 //PORTE[0..7]清0后将PORTE[0…2]拉高,不让灯亮 GPIOE->CRL &= 0x00000000; GPIOE->CRL |= 0x000001 | 0x00000010 | 0x00000100; GPIOE->BSRR &= 0x00000000;// GPIOE->ODR &= 0x00000000; GPIOE->BSRR |= 1 | (1 << 1) | (1 <<2);//GPIOE->ODR |= 1 | (1 << 1)| (1 << 2); } |
(4) 灯闪烁
根据原理图中的电路关系,只要拉低PORTE[0..2]时led就会亮,拉高PORTE[0..2]时led就会灭,而给PORTE[0..2]置高低电平靠配置寄存器来实现。所以,要使led闪烁只需要用逻辑操作对应寄存器即可: //LED blink void LedBlink(void) { //PORTE[0..2]拉低,led[1..3]亮 GPIOE->BSRR |= (1 << 16) | (1 << 17) | (1<< 18); //GPIOE->ODR &= 0 | (0 << 1) | (0 << 2); Delay(0x3FFFFF);
PORTE[0..2]灭 GPIOE->BSRR |= 1 | (1 << 1) | (1 << 2); //GPIOE->ODR |= 1 | (1 << 1) | (1 << 2); Delay(0x3FFFFF); } |
使Led亮和灭的语句可以被替换为注释的语句,其中Delay()延迟函数为:
//Delay void Delay(__IO uint32_t nCount) { while(nCount--) { } } |
(5) 主程序
main()内容如下:
#include <stm32f10x.h> #include <stdio.h>
//函数声明 void Delay(__IO uint32_t nCount); void LedBlink(void); void LedInit(void);
int main(void) { LedInit(); while(1){ LedBlink(); } } |
<stm32f10x.h>为stm32f10xxx系列芯片的头文件,其中定义了时钟、寄存器指针等类型。
(6) 调试运行
如果编译不通过就根据C语言知识和<stm32f10x.h>所规定的数据类型将程序调试正确。如果需要在线调试,就根据MDK-RAM-KEIL J-Link 在线调试进行调试。在keil中LOAD操作,如果没有在Debug中设置下载后就运行程序,则需要将板子重启后程序才会运行程序。
以上程序在吕师兄以STM32F103VC为微控芯片之上的板子的运行结果如下:
Figure2:闪烁的led灯
Practical Note Over.