一、对于STM32F芯片的认识?
STM32是一种微控制器,主要有三种类型的MCU:主流级别MCU、高性能MCU、低功耗MCU。再详细一点,我们可以具体到STM32的命名规则,比如STM32F103C8T6中的“F”,代表的就是通用型,另外还有,比如S代表的是简单型、L代表的是低功耗、H代表高性能、AL是汽车应用低功耗型、AF是汽车应用通用型。 转自:https://blog.csdn.net/xxzhaoming/article/details/104510098 对于此次实验我们选择stm32f103c8t6芯片
二、STM32F103系列芯片的地址映射和寄存器映射原理
寄存器映射参考博客STM32F103的存储器映射&寄存器映射
地址映射参考博客STM32F103ZE寄存器地址名称映射及c语言
三丶GPIO端口
1.什么是GPIO
GPIO(general porpose intput output):通用输入输出端口的简称。可以通过软件控制其输出和输入。stm32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通信,控制以及数据采集的功能。
2.初始化设置
1.打开GPIO口的时钟
GPIO和时钟的地址:
将GPIOA GPIOB GPIOC三个时钟打开
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
RCC_APB2ENR |= (1<<2);
RCC_APB2ENR |= (1<<3);
RCC_APB2ENR |= (1<<4);
2.初始化
采用推挽输出模式 端口1-7为低,端口8-15为高。每个引脚由四个位控制。 以GPIOB和0号引脚(B0)为例,将其设置为推挽输出,并设置最大速度为10MHz,则将控制B0的四个位设置为0001:
#define GPIOB_CRL (*(unsigned int *)0x40010c00)
GPIOB_CRL |= (1<<0);
GPIOB_CRL &= ~(0xE<<0);
对于GPIOB的B0、GPIOC的C15、GPIOA的A0,设置如下:
#define GPIOB_CRL (*(unsigned int *)0x40010C00)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
GPIOB_CRL |= (1<<0);
GPIOB_CRL &= ~(0xE<<0);
GPIOC_CRH |= (1<<28);
GPIOC_CRH &= ~(0xE0000000);
GPIOA_CRL |= (1<<0);
GPIOA_CRL &= ~(0xE<<0);
3. 设置低电平
1为高电平 0为低电平 以GPIOB和0号引脚(B0)为例,将其设置为低电平:
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
GPIOB_ODR &= ~(1<<0);
对于GPIOB的B0、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<<0);
GPIOC_ODR &= ~(1<<15);
GPIOA_ODR &= ~(1<<0);
四丶创建项目
创建项目可以参考以前的博客基于MDK创建纯汇编语言的STM32工程 只需要注意选择的芯片是STM32F103C8即可 创建项目之后 加入main文件(第二个选项) 将启动文件拷贝至LED项目目录下
点击此处 选择all file 加入拷贝的文件 点击魔法棒,选择生成.HEX文件 将如下代码写入main.c中
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRL (*(unsigned int *)0x40010C00)
#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);
RCC_APB2ENR |= (1<<4);
RCC_APB2ENR |= (1<<2);
GPIOB_CRL |= (1<<0);
GPIOB_CRL &= ~(0xE);
GPIOC_CRH |= (1<<28);
GPIOC_CRH &= ~(0xE0000000);
GPIOA_CRL |= (1<<0);
GPIOA_CRL &= ~(0xE);
GPIOB_ODR |= (1<<0);
GPIOC_ODR |= (1<<15);
GPIOA_ODR |= (1<<0);
while(1){
GPIOB_ODR &= ~(1<<0);
Delay_ms(1000000);
GPIOB_ODR |= (1<<0);
Delay_ms(1000000);
GPIOC_ODR &= ~(1<<15);
Delay_ms(1000000);
GPIOC_ODR |= (1<<15);
Delay_ms(1000000);
GPIOA_ODR &= ~(1<<0);
Delay_ms(1000000);
GPIOA_ODR |= (1<<0);
Delay_ms(1000000);
}
}
void SystemInit(){
}
点击编译
五丶连接电路
GND — GND 3v3 — 3v3 TXD — A10 RXD — A9 B0连接最左边的LED灯 A0连接最右边的LED灯 C15连接中间的LED灯 3.3V连接正极供电
(hex文件选择第四点生成的.hex文件) 效果如图
六丶汇编实现
RCC_APB2ENR EQU 0x40021018;配置RCC寄存器,时钟,0x40021018为时钟地址
GPIOB_BASE EQU 0x40010C00
GPIOC_BASE EQU 0x40011000
GPIOA_BASE EQU 0x40010800
GPIOB_CRL EQU 0x40010C00
GPIOC_CRH EQU 0x40011004
GPIOA_CRL EQU 0x40010800
GPIOB_ODR EQU 0x40010C0C
GPIOC_ODR EQU 0x4001100C
GPIOA_ODR EQU 0x4001080C
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_C
BL Delay
BL LED_OFF_C
BL Delay
BL LED_ON_A
BL Delay
BL LED_OFF_A
BL Delay
BL LED_ON_B
BL Delay
BL LED_OFF_B
BL Delay
B MainLoop;B:无条件跳转。
LED_Init;LED初始化
PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
;控制时钟
LDR R0,=RCC_APB2ENR;LDR是把地址装载到寄存器中(比如R0)。
ORR R0,R0,#0x1c
LDR R1,=RCC_APB2ENR
STR R0,[R1]
;初始化GPIOA_CRL
LDR R0,=GPIOA_CRL
BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
LDR R1,=GPIOA_CRL
STR R0,[R1]
LDR R0,=GPIOA_CRL
ORR R0,#0x00000001
LDR R1,=GPIOA_CRL
STR R0,[R1]
;将PA0置1
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
;初始化GPIOB_CRL
LDR R0,=GPIOB_CRL
BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
LDR R1,=GPIOB_CRL
STR R0,[R1]
LDR R0,=GPIOB_CRL
ORR R0,#0x00000001
LDR R1,=GPIOB_CRL
STR R0,[R1]
;将PB0置1
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
;初始化GPIOC
LDR R0,=GPIOC_CRH
BIC R0,R0,#0x0fffffff
LDR R1,=GPIOC_CRH
STR R0,[R1]
LDR R0,=GPIOC_CRH
ORR R0,#0x01000000
LDR R1,=GPIOC_CRH
STR R0,[R1]
;将PC15置1
MOV R0,#0x8000
LDR R1,=GPIOC_ORD
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,=GPIOA_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_A
PUSH {R0,R1, LR}
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_B;亮灯
PUSH {R0,R1, LR}
MOV R0,#0x00
LDR R1,=GPIOB_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_B;熄灯
PUSH {R0,R1, LR}
MOV R0,#0x01
LDR R1,=GPIOB_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_C;亮灯
PUSH {R0,R1, LR}
MOV R0,#0x00
LDR R1,=GPIOC_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_C;熄灯
PUSH {R0,R1, LR}
MOV R0,#0x0100
LDR R1,=GPIOC_ORD
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
七丶总结
增强动手能力更加了解STM32.
|