STM32,从字面上来理解,ST 是意法半导体,M 是 Microelectronics 的缩写,32 表示32 位,合起来理解,STM32 就是指 ST 公司开发的 32 位微控制器。在如今的 32 位控制器当中,STM32 可以说是最璀璨的新星,它受宠若娇,大受工程师和市场的青睐,无芯能出其右。
STM32 属于一个微控制器,自带了各种常用通信接口,比如 USART、I2C、SPI 等,可连接非常多的传感器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有 STM32 的身影,比如智能手环,微型四轴飞行器,平衡车、移动 POST 机,智能电饭锅,3D 打印机等等。
STM32 有很多系列,可以满足市场的各种需求,从内核上分有 Cortex-M0、M3、M4和 M7 这几种,每个内核又大致分为主流、高性能和低功耗。
单纯从学习的角度出发,可以选择 F1和 F4,F1代表了基础型,基于 Cortex-M3内核,主频为 72MHZ,F4 代表了高性能,基于 Cortex-M4 内核,主频 180M。本文则选择的F1下的stm32f103c8t6。
首先需要知道的是,STM32中对于GPIO口的操作,无非就是操作下面的寄存器而已,所谓的标准库也好,HAL库也好,它们都只是对操作寄存器的过程进行了封装,目的是为了减轻你编程时的工作负担。因此对于寄存器的描述,你只要稍微了解一下,大概知道每个寄存器是干啥的,有哪些位,是如何配置的就行,除了一些你觉得需要留意的地方,其它的完全没有必要完全记住,用的时候知道在哪里查就行了。
两个32位的配置寄存器:GPIOx_CRL、GPIOx_CRH
两个32位数据寄存器:GPIOx_IDR、GPIOx_ODR
一个32位的置位/复位寄存器:GPIOx_BSRR
一个16位复位寄存器:GPIOx_BRR
一个32位锁定寄存器:GPIOx_LCKR
注:具体的寄存器描述可以参考《STM32F10x-中文参考手册》的GPIO章节的P113页。强烈建议先花几分钟先看一下这一部分的内容。
GPIO地址
时钟地址
初始化地址以及GPIO偏移量
GPIO口有八种模式:
1.输入浮空
2.输入上拉
3.输入下拉
4.模拟输入
5.开漏输出
6.推挽式输出
7.推挽式复用功能
8.开漏复用功能
这里点亮LED灯使用推挽输出。
端口1-7为低,端口8-15为高。每个引脚由四个位控制。
以GPIOA和0号引脚(A0)为例,将其设置为推挽输出,并设置最大速度为10MHz,则将控制A0的四个位设置为0001。同理从上图可以得到另外两个的设置。
对于GPIOA的A0、GPIOC的C15、GPIOB的B9,初始化设置如下:
#define GPIOB_CRH (*(unsigned int *)0x40010C04) #define GPIOC_CRH (*(unsigned int *)0x40011004) #define GPIOA_CRL (*(unsigned int *)0x40010800) // 配置 GPIO 口为推免输出 // GPIOB----最后四位为0001 GPIOB_CRH |= (1<<4); // 最后一位变1 GPIOB_CRH &= ~(0xE<<0); // 倒数2、3、4位变0 // GPIOC----前四位为0001 GPIOC_CRH |= (1<<28); // 第四位变1 GPIOC_CRH &= ~(0xE0000000); // 前三位变0 // GPIOA----最后四位为0001 GPIOA_CRL |= (1<<0); // 最后一位变1 GPIOA_CRL &= ~(0xE<<0); // 倒数2、3、4位变0
输出高电平则为1,低电平则为0。
对于GPIOB的B9、GPIOC的C15、GPIOA的A0,设置如下:
#define GPIOB_ODR (*(unsigned int *)0x40010C0C) #define GPIOC_ODR (*(unsigned int *)0x4001100C) #define GPIOA_ODR (*(unsigned int *)0x4001080C) GPIOB_ODR &= ~(1<<9); //最后一位变为0 GPIOC_ODR &= ~(1<<15); //倒数16位变为0 GPIOA_ODR &= ~(1<<0); //最后一位变为
点击Project
下的New uVision Project
,并输入文件名LED
:
选择芯片(这里我用的是STM32F103C8T6
):
添加文件main.c
:
将启动文件从下载的代码包中粘贴到该工程目录下:
(下载地址:野火资料下载中心)
将启动文件导入:
点击魔法棒设置生成HEX文件(后面烧录需要!):
代码:
#define GPIOB_BASE 0x40010C00 #define GPIOC_BASE 0x40011000 #define GPIOA_BASE 0x40010800 #define RCC_APB2ENR (*(unsigned int *)0x40021018) #define GPIOB_CRH (*(unsigned int *)0x40010C04) #define GPIOC_CRH (*(unsigned int *)0x40011004) #define GPIOA_CRL (*(unsigned int *)0x40010800) #define GPIOB_ODR (*(unsigned int *)0x40010C0C) #define GPIOC_ODR (*(unsigned int *)0x4001100C) #define GPIOA_ODR (*(unsigned int *)0x4001080C) void SystemInit(void); void Delay_ms(volatile unsigned int); void Delay_ms( volatile unsigned int t) { unsigned int i; while(t--) for (i=0;i<800;i++); } int main(){ // ???? RCC_APB2ENR |= (1<<3); // ?? GPIOB ?? RCC_APB2ENR |= (1<<4); // ?? GPIOC ?? RCC_APB2ENR |= (1<<2); // ?? GPIOA ?? // ?? GPIO ????? // ?? GPIOB ???? 0001 (B9) GPIOB_CRH|=(1<<4); //??????? GPIOB_CRH&= ~(0xE0000000); //??? ?? // ?? GPIOC ???? 0001 (C15) GPIOC_CRH |= (1<<28); // ??????1 GPIOC_CRH &= ~(0xE0000000); // ??????0 // ?? GPIOA ????? 0001 (A0) GPIOA_CRL |= (1<<0); // ???????1 GPIOA_CRL &= ~(0xE0000000); // ???????????0 // 3?LED??????(????) GPIOB_ODR |= (1<<9); // ???9????1 GPIOC_ODR |= (1<<15); // ???15????1 GPIOA_ODR |= (1<<0); // ???????1 while(1){ GPIOB_ODR &= ~(1<<9); // ??1 Delay_ms(1000000); GPIOB_ODR |= (1<<9); // ??1 Delay_ms(1000000); GPIOC_ODR &= ~(1<<15); // ??2 Delay_ms(1000000); GPIOC_ODR |= (1<<15); // ??2 Delay_ms(1000000); GPIOA_ODR &= ~(1<<0); // ??3 Delay_ms(1000000); GPIOA_ODR |= (1<<0); // ??3 Delay_ms(1000000); } } void SystemInit(){ }
将代码写到main.c文件中之后,build一下生成hex文件
对于USB转TTL模块和STM32F103C8T6连接:
连接到电脑,打开FlyMcu,上传HEX文件到STM32F103C8T6上:
烧录到单片机后得到如下效果:
运行结果
代码:
Stack_Size EQU 0x00000400;???? AREA STACK, NOINIT, READWRITE, ALIGN=3 ;NOINIT: = NO Init,?????READWRITE : ??,???ALIGN =3 : 2^3 ??,?8????? Stack_Mem SPACE Stack_Size __initial_sp AREA RESET, DATA, READONLY __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler AREA |.text|, CODE, READONLY THUMB REQUIRE8 PRESERVE8 ENTRY Reset_Handler bl LED_Init;bl:??????????????????,????(PC)?????LR??? MainLoop BL LED_ON_B BL Delay BL LED_OFF_B BL Delay BL LED_ON_C BL Delay BL LED_OFF_C BL Delay BL LED_ON_A BL Delay BL LED_OFF_A BL Delay B MainLoop;B:?????? LED_Init;LED??? PUSH {R0,R1, LR};R0,R1,LR??????? ;???? LDR R0,=0x40021018;LDR???????????(??R0)? ORR R0,R0,#0x1c LDR R1,=0x40021018 STR R0,[R1] ;???GPIOA_CRL LDR R0,=0x40010800 BIC R0,R0,#0x0fffffff;BIC ???????,???? LDR R1,=0x40010800 STR R0,[R1] LDR R0,=0x40010800 ORR R0,#0x00000001 LDR R1,=0x40010800 STR R0,[R1] ;?PA0?1 MOV R0,#0x01 LDR R1,=0x4001080C STR R0,[R1] ;???GPIOB_CRL LDR R0,=0x40010C04 BIC R0,R0,#0xffffff0f;BIC ???????,???? LDR R1,=0x40010C04 STR R0,[R1] LDR R0,=0x40010C04 ORR R0,#0x00000020 LDR R1,=0x40010C04 STR R0,[R1] ;?PB0?1 MOV R0,#0x200 LDR R1,=0x40010C0C STR R0,[R1] ;???GPIOC LDR R0,=0x40011004 BIC R0,R0,#0x0fffffff LDR R1,=0x40011004 STR R0,[R1] LDR R0,=0x40011004 ORR R0,#0x20000000 LDR R1,=0x40011004 STR R0,[R1] ;?PC15?1 MOV R0,#0x8000 LDR R1,=0x4001100C STR R0,[R1] POP {R0,R1,PC};???????R0,R1,LR?????R0,R1,PC LED_ON_A PUSH {R0,R1, LR} MOV R0,#0x00 LDR R1,=0x4001080C STR R0,[R1] POP {R0,R1,PC} LED_OFF_A PUSH {R0,R1, LR} MOV R0,#0x01 LDR R1,=0x4001080C STR R0,[R1] POP {R0,R1,PC} LED_ON_B;?? PUSH {R0,R1, LR} MOV R0,#0x000 LDR R1,=0x40010C0C STR R0,[R1] POP {R0,R1,PC} LED_OFF_B;?? PUSH {R0,R1, LR} MOV R0,#0x200 LDR R1,=0x40010C0C STR R0,[R1] POP {R0,R1,PC} LED_ON_C;?? PUSH {R0,R1, LR} MOV R0,#0x0000 LDR R1,=0x4001100C STR R0,[R1] POP {R0,R1,PC} LED_OFF_C;?? PUSH {R0,R1, LR} MOV R0,#0x8000 LDR R1,=0x4001100C STR R0,[R1] POP {R0,R1,PC} Delay PUSH {R0,R1, LR} MOVS R0,#0 MOVS R1,#0 MOVS R2,#0 DelayLoop0 ADDS R0,R0,#1 CMP R0,#330 BCC DelayLoop0 MOVS R0,#0 ADDS R1,R1,#1 CMP R1,#330 BCC DelayLoop0 MOVS R0,#0 MOVS R1,#0 ADDS R2,R2,#1 CMP R2,#15 BCC DelayLoop0 POP {R0,R1,PC} NOP END
建立工程步骤与C语言一致,只是新建文件的时候需要选择.s类型。然后重复操作就可以得到一样的结果了。
本次实验点亮LED就像每个编程语言的入门程序HELLO WORLD一般,是嵌入式编程最基础的东西。通过本次实验了解到了关于GPIO寄存器的相关操作,相信本次实验在接下来的实验中会奠定很重要的基础。
STM32 F103之点亮LED流水灯 (STM32入门学习)
二、STM32的GPIO输出操作
【STM32】GPIO的相关配置寄存器、库函数、位操作(实例:STM32控制跑马灯)
野火产品资料下载中心