ST:意法半导体
M:微电子
32:总线宽度 也叫MCU,单片机
一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU,随机存储器RAM,只读存储器ROM,多种I/O定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到硅片上,形成小而完善的微型计算机系统,广泛应用于工业控制领域。
STM32F051R8T6xxx
STM32:家族
F:产品类别,A——汽车级,F——基础级,L——超低功耗,S——标准型,WB——蓝牙及802.15.4, WL——长途无限产品,H——高性能, Q——主流型
051:特定功能(3位数字)
R:引脚数
8:闪存容量
T:封装
6:温度范围
x:固件板税
xx:选项
包括输入输出引脚INPUT\OUTPUT, VBAT, (VDDA VSSA), (VREF VREF-)等
包括主晶振IO,RTC晶振IO
用于JTAG下载的IO,包括JTMS,JTCK,JTDI,JTDO,NJTRST
用于设置系统的启动模式,包括BOOT0,BOOT1
:用于外部复位 NRST
(1)专用设备连接到专用总线,如I2C,SPI,SDIO,FSMC,DCMI,在此期间,这些总线需要连接特殊的IO
(2)街道上的普通元器件GPIO,比如蜂鸣器,LED,按钮和其他元件使用普通元件,如普通按钮GPIO即可
(3)剩余的IO可根据项目需要引出或不引出
寄存器是一个内存地址
在不同的地址上,可以根据地址找到和使用不同的外设
int main(void){ volatile unsigned int * pointer=(unsigned int *)0x40028000; //volatile unsigned int * pointer指针变量的定义 //volatile关键字放置编译器优化程序 //比如*pointer =1;*pointer =2会被优化成*pointer =3; //(unsigned int *)将0x40028000强转为地址 //0x40028000是内存地址,数据保存在里面 //这句话表明指针指向地址 *pointer=1; //*pointer解指针符向地址中的数据 }
使用宏定义优化
#define pointer (volatile unsigned int *)0x40028000; ///宏定义只是变量替换,减少内存消耗 int main(void){ *pointer=1; }
GPIO它是通用输入输出端口的缩写,简单地说就是STM32可控引脚,STM32芯片的GPIO引脚与外部设备连接,实现与外部通信、控制和数据采集的功能GPIO引脚的电平变化达到了各种目的
(1)IO引脚模块:保护二极管可防止电压输入过高或过低,外部电压高于VDD当外部电压过低时,电流流向为Vss——IO。
(2)推拉、开漏或关闭:
当输入信号为高电平时,上面的mos导通,下面的mos截止日期,电流从VDD——OUT,当输入信号为低电平时,上述信号mos截止日期,下面mos导通,电流:OUT——GND,此时OUT相当于低电平,驱动能力强
输入高电平时,mos截至目前,上拉电阻可保证默认高电平状态(本身不能直接输出高电平),输入低电平时,mos导通,OUT接地,相当于输出低电平。优点是实现线与功能
共同决定如何控制输出
识别输入的低电平
将正弦波转换为方波,将连续信号转换为离散信号
需要注意的是,可以通过两种方式配置自己的: (1)运行环境管理工具
(2)加入库包
添加STM322Cube_FW_F1_V1.6.0库包——CMSIS,将CMSIS文件夹直接复制到当前项目目录下,具体步骤:
stm32-手动移植HAL以及错误的解决方案STM32F103ZE为例)_绿篱竹枫的博客-CSDN博客_stm移植到32标准库hal库【野火】STM32 HAL库开发实战指南 教学视频 手把手教学STM32全系列 零基础入门CubeMX HAL库,基于野火系列STM32开发板_哔哩哔哩_bilibili
通过总线的形式,可以很好地将各种外设分离开,可以独立的将各种外设来控制它的使能与否,控制外设使能与否,就是控制这个外设的时钟
编写代码前,请查询stm32F1x参考手册,知挂载在哪个总线(如图所示,上)
其中
所以APB2外设使能寄存器的地址就是
这个设置完成之后,表示GPIO已经使能,可以开始工作了
第一步:在这里,我们需要使用开漏输出和推挽式输出的功能,由于开漏输出设置高电平比较麻烦,因从直接采用推挽式输出
表18中的输出速度就是高低电平的翻转速度
第四步:设置GPIO的外设基地址
如图所示,GPIO端口B的基地址
#define GPIOB_CLK (*(volatile unsigned int *)(0x40021000+0x18))
//volatile 防止编译器对代码进行优化
//unsigned int 将地址设置为无符号数,因为地址不能是负的
//0x40021000 RCC的外设基地址,
//0x18 RCC的偏移地址
#define GPIOB_CRL (*(volatile unsigned int *)(0x40010C00+0x00))
#define GPIOB_ODR (*(volatile unsigned int *)(0x40010C00+0x0C))
int main(void){
//1.使能GPIOB的外设时钟
GPIOB_CLK |=(1<<3);
//2.GPIOB设置推挽输出模式
GPIOB_CRL &=~(0xf<<(4*0));//清除低4位寄存器
GPIOB_CRL |=(2<<0);
GPIOB_ODR &=~(0x1<<(1*0));//清除低1位寄存器
GPIOB_ODR|=(1<<0);
}
//1.使能GPIOB的外设时钟
GPIOB_CLK |=(1<<3);
这句代码相当于GPIOB_CLK=GPIOB_CLK|(1<<3)
也就是将1左移3位,结果再与GPIOB_CLK取或运算,根据参考手册知
在CKL中,1被表示为(其中的X表示未定的结果,可以是0,也可以是1)
00000000 00000000 XXXXXXXX XXXXXX01
下面将1左移3位,舍弃掉被移除的数字,空位补0,可得(1<<3)
(1<<3)=00000000 00000XXX XXXXXXXX XXX01000 //这样就将位3置1了
GPIOB_CLK为
GPIOB_CLK=00000000 00000000 XXXXXXXX XXXXXX0X
所以二者取或运算的结果为
00000000 00000XXX XXXXXXXX XXXX1X0X
可见除了位3变为1,其他位不受影响
通过查阅手册可知,PB端口对应的是位3,位3置0时,PB端口始终关闭,端口不能工作,当位置3置1时,PB端口可以工作,因此在这里将1左移3位,保证PB端口打开
//2.GPIOB设置推挽输出模式
GPIOB_CRL &=~(0xf<<(4*0));//清除低4位寄存器
GPIOB_CRL |=(2<<0);
GPIOB_CRL &=~(0xf<<(4*0));//清除低4位寄存器
这句代码等同于GPIOB_CRL=GPIOB_CRL&(~(oxf<<(4*0)));
oxf用二进制表示就是00000000 00000000 00000000 00001111
oxf<<(4*0)的意思是oxf左移0个4位,也就是
oxf<<(4*0)=00000000 00000000 0000000 00001111;
所以
~(oxf<<(4*0))=11111111 11111111 11111111 11110000;
GPIOB_CRL=XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
则
GPIOB_CRL&(~0xf<<(4*0))=XXXXXXXX XXXXXXXX XXXXXXXX XXXX0000
//这样就实现了将低4位清0
GPIOB_CRL |=(2<<0);
这句代码等同于
GPIOB_CRL=GPIOB_CRL|(2<<0);
经过分析,若想实现需要的功能,GPIOB_CRL的后4位应设置为0010,十进制就是2
(2<<0)也就是将2左移0位,相当于不移动,因此
(2<<0)=00000000 00000000 00000000 00000010;
GPIOB_CRL=XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
所以
GPIOB|(2<<0)=XXXXXXXX XXXXXXX XXXXXXXX XXXXXX1X
也就是只将1位置1
根据前面的分析可知,我们要配置输出模式,采用较低的速度即可,因此,MODE0应设置为10,也就是十进制的2,我们采用的是推挽输出模式,因此,CNF0应设置为00
GPIOB_ODR &=~(0x1<<(1*0));//清除低1位寄存器
GPIOB_ODR|=(1<<0);
要点亮PB0端口的灯,因此低1位寄存器应该为1