初学者即将毕业实习,希望利用最后两个月的学习顺利找到工作,占个地方做些笔记O(∩_∩)O哈哈~

2019-07-20 23:27发布

本帖最后由 229382777@qq.com 于 2017-2-28 10:58 编辑

        买了原子的mini开发板快一年了,一直都是断断续续的学,学习进度经常被打断,导致现在连前面的知识也忘的差不多了,自身学习的条件可能没有大学生好,即将面临毕业实习,希望在最后这两个月能把mini教程全部过完并掌握,争取出去后能适应的了这方面的工作。在此借原子哥的宝地一用,也方便自己日后的复习,学习过程中可能会出现挺多错误的地方,也希望大家能帮忙指出其中错误的地方。为了保证自己的身体健康,不忙的情况下一般都会晚上9点前进行更新,每天会坚持去操场跑步。希望各位也注重身体健康,身体是革命的本钱O(∩_∩)O!

目录

所在页数 所在楼层楼层主题 1
1
1
1
1
1
1
1
2
2
2
2
2
2
2
2
3
3
3
3
3
3
3
3
4
4
4
4
4
4
4
4
4
4
4
42#  
20#
25#
32#
38#
41#
44#
46#
54#
59#
60#
63#
71#
78#
85#
86#
100#
106#
110#
117#
122#
134#
144#
148#
152#
154#
155#
158#
163#
164#
167#
171#
173#
176#
185#
189#之后硬件篇
SYSTEM文件部分(一)
SYSTEM文件部分(二)
LED灯
按键
串口
外部中断
独立、窗口看门狗
定时器中断
PWM互补输出及死区时间
输入捕获
OLED
LCD
LCD(二)
RTC
待机唤醒
ADC
内部温度传感器
DAC
DMA
IIC
SPI
触摸屏
FLASH模拟EEPROM
内存管理
SD卡
FATFS
汉字显示实验
图片显示
IAP
触控USB鼠标实验
M3内核基础知识
UCOS任务调度
UCOS信号量和邮箱
消息队列、信号量、软件定时器
知识点分享
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
55条回答
it_do_just
1楼-- · 2019-07-24 02:30
 精彩回答 2  元偷偷看……
it_do_just
2楼-- · 2019-07-24 08:12
早上好………
brilliant
3楼-- · 2019-07-24 13:21
回复【18楼】229382777@qq.com:
---------------------------------
早上好  苦逼大四学生  马上毕业 实习了  一直在自学 不说了  得去上课了 迟到两分钟了 加油
it_do_just
4楼-- · 2019-07-24 13:55

SYSTEM文件部分(一)

先让我把这个图记一下(以后提醒自己多用堆栈窗口和内存窗口调试程序)

启动代码:

原子哥教程里面看到这句话,刚好有这方面的资料,资料对startup_stm32f10x_hd.s里面的200多行的汇编代码进行了详细的讲解,附件在底下,强烈建议看一下!

时钟树:经常要去找挺麻烦的,贴上以后直接在这看了


HSE时钟
高速外部时钟信号(HSE)由以下两种时钟源产生:
● HSE外部晶体/陶瓷谐振器
● HSE用户外部时钟
为了减少时钟输出的失真和缩短启动稳定时间,晶体/陶瓷谐振器和负载电容器必须尽可能地靠
近振荡器引脚。负载电容值必须根据所选择的振荡器来调整。

HSI时钟

HSI时钟信号由内部8MHz的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。
HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比HSE晶体振
荡器短。然而,即使在校准之后它的时钟频率精度仍较差。

 PLL

内部PLL可以用来倍频HSI RC的输出时钟或HSE晶体输出时钟。
PLL的设置(选择HIS振荡器除2或HSE振荡器为PLL的输入时钟,和选择倍频因子)必须在其被激
活前完成。一旦PLL被激活,这些参数就不能被改动。
如果PLL中断在时钟中断寄存器里被允许,当PLL准备就绪时,可产生中断申请。
如果需要在应用中使用USB接口, PLL必须被设置为输出48或72MHZ时钟,用于提供48MHz的
USBCLK时钟。

LSE时钟

LSE晶体是一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟或者其他定时功能提供
一个低功耗且精确的时钟源。
LSE晶体通过在备份域控制寄存器(RCC_BDCR)里的LSEON位启动和关闭。
在备份域控制寄存器(RCC_BDCR)里的LSERDY指示LSE晶体振荡是否稳定。在启动阶段,直
到这个位被硬件置’1’后, LSE时钟信号才被释放出来。如果在时钟中断寄存器里被允许,可产
生中断申请。

LSI时钟

LSI RC担当一个低功耗时钟源的角 {MOD},它可以在停机和待机模式下保持运行,为独立看门狗和
自动唤醒单元提供时钟。 LSI时钟频率大约40kHz(在30kHz和60kHz之间)。进一步信息请参考数
据手册中有关电气特性部分。
LSI RC可以通过控制/状态寄存器(RCC_CSR)里的LSION位来启动或关闭。
在控制/状态寄存器(RCC_CSR)里的LSIRDY位指示低速内部振荡器是否稳定。在启动阶段,直
到这个位被硬件设置为’1’后,此时钟才被释放。如果在时钟中断寄存器(RCC_CIR)里被允许,
将产生LSI中断申请。

时钟安全系统(CSS)

