🚀write in front🚀
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚
🚀Projeet source code🚀
💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com
引用:
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客
STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
江科大STM32学习笔记(上)_stm32博客-CSDN博客
STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客
术语:
英文缩写 | 描述 |
GPIO:General Purpose Input Onuput | 通用输入输出 |
AFIO:Alternate Function Input Output | 复用输入输出 |
AO:Analog Output | 模拟输出 |
DO:Digital Output | 数字输出 |
正文:
0. 概述
从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。
1. GPIO简介
通过配置GPIO的端口配置寄存器,上面的位结构的电路就会根据我们的配置进行改变(比如,开关的通断、N-MOS和P-MOS是否有效、数据选择器的选择等),端口可以配置成以下8种模式。
模式名称 | 性质 | 特征 |
浮空输入 | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定 |
上拉输入 | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 |
下拉输入 | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 |
模拟输入 | 模拟输入 | GPIO无效,引脚直接接入内部ADC |
开漏输出 | 数字输出 | 可输出引脚电平,高电平为高阻态,低电平接VSS |
推挽输出 | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS |
复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS |
复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS |
2.按键简介
按键抖动:由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动
3.传感器模块简介
传感器模块:传感器元件(传感器模块就是利用传感器元件,比如如下图的光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化(比如光线越强,光敏电阻的阻值就越小),通过与定值电阻进行串联分压即可得到模拟电压输出,再通过电压比较器进行二值化(二值化就是要么是高要么是低)即可得到数字电压输出。
这个N1就是传感器元件所代表的可变电阻,它的阻值可以根据环境的光线、温度等模拟两进行变化。
N1上面的R1,是和N1进行分压的定值电阻,R1和N1串联,一端接VCC一端接VSS,这就构成了基本的分压电路,AO电压就由R1和N1两个电阻的分压得到。
AO电压就由R1和N1两个电阻的分压得到。
N1左边的C2是一个滤波电容,它是为了给中间的电压输出进行滤波的,用来滤除一些干扰,保证输出电压波形的平滑。一般我们在电路中遇到一端接到电路中,另一端接地的电容,都可以考虑一下是不是滤波电容的作用,并不是电路的主要框架,这时候我们进行分析电路时,就可以先把这个电容抹掉,这样就可使我们的电路分析更加简单。
二值化输出是通过这个LM393芯片来完成,是一个电压比较器芯片,里面由两个独立的电压比较器电路,然后剩下的是VCC和GND供电,里面电容是一个电源供电的滤波电容,这个电压比较器其实就是一个运算放大器,当同向输入端的电压大于反向输入端的电压时,输出就会瞬间升高为最大值也就是输出接VCC;反之当同向输入端的电压小于反向输入端的电压时,输出就会瞬间降为最小值,也就是输出接GND,这样就可以对一个模拟电压进行二值化了,DO就是最后数字电压的输出。
4.上拉电阻,下拉电阻
可以用上下拉电阻的思维分析传感器电阻的阻值变化对输出电压的影响,如下:
🌷AO这个输出端可以把它想象成一个水平杆子(下图红色直线),R1上拉电阻相当于拴在上方的弹簧,将杆子向上拉,N1下拉电阻相当于拴在地面的弹簧,将杆子向下拉;
🌷电阻的阻值越小,弹簧的拉力就越强,杆子的高度就相当于电路中的电压,杠子向拉力强的一端偏移(取决于两个弹簧的弹力之差);
🌷如果上下弹簧拉力一致,杆子处于居中位置也就是电路输出VCC/2的电压;如果上面的阻值小,拉力强,输出电压就会变高;
🌷反之下面的阻值小,输出电压就会变低 ;如果上下拉电阻的阻值都为0,就是两个无穷大的力在对抗,在电路中呈现的就是电源短路(应该避免)。
🌷单片机电路中会常出现这种上拉下拉电阻,比如弱上拉,强上拉等(强和弱就是指电阻阻值的大小,也就是这个弹簧拉力大小) ,最终输出电压就是在弹簧拉扯下最终杆子的高低。
5.按键和传感器硬件电路
5.1按键电路
下接按键的方式如下,一般来说我们用下接按键的方式,这个原因和LED的接法类似,是电路设计习惯和规范;下左图中,按键按下时,PA0直接下拉到GND,此时读取PA0口的电压就是低电平,在这种接法下,必须要求PA0是上拉输入模式,使按键松下,还是高电平。下右图,外部接了一个上拉电阻,当按键松手时,引脚由于上拉作用,保持为高电平,此时PA0引脚就可以配置为浮空输入或者上拉输入。
上接按键的方式(仅了解)如下,左图1中,要求将PA0必须配置成下拉输入模式,松手时,引脚会回到默认值低电平。
5.2 传感器电路
传感器模块电路如下,DO是数字输出端口,PA0用于读取数字量。
6. 按键控制实验
6.1 模块化LED灯控制
将LED灯控制的程序进行模块话,加到一个专门的文件目录下,在STM32工程下创建一个新的目录 "Hardware",在Hardware目录下创建两个文件 "LED.h" 和 "LED.c"。
现在 LED.c 和 LED.h 中增加控制LED GPIO 引脚 PA0, PA1 的代码,测试LED功能进行初始化是否可以正常工作。
LED.c文件
#include "stm32f10x.h" // Device header
#include "LED.h"void LED_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef gpioInitStructure;gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;gpioInitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1);
}void LED1_On(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}void LED1_Off(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_0);
}void LED2_On(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}void LED2_Off(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
LED.h文件
#ifndef __LED_H__
#define __LED_H__void LED_Init(void);
void LED1_On(void);
void LED1_Off(void);
void LED2_On(void);
void LED2_Off(void);#endif
main.c 文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"int main(int argc, char *argv[])
{ LED_Init();while(1){LED1_On();LED2_Off();Delay_ms(100);LED1_Off();LED2_On();Delay_ms(100);LED1_On();LED2_Off();Delay_ms(100);LED1_Off();LED2_On();Delay_ms(100);LED1_On();LED2_Off();Delay_ms(700);}return 1;
}
实验结果:
6.2 模块下按键检测
模块下按键检测代码,将案件检测的代码模块话为 key.c 和 key.h 文件假如到STM32工程中,这样代码的逻辑更清晰,也方便以后复用按键输入检测的模块。
key.c
#include "stm32f10x.h" // Device header
#include "stdint.h"
#include "Delay.h"
#include "Key.h"void Key_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef gpioInitStruture;gpioInitStruture.GPIO_Mode = GPIO_Mode_IPU;gpioInitStruture.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;gpioInitStruture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpioInitStruture);}uint8_t Key_GetNum(void)
{uint8_t KeyNum = 0;if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){Delay_ms(20); //按键按下消抖while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);Delay_ms(20); //按键松开消抖KeyNum = 1;}if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0){Delay_ms(20); //按键按下消抖while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);Delay_ms(20); //按键松开消抖KeyNum = 2;}return KeyNum;
}
key.h
#ifndef __KEY_H__
#define __KEY_H__void Key_Init(void);
uint8_t Key_GetNum(void);#endif
在 led.c 中加入LED灯点亮和熄灭的翻转(Toggle)函数,LED翻转函数中使用 STM32 库函数中的GPIO的输出模式下的‘输出读入函数’:GPIO_ReadOutputDataBit()来获取当前GPIO的输出,然后进行翻转。
led.c
#include "stm32f10x.h" // Device header
#include "LED.h"void LED_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef gpioInitStructure;gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;gpioInitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1);
}void LED1_On(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}void LED1_Off(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_0);
}void LED1_Toggle(void)
{if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == 0){GPIO_SetBits(GPIOA, GPIO_Pin_0);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_0);}
}void LED2_On(void)
{GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}void LED2_Off(void)
{GPIO_SetBits(GPIOA, GPIO_Pin_1);
}void LED2_Toggle(void)
{if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0){GPIO_SetBits(GPIOA, GPIO_Pin_1);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_1);}
}
main.c 中循环检测按键的按下
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"uint8_t KeyNum = 0;int main(int argc, char *argv[])
{ LED_Init();Key_Init();while(1){KeyNum = Key_GetNum();if(KeyNum == 1){LED1_Toggle();}else if(KeyNum == 2){LED2_Toggle();}}return 1;
}
实验结果:
按下按键1,LED1点亮,再按下按键1,LED1熄灭。
按下按键2,LED2点亮,再按下按键2,LED2熄灭。
7.光敏传感器控制蜂鸣器实验
光敏传感器控制蜂鸣器实验,当光敏传感器光线较亮时光敏传感器 DO(数字输出)接口输出高电平,当光敏传感器光线较暗时光敏传感器 DO(数字输出)接口输出低电平同时光敏传感器上的‘DO-LED’指示灯变亮,可以根据光敏传感器上的‘DO-LED’指示灯判断光敏传感器输出是高电平还是低电平。
源码如下
buzzer.c 蜂鸣器模块源码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Buzzer.h"#include "stm32f10x.h" // Device header
#include "LED.h"void Buzzer_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef gpioInitStructure;gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;gpioInitStructure.GPIO_Pin = GPIO_Pin_12;gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpioInitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_12);
}void Buzzer_On(void)
{GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}void Buzzer_Off(void)
{GPIO_SetBits(GPIOB, GPIO_Pin_12);
}void Buzzer_Toggle(void)
{if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0){GPIO_SetBits(GPIOB, GPIO_Pin_12);}else{GPIO_ResetBits(GPIOB, GPIO_Pin_12);}
}
buffer.h
#ifndef __BUZZER_H__
#define __BUZZER_H__void Buzzer_Init(void);
void Buzzer_On(void);
void Buzzer_Off(void);
void Buzzer_Toggle(void);#endif
光敏传感器模块源码, Lightsensor.c
#include "stm32f10x.h" // Device header
#include "stdint.h"
#include "Delay.h"
#include "Lightsensor.h"void Lightsensor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef gpioInitStruture;gpioInitStruture.GPIO_Mode = GPIO_Mode_IPU;gpioInitStruture.GPIO_Pin = GPIO_Pin_13;gpioInitStruture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpioInitStruture);}uint8_t Lighsensor_Get(void)
{return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}
Lightsensor.h
#ifndef __LIGHT_SENSOR_H__
#define __LIGHT_SENSOR_H__void Lightsensor_Init(void);
uint8_t Lighsensor_Get(void);#endif
根据光敏传感器的输出来控制蜂鸣器的鸣叫,当光线亮时光敏传感器输出高电平,此时控制蜂鸣器关闭;当光线暗时光敏传感器输出低低电平,此时控制蜂鸣器鸣叫。
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "Buzzer.h"
#include "Lightsensor.h"uint8_t KeyNum = 0;int main(int argc, char *argv[])
{ LED_Init();Key_Init();Buzzer_Init();Lightsensor_Init();while(1){if(Lighsensor_Get() == 1){Buzzer_On();}else{Buzzer_Off();}}return 1;
}
实验结果:
光线亮时,光敏传感器输出高电平,光敏传感器DO-LED指示灯点亮
光线暗时,光敏传感器输出低电平,光敏传感器DO-LED指示灯点灭