什么是单片机?
单片机( Single-Chip Microcomputer )是一种集成电路芯片,把具有数据处理能力的中央处理器 CPU 、随机存储器 RAM 、只读存储器 ROM 、多种 I/O 口和中断系统、定时器 / 计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、 A/D 转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。
STM系列单片机命名规则

STM32F103C8T6单片机简介
项目
|
介绍
|
内核
|
Cortex-M3
|
Flash
|
64K x 8bit
|
SRAM
|
20K x 8bit
|
GPIO
|
37
个
GPIO
,分别为
PA0-PA15
、
PBO-PB15
、
PC13-PC15
、
PDO-PD1
|
ADC
|
2
个
12bit ADC
合计
12
路通道,外部通道
: PAO
到
PA7+PBO
到
PB1
内部通道
:
温度传感器通道ADC Channel 16
和内部参考电压通道
ADC Channel 17
|
定时器/
计数器
|
4
个
16bit
定时器
/
计数器,分别为
TIM1
、
TIM2
、
TIM3
、
TIM4TM1
带死区插入,常用于产生PWM
控制电机
|
看门狗定时器
|
2
个看门狗定时器
(
独立看门狗
IWDG
、窗口看门狗
WWDG)
|
滴答定时器
|
1
个
24bit
向下计数的滴答定时器
systick
|
工作电压、温度
|
2V3.6V
、
-40°C85°C
|
通信串口
|
2 * IIC
,
2 * SPI
,
3 * USART
,
1 * CAN
|
系统时钟
|
内部
8MHz
时钟
HSI
最高可倍频到
64MHZ
,外部
8MHZ
时钟
HSE
最高可倍频到72MHZ
|
标准库与HAL库区别
- 寄存器众多,需要经常翻阅芯片手册,费时费力;
- 更大灵活性,可以随心所欲达到自己的目的;
- 深入理解单片机的运行原理,知其然更知其所以然。
- 将寄存器底层操作都封装起来,提供一整套接口(API)供开发者调用每款芯片都编写了一份库文件,也就是工程文件里stm32F1xx…之类的;
- 配置结构体变量成员就可以修改外设的配置寄存器,从而选择不同的功能;
- 大大降低单片机开发难度,但是在不同芯片间不方便移植。
- ST公司目前主力推的开发方式,新的芯片已经不再提供标准库;
- 为了实现在不同芯片之间移植代码;
- 为了兼容所有芯片,导致代码量庞大,执行效率低下
通用输入输出端口GPIO
什么是GPIO?
组编号+引脚编号 GPIOx

推挽输出和开漏输出:
推挽输出: 可以真正的输出高电平和低电平
开漏输出: 开漏输出无法真正输出高电平,即高电平时没有驱动能力,需要借助外部上拉电阻完 成对外驱动
点亮LED
其实点亮LED的操作在上节已经实现了,这里在深入了解一下相关函数:
1. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
效果是对一个GPIO口写入1或者0,第一个参数是GPIO的组,第二个参数是GPIO的引脚,第三个参数是引脚的状态
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_PIN_ACTION(PinState));
if (PinState != GPIO_PIN_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
}
}
2. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
效果是初始化GPIO口,第一个参数是GPIO的组,第二个参数是一个结构体指针,可以通过跳转查看具体信息:
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;
因此在执行GPIO的初始化之前需要自己定义一个结构体 GPIO_InitTypeDef GPIO_InitStruct = {0};
并对其中的成员进行赋值:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);
/*Configure GPIO pins : PB8 PB9 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
3. void HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
效果是反转GPIO口的状态,第一个参数是GPIO的组,第二个参数是GPIO的引脚
使用轮询法实现按键点亮LED灯
由原理图可见, 如果按钮SW1,2被按下,会对应KEY1,2被拉低,所以可以通过观察A0和A1是否被拉低来判断按钮是否被按下。
那么首先要涉及到PA0,PA1的初始化,所以可以打开上节编辑到一半的CubeMX软件来配置:
由于按键是触发输入信号将PA0和PA1设计成“GPIO_Input”:
可以将PB8,9的初始值设置为高电平,这样程序烧录之后灯不会立刻亮起来
由于是在上节的工程基础上改的,所以不需要在设置Project Manager里面的内容
点击“GENERATE CODE”生成代码:
实现的是 按钮1被按下时,LED1亮,再次按下熄灭;如果按钮2被按下时,LED2亮,再次按下熄灭
#define KEY_ON 0
#define KEY_OFF 1
uint8_t Key_scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == GPIO_PIN_RESET)
{
/*按键按下*/
while(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == GPIO_PIN_RESET);//按键消抖,如果按键没有被按下不会触发return
return KEY_ON;
}
else
{
/*按键松开*/
return KEY_OFF;
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);
if(Key_scan(GPIOA ,GPIO_PIN_0) == KEY_ON)//如果A0对应的按钮按下
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);//反转LED1的状态
}
if(Key_scan(GPIOA ,GPIO_PIN_1) == KEY_ON)//如果A1对应的按钮按下
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);//反转LED2的状态
}
}
注意!!!HAL库有很多重定义的类型,例如uint8_t
需要根据使用查询!!