时钟安全系统可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被
使能,并在HSE时钟关闭后关闭。
如果HSE时钟发生故障, HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和
TIM8)的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。此CSSI中断连接到
Cortex?-M3的NMI中断(不可屏蔽中断)。

系统时钟(SYSCLK)选择

系统复位后, HSI振荡器被选为系统时钟。当时钟源被直接或通过PLL间接作为系统时钟时,它
将不能被停止。
只有当目标时钟源准备就绪了(经过启动稳定阶段的延迟或PLL稳定),从一个时钟源到另一个时
钟源的切换才会发生。在被选择时钟源没有就绪时,系统时钟的切换不会发生。直至目标时钟
源就绪,才发生切换。
在时钟控制寄存器(RCC_CR)里的状态位指示哪个时钟已经准备好了,哪个时钟目前被用作系统
时钟。



Delay.c (寄存器版本和库函数版本差别不大)

SysTick定时器
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操
作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,
为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期
的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时
器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问
它的寄存器,以维持操作系统“心跳”的节律。
Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时
器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,
CM3上的自由运行时钟),或者是外部时钟(CM3处理器上的STCLK信号)。不过,STCLK的
具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视
芯片的器件手册来决定选择什么作为时钟源。
SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一
席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3
产品间对其处理都是相同的。



延时的 ms 数不能太长。否则超出了 LOAD 的范围,高位会被舍去,导致延时不准。最大延迟 ms 数可以通过公式: nms<=0xffffff*8*1000/SYSCLK 计算。 SYSCLK单位为 Hz, nms 的单位为 ms。如果时钟为 72M,那么 nms 的最大
值为 1864ms。超过这个值,建议通过多次调用 delay_ms 实现,否则就会导致延时不准确。


后面delay_ms()和delay_us()两个函数就根据上面的fac_us和fac_ms进行乘法运算

OS自己还没接触过,不过看了原子哥的时钟摘取的方法也是脑洞大开


Sys.c
(寄存器版本和库函数版本的差别有点大,库函数只介绍了位带操作,而寄存器版本的教程信息量好大…..)

位带操作



支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,

有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区

的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自
己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访

问这些字时,就可以达到访问原始比特的目的。

按上面这幅图的计算公式再来看原子哥的代码就能大概看懂什么意思了,原子哥真牛B,一直不怎么会使用#define,以后也学着这样写试试

<<CM3 权威指南>>第五章(87 页~92 页),对比了使用位带操作和不使用位带操作的区别,包括读、写、以及汇编代码的区别。

 

*((volatile unsigned long *)(addr))这个解释下面该论坛的大神已经解释的很清楚了,简单明了

http://www.openedv.com/posts/list/918.htm


“<<和>>实现乘除法的优势”:位操作只需一个指令周期即可完成,而大部分的C 编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。通常,只要求是求2n 方的余数,均可使用位操作的方法来代替。通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,提醒自己以后尽量多用移位来代替乘除。


Stm32_Clock_Init(9):
库函数版本加了SystemInit,寄存器用的是原子哥写的一个Stm32_Clock_Init(9);函数

寄存器使用的是Stm32_Clock_Init(u8 PLL),库函数使用的SystemInit(),这两个里面的代码几乎都是一样的

1、先是复位配置向量表

2、配置中断向量表基址和偏移量

3、使能外部时钟HSE

4、倍频PLL选择为9倍频,即72Mhz

5、PLL作为系统时钟


Sys.c其中有这个函数还挺好用的,直接调用就能实现软复位

void Sys_Soft_Reset(void)

{  

       SCB->AIRCR =0X05FA0000|(u32)0x04;        

}    


低功耗一览表


进入待机模式

库函数:PWR_EnterSTANDBYMode()

寄存器:Sys_Standby() -> 这里面有一个函数是WFI_SET()用于进入模式的操作

__asm void WFI_SET(void)

{
         WFI;

}

该函数其实是在 C 语言里面嵌入一条汇编指令,因为CM3 内核的 STM32 支持的 THUMB 指令,并不能内嵌汇编,所以需要通过这个方法来实现汇编代码的嵌入。

__asm关键字:启动内联汇编并且能写在任何c/c++合法语句之处.它不能单独出现.它必须接汇编指令、一组被大括号包含的指令或一对空括号.术语“__asm 块”在这里是任意一个指令或一组指令无论是否在括号内。括号可以清晰的将C或C++代码和汇编代码分开,并且避免了不必要的重复__asm关键字。括号也能避免模糊性。

下面原子哥还有几个类似的函数,记录下方便以后调用

//关闭所有中断
__asm void INTX_DISABLE(void)
{
         CPSID I;

}
//开启所有中断
__asm void INTX_ENABLE(void)
{
         CPSIE I;

}

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr)
{
         MSR MSP, r0 //set Main Stack value
         BX r14

}


JTAG和SWD模式设置

// mode: JTAG,SWD 模式设置;00,全使能;01,使能 SWD;10,全关闭;

寄存器:void JTAG_Set(u8 mode) //用于设置 JTAG 的模式

库函数:GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

龙之谷
5楼-- · 2019-07-24 17:04
非常棒,nice!!!!!

有个小问题:图中LSE是外部低速时钟,标注成了32M。
it_do_just
6楼-- · 2019-07-24 17:07
 精彩回答 2  元偷偷看……

一周热门 更多>