目录
一、 实验目的
以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED 搭建电路,使用GPIOA、GPIOB、GPIOC这3个端口控制LED灯(最高时钟2Mhz),轮流闪烁,间隔时长1秒。
二、 端口初始化
1.时钟配置
以下内容皆是通过查询stm32官方文档获得,可自行至官网下载对应文档
- 查看存储器映像,找到时钟使能映射基地址。
- 可知时钟使能寄存器偏移地址为0x18
- 时钟使能
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
RCC_APB2ENR|=1<<2|1<<3|1<<4;
说明:0x40021018=基地址+偏移地址=0x40021000+0x18
2.输入输出模式设置
我的3个引脚为A12,B0,C14.
- GPIOX基地址
端口配置低寄存器(GPIOx_CRL) 0-7,端口配置高寄存器(GPIOx_CRH) 8-15
- A12,C14
- B0
- 配置对应引脚基地址
//GPIOA
#define GPIOA_CRH *((unsigned volatile int*)0x40010804)
//GPIOB
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
//GPIOC
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
- 设置输出模式为推挽输出,速率为2Mhz
GPIOA_CRH &= 0xFFF0FFFF; //设置位 清零
GPIOA_CRH |= 0x00020000; //PA12推挽输出,把第19、18、17、16位变为0010
GPIOB_CRL &=0xFFFFFFF0; //设置位 清零
GPIOB_CRL |=0x00000002; //PB0推挽输出,把第3、2、1、0变为0010
GPIOC_CRH &=0xF0FFFFFF; //设置位 清零
GPIOC_CRH |=0x02000000; //PC14推挽输出,把第27、26、25、24变为0010
三、代码编写
- c语言代码
led.h
#ifndef _LED_H
#define _LED_H
//#define LEDO PCout(13)
//时钟使能
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
//GPIOA
#define GPIOA_CRH *((unsigned volatile int*)0x40010804)
#define GPIOA_ODR *((unsigned volatile int*)0x4001080C)
//GPIOB
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
//GPIOC
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
void My_LED_Init(void);//初始化
void Delay();
#endif
led.c
#include "led.h"
#include "stm32f10x.h"
void My_LED_Init(void)
{
RCC_APB2ENR|=1<<2|1<<3|1<<4; //使能
GPIOA_CRH &= 0xFFF0FFFF; //设置位 清零
GPIOA_CRH |= 0x00020000; //PA12推挽输出,把第19、18、17、16位变为0010
GPIOA_ODR &=~(1<<12); //设置初始灯为灭
GPIOB_CRL &=0xFFFFFFF0; //设置位 清零
GPIOB_CRL |=0x00000002; //PB0推挽输出,把第3、2、1、0变为0010
GPIOB_ODR &=~(1<<0); //设置初始灯为灭
GPIOC_CRH &=0xF0FFFFFF; //设置位 清零
GPIOC_CRH |=0x02000000; //PC14推挽输出,把第27、26、25、24变为0010
GPIOC_ODR &=~(1<<14); //设置初始灯为灭
}
void Delay()
{
u32 i=0;
for(;i<5000000;i++);
}
main.c
#include "stm32f10x.h"
#include "led.h"
int main(void)
{
My_LED_Init();
while(1)
{
// GPIO_SetBits(GPIOC,GPIO_Pin_13) ;
//
// delay_ms (1000);
// GPIO_ResetBits(GPIOC,GPIO_Pin_13);
// delay_ms(1000);
//GPIOA
GPIOA_ODR|=1<<12; //PA2高电平
Delay();
GPIOA_ODR&=~(1<<12); //PA2低电平,因为是置0,所以用按位与
//GPIOB
GPIOB_ODR|=1<<0; //PB0高电平
Delay();
GPIOB_ODR&=~(1<<0); //PB0低电平,因为是置0,所以用按位与
//GPIOC
GPIOC_ODR|=1<<14; //PC14高电平
Delay();
GPIOC_ODR&=~(1<<14); //PC14低电平,因为是置0,所以用按位与
}
}
- 汇编代码
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT led
led
;使能A,B,C
ldr r0, =0x40021018
ldr r1, =0x0000001c
str r1, [r0]
;配置端口A12
ldr r0, =0x40010804
ldr r1, [r0]
bic r1, r1, #0x000f0000
orr r1, r1, #0x00010000
str r1, [r0]
;配置端口B0
ldr r0, =0x40010c00
ldr r1, [r0]
bic r1, r1, #0x0000000f
orr r1, r1, #0x00000001
str r1, [r0]
;配置端口C14
ldr r0, =0x40011004
ldr r1, [r0]
bic r1, r1, #0x0f000000
orr r1, r1, #0x01000000
str r1, [r0]
;初始为A12亮灯
ldr r0, =0x4001080c
ldr r1, =0x00000010
str r1, [r0]
ldr r0, =5000000;频率
ldr r1, =0
;循环亮灯
blink
add r1, r1, #1
cmp r1, r0
blt blink
;A12灭
ldr r1, =0x4001080c
ldr r2, [r1]
eor r2, r2, #0x00001000
str r2, [r1]
;B0亮
ldr r1, =0x40010c0c
ldr r2, [r1]
eor r2, r2, #0x00000001
str r2, [r1]
ldr r1, =0
blink1
add r1, r1, #1
cmp r1, r0
blt blink1
;B0灭
ldr r1, =0x40010c0c
ldr r2, [r1]
eor r2, r2, #0x00000010
str r2, [r1]
;C14亮
ldr r1, =0x4001100c
ldr r2, [r1]
eor r2, r2, #0x00004000
str r2, [r1]
ldr r1, =0
blink2
add r1, r1, #1
cmp r1, r0
blt blink2
;C14灭
ldr r1, =0x4001100c
ldr r2, [r1]
eor r2, r2, #0x00004000
str r2, [r1]
;A12亮
ldr r1, =0x4001080c
ldr r2, [r1]
eor r2, r2, #0x00001000
str r2, [r1]
ldr r1, =0
b blink
END
四、效果显示
3个LED对应的GPIO端口电平状态为 111 (高电平,灯不亮),
S1(011)、S2(101)和S3(110)这3个状态,按周期时间进行状态转换:
011 (S1)—> 101(S2) —> 110(S3) —>011 (S1)…
五、总结
- 学习和理解STM32F103系列芯片的地址映射和寄存器映射原理
- 了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)
- 理解了包括GPIOx端口的各寄存器地址和详细参数。
六、参考
https://blog.csdn.net/gelad_w/article/details/115555631
https://blog.csdn.net/qq_47281915/article/details/120812867