拥抱ARM妹子 第五章:拨启妹子心灵的悸动

01 Keil start splash png

终于要等到唤醒妹子的这一天啦。立即准备迎接妹纸新生的一切。嗯~给她买件合适的衣服!给她~~ 准备套洗漱用品!! ~~ ~ 哇咔咔 ~~ ~

等等!! 还是自己把口腔清洁一下,准备世纪之吻!!哇咔咔~~ 这就是传说中的睡美人,接受王子这魅力一吻后苏醒的场景吗???吼吼 ~~ ~ 对去刷牙!! 吼吼~~~ -_-!! 好吧,俺想入非非啦。

开发环境继续沿用Keil ARM 的IDE,51时熟悉的环境,可以节省IDE环境熟悉过程,比较适合我。网络真是好东东,搜一下一堆MDK。下载安装注册一气呵成。打开IDE很亲切,环境布局一点都米有变,和51完全一样。看来一切都在俺的掌控中。

偷偷告诉你们,Keil的代码编辑器实在太水,多字节字符(中文)支持比较差。不太喜欢它的文本编辑器,随便找个代码文本编辑器都比它强-_-!!。话说回来,人家公司用大量的人力物力开发的产品,俺不交保护费还在这里说三道四实在不该。还是得感谢做出这么方便的IDE给我试用。

快速创建一个ARM工程,只要点几下鼠标就OK啦。

一、创建测试工程

1、选择Project->New uVision Project...保存工程文件

02 new project png

2、选择ARM芯片规格【STM32F103C8

03 select CPU png

3、生成启动文件OK。

04 Create startup file png

4、完成V~~~ 一堆符文##!@#!¥!@#¥ .....

05 final create png

接下来木~~ 接下来木~~ -_-!! 哇~~ ~ 卡住啦~~ ~

得去了解芯片的IO脚怎么拉低拉高电平,LED就可以点亮咯。拿出葵花宝典外传《STM32F103参考手册》傻眼啦,这个要比51复杂多啦,光目录就分了20个部分。不愧为盖世秘笈,欲练神功必先自宫~~ ~ 。”!! 妹纸啊,哥难道要去做阉人不成??_!!拿刀来~~ ~ 哥去削苹果!!!

找找IO口说明,内容挺多的... ...

06 Guide IO png

翻到60页... 这个也太强了,就一个小小的IO口就如此复杂。这可难杀我也~~ ~ 一下子跌入万丈深渊,妹纸~~~ 等哥我爬上来再相会!

07 IO frame png

去找教材去,^_^看来小弟还是非常幸运的,材料是大把大把的。看来能很快从深渊爬出,与妹子相会。 经过快速入门,习得三脚猫功夫。这个图看似很复杂其实很简单,就是2块输入和输出。要控制引脚电平的高低,只要看输出就OK啦。这个和STC的51一样有推挽输出。比51强大的是,引脚可以非常灵活的配置。

09 IO Config png

从图表上可以看到,只要设置3个状态,就能实现推挽输出高低电平。

1、设置端口功能 CNF 2、设置模式 MODE 3、设置输出PxODR 1 & 0

10 IO Outup config png

吼吼~~ ~ 还是很简单的嘛!~ LED小灯泡就可以闪亮闪亮咯。每个IO口都可以控制,这个太强大了。一共 A~E 5组IO口,每组由16个IO。16x5=?? 啊~~ 不会算乘法啦~

11 IO config register setup png

俺妹的核心A、B组的IO是全的,共37个IO。

12 IO array png

想要B0端口其效果,那只要设置GPIOB_CRL3~0 位寄存器为0011就大功告成了。

继续写程序!创建一个main.c文件,保存并把文件加入到工程组。右击工程组->Add Existing Files to Group 'Source Group 1'...

13 test project building png

V~~~ Rebuild! 呃~~~ 1 Error

d:\Keil\ARM\Inc\ST\STM32F10x\stm32f10x.h(96): error: #35: #error directive: "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)"

大致意思:请选择STM32F10x驱动。

双击一下错误行,直接定位到报错位置。是STM32的头文件定义报错了。

14 define stm32 device png

根据上面的描述,意思大致是需要告诉头文件,你用的芯片Flash是多少K的。噢噢~~~ 妹子的心是STM32F103C8Flash64K。那就是需要定义STM32F10X_MD编译开关。其实在选ARM芯片的时候已经明确,生成的startup_stm32f10x_md.s启动文件命名中标明是MD( Medium density devices) 。这个只能说明IDE还是不够智能=_=,需要自己加STM32F10X_MD的编译开关。 直接在main.c 的都可以行加入 #define STM32F10X_MD

15 define compile switch and new error png

“大哥!为啥要加第一行呀?”
“这个嘛,是编译器问题!你必须首先给他一些基本说明,后边编译器才会知道你的意图。”。

OK,继续Rebind!天哪~~~,为啥有这么多问题???

.\test.axf: Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_md.o).

Error:未定义类型 SystemInit (来源 startup_stm32f10x_md.o)

是启动文件中找不到SystemInit这个定义,打开startup_stm32f10x_md.s搜索SystemInit

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

