初识32
1、初识STM32
在学习51单片机后,对于寄存器、定时器、中断、数码管等有了基本的了解。知道其工作原理后。准备开始上手功能更强大的32单片机。相对于51单片机32单片机处理数据能力更强,一次可以处理32位数据,而51只能处理8位数据。STM32的内部RAM和ROM(flash)都比51大得多,STM32F103有64kRAM,512kROM,STM32F407有256Kram,1M ROM,主频也很高,分别达72M和168M 因此运算能力要强大的多。
片上外设也比较丰富,定时器多达14个或17个,PWM 功能强大,其ADC精度也达到12位, 还有DA模块 实时时钟 较高档次的还有浮点运算单元 DSP功能特别DMA控制器,将CPU从繁忙的数据中转中解脱出来。
另外还有FMSC内存接口
它的外部接口也很丰富,多个串口 USB控制 SPI I2C 等一应俱全,高档有的还有摄像头接口,网络接口等 。所以32的功能比51的功能更加强大。伴随随着强大的功能32单片机内部结构更加繁琐、编码复杂度更高。配置的寄存器更多。
2、STM32F10X的学习方法
1.跟着正点原子提供的视频学习,了解基本的编码规则和开发环境。
2.借助正点原子提供的资料stm32开发指南进行开发编程。
3.查阅ST官方提供的stm32f10x中文手册(或者英文版)
4.有问题可以去查阅相关的论坛找解决办法。
5.实际用keil5来实现相关功能。
6.实战编写相关代码,用32开发板制作一个智能小车。
7.做一个简单的应用系统
3、STM32F10 IO口简介
STM32的IO口由软件配置为8种模式:
1、 输入浮空
2、 输入上拉
3、 输入下拉
4、 模拟输入
5、 开漏输出
6、 推挽输出
7、 推挽式复用功能
8、 开漏复用功能
STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2 个 32 位的端口配置寄存器 CRL 和 CRH; 2 个 32 位的数据寄存器 IDR 和 ODR; 1 个 32 位的置位/复位寄存器BSRR;一个 16 位的复位寄存器 BRR; 1 个 32 位的锁存寄存器 LCKR;这里我们仅介绍常用的几个寄存器,我们常用的 IO 端口寄存器只有 4 个: CRL、 CRH、 IDR、 ODR。
CRL 和 CRH 控制着每个 IO 口的模式及输出速率
STM32IO口配置表:
STM32输出模式配置:
接下来我们看看端口低配置寄存器 CRL 的描述:
CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8位输出口。给个实例,比如我们要设置 PORTC 的 11 位为上拉输入, 12 位为推挽输出。
GPIOC->CRH&=0XFFF00FFF; //清掉这 2 个位原来的设置,同时也不影响其他位的设置
GPIOC->CRH|=0X00038000; //PC11 输入, PC12 输出
GPIOC->ODR=1<<11; //PC11 上拉
- 1
- 2
- 3
通过这 3 句话的配置,我们就设置了 PC11 为上拉输入, PC12 为推挽输出。
IDR 是一个端口输入数据寄存器,只用了低 16 位。该寄存器为只读寄存器,并且只能以16 位的形式读出。
ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平。
了解这些寄存器以后就可以进行跑马灯编程了。
代码练习:
新建一个工程。在该工程文件夹下面新建一个 HARDWARE 的文件夹,用来存储以后与硬件相关的代码。然后在 HARDWARE 文件夹下新建一个 LED 文件夹,用来存放与 LED 相关的代码。然后我们打开test.uvprojx 工程,新建一个文件,然后保存在HARDWARELED 文件夹下面,保存为led.c在该文件中输入如下代码:
#include "led.h"
//初始化 PB5 和 PE5 为输出口.并使能这两个口的时钟
//LED IO 初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<3; //使能 PORTB 时钟
RCC->APB2ENR|=1<<6; //使能 PORTE 时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000;//PE.5 推挽输出
GPIOE->ODR|=1<<5; //PE.5 输出高
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
该代码里面就包含了一个函数 void LED_Init(void),该函数的功能就是用来实现配置 PB5和 PE5 为推挽输出。 这里需要注意的是: 在配置 STM32 外设的时候,任何时候都要先使能该外设的时钟!APB2ENR 是 APB2 总线上的外设时钟使能寄存器,其各位的描述如下图所示:
我们要使能的 PORTB 和 PORTE 的时钟使能位,分别在 bit3 和 bit6,只要将这两位置 1 就可以使能 PORTB 和 PORTE 的时钟了。该寄存器还包括了很多其他外设的时钟使能。在设置完时钟之后就是配置完时钟之后, LED_Init 配置了 PB5 和 PE5 的模式为推挽输出,并且默认输出 1。这样就完成了对这两个 IO 口的初始化。保存 led.c 代码,然后我们按同样的方法,新建一个 led.h 文件,也保存在 LED 文件夹下面。
在 led.h 中输入如下代码:
#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义
#define LED0 PBout(5) // DS0
#define LED1 PEout(5) // DS1
void LED_Init(void); //初始化
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这段代码里面最关键就是 2 个宏定义:
#define LED0 PBout(5) // DS0
#define LED1 PEout(5) // DS1
这里使用的是位带操作来实现操作某个 IO 口的 1 个位的,关于位带操作前面已经有介绍,
这里不再多说。需要说明的是,这里可以使用另外一种操作方式实现。如下:
#define LED0 (1<<5) //led0 PB5
#define LED1 (1<<5) //led1 PE5
#define LED0_SET(x) GPIOB->ODR=(GPIOB->ODR&~LED0)|(x ? LED0: 0)
#define LED1_SET(x) GPIOE->ODR=(GPIOE->ODR&~LED1)|(x ? LED1: 0)
后者通过 LED0_SET(0)和 LED0_SET(1)来控制 PB5 的输出 0 和 1。而前者的类似操作为:
LED0=0 和 LED0=1。显然前者简单很多,从而可以看出位带操作带来的好处。以后像这样的IO 口操作,我们都使用位带操作来实现,而不使用第二种方法。
将 led.h 也保存一下。接着,我们在 Manage Components 管理里面新建一个 HARDWARE的组,并把 led.c 加入到这个组里面.
将 led.h 头文件包含路径加入到工程里面。回到主界面,在 main 函数里面编写如下代码:
#include "sys.h"
#include "delay.h"
#include "led.h"
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //初始化与 LED 连接的硬件接口
while(1)
{
LED0=0;
LED1=1;
delay_ms(300);
LED0=1;
LED1=0;
delay_ms(300);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
代码包含了#include "led.h"这句,使得 LED0、 LED1、 LED_Init 等能在 main 函数里被调用。接下来, main 函数先调用 Stm32_Clock_Init 函数, 配置系统时钟为 9 倍频,也就是 8*9=72M(外部晶振是 8Mhz),然后调用 delay_init 函数,初始化延时函数。接着就是调用 LED_Init 来初始化 PE5 和 PB5 为输出。最后在死循环里面实现 LED0 和 LED1 交替闪烁,间隔为 300ms。
文章来源: wlybsy.blog.csdn.net,作者:万里羊,版权归原作者所有,如需转载,请联系作者。
原文链接:wlybsy.blog.csdn.net/article/details/96575783
- 点赞
- 收藏
- 关注作者
评论(0)