马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
写这个文章是用来学习的,记载一下我的学习过程。渴望我能不绝对峙下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.04.03
前言
本次条记是用来记载我的学习过程,同时把我必要的困难和思考记下来,有助于我的学习,同时也作为一种风俗,可以督促我学习,是一个鼓励自己的过程,让我们开始32单片机的学习之路。
欢迎各人给我提意见,能给我的嵌入式之旅提供方向和门路,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
在这里会记载下江协科技32单片机开辟板的配套视频教程所作的实行和学习条记内容,由于我之前有一个开辟板,我大概率会用我的板子模仿着来做.让我们一起加油!
别的为了增强我的学习结果:每次条记把我不知道大概题目在反面提出来,再下一篇开头作为解答!
开辟板分析
本人接纳的是慧净的开辟板,由于这个板子是我N年前就买的板子,索性就拿来用了。别的我也购买了江科大的学习套间。
原理图如下
1、开辟板原理图
2、STM32F103C6和51对比
3、STM32F103C6焦点板
视频中的都用这个开辟板来实现,如果有资源就利用起来。别的也筹划实现江协科技的套件。
下图是实物图
引用
【STM32入门教程-2023版 过细解说 中笔墨幕】
还参考了下图中的册本:
STM32库开辟实战指南:基于STM32F103(第2版)
数据手册
解答和科普
一、外部克制代码
DO数字输出端,恣意接一个GPIO,当我们的挡光片大概编码器在对射式红外传感器中心颠末时,这个DO就会输出电平跳变的信号,就会触发STM32 PB14口的克制,我们在克制函数中,实行变量++的步伐,然后主循环里调用OLED表现这个变量。
第一步,设置RCC,把我们这里涉及的外设的时钟都打开
第二步,设置GPIO。选择我们的端口为输入模式
第三步,设置AFIO,选择我们用的这一起GPIO,毗连到反面的EXTI
第四步, 设置EXTI,选择边沿触发方式,比如上升沿、降落沿大概双边沿
另有选择触发相应方式,可以选择克制相应和变乱相应
第五步,设置NVIC,给我们这个克制选择一个符合的优先级,末了通过NVIC,外部克制信号就能进入CPU了。
如许CPU才气收到克制信号,才气跳转到克制函数里实行克制步伐。
设置时钟
- void CounterSensor_Init(void) //外部中断配置
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启APB2的GPIOB的外设时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启APB2的AFIO的时钟
- //接着还有EXTI和NVIC两个外设:这两个外设时钟一直都是打开着的,不需要我们再开启时钟了
复制代码 EXTI和NVIC这两个外设的时钟是不绝都制开着的,不必要我们再开启时钟了.
NVIC是内核的外设,内核的外设都是不必要开启时钟的,和CPU一起住在皇宫里的。
设置GPIO
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入默认高电平
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOB,&GPIO_InitStructure);
复制代码 对于克制来说:要选择浮空输入、上拉输入、大概下拉输入。这此中的一个模式(可以看参考文档)
设置AFIO
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource8);
复制代码 当实行完这个函数后,AFIO的第8个数据选择器就拨好了,此中输入端被拨到了GPIOA外设上,对应的就是PA8引脚,输出端固定毗连的是EXIT的第8个克制线路,如许PA8引脚的电平信号就可以顺遂通过AFIO,进入到后级EXTI电路了。
设置EXTI
对于标志位,有的比力告急,在指标值位后会触发克制,在克制函数里,如果你想检察标志位和扫除标志位,就用下面两个函数;
以是你现在主步伐里检察和扫除标志位,就用上面两个函数;
如果想在克制函数里检察和扫除标志位,就用下面两个函数。
都是读写寄存器,只不外下面两个函数只能读写与克制有关的标志位,而且对克制是否允许做出来判定,而上面的这两个函数只是一样平常的读写标志位,没有额外的处置惩罚,能不能触发克制的标志位都能读取,以是发起主步伐用上面两个,克制步伐里用下面两个。只不外是举行了区分。
- EXTI_InitTypeDef EXTI_InitStructure;
- EXTI_InitStructure.EXTI_Line=EXTI_Line8 ;
- EXTI_InitStructure.EXTI_LineCmd=ENABLE;
- EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;
- EXTI_Init(&EXTI_InitStructure);
复制代码 现在的设置是:将EXTI的第8个线路设置为克制模式,降落沿触发,然后开启克制,如许PA8的电平信号就能通过EXTI通向下一级NVIC了。
设置NVIC
NVIC是内核外设,以是它的库函数是被ST发配到杂项这里来了,打开misc.h文件
1、分组
2、设置一下初始化参数
界说不在本文件在stm32f10x.h文件
克制通道列表
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //只能用一组,放在模块中进行分组,要确保每个模块分组都选的同一个
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel= EXTI15_10_IRQn ;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
- NVIC_Init(&NVIC_InitStructure);
复制代码 外部克制函数设置完成
外部信号从GPIO到AFIO,再到EXTI,再到NVIC,终极通向CPU,如许才气让CPU由主步伐跳转到克制步伐实行。克制步伐应该放到那里呢?
克制函数
在STM32中,克制函数都是固定的,每个克制通道都对应一个克制函数,克制函数的名字可以参考一下启动文件,
这就是克制函数的格式,克制函数都是无参无返回值的,克制函数名字不要写错了,写错了就进不了克制了,最好是直接从启动文件复制过来,如许就不会有题目。
在克制函数里,一样平常都是先举行一个克制标志位的判定,确保是我们想要的克制源触发的这个函数,由于这个函数EXTI5和EXTI9都能进来,以是要先判定是不是我们想要的EXTI8进来的,
这个时间就必要去exti.h看一下,
- if(EXTI_GetITStatus(EXTI_Line8)==SET)
- {
-
- }
复制代码 判定一下是不是返回值为SET,如果是的话,我们就可以实行克制步伐了,末了克制步伐竣事后,肯定要调用一下扫除克制标志位的函数,由于只要克制标志位置1了,步伐就会跳转到克制函数,如果你不扫除克制标志位,那它就会不绝申请克制,如许步伐就会不绝相应克制,实行克制函数,那么步伐就卡死在克制函数里了,以是我们每次克制函数竣事后,都应该扫除一下克制标志位。
- void EXTI9_5_IRQHandler (void)
- {
- if(EXTI_GetITStatus(EXTI_Line8)==SET)
- {
-
-
- EXTI_ClearITPendingBit(EXTI_Line8);
- }
-
- }
复制代码 测试能不能进入克制
将 Dialog修改为DARMSTM.DLL Parameter修改为-pSTM32F103C8(这里请根据你的芯片填写型号)
main.c
- #include "stm32f10x.h" // Device header
- #include "Delay.h"
- #include "LED.h"
- #include "Key.h"
- #include "OLED.h"
- #include "CountSensor.h"
- int main(void)
- {
-
- OLED_Init();
- OLED_ShowString(1,1,"Hello STM32 MCU");
- OLED_ShowString(2,1,"Count:");
- CounterSensor_Init();
- while(1)
- {
-
- OLED_ShowNum(2,7,CounterSensor_Get(),5);
- }
- }
复制代码 Key.C和H
- #include "stm32f10x.h" // Device headeruint16_t CounterSensor_Count;void CounterSensor_Init(void) //外部克制设置{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启APB2的GPIOB的外设时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启APB2的AFIO的时钟 //接着另有EXTI和NVIC两个外设:这两个外设时钟不绝都是打开着的,不必要我们再开启时钟了 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入默认高电平 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource8);
- EXTI_InitTypeDef EXTI_InitStructure;
- EXTI_InitStructure.EXTI_Line=EXTI_Line8 ;
- EXTI_InitStructure.EXTI_LineCmd=ENABLE;
- EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;
- EXTI_Init(&EXTI_InitStructure);
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //只能用一组,放在模块中举行分组,要确保每个模块分组都选的同一个 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel= EXTI9_5_IRQn ; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStructure); }uint16_t CounterSensor_Get(void){ return CounterSensor_Count;}void EXTI9_5_IRQHandler (void){ if(EXTI_GetITStatus(EXTI_Line8)==SET) { CounterSensor_Count++; EXTI_ClearITPendingBit(EXTI_Line8); } }
复制代码- #ifndef __COUNT_SENSOR_H
- #define __COUNT_SENSOR_H
- void CounterSensor_Init(void);
- uint16_t CounterSensor_Get(void);
- #endif
复制代码 实现征象
按键触发外部克制,实现计数加1,降落沿触发,感觉按键必须得到场消抖步伐。
按键触发外部克制计数加1
二、旋转编码器计次
旋转编码器,下面这两个A,B相的输出引脚,分别接到了STM32的PB0和PB1两个引脚。
正向旋转时,A,B相输出的是如许的波形,反向旋转时,输出是下面的波形,如果把一相的降落相沿作触发克制,在克制时间读取另一相的电平,正转就是高电平,反转就是低电平,如许就能区分旋转方向了,这不外有一点小瑕疵;
A,B相都触发克制,只有在B相降落沿和A相低电平常,才判定为正转,在A相降落沿和B相低电平常,才判定为反转,如许就能包管正转和反转都是转到位了,才实行数字加减的操纵,同时也演示一下两个克制的初始化代码。
main.c
- #include "stm32f10x.h" // Device header
- #include "Delay.h"
- #include "LED.h"
- #include "Key.h"
- #include "OLED.h"
- #include "Encoder.h"
- int16_t Num;
- int main(void)
- {
-
- OLED_Init();
- Encoder_Init();
-
- OLED_ShowString(1,2,"Hello STM32 MCU");
- OLED_ShowString(2,1,"Num:");
- while(1)
- {
- Num+=Encoder_Get(); //Get是旋转编码器产生的正负脉冲数,所以这个返回值+=Num,就能对Num进行加减操作了
- OLED_ShowSignedNum(2,5,Num,5);
-
- }
- }
复制代码 Encoder.c和h
- #include "stm32f10x.h" // Device header
- int16_t Encoder_Count;
- void Encoder_Init(void)
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启APB2的GPIOB的外设时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启APB2的AFIO的时钟
- //接着还有EXTI和NVIC两个外设:这两个外设时钟一直都是打开着的,不需要我们再开启时钟了
-
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入默认高电平
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOB,&GPIO_InitStructure);
-
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); //
-
- EXTI_InitTypeDef EXTI_InitStructure;
- EXTI_InitStructure.EXTI_Line=EXTI_Line0|EXTI_Line1 ; //
- EXTI_InitStructure.EXTI_LineCmd=ENABLE;
- EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;
- EXTI_Init(&EXTI_InitStructure);
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //只能用一组,放在模块中进行分组,要确保每个模块分组都选的同一个
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQn ;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
- NVIC_Init(&NVIC_InitStructure);
-
- NVIC_InitStructure.NVIC_IRQChannel= EXTI1_IRQn ;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
- NVIC_Init(&NVIC_InitStructure);
-
- }
- int16_t Encoder_Get(void) //返回变化值用于外部加减一个变量
- {
- int16_t Temp;
- Temp=Encoder_Count;
- Encoder_Count=0;
- return Temp;
- }
- void EXTI0_IRQHandler(void)
- {
- if(EXTI_GetITStatus(EXTI_Line0)==SET)
- {
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))
- {
- Encoder_Count--;
-
- }
- EXTI_ClearITPendingBit(EXTI_Line0);
- }
- }
- void EXTI1_IRQHandler(void)
- {
- if(EXTI_GetITStatus(EXTI_Line1)==SET)
- {
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0))
- {
- Encoder_Count++;
- }
- EXTI_ClearITPendingBit(EXTI_Line1);
- }
- }
复制代码- #ifndef __ENCODER_H
- #define __ENCODER_H
- void Encoder_Init(void);
- int16_t Encoder_Get(void);
- #endif
复制代码 实行征象
旋转编码器计次
**第一个就是,在这个克制函数里。最好不要实行耗时过长的代码,:克制函数要简短快速。别刚进克制就实行一个Delay多少毫秒如许的代码, 由于克制是处置惩罚突发的变乱。如果你为了一个突发的变乱待着克制里不出来了, 那主步伐就会受到严峻的壅闭。
别的就是。最好不要在克制函数和主函数调用雷同的函数大概操纵同一个硬件, 如果你既在主步伐里调用OLED。又在克制里调用OLED, OLED就会表现错误。
在主步伐中,OLED刚表现一半,然后就进克制了,结果克制还是OLED表现函数,那OLED就挪到其他地方表现了,这时还没有题目,但当克制竣事后,必要继承原来的表现,这时就出现题目了, == 由于硬件的表现位置被挪到其他位置了==,以是再返来的时间,继承表现的内容就会跟着跑到其他地方去,这就会造成题目,固然克制有掩护现场和规复现场,但这只能包管CPU步伐能正常返回不出题目,对于外部硬件的话,并没有在进入克制时,举行现场掩护,以是克制返回后,就出现题目了。
末了不要在主函数和克制函数里,操纵大概产生辩论的硬件,在实现功能的时间,可以在克制里操纵变量大概标志位,当克制返回时,我再对这个变量举行表现和操纵。
如许既可以大概包管克制函数的简单快捷,又能包管不产生辩论的硬件操纵,这就是克制步伐筹划的注意事项。可以多用用变量大概标志位,来镌汰代码之间的耦合性,让部分代码相互独立,仅利用变量、标志位大概函数作为接口,如许能让步伐更加清楚,代码更增矫健。
题目
1、按键克制能不能消抖
总结
本节课重要是了学习了克制的代码实现,表现举行设置NVIC的整个门路买通,第一步,设置RCC,把我们这里涉及的外设的时钟都打开第二步,设置GPIO。选择我们的端口为输入模式第三步,设置AFIO,选择我们用的这一起GPIO,毗连到反面的EXTI第四步, 设置EXTI,选择边沿触发方式,比如上升沿、降落沿大概双边沿另有选择触发相应方式,可以选择克制相应和变乱相应第五步,设置NVIC,给我们这个克制选择一个符合的优先级,末了通过NVIC,外部克制信号就能进入CPU了。
然后另有设置两个克制时的操纵,也是打来有的地方也是可以|,有的必要单独设置,再写一行打开所必要的时钟。
|