希望每天都能有所收获鸭~
最近准备开始学习stm32,当然51的学习也会一起进行,如开头所讲,希望每天都能有所收获吧!!!菜鸟思维,写的可能会有一点繁琐,但是我觉得学习是要一步一步来的,也希望自己可以把每一点都弄懂,嗯,就是这样
开始学习之前当然要先搭建好学习环境,关于软件的下载以及工程搭建,CSDN上有很多博主写的都很详细,下面给出两篇参考博客,也是我在学习过程中借鉴的博客(博主写的可以说超级详细了):
stm32编程方式有两种:一种是直接操作寄存器,另一种是配置库函数, emmm,感觉大多数情况下还是库函数比较好用,配置寄存器的话要记的东西比较多,感觉我也记不住,哈哈。但是关于寄存器的知识我们还是要了解的,具体知识可以参照《STM32中文参考手册》来学习,下面我们来说说怎么实现LED的配置的。
开始写配置LED的函数之前,我们还是和学习51时一样,需要先看一下原理图,明确一下LED的电路结构:
从原理图上我们可以看到:单片机的各个引脚是通过一个573锁存器和LED相连的,这个573我们在51里也很常见,需要注意的就是只有在使能573的情况下才能实现端口数据的传输,也就是说我们需要把N-LE对应的引脚拉高。
接下来我们找一下红线框部分对应的引脚(emmm,这里和51就不太一样,可以看一下图)
上面分别是J1和J2两个排针,上面的引脚是一一对应的,从开发板上我们也可以看到,这两个排针的对应引脚是用跳线帽连接在一起的(感觉很方便呀)
N-LE对应的是PD2,而D0到D7这八个LED分别对应PC8-PC15
那么LED的配置是配置什么呢?
引脚模式,也可以理解成一种初始化函数,具体步骤是:配置端口时钟(时钟使能),设置引脚号,设置引脚速率,配置端口模式,配置输出数据。
下面我们就按照步骤来一步一步完成LED的配置:
RCC->APB2ENR |= (1 << 4);//使能GPIOC时钟
RCC->APB2ENR |= (1 << 5);//使能GPIOD时钟
我们上面解释过了RCC是一个结构体指针,APB2ENG是这个结构体内部声明的一个变量,所以在调用时就需要用 “->” 这个符号,下面以使能GPIOC为例解释一下为什么可以实现位4置1:
先来看1 << 4:1用16进制表示出来是:00000001,左移四位变成了00010000;RCC->APB2ENR |= (1 << 4),APB2外设时钟使能寄存器的复位值是00000000,和00010000进行或运算,结果是:00010000,实现了位4置1,并且不改变其它位
注意:位是从0 开始表示的,所以位4实际上就是第5位
第一个变量表示使能哪一个时钟,NewState表示使能(ENABLE)还是不使能(DISABLE)
看代码:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOD和GPIOC
/*还可以分开写*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//使能GPIOD
ok,现在我们来写引脚模式配置的部分,以GPIOD(PD2)为例说明:
思想就是:先定义一个GPIO_InitTypeDef类型的结构体变量,然后为这个结构体的各个变量赋值,然后再调用初始化函数
GPIO_InitTypeDef GPIO_InitStructure;//定义一个结构体变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//设置引脚号
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//设置引脚速率10MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//设置为通用推挽输出模式
GPIO_Init(GPIOD, &GPIO_InitStructure);//调用初始化函数,初始化引脚配置
关于初始化函数,在stm32f10x_gpio.h文件里可见定义,还是同样的操作,按快捷键F12,找到对应的函数体:
关于GPIOC相关引脚的配置,在设置引脚号时有技巧:
我们如果一个一个引脚定义的话,需要从PC8定义到PC15,太麻烦了,我们可以把对应的地址相加,得到结果是0xFF00,就实现了这8个引脚号的配置了:
GPIOC->ODR |= 0xFF00;//将PC8-PC15引脚拉高
GPIOD->ODR |= (1 << 2);//拉高PD2,使能573
GPIOD->ODR &= ~(1 << 2);//关闭使能
下面是完整代码:
#include "stm32f10x.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOD和GPIOC
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//设置引脚号
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//设置引脚速率10MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//设置为通用推挽输出模式
GPIO_Init(GPIOD, &GPIO_InitStructure);//调用初始化函数,初始化引脚配置
GPIO_InitStructure.GPIO_Pin = 0xFF00;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->ODR |= 0xFF00;//将PC8-PC15引脚拉高
GPIOD->ODR |= (1 << 2);//拉高PD2,使能573
GPIOD->ODR &= ~(1 << 2);//关闭使能
}
完毕~~
emmm,再给一个测试例程吧,实现L1每隔1s闪烁:
#include "stm32f10x.h"
#include "led.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
//Main Body
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
LED_Init();
while(1)
{
GPIOC->ODR ^= (1 << 8);
GPIOD->ODR |= (1 << 2);
GPIOD->ODR &= ~(1 << 2);
Delay_Ms(1000);
}
}
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
解释一下 “GPIOC->ODR ^= (1 << 8);” 介个东东:
^异或符学过51的应该不陌生,很好用,这个异或是按位异或,对每一位都执行操作的,我们每隔1000ms让GPIOC->ODR中的数据和(1 <<8)相异或,也就是实现第8位每隔1s取反,视觉上就是L1每隔1s闪烁了:
GPIOC->ODR初始化数据:11111111
(1 << 8):10000000
按位异或 GPIOC->ODR ^= (1 << 8):01111111
实现了第8位每隔1s取反的操作~~~