第五章:拨启妹子心灵的悸动
终于要等到唤醒妹汁的这一天啦。立即准备迎接妹纸新生的一切。嗯~给她买件合适的衣服!给她~~准备套洗漱用品!! ~~~ 哇咔咔 ~~~
等等!! 还是自己把口腔清洁一下,准备世纪之吻!!哇咔咔~~ 这就是传说中的睡美人,接受王子这魅力一吻后苏醒的场景吗???吼吼 ~~~ 对去刷牙!! 吼吼~~~
-_-!! 好吧,俺想入非非啦。
开发环境继续沿用Keil ARM 的IDE,51时熟悉的环境,可以节省IDE环境熟悉过程,比较适合我。网络真是好东东,搜一下一堆MDK。下载安装注册一气呵成。打开IDE很亲切,环境布局一点都米有变,和51完全一样。看来一切都在俺的掌控中。
01 Keil start splash png
偷偷告诉你们,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_CRL的 3~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的。噢噢~~~ 妹汁的心是STM32F103C8,Flash是64K。那就是需要定义【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跟杜邦就能搞定下载工作咯。^_^,V~~V~~~
接下来就是怎么连接到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不亮。老天为啥总喜欢和我寻开心啊,难道我不够心诚?难道俺的吻不够热烈?仰天长叹~~~掉进无底深渊,妹汁啊,等哥回来~ 来~~~ 来~~~~。
继续爬文~~ 噢,次拿!台湾人才说爬文~~ 看来需要俺重振雄风,翠花上咖啡!
原来51和ARM的晶振使用完全不同。STC51只要连接晶振,在烧写时设置外部晶振就能正常使用,而ARM~~ 和引脚一样又是一张非常复杂的设置图。
23 clock tree png
ARM有2种时钟高速和低速,内部集成了这2种时钟,高速的是8MHz,低速的是40KHz。-_-!! 难道我多焊了2颗多余的晶振啦?51也有内部的,不管啦,当然是用外部晶振咯。在葵花宝典上还提到一种叫PLL的时钟。这个东东是啥,完全没有概念。看图上N多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】
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
百度网盘:http://yun.baidu.com/share/link?shareid=3295581999&uk=2754976235
推荐资源
李想老师的STM32视频 http://pan.baidu.com/s/1DuDY2