stm32点亮流水灯(小白的求学之路)
作者:互联网
文章目录
前言
由于之前作者仅仅只学习了51单片机的一些操作,对stm32单片机操作完全不会,过程中很曲折,如果有什么错的地方,希望可以告诉作者加以改正。
一、怎么点亮一个LED?
这个问题困扰了很久,因为stm32与51不同,51单片机直接可以操作引脚,而stm32要复杂得多。下面我们先来了解一下输入输出管脚——GPIO。
1、GPIO简介
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如 GPIOA、GPIOB、GPIOC,所有的 GPIO 引脚都有基本的输入输出功能。
(这里我们可以类比51单片机的引脚,点灯的时候只需要将GPIO管脚置为高电平或者低电平)
问题又来了,怎么设置GPIO管脚呢?
这个时候就会用到寄存器啦。
2、寄存器
1、片上外设区分为三条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1挂载低速外设,APB2 和 AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。其中 APB1 总线的地址最低,片上外设从这里开始,也叫外设基地址。
总线名称 | 总线基地址 | 相对外设基地址的偏移 |
---|---|---|
APB1 | 0x4000 0000 | 0x0 |
APB2 | 0x4001 0000 | 0x0001 0000 |
AHB | 0x4001 8000 | 0x0001 8000 |
(到这里可以发现一个公式:地址=基地址+相对地址偏移)
2、外设基地址
GPIO 属于高速的外设 ,挂载到APB2 总线上。
外设名称 | 外设基地址 | 相对 APB2 总线的地址偏移 |
---|---|---|
GPIOA | 0x4001 0800 | 0x0000 0800 |
GPIOB | 0x4001 0C00 | 0x0000 0C00 |
GPIOC | 0x4001 1000 | 0x0000 1000 |
现在我们知道了GPIO的地址,是不是意味着可以直接通过地址来设置GPIO呢?
答案还是否定的,还需要操作里面特定功能的寄存器来设置GPIO管脚,比如:输入数据寄存器 GPIOx_IDR,GPIO 模式GPIOx_CRL或者GPIOx_CRH,时钟使能RCC_APB2ENR。
3、 APB2 外设时钟使能寄存器(RCC_APB2ENR)
为减小stm32的功耗而设置,如果不把对应管角的时钟使能,对应管脚不会工作。
这里我们以打开GPIOA的时钟为例子:
首先找到APB2的地址0x4001 0000,通过地址=基地址+相对地址偏移,得到RCC_APB2ENR的地址0x4001 0018。我们可以直接赋值为0x00000004
4、GPIO 模式GPIOx_CRL或者GPIOx_CRH
每个 GPI/O 端口有两个 32 位配置寄存器(GPIOx_CRL,GPIOx_CRH)。低8位GPIOx0—7在GPIOx_CRL,高8位GPIOx8—15在GPIOx_CRH。
什么是推挽输出?什么又是开漏输出呢?
推挽输出:可以输出高,低电平,连接数字器件。(我们点亮LED的模式)
开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
例如把GPIOB8设置为推挽输出,就找到GPIOB_CRH的地址,赋值为0x00000002。
5.输入数据寄存器 GPIOx_IDR
假如我们想点亮PA0,只需要将IDR0位置为0;
二、硬件
现在我们知道了软件的编写,硬件又该怎么连接呢?
我用的是stm32f103c8t6芯片,本次运用了GPIO_A8和GPIO_B8,和GPIO_C13,找到与之对应的管脚A8,B8,C13,用线把管脚引出来,再将LED的低电平引脚相连(LED长的引脚为高电平)。
采用串口通信,需要usb与STM32如图链接。其中要求usb的RXD连接核心板的TXD(A9),usb的TXD连接核心板的RXD(A10)。
烧录软件:
需要用到MCUISP
使用教程: STM32最小系统下载程序方法.
三、用寄存器点亮流水灯
代码如下:
#include<stdio.h>
#define pRCC_APB2ENR *((unsigned volatile int*)0x40021018)//APB2的地址
#define pGPIOB_CRH *((unsigned volatile int*)0x40010c04)//GPIO_B8的模式
#define pGPIOB_ODR *((unsigned volatile int*)0x40010c0c)//GPIO_B8的数据
//GPIO_B8配置寄存器
#define pGPIOC_CRH *((unsigned volatile int*)0x40011004)//GPIO_C13的模式
#define pGPIOC_ODR *((unsigned volatile int*)0x4001100c)//GPIO_C13的数据
//GPIO_C0配置寄存器
#define pGPIOA_CRH *((unsigned volatile int*)0x40010804)//GPIO_A8的模式
#define pGPIOA_ODR *((unsigned volatile int*)0x4001080c)//GPIO_A8的数据
//GPIO_A8配置寄存器
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
int main(void)
{
pRCC_APB2ENR =0x0000001c;//打开APB2中B,C,D外设时钟
pGPIOB_CRH =0x00000002;
pGPIOC_CRH =0x00200000;
pGPIOA_CRH =0x00000002;
//设置寄存器为推挽模式
while(1)
{
pGPIOB_ODR =0x00000000;
Delay_ms(10000000);
pGPIOB_ODR =0x00000100;
Delay_ms(10000000);
//闪烁GPIO_B8
pGPIOA_ODR =0x00000000;
Delay_ms(10000000);
pGPIOA_ODR =0x00000100;
Delay_ms(10000000);
//闪烁GPIC_A8
pGPIOC_ODR =0x00000000;
Delay_ms(10000000);
pGPIOC_ODR =0x00002000;
Delay_ms(10000000);
//闪烁GPID_C13
}
}
实验效果
总结
通过本次的学习,初步了解并实现了从软件到硬件的过渡,同时也学习到了很多关于stm32寄存器的知识,在学习的过程中有很多次都想放弃了,特别是在写软件的时候。最后,功夫不负有心人,做出来的效果还是不错的。
标签:求学,点亮,GPIOx,stm32,地址,寄存器,GPIO,CRH,外设 来源: https://blog.csdn.net/weixin_57517458/article/details/120883428