启动文件中导入了一个SystemInit的函数,但是并没有定义这个函数。这个简单只要在main.c中定义这个函数。

16 define fun SystemInit png

二、软件仿真

吼吼~~ Rebind!!编译成功咯。开启软件仿真模式。

17 set debug mode png

启动仿真。点开分析界面。 可以先看看效果^^ 。噢~~ ~~ ~ 状态一片绿色,延迟太短了。稍微改一下延迟过程,呵呵~~ 1s一次,嗯LED的拉高拉低1秒闪烁一次应该能看清了。

18 debug test program png

点开引脚可以非常清楚的看到,实际设置B组引脚的状态信息。PB0脚是推挽输出,模式3输出50MHz

19 General purpose IO B States png

IDE确实比较方便,不用烧写硬件就能看到实际的状态。大功告成,妹子被我的世纪之吻惊扰了吗??马上上电烧写!!!小弟直接上高级品J-Link进行烧写。哇咔咔!!!一步到位以后硬件调试也方便,看来俺太懒了-_-!!。做板子的时候考虑先加烧写接口,但不知道应该加那种比较适合自己。翻来覆去还是决定取消没加调试口。主要考虑其一直接杜邦线插能强化各引脚功能记忆,其二是完全没经验那种适合我,而且是连初学都不如,万一错了又得哭泣啦。基于这2个因素考虑,这版本不加调试接口。作为初级学习还是非常适合。将来熟悉再重新打样,知道自己需要什么,常用外围设备会相对固定,那时的版本就适合中级水准的我啦。哇~~ 咔~~ ~咔~~ ~ “嗯~ 俺太自恋啦~~”!

JTAG正常调试接口有20个引脚,让小弟插20条杜拜那也可怕了。还好有串行调试(Serial Wire)接口,只要2根线就能搞定。根据SW要求实际还要2根线GND参考电压。看来只要4跟杜邦就能搞定下载工作咯。^_^,VV~ 接下来就是怎么连接到JTAG那20个接口上对应的位置。

20 SW Debug IO

SW连接还是很简单的,只用4根线就完成了(前提:你的JTAG支持SW模式)。连接完成开始准备烧写,把工程编译成HEX格式。设置工程属性,选中Create HEX File 选项

21 set create HEX file property

打开SEGGER J-Flash ARM 烧写程序,打开编辑的工程文件【test.hex】。开始烧写

1、连接ARM 【Target -> Connect】 2、下载程序 【Target -> Program & Verify】

22 download bin fine png

提示成功下载,OK大功告成啦。连接LED进行测试。~~ ~~ ~~ ~ ~ 噢,NO~~ ~ ~ LED不亮。老天为啥总喜欢和我寻开心啊,难道我不够心诚?难道俺的吻不够热烈?仰天长叹~~ ~ 掉进无底深渊,妹子啊,等哥回来~ 来~~ ~ 来~~ ~ ~。

三、ARM时钟树 PLL锁相环

继续爬文~~ 噢,次拿!台湾人才说爬文~~ 看来需要俺重振雄风,翠花上咖啡!

原来51和ARM的晶振使用完全不同。STC51只要连接晶振,在烧写时设置外部晶振就能正常使用,而ARM~~ 和引脚一样又是一张非常复杂的设置图。

23 clock tree png

ARM有2种时钟高速和低速,内部集成了这2种时钟,高速的是8MHz,低速的是40KHz。-_-!! 难道我多焊了2颗多余的晶振啦?51也有内部的,不管啦,当然是用外部晶振咯。在葵花宝典上还提到一种叫PLL的时钟。这个东东是啥,完全没有概念。看图上N多PLL标识,看来一定是很有用的东东。

PLL 锁相环: “万能的网络啊,快快告诉我PLL是啥鸟玩意?”
“PLL是锁相环”,
“啊~~ 啥~~ 万能的网络啊,请你再说一次吧!”
“PLL是锁相环”
“万能的网络啊,怎么有这么拗口的东东,到底是气啥作用的?”
“你这小子太懒惰,说明书~ ”,万能的网络丢下一个网页,佛袖而去~~

PLL(锁相环)原来是一种很高级的时钟电路,精度很高。--!! 完全没电子基础概念,还是看的云里雾里。只知道一点PLL是个好东东。^^

看时钟树终于明白最高时钟频率72MHz是怎么来的,外部8MHz的晶振是可以通过PLL(锁相环)这个东东配置产生72MHz时钟。

24 HES 72MHz setup png

从外部高速时钟(HSE)到达72MHz的迷宫路线图^_^,发现有好几机关。

1、PLLXTPRE
2、PLLSRC
3、PLLMUL
4、SW

路线真是曲折。外部 8MHz * 9 = 72MHz,这个迷宫粗看复杂,其实细看还是很简单的。按照图上的意思,要使用USB功能就必须启动PLL。其他外设都是通过系统时钟,再进行细分。需要设置的寄存器也基本可以知道。 按上述妹子72MHz的心跳作战地图,呃~~ ~ 妹子的心是高速的心 ~ ~

