STM32入门(一)
学习单片机主要学习单片机的外设部分,主要有GPIO,UART,其他外设在应用中学习。
一、GPIO
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片
的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
STM32芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103VET6型号的
芯片有 GPIOA、GPIOB、GPIOC 至 GPIOE 共 5 组 GPIO,芯片一共 100 个引脚,其中
GPIO就占了一大部分,所有的 GPIO引脚都有基本的输入输出功能。
GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器为 32bit,占四个字节,
在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描
述。这里我们以 GPIOB 端口为例,来说明 GPIO 都有哪些寄存器
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
首先定义了 “片上外设”基地址 PERIPH_BASE,接着在 PERIPH_BASE 上加入各个总线的地址偏移,得到 APB1、APB2 总线的地APB1PERIPH_BASEAPB2PERIPH_BASE,在其之上加入外设地址的偏移,得到 GPIOA-G 的外设地址,最后在外设地址上加入各寄存器的地址偏移,得到特定寄存器的地址。一旦有了具体地址,就可以用指针读写
二、使用寄存器点亮LED灯
1.启动文件
名为“startup_stm32f10x_hd.s”的文件,它里边使用汇编语言写好了基本程序,当STM32 芯片上电启动的时候,首先会执行这里的汇编程序,从而建立起 C 语言的运行环境,所以我们把这个文件称为启动文件。该文件使用的汇编指令是 Cortex-M3 内核支持的指令
2.stm32f10x.h文件
看完启动文件,那我们立即写 SystemInit 和 main 函数吧?别着急,定义好了SystemInit 函数和 main 我们又能写什么内容?连接 LED 灯的 GPIO 引脚,是要通过读写寄存器来控制的,就这样空着手,如何控制寄存器。我们知道寄存器映射就是给一个已经分配好地址的特殊的内存空间取的一个别名,这个特殊的内存空间就是寄存器,它可以通过指针来操作。
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
3.main文件
从分析启动文件时我们知道,Reset_Handler 调用了该函数用来初始化 SMT32 系统时钟,为了简单起见,我们在 main 文件里面定义一个SystemInit 空函数,什么也不做,为的是骗过编译器,把这个错误去掉。关于配置系统时钟我们在后面再写。当我们不配置系统时钟时,STM32 会把 HSI 当作系统时钟,HSI=8M,由芯片内部的振荡器提供。
#include "stm32f10x.h"
int main(void)
{
// 开启GPIOC 端口时钟
RCC_APB2ENR |= (1<<4);
//清空控制PC2的端口位
GPIOC_CRL &= ~( 0x0F<< (4*2));
// 配置PC2为通用推挽输出,速度为10M
GPIOC_CRL |= (1<<4*2);
// PC2 输出 低电平
GPIOC_ODR &= ~(1<<2);
while(1);
}
// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{
}