联系方式
作者:马一飞
QQ:791729359 在学习过程中有什么问题可以联系
(原本资料是以网盘的方式公开提供给任何蓝桥杯爱好者进行下载的,但是最近临近蓝桥杯考试,遇到了很多伸手党,我无偿给爱好者们解答学习上的问题,回复得比较慢居然还有同学来说我这样那样,所以决定不再随意提供自己写的源码和资料。博主已经开始参加工作了,也不是闲着没事干盯着电脑手机为你们服务。记住,不要成为伸手党,要自己多动手实现。)
如果对stm32有了解的都知道,stm32的编程有两种方式,一种是直接配置寄存器,一种是使用库函数配置。那么,使用哪种方式配置都是可以的,最主要是看使用什么方式配置比较方便,比较复杂的地方,建议使用库函数,如果是一些简单的寄存器,直接配置寄存器可能会更方便更快,但是你需要去了解这个寄存器的功能。
在编程前,我们要先打开stm32的中文参考手册和CT117E的电路原理图。
我个人对于蓝桥杯编程外设的习惯是创建一个HARDWARE文件夹
然后再HARDWARE创建一个IO.c和IO.h,所有外设的配置都会放在IO.c这个文件里面,你也可以每个文件都创建各自的.c文件和.h文件,只不过在蓝桥杯里面,直接使用一个IO.c和IO.h会比较省时间,因此我这么做了,大家也可以有各自的习惯,并不影响。
我们要编写一个LED初始化函数LED_Init(),我们先看开发板的电路原理图,我们找到8个LED所对应的引脚,在LED的另外一边还有着一个74HC573锁存器,大家可以去找一下这个锁存器的数据手册看看这个锁存器是什么用来做什么功能的。
那么我这里就直接告诉大家这个锁存器的功能,当N_LE引脚为高电平时,H_D0~H_D7的电平信号可以直接传到右端给到LED,如果N_LE引脚为低电平的时候,无论H_D0~H_D7的电平信号如何改变,HC573锁存器右端的电平信号都不会改变。因为LED灯的引脚与LCD显示屏的数据引脚是共用了,因此为了两者互不干扰,需要利用这个锁存器。
接下来我们就来编写这个LED_Init()函数,编写的函数如下:
#include "io.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_10MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = 0XFF00;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_10MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIOD->ODR |= (1<<2);
GPIOC->ODR |= 0xff00;
GPIOD->ODR &= ~(1<<2);
}
代码的第7,8行,我们先使能APB2总线上GPIOD和GPIOC 端口的时钟。RCC_APB2PeriphClockCmd();函数的原型定义是在RCC的库函数里我们可以在这个函数的.h文件快速找到RCC_APB2PeriphClockCmd();并查看里面的定义并进行配置。
GPIO_Init();函数则是在里面定义的,我们可以打开stm32f10x_gpio.h这个文件复制到他的函数原型GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);并进行配置,第一个入口参数代表使能哪一组GPIO端口,第二个入口参数则是一个结构体指针类型的,这个结构体里面有3个成员变量。
分别是可以配置哪一个IO口,IO口的速率,IO口的模式。那么因为我们的这个端口是用做LED灯的控制的,我们需要把GPIO_Mode配置为输出模式。
我们先把PD2引脚配置为输出。
而后我们还需要吧PC8~PC15的引脚也需要去配置为输出,那么我们如果一个一个配置的话,会非常麻烦,我们可以来看一下这个GPIO_Pin库函数的定义。
我们可以对这个Pin的定义总结一下规律,很容易就可以看出,我们想配置Pin8~Pin15,我们可以直接0x0100+0x0200+0x0400+0x0800+0x1000+0x2000+0x4000+0x8000=0xff00 所以说,我们直接使GPIO_Pin = 0xff00;就可以达到一次性配置PC8~PC15的作用了。
我们对PC8~PC15,PD2这9个引脚配置完成后,我们还要把LED全部熄灭,因为开发板复位后,LED默认是点亮的。
到了这一步,我个人比较喜欢直接操作寄存器来配置LED了,大家也可以去GPIO库函数里面找到相应的库函数来配置这些IO口。
先把PD2置1 ,也就是把GPIOD的ODR寄存器(端口输出寄存器)的第2位置高,使能74HC573锁存器,之后把,GPIOC的ODR寄存器的8~15位置高后,关闭锁存器,也就是PD2要置回0。
我们在主函数写一个LED1闪烁的程序来测试效果
每过1000ms(也就是1s)的时间,我们就对PC8端口取反,并且打开锁存,关闭锁存的操作。
我们把这个程序烧录到开发板中,就能看到效果了LED1以1S的间隔进行闪烁。
(以上仅属于个人观点)
补充:(基础薄弱者看)
问题一:怎么知道RCC_APB2PeriphClockCmd()时钟使能函数到底是在哪里可以找到?
回答一:点开我们可以看到有stm32f10x_rcc.h这个文件,我们点开,拉到最下面,从下往上找,找到693行就能找到这个函数了。
问题二:怎么这么多函数,有APB2,APB1的时钟使能函数,怎么确定要使用哪一个函数去配置?
回答二:如果你不知道使用哪个配置的话,这时候就需要看数据手册了。打开stm32中文参考手册,翻到25页,找到下图
从图中就可以知道,使能哪些东西,需要配置哪个时钟。或者还有第二个方法,我们直接在库函数里面看选中函数名称
,按右键,点击Go To Definition xxx的这个选项,就可以查看函数原型,可以观察到他的函数原型
,有两个入口参数,我们再选中第一个入口参数再次右键点击Go To Definition 查看他的成员,看看有没有你需要的成员
就能够知道应该使用APB1还是APB2了。
问题3:GPIO_Init()又应该去哪里找?怎么知道有这个函数?
回答3:点开stm32f10x_gpio.h这个文件,翻到最下面,从下网上找
在第351行就能看到它的库函数了。第一个入口参数为配置哪一组IO口,第二个入口参数是一个结构体指针。
问题4:找到了GPIO_Init()里面的入口参数又是应该如何确定呢?
回答4:与上面的问题一样,我们先Go To Definition这个函数,会看到它的函数原型
然后我们就可以看到每个入口参数的定义了,第二个入口参数是一个结构体指针,我们需要对这个结构体指针的成员变量进行初始化,那么从这个函数原型我们也可以看到,他的结构体成员变量有3个,分别是Mode,Pin,Speed。如果我们不知道某个变量应该去什么模式,我们可以进入变量的定义里看看有什么选择,例如我不知道Mode要设置成什么,我选中如图部分
点击鼠标右键,同样选择Go To Definition xxx,我们就能看到一个枚举类型,枚举类型里面的东西就是我们可以选择的东西,
有模拟输入,浮空输入,下拉输出,上拉输出,开漏输出,推挽输出等等的模式,我们需要哪个模式就选择哪个就好,其他的成员变量也类似的方法。
问题5:ODR寄存器是个什么鬼,怎么知道ODR寄存器是用来干嘛的,为什么要这么设置?
回答5:ODR就是也就是端口输出寄存器,具体的作用可以看数据手册,找到通用和复用功能IO的那一章节
问题6:代码里面GPIOC->ODR ^= (1<<8);是什么?
回答6:这个操作实际上就是把GPIOC里的ODR寄存器的第八位取反,其他位不变。^是异或符号,如果大家不懂什么是异或的话应该好好学学C语言的逻辑运算符了,因为stm32里面不能直接使用取反操作,也就是你们51单片机的LED = ~LED; stm32里面不能这么做,这么做可以是可以,前提是需要使用stm32里面的位运算,但是蓝桥杯的话还是没必要单独弄个位运算,还是直接按位异或就好。
以上问题如果还没能解决大家初学蓝桥杯嵌入式的疑惑的话,建议看看正点原子LED那一讲的视频再理解以上内容。