STM32笔记
SWD连接开发板
什么是SWD
SWD与JTAG同属调试接口,是芯片在设计之初就预制的对芯片进行开发调试并在开发板上预留的接口,
JTAG接口
目前开发板上的接口大多是20PIN的,与此对应的关系如下:
DAPLink在JTAG接口连接
只用连接3根线 SWD、SWCLK、GND。对应关系为
连接时要注意将接口摆放与图片一致后接线,这样不容易弄反
GPIO
通用输入输出接口
GPIO_MODE
(1)GPIO_Mode_AIN 模拟输入
模式:GPIO_Mode_AIN
TTL肖特基触发器
(2)GPIO_Mode_IN_FLOATING 浮空输入
模式:GPIO_Mode_IN_FLOATING
上、下拉都不启用
(3)GPIO_Mode_IPD 下拉输入
模式:GPIO_Mode_IPD
默认低电平
下拉电阻启用
(4)GPIO_Mode_IPU 上拉输入
模式:GPIO_Mode_IPU
默认高电平
上拉电阻启用
小结
上拉输入模式:区别在于没有输入信号的时候默认输入高电平(因为有弱上拉)。下拉输入模式:区别在于没有输入信号的时候默认输入低电平(因为有弱下拉)。对于浮空输入模式顾名思义也就是输入什么信号才是什么信号,对于浮空输入要保证有明确的输入信号。
(5)GPIO_Mode_Out_OD 开漏输出
模式:GPIO_Mode_Out_OD
开漏:有一极处于开路状态(或称为高阻态)
小结:
推挽输出 | 开漏输出 | |
---|---|---|
高电平 | P-MOS激活N-MOS断开,3.3V | P-MOS断开N-MOS断开,外部决定 |
低电平 | P-MOS断开N-MOS激活,0V | P-MOS断开N-MOS激活,0V |
优点 | 直接输出3.3V | 配合外部电路更加灵活 |
缺点 | 只能输出3.3V | 高电平是高阻态,无输出能力 |
(7)GPIO_Mode_AF_OD 复用开漏输出
模式:GPIO_Mode_IPD
管脚复用状态下的开漏输出
(8)GPIO_Mode_AF_PP 复用推挽输出
模式:GPIO_Mode_IPD
管脚复用状态下的推挽输出
GPIO库函数简单说明
- GPIO_DeInit 重新初始化外围设备GPIOx相关寄存器到它的默认复位值
- GPIO_AFIODeInit 初始化交错功能(remap, event control和 EXTI 配置) 寄存器
- GPIO_Init 根据GPIO_初始化结构指定的元素初始化外围设备GPIOx
- GPIO_StructInit 填充GPIO_初始化结构(GPIO_InitStruct)内的元素为复位值
- GPIO_ReadInputDataBit 读指定端口引脚输入数据
- GPIO_ReadInputData 读指定端口输入数据
- GPIO_ReadOtputDataBit 读指定端口引脚输出数据
- GPIO_ReadOtputData 读指定端口输出数据
- GPIO_SetBits 置1指定的端口引脚
- GPIO_ResetBits 清0指定的端口引脚
- GPIO_WriteBit 设置或清除选择的数据端口引脚
- GPIO_Write 写指定数据到GPIOx端口寄存器
- GPIO_ANAPinConfig 允许或禁止 GPIO 4 模拟输入模式
- GPIO_PinLockConfig 锁定GPIO引脚寄存器
- GPIO_EventOutputConfig 选择GPIO引脚作为事件输出
- GPIO_EventOutputCmd 允许或禁止事件输出
- GPIO_PinRemapConfig 改变指定引脚的影射
- GPIO_EMIConfig 允许或禁止GPIO 8 和 9 的EMI 模式
PNP继电器
继电器原理图如下:
1. 工作状态分析
当PE2管脚输出为低电压,PNP三极管发射极(2号管脚)与集电极(3号管脚)导通,PNP三极管的发射极(2号管脚)与基极(1号管脚)导通,此时继电器处于工作状态,LED被点亮。此时继电器JDQ工作(因两侧存在电压差,2号管脚高),此时电流方向为2->1、2->3。
2. 静止状态分析
当PE2管脚输出高电压时,PNP三极管发射极(2号管脚)与基极(1号管脚)不存在电压差,此时电流被断开,不存在电流。继电器关闭,LED不点亮。
上拉电阻、下拉电阻、不上拉也不下拉
1、上拉电阻: 将电路连接到外部电源,提升电压。常用于漏极开路输出
2、不上拉也不下拉: 电路无变化连接到外部电源,常用于推挽输出
3、下拉电阻: 输入低电平
继电器与按钮Demo
案例实现点击key0继电器吸合两秒后自动关闭
mian.c
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "jdq.h"
#include "key.h"
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
JDQ_Init(); //初始化蜂鸣器端口
Key_Init();
while(1)
{
LED1 =0;
JDQ = 1;
delay_ms(100);
if(KEY0 == 0){
LED0 = 0;
JDQ = 0;
KEY0 = 1;
delay_ms(1000);
delay_ms(1000);
}
LED0 = 1;
JDQ = 1;
}
}
led.c
#include "led.h"
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
jdq.c
#include "jdq.h"
//初始化PE2为输出口.并使能这个口的时钟
//继电器初始化
void JDQ_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能GPIOE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //JDQ-->PE.2 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure); //根据参数初始化GPIOE.2
GPIO_ResetBits(GPIOE,GPIO_Pin_2);//设置继电器关闭
}
优化按钮捕捉,检测按钮是否被处于空状态,代码编写提示、对按钮全过程检测
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "jdq.h"
#include "key.h"
int getKey0Static(void);
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
JDQ_Init(); //初始化蜂鸣器端口
Key_Init();
LED1 =0;
JDQ = 1;
while(1)
{
int key0Static = getKey0Static();
if( key0Static == 1){
JDQ=~JDQ;
}
}
}
int getKey0Static(void){
static int key_up = 1;//按钮原位置
if(key_up&&KEY0 == 0){
delay_ms(30);
if(KEY0 ==0){
key_up = 0;
return 1;
}
return 0;
}else if(KEY0==1){
key_up = 1;
return 0;
}
return 0;
}
C语言按位操作
>>= 右移后赋值
例如 x=0x08 x>>=3
计算步骤如下:
- x=0000 1000
- 右移3位0000 0001
- 赋值后为0000 0001
- 结果x=0x01
<<= 左移后赋值
例如 x=0x08 x<<=3
- x=0000 1000
- 左移三位 0100 0000
- 赋值后为 0100 0000
- 结果 x=0x40
&= 按位与后赋值
例如 x=0x08 x &= 0x03
- x = 0000 1000
- 0x03=0000 0011
- end 0000 0000
- 赋值后为 0000 0000
- x=0x00
^= 按位异或后赋值
异或:两个不一样取1,一样取0
例如 x=0x09 x ^= 0x03
- x = 0000 1001
- 0x03=0000 0011
- end 0000 1010
- 赋值后为 0000 1010
- 结果x=0x0A
|= 按位或后赋值
有一个1就取1,两个都为0才取0
例如 x=0x08 x |= 0x03
- x = 0000 1000
- 0x03=0000 0011
- end 0000 1011
- 赋值后为 0000 1011
- 结果x=0x0B
小结
- 或等于(|=)常用于对某一位赋值,因其后给的数与原数或后原数的1保持不变,只改变其他为0的位,
- 与等于(&=)常用来对某一位或多个位清零,引起有0就为0,只有两个1才不为0的特性。要保留1位的就赋1,清除的就赋0
时钟树
- HSE、LSE分别为高速和低速外部时钟,一般为晶振产生。高速外部时钟输入范围为4-16MHz,低速外部时钟为定频40kHz
- HSI、LSI分别为高速和低速内部时钟,一般为内部RC震荡电路产生受温度影响。高速内部时钟为定频8MHz,低速内部时钟为定频32.768kHz
- 红圈2为选择器,选择应用哪个源作为输出时钟信号
- 红圈3为倍频器,将信号倍频x2~x16,
- 红圈5为分频器,将信号分频为/1、/2、/4、/8、/16、/64、/128、/256
设置系统时钟库函数
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
// ① 使能HSE,并等待HSE稳定
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
// 等待HSE启动稳定,并做超时处理
do {
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0)
&&(StartUpCounter !=HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
HSEStatus = (uint32_t)0x01;
} else {
HSEStatus = (uint32_t)0x00;
}
// HSE启动成功,则继续往下处理
if (HSEStatus == (uint32_t)0x01) {
//-----------------------------------------------------------
// 使能FLASH 预存取缓冲区 */
FLASH->ACR |= FLASH_ACR_PRFTBE;
// SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
// 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
// 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
//------------------------------------------------------------
// ② 设置AHB、APB2、APB1预分频因子
// HCLK = SYSCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//PCLK2 = HCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK/2
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
// ③ 设置PLL时钟来源,设置PLL倍频因子,PLLCLK = HSE * 9 = 72 MHz
RCC->CFGR &= (uint32_t)((uint32_t)
~(RCC_CFGR_PLLSRC
| RCC_CFGR_PLLXTPRE
| RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE
| RCC_CFGR_PLLMULL9);
// ④ 使能 PLL
RCC->CR |= RCC_CR_PLLON;
// ⑤ 等待PLL稳定
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
}
// ⑥ 选择PLL作为系统时钟来源
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
// ⑦ 读取时钟切换状态位,确保PLLCLK被选为系统时钟
while ((RCC->CFGR&(uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){
}
} else {// 如果HSE启动失败,用户可以在这里添加错误代码出来
}
}
标签:0000,CFGR,笔记,STM32,Mode,GPIO,uint32,RCC
From: https://www.cnblogs.com/yuknight/p/17602112.html