个人成就
- 发布了50篇内容
- 获得了4次赞同
- 获得了3次收藏
个人简介
擅长领域
暂时没有设置哦~
-
STM32学习回忆录---------第3次写流水灯程序
这是我第3次用STM32写流水灯程序了,感触颇深,想和大家分享我学习STM32的故事。
初次相识STM32
2008年春天的第一场雪,来的比往年更大一些,这个春节,我留在深圳,无法回到河南。我在街上乱逛,无意间看到公交站台上的广告,深圳会在春季举办IIC (国际集成电路)大会,那是我刚刚大学毕业,学的是芯片制造专业,所以我决定参加。
到那一天,在会展上,我看到了国外IC的先进制程,心想中国再过几年也会达到这个水平吧。
后来,我看到了一个蝴蝶展厅,那是STM32展馆,我感觉这个芯片不错。这是我和STM32的初次相识。
几年以后,STM32在国内迅速火了起来,因为我的专业在国内很难找到工作,我决定学习STM32。
第1次学习STM32
培训地点: 河南郑州,时间: 2013年,学习方式:线下。
这是我第1次用STM32写流水灯,也是第一次用库函数,使用的芯片是STM32F103,用库函数的方式写流水灯,终于告别了寄存器,当时认为这是一种先进的方法,因为使用起来相当方便,想着以后单片机就不用查寄存器了,这是单片机历史上的伟大跨越。这个老师的教学方式是直接使用库函数,没有讲过库函数。在学习中,查错是一件让我头痛的事情,没有用过单步仿真,出现问题不知道,错在哪里,库函数固然好用,但库函数无法找出错误。使用printf(),有效果,但效果有限。我的这个老师非常诚实,我有不会的问题,他能给我解决就解决了,解决不了,老师就会说:“这个我也不会” !
第2次学习STM32
培训地点: 广东深圳,时间: 2016年,学习方式:线下。
这是我第2次用STM32写流水灯,也是用库函数的方式,使用的芯片是STM32F103。这个老师的水平要高一些,他把用到的库函数都讲了一遍,但是很少讲解寄存器。当我写流水灯程序的时候,我不仅会用库函数,而且还能够看懂库函数。当时觉得官方的库函数写的太好了,我不禁为官方点赞!。我问老师,这个启动代码能不能讲一下,老师说:你会用就行了,启动代码官方已经为你写好了,你不用知道为什么,你需要知道哪个是F1 的启动代码就可以了。出现错误的时候,依然没有查看寄存器和变量,用的是printf(),来进行调试,排查错误还是让人头疼。
4月份的时候,我参加了STM32深圳峰会,官方介绍了CubeMx ,并说这是一种比库函数还方便的图形化编程方法,我认为汇编语言过时了,用C语言查寄存器的方法也过时了,现在STM32用的是库函数,但这种方法必将被CubeMx 所代替,因为随着编程技术的不断发展,新的技术必然会取代旧的技术。
随着STM32 学习的深入,我开始学习一些高大上的东西,例如 触摸屏CAN SDIO 文件系统 USB等,难度太大了,我陷入其中,无法自拔。
第3次学习STM32
培训地点: 河南老家,时间2021年,学习方式:线上。
学了单片机两个月了,以流水灯为例,学到了前两次所没有学到的东西,因此感悟大不相同。
1. 对寄存器的操作,就是往正确的地址写或读正确的数据。有点像送快递的,找到地址送或收快递。
2. 能够被编译器发现的错误,解决比较容易,而能通过编译,却不能实现期望的功能,这种错误往往要费点时间,这个需要单步仿真,查看寄存器或变量值,此便对错误进行定位,因此必须缩小代码的范围,从工程到文件,到函数,到语句,这个有点像修电路板,从电路板到单元电路,最终找到坏的那个元器件。有些情况下,即便通过单步调试,但当整个程序运行时,还是无法实现功能。这时,还要对程序进行优化,直到实现期望的功能。自己的程序出现错误,自己检查几遍都检查不出来,但是交给别人,别人很快就能找到问题,可是问题来了,自已必须具备查错的能力,因为别人不可能总为你查错。
3.即然编译器可以把C语言翻译为汇编语言,那么写程序的人也能够这样,汇编语言有一定的难度,不是面向人的,那么就可以用面向人的C语言,去翻译成汇编语言,用C语言作为桥梁,就可以大大降低难度。不得不承认,汇编语言在一些场合,还是要用到的,无法替代,例如有的8位单片机,或者FOC中。以前,我认为学习单片机,跳过汇编语言,跳过寄存器,是一种好的方法,但事实并非如此!而操作寄存器是一种通用的方法,不受库函数的依赖,换了单片机,依旧可以很快上手!
我感觉这两个月确实收获很大,报这个单片机线上班我觉得很值,比前两个靠谱多了,因为我发现:我再也不用走弯路了!
河南学员
2021/3/26
-
【重磅】在这 一芯难求 各种涨价的时代,STM32G0闪亮登场了........
由于芯片制造工艺的区别,STM32G0被委以重任,撑起一片天,据我从官方了解的情况可以得出一个结论,不管从价格上还是从性能上STM32G0都可以用来代替STM32F0,我们话不多说直接来看看它的区别:
一:我们从外部封装引脚上来看
G0没有F0的100PIN的封装,但是它增加了SO8封装的引脚,这样的话性能很强大,价格很有诱惑力,极具性价比。
二:我们从外设配置资源来看:
1. 内核更高级:F0:Cortex-M0内核,主频高达48MHZ;G0:Cortex-M0+内核,主频高达64MH,主频高,程序运行更快!
2. G0的FLASH存储器方面有缩小,SRAM方面有扩展。
4. ADC速率更高,F0:ADC时钟频率提高到14Mhz,G0:ADC时钟频率提高到16Mhz,G0的AD模拟采样转换速率更快。举例:(1.5为采样周期,12.5为转换周期)
G0:With ADC_CLK = 16 MHz and a sampling time of 1.5 ADC clock cycles:
Tconv = 1.5 + 12.5 = 14 ADC clock cycles = 0.875 µs
F0:With ADC_CLK = 14 MHz and a sampling time of 1.5 ADC clock cycles:
Tconv = 1.5 + 12.5 = 14 ADC clock cycles = 1 µs
5. 外设资源更丰富,增加了AES加密单元、普通定时器单元、硬件随机数RNG单元、DMA多路复用请求仲裁单元,可编程映射DMA请求,好处是使DMA通道对应的外设更加灵活,不再受限、低功耗串口等,更加安全高效。当然相比之下也有牺牲,比如说全速USB2.0,串口数量、CAN等。
三:我们从系统架构上来瞧瞧看:
1. F0的AHB2总线消失了,引入了新的IOPORT总线,STM32F0的GPIO Ports由总线矩阵通过AHB2总线访问,STM32G0的GPIO Ports直接挂在IOPORT总线上,CPU可直接访问,速度更快!
2. STM32F0的外部中断EXIT模块由总线矩阵通过AHB1总线->(AHB->APB桥)来访问,STM32G0的外部中断EXIT模块由总线矩阵通过AHB1总线直接访问,速度更快!
四:从时钟来看:
由于内核使用区别,两款芯片的RCC时钟也略有区别,如上图所示,主要体现在内部的时钟资源及频率差异,最大主频差异以及复位后的系统时钟频率差异。
五:从电源供电来看
供电电压范围更宽,G0:1.6V-3.6V F0:1.8V-3.6V,相比之下G0的低功耗睡眠模式更加出色。
六:最后跟大家看一下M0和M0+内核的区别
除了上面展示的内容之外,还有部分区别未展示,比如说中断向量表的内容有改变,G0支持向量表位置重定义、低功耗改善等等、其中不得不提到一点相比F0,G0增加了内部外设的互联功能,通过配置外设中间可直接互联,可以减小CPU额外开销!
-
看完这篇,SPI其实也很简单嘛
首先我们来简单介绍一下SPI,SPI是串行外设接口(Serial Peripheral Interface),简单来讲就是它一种高速的,全双工,同步的通信总线。
那么被各种总线搞的晕头转向的人来说就会问了,为什么要弄那么多种总线?太难了。一会I2C,一会SPI;一会内部总线,一会外部总线。
碰到总线这样的字眼,千万别急,通过接触你会发现都有各自的特点,通过实践了你才会真正理解这些总线的用途,那么我们今天就来聊一聊SPI。
下面我们来看一下SPI的框图,我们从框图上来介绍SPI通信的原理
1. SPI传输需要有一个时钟,因为他是同步通信,所以连接引脚有串行时钟SCK
2. SPI以主从方式工作,通常有一个或者多个从设备连接。所以MOSI,M是主机,S就是从机,从机输入,所以叫MOSI,I就是input输入的意思,那么MISO也是一样的原理。
3. NSS就是片选,是SPI从设备是否被选中的,只有片选信号为预先规定的使能信号时(高电位或低电位),对此 SPI 从设备的操作才有效。如果从机没有被选中,主机发送数据从机是不会接收的。
4. Rx FIFO,Tx FIFO:发送缓冲和接收缓冲,当高速通信的时候,数据来不及处理就可以放在缓冲区里面,可以节省一定的时间去处理其他事情。
5. CRC controller:CRC校验,是一种数据检测方式。
6. Communication controller:SPI的主控模块,从框图中我们得到一些重点信息,就是关于寄存器的配置信息。时钟输出波特率受BR[2:0],这3个位来控制。
以上就是单片机整个的SPI通信的架构,只有这些配合工作才能实现SPI通信。单片机SPI一般作为主机工作,那么参数配置就需要从机的一些信息了。那么看到这里大家可能觉得这不算讲了SPI啊,我还不懂怎么应用啊,没关系,上面只是简单介绍,知道基本信息了再去实现不就容易多了嘛。
首先既然有时钟,那么就存在时钟极性的问题,既然有从机,那么可以根据从机的时钟极性来设置主机的,保持一致就好了,相当于相约好规则。
SPI的时钟极性(哪种电平状态是有效的):
CPOL为0的时候,空闲状态(不传输数据的时候)是低电平,CPOL为1的时候,空闲状态是高电平;两种时钟极性是相反的
其次时钟频率,波特率表示每秒钟发送多少位数据,可以根据波特率计算发送一位需要的时间。波特率由主机决定。
接着就是时钟相位,也就是时钟信号SCK的第一个边沿出现对应位置在数据传输周期的开始位置还是中央位置。是不是有点绕,那看图说话,直接理解了。
上面是开始位置,下面是中间位置,注意是第一个时钟信号的边沿啊。
这里还要注意就是时钟极性和相位主从机必须设置一致(如果从机是不可编程的,那么要根据从机时序决定)
那么对于从机来说是不是还要看个时序图,那什么是时序图?
就是根据时间做不同的动作,就是时序图会把大家搞晕吧。我们来看一个时序图:
根据上面对单片机SPI的分析,拿到这个从机的时序图你能分析出一些什么呢?
如果根据这个时序图让你来做模拟SPI通信,你是否可以实现呢?(平时设计项目或产品碍于各种问题不得不用普通管脚实现SPI通信,这是很常见的)
-
白话文讲解STM32时钟树
时钟就像是单片机的“心脏”,单片机正常工作离不开时钟的支持,下图是我们单片机的时钟树 ,它反映了单片机的时钟关系。我们来详细描述一下时钟树的工作原理。
寄存器上电后有一个复位值,大家看我画红线的这个,这个是单片机上电默认使用时钟的配置线路,默认使用的是内部默认的8M RC振荡器,有两条路可以选,我们先看上面红色的第一条,到多路选择器SW的时候,我们可以通过配置寄存器中的SW位来决定HSI/PLLCLK/HSE哪一个输入信号从多路选择器通过,在默认的状态下SW选择的是HSI8M从多路选择器通过。
通过了SW这个选择开关后,第一个是SYSCLK 一路朝上可以供I2C1选择时钟,另外一个就是继续向后,通过AHB 这个方框,在这里我们可以配置寄存器选择这个8M是否分频,默认是不分频 也就是经过这个方框后出来往后的还是8M,如果这里配置为2分频,方框出来后就是 4M 了,经过AHB分频出来后还是8M ,这个8M 提供给了很多路大家可以从上面的图中看出来,那么继续向后是 APB 分频
这里分了两个箭头指向,一个是朝上的给AHB总线 、内核、Memory 、DMA、内核定时器和FCLK。从这里我们可以看到 内核是8M时钟(这个频率决定了单片机指令的执行时间,频率越小,指令执行速度越慢),一路是向后给了APB分频器,这里可以配置你想要的分频系数,如果这里还是不分频出来的PCLK 还依然是8M,那么PCLK又给了 APB外设 ,还给了定时器、串口等外设。通过这个关系,我们可以清楚的知道,每个外设的工作频率,那可能就会有人问了,这有什么用呢?每个外设都需要时钟来提供振荡源来帮助完成工作,举个例子讲,比如说串口配置一个波特率,那么波特率(通信速率,表示每秒钟传送的数据的位数,即bit/s)是如何来配置呢,就是根据这个时钟频率来配置的,知道了时钟频率,厂家有一个计算公式,就能很容易的算出某一个波特率对应的寄存器值是多少。
默认的我们知道了,M0支持最大48M,内部RC振荡器只有8M,这个咋整呢?不要慌,我们继续往下看。
既然HSI直接给SW多路选择器,不能到48M,那我不直接给通过SW了行不行,请看图中箭头处,HSI绕一下从 PLLSRC 多路选择器通过,那么PLLSRC多路选择器也有两个选择可以通过寄存器配置,假设配置寄存器选择 HSI作为输入,多路选择器输出后经过PREDIV分频器,假设 PREDIV 我们配置不分频,这个分频器出来输入到PLL模块的时候还是8M
PLL模块起到 一个倍频的作用,大家可以看到方框里面是乘2 3...,如果这个时候我们配置寄存器设置PLLMUL为6,那么出来的PLLCLK是 48M,那么这个时候 SW多路开关选择 PLLCLK作为输入,后面出来的时钟就是48M了,再往后面就跟上面讲的情况一样了,可以自由去配置分频
使用内部RC振荡器我们理解了,但是内部的振荡器往往会因为,精度低,受温度影响比较大等情况,不会被选择,这个时候工程师们就会选择使用外部晶振,外部晶振也是一样的配置方式,大家是否能根据上面讲的思路,配置出来呢? -
单片机学习之基础篇
①寄存器
寄存器,是集成电路中非常重要的一种存储单元,在集成电路设计中,寄存器可分为电路内部使用的寄存器和充当内外部接口的寄存器这两类。内部寄存器不能被外部电路或软件访问,只是为内部电路的实现存储功能或满足电路的时序要求。而接口寄存器可以同时被内部电路和外部电路或软件访问,CPU中的寄存器就是其中一种,作为软硬件的接口,为广泛的通用编程用户所熟知。
我们举例STM32的一个寄存器:
1. 关于学习资料
对于学习一款单片机而言,资料不需要很多,最主要的还是芯片的手册,手册里面会体现出你想要的,有的人忽视手册,想要通过某种捷径直接去跳过这一步,在这里我想说,除非你有一定的了解,有信心前面的过程不会出现问题,否则还是老老实实的去啃手册,下面我们来介绍下学习STM32F373CCT6这款单片机我们用到的文档:
1.《STM32F373_Reference_Manual》是 ST 出的官方资料,有 STM32F3的详细介绍,包括了STM32F3 的各种寄存器定义以及功能等,是学习 STM32F3 的必备资料之一。
2.《STM32F373xx》也是 ST 出的官方资料,有关于芯片引脚定义,模块功能概括,以及芯片的电气属性等介绍,是学习 STM32F3 的必备资料之一。
3. 《STM32F3 与F4 系列 Cortex M4 内核编程手册》 则是对 上述资料的补充, 很多关于 CortexM4 内核的介绍(寄存器等) ,都可以在这个文档找到答案,该文档同样是 ST 的官方资料,专门针对 ST 的 Cortex M4 产品。4. 《Cortex M3 与 M4 权威指南》则针对 Cortex M4 内核进行了详细介绍,并配有简单实例,对于想深入了解 Cortex M4 内核的朋友,此文档是非常好的参考资料。
2. 关于学习方法
首先你要有个实验平台,不管资料再多这些资料的来源依据还是数据手册,一定要自己去对着数据手册仔细研读,自己独立动手配置,在平台上去做实验。只有不断的实验你才能理解。当遇到问题时不要在第一时间去网上搜索答案,再去研读数据手册,解决不了的时候,再试图去网上参考借鉴一下其他朋友的案例。
3. MDK5软件的使用
3.1 STM32 官方 标准 固件库简介
ST(意法半导体)为了方便用户开发, 提供了一套丰富的 STM32 固件库。 到底什么是固件库?它与操作寄存器有什么区别?这一节,我们将讲解 STM32 固件库相关的基础知识, 希望能够让大家对 STM32固件库有一个初步的了解。
3.1.1 库开发与寄存器开发的关系
固件库就是函数的集合,固件库函数的作用是向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API) ,最终操作的还是寄存器。
在 51 的开发中我们常常的做法是直接操作寄存器,比如要控制某些 IO 口的状态,我们直接操作寄存器:
我们写成十六进表示:P0 = 0xAA;
而在 STM32 的开发中,我们同样可以操作寄存器:
GPIOA->BSRR=0x0001;
为了省却麻烦, ST(意法半导体)推出了官方固件库, 固件库将这些寄存器底层操作都封装起来, 提供一整套接口 (API)。
比如上面的控制 BSRR 寄存器实现对某一引脚的电平控制,官方库封装了一个函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BSRR = GPIO_Pin;
}
②位操作
C 语言位操作相信学过 C 语言的人都不陌生了,简而言之, 就是对基本类型变量可以在位级别进行操作。这里简单再复习一下。我们讲解几种位操作符,然后讲解位操作使用技巧。
运算符
含义
运算符
含义
&
按位与
~
取反
|
按位或
<<
左移
^
按位异或
>>
右移
1. 不改变其他位的值的情况下,对某几个位进行清0
GPIOA-> BSRR = GPIOA-> BSRR & 0XFF0F; //将第 4-7 位清 0
不改变其他位的值的状况下,对某几个位进行置1
GPIOA-> BSRRL = GPIOA-> BSRRL | 0X0040; //设置相应位第6位的值,不改变其他位的
2. 移位操作
GPIOx->ODR = 1 << 2; //1<<2 = 4 相当于把4赋给了ODR寄存器
GPIOx->ODR = 4 >> 2; //4<<2 = 1 相当于把1赋给了ODR寄存器
~取反操作 //用来对一个二进制数按位取反,即0变1,1变0。
GPIOx->ODR = ~GPIOx->ODR;
3. ^按位异或 //若参加运算的两个二进制位值相同则为0,否则为1.
GPIOx->ODR = 0x05^GPIOx->ODR;
以上就是做单片机控制的基础知识,踏实学了可以节省时间和精力去做应用模块的逻辑和算法了。基础扎实了会让产品更稳定,不能模棱两可的设计,否则故障会意想不到的出现。