写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.04.02
前言
本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!
开发板说明
本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
原理图如下
1、开发板原理图
2、STM32F103C6和51对比
3、STM32F103C6核心板
视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。
下图是实物图
引用
【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
数据手册
解答和科普
一、LED闪烁
新建一个工程,需要新建Start、Library、User
1、创立Start文件夹:文件从Libaries-CMSIS-CM3-DeviceSupport-ST-STM32F10x-startup-arm,这些就是STM32的启动文件,STM32的程序就是从启动文件开始执行的。
然后startup文件夹同级的stm32f10x.h(STM32外设寄存器描述文件和51单片机RGEX52.H一样);这两个system文件是用来配置时钟的,STM32主频72MHz,就是system文件里的函数配置的。
STM32是内核和内核外围的设备组成的,所以还要加入一个内核寄存器的描述文件:DeviceSupport同级的Libaries-CMSIS-CM3-CoreSupport中的两个cm3就是内核的寄存器描述
2、Library存放库函数:打开固件库Libaries-STM32F10x_StdPeriph_Driver(标准外设驱动)-src中的文件,其中misc是内核的库文件,其他的就是内核外的外设库函数
打开固件库的inc文件夹,这些是库函数的头文件,继续ctrl+A全选
3、User文件夹: 打开固件库文件夹,打开Project-STM32Template,选择main、stm32f10x_conf.h和两个it结尾的文件,conf文件是用来配置库函数头文件的包含关系的,还有用来参数检查的函数定义,这是所有库函数都需要的,两个it文件是用来存放中断函数的。
工程文件复制完成
在keil创建三个组:Start、Library、User、添加文件;
Start文件添加带md.s,然后选择其他的.c.h文件,选择并添加
Library是all files Ctrl+A全选
User也是一样all files Ctrl+A全选
注意要留有空行
批处理文件可以把工程编译产生的中间文件都删掉
1.1控制LED的亮灭
#include "stm32f10x.h" // Device header
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//GPIO_SetBits(GPIOA,GPIO_Pin_0);
while(1)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
}
}
1.2LED闪烁
用到延迟函数
用SysTick定时器来实现的延迟,具体怎么实现的,暂时不用管。直接拿来用。
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
实验现象
LED闪烁
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//GPIO_SetBits(GPIOA,GPIO_Pin_0);
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
Delay_ms(500);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
Delay_ms(500);
}
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//GPIO_SetBits(GPIOA,GPIO_Pin_0);
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
Delay_ms(500);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0); //强制转换类型为BitAction
Delay_ms(500);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1); //强制转换类型为BitAction
Delay_ms(500);
}
}
推挽输出的驱动能力
在推挽模式下,高低电平都是有驱动能力的。
一般输出就用推挽输出就行了。
二、LED流水灯
0000 0000 0000 0001
0000 0000 0000 0010
0000 0000 0000 0100
0000 0000 0000 1000
…
1111 1111 1111 1111
为1就是选择哪个引脚,如果是按位|就是把响应为置1,也就是选择相应的引脚,all是全部是1,也就是选中所有的引脚。
也是可以选择多个时钟按位|
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//GPIO_SetBits(GPIOA,GPIO_Pin_0);
while(1)
{
GPIO_Write(GPIOA,~0x0001); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0002); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0004); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0008); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0010); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0020); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0040); //0000 0000 0000 0001
Delay_ms(500);
GPIO_Write(GPIOA,~0x0080); //0000 0000 0000 0001
Delay_ms(500);
}
}
流水灯可以改变数据,或者定义一个数组,依次取出数组中的数据来进行花式点灯。
实验现象
LED流水灯
三、蜂鸣器
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//GPIO_SetBits(GPIOA,GPIO_Pin_0);
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_4);
Delay_ms(500);
GPIO_SetBits(GPIOB,GPIO_Pin_4);
Delay_ms(500);
}
}
问题是我这个蜂鸣器好像是B4,因为这个引脚是用来调试的,好像需要重新映射,所以我好想不能直接这样,哭了。
新的来了
我如果想完成就可以直接用杜邦线连起来,我真的哭死,甚至在这里我根本没必要买这个32开发板,只需要用外设就行了,我的乖乖,现在才明白,好像只需要处理好电源,就可以连接了。
因为外面有排针,这样的话,我能在一定程度上控制。
问题
1、就是复用功能,比如B4如何用作普通IO口。
总结
本节课主要是学习了如和配置时钟,配置引脚当然可以一下子选中多个引脚,进而还有生成的延迟函数,完成了点灯和流水灯,不解的是如何把有功能的配置成普通IO口。还有生成的延迟函数。