这几天的碎碎念
这两天还在捣鼓单片机,以及esp8266wifi模块,每次在学这些东西以及想上手的时候,总有几个知识点是我卡住的,包括我在看视频的时候也种有几个知识点是up主理所当然以为我们知道的,但是我却会因为这一块的知识点不理解而卡住,所以我现在还没有正式将esp8266连接上云。
今天看了会儿《纳瓦尔宝典》这本书,里面一句话给我的启发很大
“只有掌握好基础知识,才能不忌惮任何书籍。如果在图书馆找到一本自己无法理解的书,那么你先要了解读懂这本书需要那些基础知识,打好基础后再深入研究。基础是极为重要的。”
从大二上册开始,我觉得学习任何东西直接上手就行了,我觉得很多东西不需要经过太多的路径才说适合我们去做,就是“项目式学习”,所以那个时候起,我学习乐器,学习代码都是直接上手的,这也使我在学习的过程中,学习的耐心逐渐变得急躁,很多东西开始选择忽略,只是大概了解一下或者还没有完全理解就跳过,导致我在后面的学习碰壁。
我不想否认我的学习方式,对我的影响就是,得承认基础很重要,重视每一个我没弄明白的知识,重视每一个模糊的地方,要基于我想实现的目标来弥补我的基础。
知识是网状的,但网也是分层的
说多了,简单分享一下最近的学习。
一. STM32学习(PWM代码篇)
前几天更新了PWM的原理(暑假嵌入式自学笔记 Day1-CSDN博客),还有STM32的定时器外设是如何输出PWM信号的(暑假嵌入式自学笔记 Day2-CSDN博客),今天学习的重点在“怎么通过代码来控制单片机输出PWM信号”
今天做的项目是跟着江科大的STM32的教程“PWM驱动呼吸灯”实现的,同时在这次学习中,我还发现手册还是很有用的。
今天这个项目要实现的目标是这样的
PWM驱动呼吸灯
我们可以看到LED灯是暗亮变化的,这个就是今天要是实现的很简单的项目(感觉代码还挺复杂的)
提前申明一下,后面很多出现的图片都出自江科大的PPT,以及他们所分享的资料,感谢江科大的教程QvQ(避免每次用图片的时候都要声明)
1.大致思路讲解
这个是我们STM32的外设TIM(定时器)的原理图
其中主要控制着PWM输出的就是我红色框框圈住的那一块,我们用这幅图来简化一下这一块,这幅图也是我们编写PWM的一个重要参照。
对照着原理图,上面是时基单元,下面是输出比较单元(都连接在时基单元的CNT下)
所以我们的思路是这样,
1,开启片上外设的时钟:GPIO,TIM等(基本上这都是第一步)
2,配置TIM的时基单元
3,配置输出比较单元
4,配置GPIO口的模式
5,运行控制
对应接线图如下:实物接线图如下
2.代码详解及分析
首先,我假如大家之前的课都听过了,或者有一些些用keil编写STM32的基础。
那么我们要编写PWM这一块的代码,肯定不会在main函数里面去编写,会创建两个同名文件,一个C文件(PWM.c)负责编写主代码,一个库文件(PWM.h)负责存放我们C文件的代码,后面我们在main.c文件里面直接调用就好了,同时我们将这两个文件存放进Hardware文件里面。
首先在C文件里面编写代码,在我们导入了STM32标准库函数以后,首先初始化一个函数,
void PWM_Init(void)
{
代码内容
}
而后根据我们的思路来写代码,
第一,开启片上外设的时钟:GPIO,TIM等
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
第二,配置TIM的时基单元
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
第三,配置输出比较单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
//则最好执行此函数,给结构体所有成员都赋一个默认值
//避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
第四,配置GPIO口的模式
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出
//受外设控制的引脚,均需要配置为复用模式
第五,运行控制
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
这是我们大致的代码,其实我们能发现,在配置很多外设上的时候,我们都会用到结构体来配置,在我们写代码的时候,我们最多只需要知道要做什么,平时常用到哪些代码,能够通过我们的库函数来找到并调用就好了,以及我们可以查询我们的函数库文件,了解每一个函数具体是怎么用的,现在很多模块封装得比较好,我们大部分会用就好
PS:托更了好几天,就是我这几天懒了,同时在写这篇文章的时候草稿已经打好了,想写得长一点,但是最后还是因为自己没有维持好这个习惯而脱了好久
这几天也确实在学习,但是并没有整理成博客,导致我感觉这几天学了什么也不太清楚,后面得坚持下来了,每天留点固定时间来整理博客试一试