1、启动外部时钟
2、启动PLL
3、关闭内部时钟

25 HES PLL Open png

迷宫战略地图上的路径。还有2部分蓝色PLL部分和紫色设备部分。AHB外设总想STM分成2类,低速36MHz和高速72MHz。系统时钟在72MHz状态下,那是肯定需要降低APB1上的时钟。除以2就能满足36MHz的需求。

“干嘛APB1必须最高36MHz?”,
“这个木设计如此”,hoho~~~ 高了天晓得会发生什么情况。

第五个圈圈USB设备必须保持48HMz的速度,“哥,你不想用USB?”,那就不鸟他,“想用?” 72 /1.5 = 48正好噢。STM都帮我算好啦。

初始值:0000 0083
二进制:0000 0000 0000 0000 0000 0000 1000 0011
设置完:0000 0001 0000 0001 0000 0000 1000 0010
最终值:0 1 0 1 0 0 8 2

解决了设备,后面PLL方便,只要选择正确的路线开关,倍频设置x9。系统时钟72HMz就这么容易的出来啦。

26 RCC config register png

根据上面的数值拼凑出二进制 00000 000 0 0 0111 0 1 00 000 100 0000 00 10 整理一下,

二进制:0000 0000 0001 1101 0000 0100 0000 0010
十六进制:0 0 1 D 0 4 0 2
整理 0x001D0402

哒~ ~ 哒~~ ~ 哒~~ ~~ ~~ ~~ ~ ~ 配置时钟的值搞定咯。

配置信息都确定好了,就剩下修改程序咯。是SystemInit这个函数起效的时候到了。

void SystemInit(void)
{
  // 使用外部8MHz晶振,启用PLL设置系统时钟为 72HMz
  // USB 可用
  // APB1 低速总线 36HMz
  // APB2 高速总线 72HMz
  RCC->CFGR = 0x001D0402;
  RCC->CR   = 0x01010082;
  // 确定外部高速晶振起效
  while (!(RCC->CR>>17));
  // 确定PLL设置起效
  while (!(RCC->CR>>25));
}

代码OK~ 调试看效果。打开配置状态界面 Perripherals -> Power,REset and Clock Control<./kbd>

27 rewrite systeminit fun set RCC

调试结果和实际的需求完全一致,使用外部晶振,开启锁相环(PLL),设置系统时钟为72HMz,低速外设为36MHz。万事具备,只欠哥给妹子一个深深的吻。

#给你一个吻~ ~ ,可以不可以~~#

重复下载步骤!... .... ....

啊~~ ~~ ~~ ~ 妹子啊,俺的妹子啊!! 你为啥还是不醒啊!!此时已经是半夜3:30~~ ~ -_-!!

只得求助网络上的大神们的指点。经过反复对照大神们初始化过程之间的差异。反复了N次啊,N次~~~ !终于在一个阴暗的角落里看到差异所在。FLASH->ACR(访问控制寄存器)这个东东未设置过!按照大神们的说法这个需要设置成 0x32。具体在『STM32F10xx闪存编程手册』上有详细说明,从葵花宝典之参考手册上确认了这点。

FLASH_ACR 复位值:0x0000 0030 
  LATENCY:时延
  这些位表示SYSCLK(系统时钟)周期与闪存访问时间的比例
    000:零等待状态,当 0 < SYSCLK ≤ 24MHz
    001:一个等待状态,当 24MHz < SYSCLK ≤ 48MHz
    010:两个等待状态,当 48MHz < SYSCLK ≤ 72MHz

根据上面的意思,如果系统时钟小于等于24MHz。那么系统运行是不会出问题的。俺妹在72MHz,-_-!!! 那意思运行程序肯定是有问题的,应该设置为 010 两个等待状态。重新修改初始化函数

void SystemInit(void)
{
  unsigned char dump = 0;

  // 使用外部8MHz晶振,启用PLL设置系统时钟为 72HMz
  // APB1 低速总线 36HMz 
  // APB2 高速总线 72HMz
  RCC->CFGR = 0x001D0402;
  RCC->CR   = 0x01010083;

  // 闪存访问延迟,48MHz ~ 72MHz = 010。 复位值:0x30
  FLASH->ACR = 0x32;

  // 确定外部高速晶振起效
  while (!(RCC->CR>>17));
  // 确定PLL设置起效
  while (!(RCC->CR>>25));
  // 确定PLL为系统时钟源
  while(dump != 0x02) {
    dump = RCC->CFGR >> 2;
    dump &= 0x03;
  }       

  // APB2 B组引脚使能
  RCC->APB2ENR = 0x00000009;
}

重新编译再次下载!!!妹子~~ 我的~ 子~~ 终于等到你苏醒的这一刻~~~ ... ... ... ...

.
第一季 完结散花
.


相关内容:

  • Keil ARM 开发调试
  • GPIO 功能配置
  • 系统时钟配置

相关资源:

  • STM32中文参考手册_V10.pdf
  • STM32闪存编程.pdf

推荐资源:

  • 李想老师的STM32视频

拥抱ARM妹子